fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(search): hide unready Tavily WebSearch - #3168

Merged
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness
Aug 17, 2026
Merged

fix(search): hide unready Tavily WebSearch#3168
Astro-Han merged 2 commits into
apache:mainfrom
YayoiNanoka:agent/websearch-tavily-readiness

Conversation

@YayoiNanoka

@YayoiNanokaYayoiNanoka commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Problem

When Web Search selected Tavily, the effective model tool surface kept advertising WebSearch even when the canonical runtime-policy resolver reported that the Tavily or required proxy credential was unavailable. The model could therefore spend a turn calling a tool that was guaranteed to fail, and child-agent composition could advertise the web_research profile without a runnable search tool.

The existing call-time fail-closed check remains necessary, but it happens after the model has already chosen the tool.

Solution

  • Derive Tavily readiness from the existing canonical resolveWebSearchExecution({ provider: 'tavily' }) authority.
  • Pass that readiness into the unified routeWebSearchTools() seam and retain the client-executed WebSearch only when the result is ready.
  • Apply the same routed surface to root, bound, and child tools, so web_research is omitted when Tavily cannot run.
  • Preserve provider-native search behavior: selecting model still depends only on the selected model's hosted-search capability and never requires a Tavily credential.
  • Keep the call-time fail-closed guard as defense in depth.

Closes#2085.

Verification

  • npm --workspace @maka/runtime run typecheck
  • npm --workspace @maka/runtime-host run typecheck
  • Biome check for all 7 touched files
  • Focused Runtime and Runtime Host WebSearch tests: 10/10 passed
  • Relevant Runtime Host production lifecycle tests: 2/2 passed
    • canonical AI SDK session omits unready Tavily WebSearch
    • child-agent surface omits web_research when Tavily is unavailable

Broader checks attempted:

  • npm run build:test compiled Code Mode, Core, Storage, MCP, Runtime, Runtime Host, Computer Use, Eval, and the CLI, then stopped in untouched UI files on existing interface mismatches involving settledText, conversationKey, and unlockAutoFollow.
  • The full Runtime test file was not claimed green: unrelated macOS sandbox/process smoke tests cannot run in the managed sandbox, and unrelated model-factory streaming assertions also failed. The focused WebSearch suite is green.

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex assisted with repository analysis, implementation, regression tests, and review revisions. The human contributor reviewed, tested, and accepted the final change.

点击展开中文

问题

当联网搜索选择 Tavily 时,即使 Runtime Policy 的权威解析器已经确认 Tavily 凭证或必需的代理凭证不可用,WebSearch 仍然会出现在模型可见的工具列表中。模型可能因此浪费一轮调用一个必然失败的工具,子代理表面也可能错误地提供无法真正执行搜索的 web_research

现有的调用阶段 fail-closed 检查仍然有必要,但它发生在模型选择工具之后,无法避免这次无效调用。

解决方案

  • 复用现有的权威检查 resolveWebSearchExecution({ provider: 'tavily' }) 获取 Tavily 就绪状态。
  • 将就绪状态传入统一的 routeWebSearchTools();只有结果为 ready 时,才保留由 Runtime 执行的 WebSearch
  • 根任务、受限工具表面和子代理工具表面全部使用相同的路由结果;Tavily 不可用时同时移除 web_research
  • 保持模型原生搜索逻辑不变:选择 model 时只检查当前模型是否支持原生联网搜索,不要求 Tavily 凭证。
  • 保留调用阶段的 fail-closed 检查,作为第二层保护。

验证

  • Runtime 与 Runtime Host 类型检查通过。
  • 7 个修改文件的 Biome 检查通过。
  • WebSearch 聚焦测试 10/10 通过。
  • 相关 Runtime Host 生产生命周期测试 2/2 通过:根任务不再暴露不可用的 Tavily WebSearch,子代理也不再暴露不可用的 web_research

更大范围检查中,npm run build:test 在完成 Code Mode、Core、Storage、MCP、Runtime、Runtime Host、Computer Use、Eval 和 CLI 编译后,停在未修改的 UI 文件接口不一致;完整 Runtime 测试还受到受管沙箱中的 macOS sandbox/process smoke test 和无关 model-factory streaming 断言影响,因此没有声明全量测试通过。

