Skip to content

feat(google): native Google Search grounding behind OPENCLAW_GOOGLE_GROUNDING#4

Merged
StevenMend merged 2 commits into
mainfrom
steven/web-grounding
Jul 24, 2026
Merged

feat(google): native Google Search grounding behind OPENCLAW_GOOGLE_GROUNDING#4
StevenMend merged 2 commits into
mainfrom
steven/web-grounding

Conversation

@StevenMend

Copy link
Copy Markdown
Member

What

Opt-in native web search for Gemini models, gated by the OPENCLAW_GOOGLE_GROUNDING env var (off by default — zero behavior change without it):

  • Transport (google-transport-stream.ts): adds the google_search built-in tool to every request and, when function declarations are present, sets toolConfig.includeServerSideToolInvocations (the API 400s on the mix without it). Streamed groundingMetadata is normalized onto the assistant output as webGrounding — queries + sources with per-source citation counts derived from groundingSupports.
  • Runner (pi-embedded-subscribe.handlers.messages.ts): at message end, a message carrying webGrounding emits a grounding agent event.
  • OpenAI-compat endpoint (openai-http.ts): forwards that event as a content-free delta.dojo_grounding chunk. Standard OpenAI clients ignore the unknown delta field; the Dojo web-chat proxy consumes it to render a cited-sources card.

Why

Cross-pillar conversational web search for the Dojo agent (Claude/ChatGPT-style grounded answers with real citations), verified E2E against the live UI locally. Companion PRs: dojo-agent-openclaw-plugin (proxy/card/booster) and dojo-os (web-results card).

Notes

  • Branch includes the previously local-only cut-dojo-tarball.yml one-shot release workflow (authored 2026-07-02) — needed to cut the next fork tarball with this change.
  • Pre-commit lint surfaces pre-existing baseline findings on the touched files (__testOnlyOpenAiHttp dangling underscore, resolveThinkingLevel consistent-return) — untouched by this diff; CI is the gate.

Created by Claude Code on behalf of @StevenMendez

🤖 Generated with Claude Code

…ROUNDING

When the env flag is set, the Google transport adds the google_search
built-in tool to every request (with includeServerSideToolInvocations so
it can coexist with function declarations), captures the streamed
groundingMetadata onto the assistant message as a normalized webGrounding
payload (queries + sources ranked by citation count), and surfaces it as
a 'grounding' agent event that the OpenAI-compat endpoint forwards as a
content-free delta.dojo_grounding chunk for downstream consumers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@dojo-code-reviewer dojo-code-reviewer Bot 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.

✅ Approved

Approved — 0 blockers, 1 P3. Confidence: 4.80/5.00.

Walkthrough

⚠️ Governance Warning: This PR targets the main branch directly, departing from the standard GitFlow pattern (expected: feature → develop → main). This is an informative warning only and does not affect the technical merge status.

Walkthrough

This PR adds native Google Search grounding for Gemini models, gated under the OPENCLAW_GOOGLE_GROUNDING opt-in environment variable. It implements:

  1. Tool Configuration & Mapping (src/agents/google-transport-stream.ts): Injects the google_search tool dynamically. When combined with client-side function declarations, it configures toolConfig.includeServerSideToolInvocations to prevent Gemini API 400 errors. It also parses and normalizes streamed groundingMetadata (queries and source citation counts) onto the assistant message as webGrounding.
  2. Event Dispatching (src/agents/pi-embedded-subscribe.handlers.messages.ts): Emits a grounding agent event downstream when webGrounding is present on the assistant message.
  3. SSE Compat Layer (src/gateway/openai-http.ts): Forwards this event as a content-free delta.dojo_grounding chunk, allowing custom clients to render cited source cards while remaining fully backward-compatible with standard OpenAI clients.

Reviewed Areas

