Skip to content

feat(verify): force tool use on temporal-dismissal-prone OpenAI/Gemini calls#11

Draft
aRealGem wants to merge 2 commits into
mainfrom
claude/temporal-tool-choice-required
Draft

feat(verify): force tool use on temporal-dismissal-prone OpenAI/Gemini calls#11
aRealGem wants to merge 2 commits into
mainfrom
claude/temporal-tool-choice-required

Conversation

@aRealGem

@aRealGem aRealGem commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Summary

Substance-track fix for two of the three temporal-dismissal failure modes observed in the 2026-05-23 regression rerun (0/4 pass).

  • OpenAI adapter: set tool_choice: "required" on batch payload, multi-batch payload, and the live _call_with_search path. Forces the model to invoke web_search instead of skipping straight to a no-search "Unverifiable" verdict.
  • Gemini adapter: set tool_config.function_calling_config.mode = "ANY" on batch payload, cached-content create config, and the non-cached call / call_multi paths (cached-retrieve path intentionally left alone).
  • Temporal preamble (src/truthbot/verify/context/temporal.py): added rules 5 ("VERIFY, DON'T DISMISS") and 6 ("INVOKE SEARCH BEFORE DECIDING") to counter the "training cutoff -> Unverifiable" reflex.

New / extended unit tests pin the three payload knobs and the two new preamble rules:

  • tests/test_openai_tool_choice.py (new)
  • tests/test_gemini_tool_config.py (new; includes a regression guard that the cached-retrieve path does NOT set tool_config)
  • tests/test_temporal_context.py (extended)

Validation

  • uv run pytest -q -> 798 passed, 18 deselected (live tests, correctly excluded), 1 xfailed. Green locally.
  • Live temporal-regressions rerun deferred. Mini-transcript is already at data/temporal-regressions-mini-transcript.txt; runbook at eval/sotu-2026/temporal-regressions-runbook.md. Expected outcome once run: 3/4 pass. The Rubio case is expected to remain failing -- it is gated on the deferred intra-family consensus tie-break follow-up, which is out of scope for this PR.

What is deliberately NOT in this PR

  • Intra-family consensus tie-break for the 4th failure mode (Rubio-shaped case). Separate follow-up.
  • Live regression evidence attached to this PR. Willing to run + attach before marking ready-for-review; ping and I will.

Follow-ups

  1. Run the temporal-regressions live probe (~$0.40-0.60) and post results as a PR comment.
  2. Design + implement the intra-family tie-break; land as its own PR.
  3. Mark this PR ready-for-review once (1) is done and passes as expected.

Made with Cursor

aRealGem and others added 2 commits May 23, 2026 09:13
PR #10 (Rev-2 reliability checkpoint) squash-merged 2026-05-04 as b06dddf;
3 weeks idle since. Moved the row from WIP to Done, added a 2026-05-23
session note in STATUS.md, and bumped the new "temporal-dismissal substance
fix" row to WIP (bundles two of the three (NEW 2026-05-04) P0 rows;
intra-family tie-break stays in Backlog).

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…i calls

OpenAI: add tool_choice="required" at every web_search call site
(build_batch_payload, build_multi_batch_payload, _call_with_search live
path). Per OpenAI Responses API docs: "With tool_choice: 'auto', search
is optional. Use tool_choice: 'required' [...] when search must run."

Gemini: add tool_config.function_calling_config.mode="ANY" at every call
site (build_batch_payload, CreateCachedContentConfig for the cache-hit
path, GenerateContentConfig for the non-cached call/call_multi fallbacks).
Cached and non-cached paths land the nudge in different spots because
tool_config on a per-request GenerateContentConfig with cached_content is
a hard Google API error (see test_gemini_cache.py contract).

SYNTHESIS_SYSTEM temporal preamble (build_temporal_preamble) gains two
new rules:
  5. VERIFY, DON'T DISMISS — a claim's date being past training cutoff
     is NOT grounds for "Unverifiable"; Unverifiable is reserved for
     claims the web genuinely cannot resolve. Carries a concrete worked
     example using today's runtime-injected date.
  6. INVOKE SEARCH BEFORE DECIDING — returning "Unverifiable" without
     having invoked the search tool on a checkable claim is a contract
     violation, not a humble admission of uncertainty.

Tests: +12 (test_openai_tool_choice.py x3, test_gemini_tool_config.py x5,
test_temporal_context.py x4). 798 passing total.

Targets the temporal-dismissal failure mode that scored 0/4 on the first
live run of the 4-case regression set (run cbc335a1, 2026-05-01). Expected
3/4 pass post-fix (TrumpRx + Venezuela + Helicoide); Rubio still gated on
the deferred intra-family consensus tie-break P0.

Caveat: Gemini's function_calling_config.mode="ANY" is documented for
function-call tools, not the built-in google_search grounding tool. If
ANY is a no-op for grounding, the temporal preamble revisions are the
bigger lever. Plumbing the knob anyway keeps the adapter surfaces
symmetric and is harmless either way.

Refs: eval/sotu-2026/temporal-regressions-runbook.md;
PROJECT_BOARD.md P0 rows (NEW 2026-05-04).

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
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