@coderabbitai

coderabbitaiBot commented Aug 17, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Problem solved

This PR hides WebSearch and web_research when Tavily or its proxy credential is unavailable. It prevents models and child agents from invoking search tools that will fail.

Provider-native search remains controlled by the selected model’s hosted-search capability. It does not require Tavily credentials. The call-time fail-closed guard remains in place.

Source of truth

The PR extends the existing resolveWebSearchExecution() runtime-policy authority. It does not create a parallel availability policy.

Readiness flows through routeWebSearchTools() and applies to root, bound, and child-agent tool surfaces. The resolver runs during effective tool-surface composition, so configuration changes can apply per turn.

Scope and complexity

The solution is the smallest coherent change shown by the diff. The added readiness resolver, composition plumbing, and routing input are required to apply the existing policy before tools reach the model.

No behavior or regression coverage is an obvious candidate for deletion. Obsolete child-agent sentinel and validation logic was removed. Existing native, external, disabled, incognito, provider, root, child-scope, and WebFetch coverage remains.

Validation

Reported validation includes:

  • Runtime and Runtime Host typechecks.
  • Biome checks for seven files.
  • Focused WebSearch tests passing 10/10.
  • Two Runtime Host lifecycle tests passing.

Broader checks reported unrelated UI interface mismatches, sandbox limitations, and unrelated test failures. Required-check status is not independently verified here.

Review-relevant risks

  • The model-visible tool surface changes. Unavailable Tavily search tools are no longer advertised. This user-visible behavior requires independent human review under repository policy.
  • routeWebSearchTools() now requires the public tavilyReady input. InteractiveRunComposerFactoryInput also gains resolveTavilyWebSearchReadiness. These contract changes require independent human review under repository policy.
  • Privacy-mode and runtime-policy outcomes can remove search tools from root and child-agent surfaces. This policy behavior requires independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The runtime now resolves Tavily readiness before composing web-search tools. Unavailable Tavily configurations omit WebSearch from root, child-agent, and skill preview surfaces. Tests cover policy, credential, routing, and hosted execution flows.

Changes

Web-search readiness routing

Layer / File(s)Summary
Native web-search routing contract
packages/runtime/src/native-web-search-tool.ts, packages/runtime/src/__tests__/native-web-search-tool.test.ts
routeWebSearchTools now requires tavilyReady and removes WebSearch when Tavily is unavailable. Tests cover available, unavailable, disabled, incognito, root, child, and WebFetch paths.
Host readiness resolution and composition
packages/runtime-host/src/server/web-search-tool.ts, packages/runtime-host/src/server/interactive-run-composer.ts, packages/runtime-host/src/server/execution-composition.ts, packages/runtime-host/src/__tests__/web-search-tool.test.ts
Host composition resolves Tavily execution readiness and passes it to interactive, existing-session, new-session, and child-tool routing. Readiness tests cover policy and credential states.
Skill preview filtering
packages/runtime-host/src/__tests__/execution-composition.test.ts
Existing-session and new-session skill catalog previews omit skills that require unavailable Tavily-backed tools.
Hosted composition validation
packages/runtime-host/src/__tests__/execution-model-composition.test.ts
Hosted fixtures and assertions exclude unavailable Tavily search and do not create a web_research child session.

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

Merge Risk:⚪ Minimal · up to 88658

This change hides Tavily search when its credentials are unavailable while preserving native model search and call-time safeguards. No actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers:m4n5ter, hqhq1025, jackwener

Sequence Diagram(s)