We reviewed the tool parameter builder and metadata streaming helpers in google-transport-stream.ts, message-end lifecycle handling in pi-embedded-subscribe.handlers.messages.ts, and the custom SSE chunk delivery schema in openai-http.ts.

Safety Rationale

The feature is strictly opt-in and fully gated behind process.env.OPENCLAW_GOOGLE_GROUNDING. Without this environment variable enabled, the entire code path is bypassed, guaranteeing zero behavioral regressions or runtime impacts for existing clients and services.

Approved — 0 blockers, 1 P3.

🔵 P3 — Minor

  • src/agents/pi-embedded-subscribe.handlers.messages.ts:536 — 🔵 P3 (minor) — Use a defensive array check on webGrounding.sources before evaluating .length. This prevents any potential runtime TypeError crashes if a provider or plugin initializes webGrounding with missing or malformed properties in the future.

[pass 1]


Total findings: 1 business context (1 total)

// `webGrounding`. Surface it as its own event stream so channel consumers
// (e.g. the OpenAI-compat endpoint) can forward the cited sources.
const webGrounding = (
assistantMessage as { webGrounding?: { queries: string[]; sources: unknown[] } }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 P3 (minor) — Use a defensive array check on webGrounding.sources before evaluating .length. This prevents any potential runtime TypeError crashes if a provider or plugin initializes webGrounding with missing or malformed properties in the future.

[pass 1]

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

@dojo-code-reviewer dojo-code-reviewer Bot 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.

✅ Approved

Approved — no findings. Confidence: 5.00/5.00.

Walkthrough

⚠️ Governance Warning: This Pull Request targets main directly instead of following GitFlow conventions (feature → develop → main). Since this is informative only, the technical verdict remains based purely on the code quality.

Walkthrough

This PR implements opt-in native Google Search grounding for Gemini models, gated behind the OPENCLAW_GOOGLE_GROUNDING environment variable. It adds the built-in google_search tool to requests, normalizes raw groundingMetadata into a clean webGrounding representation, surfaces grounding events via the agent stream, and exposes them in the OpenAI-compatible gateway as standard SSE chunks carrying the custom dojo_grounding delta field.

Reviewed Areas

  • Transport (src/agents/google-transport-stream.ts): Reviewed type definitions, parameter construction logic (buildGoogleGenerativeAiParams), and the chunk-merging utility (mergeWebGrounding).
  • Runner (src/agents/pi-embedded-subscribe.handlers.messages.ts): Reviewed the message-end handler (handleMessageEnd) and event emissions for the grounding stream.
  • Gateway API (src/gateway/openai-http.ts): Reviewed the OpenAI-compatible HTTP response streaming loop and chunk-writing helpers.

Safety Rationale

The entire Google Search grounding feature is completely opt-in and gated behind the OPENCLAW_GOOGLE_GROUNDING environment variable, ensuring zero behavior changes or regressions for existing configurations when disabled.

Approved — no findings.

@StevenMend

Copy link
Copy Markdown
Member Author

CI triage before merge — the branch's own diff is clean; every remaining red is pre-existing baseline (main has received direct pushes without PR CI since the last green run):

  • check → the only finding attributable to this diff (empty-fallback spread) was fixed in 9e3a1b0; the job still fails on extensions/imessage|whatsapp/secret-contract-api.ts "Empty files are not allowed" — comment-only files landed on main in e608b7e.
  • checks-fast-contracts-protocolboundary-invariants.test.ts fails identically (2/12) on a pristine origin/main checkout (verified locally).
  • checks-fast-extensions* → memory-core dreaming-phases/cli assertion failures + whatsapp implicitMentionKindWhen mock drift; none of those paths are touched here.
  • security-fast → production dependency audit; lockfile untouched.
  • label/label-issues → GitHub App privateKey secret missing (infra).

Merging per the agreed flow; baseline cleanup tracked separately.

@StevenMend
StevenMend merged commit db8412e into main Jul 24, 2026
21 of 32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant