mirror of
https://github.com/openclaw/openclaw.git
synced 2026-10-03 09:39:25 +00:00
Closes #155956 ## What Problem This Solves Fixes: automatic `web_search` chooses Tavily ahead of Grok when both a Tavily environment key and a usable xAI OAuth profile are present. ## User Impact Automatic search follows the documented credential precedence: Grok (30) before Tavily (70), with Tavily still available if Grok fails. Explicit provider selections and environment-only setups retain their behavior. No configuration or migration changes are required. ## Why This Change Was Made The secrets snapshot cannot see OAuth profiles. Its environment-selected provider must not override the runtime's OAuth-aware ordering. Configured selections and resolved non-environment snapshot preferences remain unchanged. ## Evidence Exercised an isolated Gateway started with `pnpm openclaw gateway run --allow-unconfigured`, invoking the shipped `POST /tools/invoke` endpoint with `{"tool":"web_search","args":{"query":"..."}}`. The real bundled xAI and Tavily implementations used configured HTTP base URLs through a local synthetic provider proxy. Credentials were synthetic: a persisted, unexpired xAI OAuth profile and `TAVILY_API_KEY`. No provider-selection callbacks or runtime snapshots were mocked in this Gateway proof; no paid provider calls were made. Observed provider HTTP requests and returned Gateway results: | Scenario | HTTP request order | Returned provider | | --- | --- | --- | | Original selection code, OAuth + environment | Tavily 200 only | Tavily (bug reproduced) | | Candidate, same persisted configuration | Grok 200 only | Grok | | Candidate after merging current main | Grok 200 only | Grok | | Grok temporarily returns 503 | Grok 503, Tavily 200 | Tavily | | Grok recovers on next query | Grok 200 only | Grok | | Existing config explicitly pins Tavily | Tavily 200 only | Tavily | | Existing config pins Grok, Grok returns 503 | Grok 503 only; no Tavily request | Grok error retaining HTTP 503 | | Pinned Grok recovers on next query | Grok 200 only | Grok | | Fresh state with only the Tavily environment key | Tavily 200 only | Tavily | | Fresh-state setup with OAuth + environment, pinned Tavily at startup | Tavily 200 only | Tavily | | Removing that pin through normal config reload | Grok 200 only | Grok | The negative control restored only the original production selection block, rebuilt through the supported CLI wrapper, and restarted the same Gateway/state; it selected Tavily. Restoring the fix selected Grok. Initial fixture setup exposed Doctor's OAuth-refresh invalidation of the synthetic token; reseeding an unexpired synthetic profile through the auth SDK before the comparison resolved that fixture issue. Focused regression proof: `node scripts/run-vitest.mjs src/web-search/runtime-autodetect-order.test.ts src/web-search/runtime.test.ts --maxWorkers=1` passed **37/37** after the main merge (19.94 seconds wall; four ordering cases took 288 ms). With the production fix removed, the OAuth-first and fallback-order cases both failed for the intended wrong-order reason; environment-only and explicit-pin controls passed. The new cases live in a focused sibling suite, avoiding growth of the over-cap runtime suite. The line-cap ratchet passes. Hosted CI owns test-type validation; no local project-wide typecheck was run. Co-authored-by: Ayaan Zaidi <hi@obviy.us> |
||
|---|---|---|
| .. | ||
| acp | ||
| agents | ||
| audit | ||
| auto-reply | ||
| boards | ||
| bootstrap | ||
| canvas | ||
| channels | ||
| chat | ||
| claws | ||
| cli | ||
| commands | ||
| compat | ||
| config | ||
| context-engine | ||
| cron | ||
| daemon | ||
| decisions | ||
| docs | ||
| fleet | ||
| flows | ||
| gateway | ||
| hooks | ||
| image-generation | ||
| infra | ||
| interactive | ||
| link-understanding | ||
| llm | ||
| logging | ||
| mcp | ||
| media | ||
| media-generation | ||
| media-understanding | ||
| meeting-bot | ||
| memory | ||
| memory-host-sdk | ||
| model-catalog | ||
| model-picker | ||
| music-generation | ||
| node-host | ||
| pairing | ||
| plugin-sdk | ||
| plugin-state | ||
| plugins | ||
| process | ||
| projects | ||
| provider-runtime | ||
| proxy-capture | ||
| realtime-transcription | ||
| routing | ||
| scripts | ||
| secrets | ||
| security | ||
| session-cards | ||
| sessions | ||
| shared | ||
| skills | ||
| snapshot | ||
| state | ||
| status | ||
| system-agent | ||
| talk | ||
| tasks | ||
| test-fixtures | ||
| test-helpers | ||
| test-utils | ||
| trajectory | ||
| transcripts | ||
| tts | ||
| tui | ||
| types | ||
| utils | ||
| video-generation | ||
| web | ||
| web-fetch | ||
| web-search | ||
| wizard | ||
| worker | ||
| browser-lifecycle-cleanup.test.ts | ||
| browser-lifecycle-cleanup.ts | ||
| docker-build-cache.test.ts | ||
| docker-healthcheck.test.ts | ||
| docker-healthcheck.ts | ||
| docker-image-digests.test.ts | ||
| docker-setup.e2e.test-support.ts | ||
| docker-setup.e2e.test.ts | ||
| dockerfile.test.ts | ||
| entry.compile-cache.test.ts | ||
| entry.compile-cache.ts | ||
| entry.esm-resolve-fast-path.test.ts | ||
| entry.esm-resolve-fast-path.ts | ||
| entry.memory-json.test.ts | ||
| entry.respawn-diagnostics.test.ts | ||
| entry.respawn.test.ts | ||
| entry.respawn.ts | ||
| entry.run-main.test.ts | ||
| entry.test.ts | ||
| entry.ts | ||
| entry.version-fast-path.test.ts | ||
| entry.version-fast-path.ts | ||
| global-state.ts | ||
| globals.test.ts | ||
| globals.ts | ||
| index.entrypoint.test.ts | ||
| index.test.ts | ||
| index.ts | ||
| install-sh-version.test.ts | ||
| library.test.ts | ||
| library.ts | ||
| logger.test.ts | ||
| logger.ts | ||
| logging.ts | ||
| param-key.ts | ||
| plugin-activation-boundary.test.ts | ||
| poll-params.test.ts | ||
| poll-params.ts | ||
| polls.test.ts | ||
| polls.ts | ||
| runtime.test.ts | ||
| runtime.ts | ||
| tsconfig.json | ||
| utils.test.ts | ||
| utils.ts | ||
| version.test.ts | ||
| version.ts | ||