sequenceDiagram
participant RuntimePolicyOperationCoordinator
participant ExecutionComposition
participant InteractiveRunComposer
participant Model
RuntimePolicyOperationCoordinator->>ExecutionComposition: Resolve Tavily execution state
ExecutionComposition->>InteractiveRunComposer: Pass runtime policy and tavilyReady
InteractiveRunComposer->>InteractiveRunComposer: Route host, child, and parent-agent tools
InteractiveRunComposer-->>Model: Return filtered tool surface
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check nameStatusExplanationResolution
Linked Issues check⚠️ WarningThe PR satisfies the Runtime Host objectives, but it does not address the linked issue's desktop path where WebSearch remains unconditionally exposed.Update the desktop tool assembly and specialized desktop search surfaces, or link a separate PR that implements the desktop requirements.
Ai Use Disclosure⚠️ WarningThe PR description selects neither AI-use declaration, and both introduced commits lack a valid Generated-by trailer.Complete the AI use section by selecting exactly one declaration and naming tool/scope when applicable; follow CONTRIBUTING.md Human ownership and AI attribution for responsibility, provenance, licensing, and obligations. Preserve requir...
✅ Passed checks (3 passed)
Check nameStatusExplanation
Out of Scope Changes check✅ PassedThe changes are focused on Tavily readiness routing, effective tool surfaces, child-agent exposure, and related tests.
Title check✅ PassedThe title clearly and concisely states the main change: hiding Tavily WebSearch when it is not ready.
Description check✅ PassedThe description explains the problem, solution, issue, verification results, AI use, and known limitations, but omits the repository checklist.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@YayoiNanoka
YayoiNanoka marked this pull request as ready for review August 17, 2026 10:17
@hqhq1025
hqhq1025 requested a lite review from CopilotAugust 17, 2026 10:17
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Hide Tavily WebSearch when runtime policy says it’s not runnable

🐞 Bug fix🧪 Tests🕐 20-40 Minutes

Grey Divider

AI Description

• Derive Tavily WebSearch readiness from the canonical runtime-policy execution resolver.
• Route root/bound/child tool surfaces to omit WebSearch and web_research when unready.
• Add/update host + runtime tests to prevent advertising guaranteed-to-fail search tools.
Diagram

graph TD
P["Runtime policy"] --> R["Tavily readiness"] --> H["Runtime Host"] --> W["WebSearch router"] --> T["Root tool surface"]
W --> C["Child tool surface"] --> S["agent_spawn profiles"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Make routeWebSearchTools async and self-resolve Tavily readiness
  • ➕ Reduces plumbing (no need to thread tavilyReady through multiple host call sites).
  • ➕ Centralizes all WebSearch selection logic in one function.
  • ➖ Turns a pure/fast routing helper into an async, policy-dependent API.
  • ➖ Harder to use in places that expect synchronous tool list computation or reuse across packages.
2. Rely only on call-time fail-closed behavior
  • ➕ Minimal code changes; no new readiness plumbing.
  • ➕ Keeps tool surfaces stable regardless of credential state.
  • ➖ Still advertises a tool that is guaranteed to fail, wasting model turns.
  • ➖ Child-agent composition can still expose web_research without a runnable search tool.

Recommendation: Current approach is best: it uses the canonical runtime-policy resolver as the single authority for Tavily readiness, keeps routeWebSearchTools pure by passing a boolean, and prevents the model/subagents from selecting a guaranteed-to-fail tool while retaining the existing call-time fail-closed guard for defense in depth.

Files changed (7) +78 / -54

Bug fix (4) +28 / -1
execution-composition.tsPass Tavily readiness into child tool routing+8/-0

Pass Tavily readiness into child tool routing

• Wires resolveHostTavilyWebSearchReadiness into runtime-host composition and uses it when routing child agent tools via routeWebSearchTools, ensuring WebSearch/web_research are excluded when Tavily cannot run.

packages/runtime-host/src/server/execution-composition.ts

interactive-run-composer.tsThread Tavily readiness through interactive run composition+9/-0

Thread Tavily readiness through interactive run composition

• Extends the composer factory input with resolveTavilyWebSearchReadiness and uses it during backend creation to compute tavilyReady, applying the same routeWebSearchTools result to host, bound, and child tool surfaces.

packages/runtime-host/src/server/interactive-run-composer.ts

web-search-tool.tsExpose resolveHostTavilyWebSearchReadiness helper+6/-0

Expose resolveHostTavilyWebSearchReadiness helper

• Adds a small helper that queries runtime-policy resolveWebSearchExecution({provider:'tavily'}) and returns a boolean readiness signal for tool-surface routing.

packages/runtime-host/src/server/web-search-tool.ts

native-web-search-tool.tsGate Tavily WebSearch selection on explicit readiness+5/-1

Gate Tavily WebSearch selection on explicit readiness

• Extends routeWebSearchTools with a tavilyReady boolean and uses it to select the client-executed WebSearch tool only when Tavily is actually runnable, while leaving provider-native search selection unchanged for the 'model' provider path.

packages/runtime/src/native-web-search-tool.ts

Tests (3) +50 / -53
execution-model-composition.test.tsAssert host omits WebSearch/web_research when Tavily is unready+7/-52

Assert host omits WebSearch/web_research when Tavily is unready

• Updates production-like host composition tests so the effective root tool surface never includes WebSearch when Tavily is selected but credentials are missing. Also verifies the child-agent routed surface no longer advertises the web_research profile and removes the now-impossible web child run assertions.

packages/runtime-host/src/tests/execution-model-composition.test.ts

web-search-tool.test.tsAdd test for host Tavily readiness derived from policy resolver+23/-1

Add test for host Tavily readiness derived from policy resolver

• Imports and tests resolveHostTavilyWebSearchReadiness to ensure it strictly mirrors the canonical resolveWebSearchExecution({provider:'tavily'}) readiness result.

packages/runtime-host/src/tests/web-search-tool.test.ts

native-web-search-tool.test.tsCover Tavily unready routing behavior+20/-0

Cover Tavily unready routing behavior

• Updates routeWebSearchTools test calls to include tavilyReady and adds a case asserting that when Tavily is selected but unready, WebSearch is removed from the routed tool list.

packages/runtime/src/tests/native-web-search-tool.test.ts

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0256d7d9-107b-4055-9656-37230860edba

📥 Commits

Reviewing files that changed from the base of the PR and between a81719d and 0821afd.

📒 Files selected for processing (7)
  • packages/runtime-host/src/__tests__/execution-model-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts
  • packages/runtime/src/__tests__/native-web-search-tool.test.ts
  • packages/runtime/src/native-web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

Comment threadpackages/runtime-host/src/server/execution-composition.ts

CopilotAI 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

This PR prevents the Tavily-backed WebSearch tool (and dependent child-agent web_research profile) from being advertised to the model when the canonical runtime-policy resolver reports Tavily is unavailable, avoiding wasted model turns on guaranteed-to-fail tool calls.

Changes:

  • Adds a tavilyReady input to routeWebSearchTools() and hides the client-executed WebSearch when Tavily is not canonically ready.
  • Introduces a host-side resolveHostTavilyWebSearchReadiness() helper and threads readiness through root/bound/child tool routing in the runtime host.
  • Updates runtime and host tests to validate tool-surface omission for unready Tavily and removal of web_research when Tavily can’t run.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
FileDescription
packages/runtime/src/native-web-search-tool.tsAdds tavilyReady gating so Tavily WebSearch is only exposed when canonically ready.
packages/runtime/src/tests/native-web-search-tool.test.tsAdds coverage for Tavily-unready routing behavior.
packages/runtime-host/src/server/web-search-tool.tsAdds a host helper to derive Tavily readiness from the canonical resolver.
packages/runtime-host/src/server/interactive-run-composer.tsThreads Tavily readiness into unified routeWebSearchTools() routing for root/bound/child surfaces.
packages/runtime-host/src/server/execution-composition.tsApplies the same readiness-gated routing to child-agent tool resolution.
packages/runtime-host/src/tests/web-search-tool.test.tsTests readiness derivation follows resolveWebSearchExecution() states.
packages/runtime-host/src/tests/execution-model-composition.test.tsEnsures effective tool surfaces omit WebSearch/web_research when Tavily cannot run.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated
Comment threadpackages/runtime-host/src/server/execution-composition.ts Outdated
@qodo-code-review

qodo-code-reviewBot commented Aug 17, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0)📘 Rule violations (0)📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unneeded readiness resolution✓ Resolved🐞 Bug➹ Performance
Description
createInteractiveRunComposerFactory() resolves Tavily readiness whenever defaultProvider is
'tavily', even when web search is disabled or privacy mode is active, adding avoidable
policy/storage I/O (and a new awaited dependency) on paths that will never expose WebSearch. The
same unconditional pattern also exists in child-tool resolution (resolveChildTools) and should be
guarded similarly.
Code

packages/runtime-host/src/server/interactive-run-composer.ts[R348-351]

+ const tavilyReady =+ runtimePolicy.policy.webSearch.defaultProvider === 'tavily'+ ? await readDuringBackendCreation(+ input.resolveTavilyWebSearchReadiness,
Evidence
The composer now resolves readiness solely based on defaultProvider === 'tavily', but
routeWebSearchTools() immediately strips WebSearch when search is disabled or incognito is active,
meaning the readiness result cannot influence the output in those cases. The readiness helper calls
resolveWebSearchExecution, which reads policy state from storage; doing that when routing will
drop WebSearch anyway is unnecessary overhead and an avoidable awaited dependency.

packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
packages/runtime/src/native-web-search-tool.ts[57-67]
packages/runtime-host/src/server/web-search-tool.ts[30-34]
packages/storage/src/runtime-policy/coordinator.ts[703-716]
packages/runtime-host/src/server/execution-composition.ts[817-832]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution
### Issue description
`resolveTavilyWebSearchReadiness()` is awaited whenever `defaultProvider === 'tavily'`, even when WebSearch will be excluded anyway because the feature is disabled or incognito is active. This adds avoidable policy reads/latency and introduces an unnecessary awaited dependency on the policy store.
### Issue Context
`routeWebSearchTools()` already returns early without WebSearch when `settings.enabled` is false or `privacy.incognitoActive` is true, so `tavilyReady` is irrelevant in those cases.
### Fix approach
- Only resolve Tavily readiness when it can affect routing:
- `policy.webSearch.enabled === true`
- `policy.webSearch.defaultProvider === 'tavily'`
- `policy.privacy.incognitoActive !== true`
- Otherwise set `tavilyReady = false` without calling the resolver.
- Apply the same guard in both:
- interactive composer root/bound/child routing
- child-agent tool resolution path in `execution-composition.ts`
### Fix Focus Areas
- packages/runtime-host/src/server/interactive-run-composer.ts[348-354]
- packages/runtime-host/src/server/execution-composition.ts[817-832]
- packages/runtime/src/native-web-search-tool.ts[57-67]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
Review mode: ⚖️ Balanced: This is a behavior-changing, cross-file routing change affecting root, bound, and child tool surfaces plus canonical credential readiness; it has meaningful integration risk, but not enough independent logic density to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can route each action level your way: inline, summary, both, or drop

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment threadpackages/runtime-host/src/server/interactive-run-composer.ts Outdated

@coderabbitaicoderabbitaiBot 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: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2c313c8e-aed7-413a-9a68-94dba2043208

📥 Commits

Reviewing files that changed from the base of the PR and between 0821afd and 88658e4.

📒 Files selected for processing (5)
  • packages/runtime-host/src/__tests__/execution-composition.test.ts
  • packages/runtime-host/src/__tests__/web-search-tool.test.ts
  • packages/runtime-host/src/server/execution-composition.ts
  • packages/runtime-host/src/server/interactive-run-composer.ts
  • packages/runtime-host/src/server/web-search-tool.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 1 remains after this review.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/interactive-run-composer.ts:352

  • Avoid hard-coding the WebSearch tool name here. The canonical tool name already exists as NATIVE_WEB_SEARCH_TOOL_NAME in @maka/runtime/native-web-search-tool (used by the router you call below). Importing and reusing that constant reduces drift risk if the tool name ever changes.
 const route = (tools: readonly MakaTool[]): MakaTool[] => {
const webFetchTools = routeWebFetchTools(tools, input.runtimePolicy.policy.privacy);
if (!input.connection) {
return webFetchTools.filter((tool) => tool.name !== 'WebSearch');
}

@jackwener

Copy link
Copy Markdown
Member

@YayoiNanoka I verified the bug against current main: Tavily-backed WebSearch is still advertised when the canonical execution resolver says the credential path cannot run. The current solution uses the right authority, keeps provider-native search independent, and consistently derives root/bound/child/skill surfaces; I found no implementation blocker on head 88658e4, and all hosted checks are green. Two merge gates remain: this model-visible tool-contract change needs an independent human review under CONTRIBUTING.md, and the PR needs an explicit AI-use declaration (plus Generated-by trailers if generative tooling authored material code). Please complete that provenance declaration while the human review is pending.

@YayoiNanoka

Copy link
Copy Markdown
ContributorAuthor

@jackwener Provenance is now complete: the PR body explicitly declares substantive OpenAI Codex use and its scope, and both PR commits carry Generated-by: Codex trailers. The trailer-only history rewrite did not change the code tree; the current head is 35920ec. Independent human review remains pending.

CopilotAI 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

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Suppressed comments (1)

packages/runtime-host/src/server/web-search-tool.ts:45

  • resolveHostTavilyWebSearchReadiness() propagates exceptions from resolveWebSearchExecution(). Since this function is now called during tool-surface assembly (not just at tool call-time), an unexpected store/vault read failure would fail the entire session/tool-surface resolution rather than failing closed by simply omitting WebSearch. Consider catching errors here and returning false so the surface stays usable and remains fail-closed.
export async function resolveHostTavilyWebSearchReadiness(
policy: Pick<RuntimePolicyOperationCoordinator, 'resolveWebSearchExecution'>,
): Promise<boolean> {
return (await policy.resolveWebSearchExecution({ provider: 'tavily' })).kind === 'ready';
}

@Astro-HanAstro-Han 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.

No P0–P2 findings on 88658e446.

The problem is correctly defined as a mismatch between the model-visible tool surface and the canonical execution authority. This change fixes it at the right owner: resolveWebSearchExecution() remains the sole Tavily credential/proxy readiness authority, while the synchronous routing layer consumes only the minimal tavilyReady projection. The call-time resolver remains in place as the final fail-closed boundary.

I independently verified that the follow-up commit closes the earlier composition gap: root, bound, child, parent-agent, current-session preview, new-session preview, and durable child surfaces now pass through the shared routing seam. Provider-native search remains independent of Tavily readiness. I found no stale-backend or settings/credential lifecycle path that re-exposes an unavailable tool.

One non-blocking P3 test follow-up remains: the new integration coverage is negative-only. Please add a positive catalog control so an empty catalog cannot satisfy the test, and consider a configured-Tavily composition control proving that ready WebSearch and web_research remain present. The existing unit coverage and direct wiring are sufficient for approval, so this does not need to block the PR.

Verdict: Approve. The implementation is the smallest coherent root fix, does not need a PR split, and should not be replaced by duplicated readiness logic or an async router.

Before merge, please complete the PR's AI-use declaration and preserve Generated-by trailers if material generated code was used. This model-visible contract change still requires the repository's independent human review.

Codex assisted this review by reconstructing the feedback ledger, tracing the current production surfaces and lifecycle, and checking CI evidence. The human reviewer remains responsible for the final judgment and merge decision.

简体中文

当前 head 没有 P0–P2。PR 在正确 owner 修复了模型可见工具表面与实际执行能力不一致的问题:Tavily readiness 继续由权威 resolver 决定,routing 只消费最小布尔投影,调用阶段仍保持 fail closed。

root、bound、child、parent-agent、当前 Session、新 Session 和 durable child preview 已统一经过同一 routing seam;模型原生搜索不依赖 Tavily,没有被误删。

仅剩非阻塞 P3 测试建议:补普通 skill 正向控制,避免空 catalog 也通过;最好再补有效 Tavily credential 的 composition 正向控制。当前实现可以 Approve,无需拆 PR。

合并前仍需完成 AI-use declaration;若存在实质生成代码,应保留 Generated-by trailer。本次模型可见契约变更仍需独立人工 review。

@Astro-Han
Astro-Han merged commit e04faa3 into apache:mainAug 17, 2026
14 checks passed
Sign up for freeto 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.

bug(desktop): WebSearch is exposed to the model even when disabled, unconfigured, or in privacy mode

4 participants

@YayoiNanoka@jackwener@Astro-Han