Skip to content

Delegate research upgrade - #26

Merged
allocsys merged 27 commits into
mainfrom
delegate-research-upgrade
Jul 27, 2026
Merged

Delegate research upgrade#26
allocsys merged 27 commits into
mainfrom
delegate-research-upgrade

Conversation

@allocsys

Copy link
Copy Markdown
Owner

No description provided.

allocsys added 27 commits July 27, 2026 13:55
callGenerateContentOnce had no timeout at all -- a hung/dropped connection
(as opposed to a clean 429/503 HTTP status) would just leave the caller
waiting indefinitely with no error to react to. Add an AbortController
timeout and mark network-level failures (abort, fetch TypeError) as
`transient` so the existing model-cascade + resumable-checkpoint logic in
delegate.js treats them the same way it already treats 429/503, instead of
only recognizing HTTP status codes as retryable.
Mirrors the existing 429/503 cascade behavior for the new `err.transient`
flag from the timeout/network-error handling above -- a dropped connection
to model A should try model B same as a 503 would, and should NOT record a
cooldown (no per-model quota signal in a network failure, same reasoning
already applied to 503).
isTransientGeminiError gates the resumable/resume_run_id messaging shown to
the caller on a failed step -- without this, a timeout or dropped
connection (now marked err.transient in client.js) would tell the caller
"this doesn't look transient, resuming will likely reproduce the same
failure," which is backwards for exactly the kind of blip that motivated
the checkpoint system in the first place.
Closes gap #1 (no web access in the investigation loop) WITHOUT adding a
new MCP-facing tool: web_fetch reuses the exact same fetchUrl/htmlToText
helpers the standalone web_fetch and Delegate_web_fetch tools already use,
just exposed as one more function in Gemini's own tool-calling loop instead
of a separate server.tool(). Google Search grounding is added as a native
Gemini tool (not a function -- Gemini calls it internally, no execute()
needed on our side) so the loop can actually discover URLs/facts it doesn't
already have, not just fetch a URL it was handed. Combined with a function-
declarations tool in the same request is a newer Gemini capability
("multi-tool use") that may not be supported on every model in the fallback
cascade -- see the fallback-on-error handling below for why this degrades
instead of hard-failing if a given model rejects the combination.
The execute() here is intentionally the same shape as the standalone
web_fetch tool and Delegate_web_fetch (fetchUrl + conditional htmlToText),
just truncated tighter for server-side loop context (WEB_FETCH_MAX_CHARS)
since this text is consumed by Gemini's next turn, not returned to the
calling model.
…unctions

web_fetch (previous commit) only reads a URL the loop already has -- it
can't discover one. Google Search grounding is a built-in Gemini tool (no
execute() -- Gemini runs it itself and returns grounded text), so adding it
here is what actually closes "no general web search" rather than just
"can re-fetch a known page inside the loop too."

Combining a grounding tool with custom functionDeclarations in one request
is real but newer Gemini behavior, not guaranteed across every model in the
fallback cascade. TOOLS_WITH_SEARCH is tried first each run;
searchToolDisabledThisRun latches off after the first same-step 400
suggesting the combination isn't accepted, so the rest of the run doesn't
keep re-paying for a doomed retry every single step.
…cation

Two additions: (1) tell the model web_fetch/search exist now, since an
unchanged preamble would leave a model that's seen prior GitHub/Notion/CF-
only framing less likely to reach for them; (2) explicit instruction to
actively cross-check claims between sources rather than reporting each
source's status independently -- addresses gap #3 (no cross-source
synthesis), which came up concretely in practice: a GitHub PR looking
"open" and unclaimed was contradicted by an external tracking spreadsheet
showing the same bounty already paid out elsewhere, and nothing prompted
checking for that kind of contradiction before this.
Deliberately NOT persisted in the checkpoint (unlike repeatCounts/
consecutiveAllRepeatSteps) -- it's a same-run fast-fail heuristic, not
correctness-affecting state; worst case a resumed run pays for one extra
same-step retry before re-latching, which is cheap and simpler than adding
another checkpoint field for it.
…jection

The withholdTools branches (final step, stuck-loop force) are unaffected --
they already pass undefined regardless of search. Only the normal case
(tools enabled) now tries TOOLS_WITH_SEARCH first and drops to
FUNCTION_DECLARATIONS-only, in the SAME step, if the model rejects the
combination with a 400 -- avoiding burning a whole failed-step/checkpoint
cycle over what's a request-shape mismatch, not a real failure.
This description is what the CALLING model (Claude) reads to decide when
to use this tool -- distinct from delegate.js's FUNCTIONS descriptions,
which only Gemini's own internal loop sees (see delegate.js's file header
for why those two are never edited as if they were the same text). Without
this update, Claude would have no way to know the tool now does live web
research + explicit cross-source verification, and would keep reaching for
manual web_search + delegate_gemini combinations instead of one call.
Every other connector's tunables (GITHUB_MIN_REQUEST_INTERVAL_MS,
NOTION_MAX_RETRIES, MEM0_RETRY_BASE_MS, etc.) live in config.js as named
exports, not inline in their client.js -- this had been added directly in
gemini/client.js in the prior commit, which broke that pattern. Moving it
here for anyone scanning config.js for the full list of overridable knobs.
…tions when combining google_search with function declarations); update comments to reflect delegate_research rename/split
…PREAMBLE to drop web references and explain the security boundary with research.js
…y (no search-tool combination/fallback needed anymore)
…-step loop backing delegate_research's wide mode. No access to GitHub/Notion/Cloudflare/Context7/Mem0 -- see file header for the security rationale.
…de schema (precision url+question / wide task), wire in research.js's runResearch for wide mode; update delegate_gemini's description to drop web-access claims (delegate.js no longer has web access)
…rch dual-mode tool (precision url+question path unchanged; wide task path delegates to research.js's runResearch, with mutual-exclusivity validation)
…er has web access (moved to research.js/delegate_research), so drop the "AND the live web" / web_fetch+Google Search claims and point callers at delegate_research for web tasks
… and reflect that delegate_gemini is now internal-systems-only (GitHub/Notion/Cloudflare) while delegate_research covers web (precision + wide research mode)
…delegate_research, and note it's now shared by both precision mode (tools.js) and wide mode (research.js)
@allocsys
allocsys merged commit 196ee7d into main Jul 27, 2026
2 checks passed
@allocsys
allocsys deleted the delegate-research-upgrade branch July 27, 2026 11:55
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