Skip to content

feat(core): add a google_interactions dialect for the Gemini Interactions API - #249

Closed
ethan-scitix wants to merge 1 commit into
mainfrom
feat/google-interactions-dialect
Closed

ethan-scitix wants to merge 1 commit into
mainfrom
feat/google-interactions-dialect

Conversation

@ethan-scitix

Copy link
Copy Markdown
Collaborator

Type

  • feature — new benchmark, task, or capability

Summary

  • New dialect: google_interactions for Gemini's Interactions API (POST /{v1,v1beta}/interactions), beside google_genai (generateContent), as [Feature]: google_interactions dialect for the Gemini Interactions API #152 proposes. Interactions has no candidate count, top_k, penalties or logprobs, so those requests are refused before any I/O and stay on google_genai.
  • store: false on every request. Google otherwise retains prompt and reply server-side by default (55 days paid). The final HTTP body is re-checked for store: false, the bound model, and the absence of background / previous_interaction_id / agent. store is recorded in request_params, and no dialect option may override it.
  • Stateless multi-turn, because store: false disables previous_interaction_id. History is resent as user_input / model_output / function_call / function_result steps. Signed thought steps round-trip verbatim through opaque_continuation.
  • Supported: text and image input, function tools and tool choice, JSON output via response_format, thinking_level, thinking_summaries, temperature, top_p, max_tokens, stop, seed, and streaming (step.start / step.delta / step.stop, with streamed function arguments reassembled). Hosted tools are not lifted yet and are refused.
  • Termination: the interaction status is the finish reason, recorded verbatim. incomplete is added to the n_truncated spellings in core/utils/meta.py. As the issue notes, the record cannot tell a budget stop from a policy stop. requires_action is a function call; failed fails the sample with Google's message.
  • Usage: input = total_input_tokens + total_tool_use_tokens and output = total_output_tokens + total_thought_tokens, the same split as google_genai. reasoning_tokens stays a breakdown of output_tokens (cf. the feat(models): add native Google GenAI generateContent dialect #147 accounting fix).
  • Per [Feature]: Gemini model-family limits via model profiles; split google_genai.py #151: no model-family request limits, and no provider_enforced_capabilities, since none was measured on this endpoint.
  • Answers to the issue's open questions, from Google's own typed models in google-genai 2.33.0 (_gaos/types/interactions):
    • GenerationConfig does have temperature and top_p, though both are marked deprecated there.
    • Usage.total_output_tokens documents only "generated responses", with total_thought_tokens separate. Folding thoughts in mirrors generateContent's verified behaviour but is not live-verified here.
  • No identity or on-disk format change. RESULT_SCHEMA_VERSION and IDENTITY_SCHEMA are unchanged. No existing dialect emits a bare incomplete finish reason (openai_responses records incomplete_details.reason), so existing counts are unaffected.

Risk: the dialect is not live-verified. The scitix gateway does not proxy /interactions: POST .../v1beta/interactions and .../v1/interactions both return 404, while generateContent on the same key returns 200; probed 2026-10-27. Wire shapes come from the API reference and the SDK models. A first run against generativelanguage.googleapis.com should confirm the usage split and the streaming event order.

Related Issues

Closes #152. Refs #147, #151.

Test Plan

Automated

  • Lint/format clean (ruff check && ruff format --check): all checks passed, 687 files formatted
  • Type check clean: bare ty check (sieval + tests), all checks passed
  • Unit + integration: pytest tests/unit tests/integration -n 8, 10127 passed, 1 skipped
  • New tests/unit/core/models/dialects/test_google_interactions.py: 153 tests; coverage of google_interactions.py is 96%
  • Registry tests list the new dialect; the CLI dry-run reconcile test is parametrized over both Google dialects × {"", /v1, /v1beta}; the CLI api_key_env test asserts x-goog-api-key on the wire
  • scripts/check_preflight.py, check_layer_imports.py, sync_package_stubs.py --check: all pass

Manual

  • Probed the scitix gateway: /interactions 404 on both versions; generateContent control 200
  • Live call against generativelanguage.googleapis.com with a Gemini key: not done, since no key is available in this environment

Checklist

Required (all PRs)

  • PR title follows conventional format (type(scope): description)
  • No internal paths, credentials, or personal info in committed files
  • AI-generated code has AI-Generated Code - <model> (<provider>) in module docstring
  • No new upper-layer dependencies added to core/
  • Deleted code verified — no remaining call sites depend on it (none deleted)

🤖 Generated with Claude Code

…ions API

Google made the Interactions API (`POST /{v1,v1beta}/interactions`) GA and
recommends it for new work; new Gemini models and features launch there. It
sits beside `google_genai` (generateContent), not in place of it: the
Interactions GenerationConfig has no candidate count, no top_k, no penalties
and no logprobs, so those requests are refused before any I/O and stay on
`google_genai`.

- Every request sends `store: false`. Google otherwise retains the prompt and
  reply server-side by default (55 days paid). The flag is re-checked on the
  final HTTP body, together with the bound model and the absence of
  `background` / `previous_interaction_id` / `agent`, and recorded in
  `request_params`.
- Multi-turn is stateless (store=false disables previous_interaction_id):
  history is resent as `user_input` / `model_output` / `function_call` /
  `function_result` steps, and signed `thought` steps round-trip verbatim
  through `opaque_continuation`.
- Supported: text + image input, function tools and tool choice, JSON output
  (`response_format`), `thinking_level`, `thinking_summaries`, temperature,
  top_p, max_tokens, stop, seed, streaming (step.start/delta/stop events,
  streamed function arguments reassembled).
- The interaction `status` is the finish reason, recorded verbatim.
  `incomplete` counts toward `n_truncated`; it covers a budget and a policy
  stop alike. `failed` fails the sample with Google's message.
- Usage: input = total_input_tokens + total_tool_use_tokens, output =
  total_output_tokens + total_thought_tokens, the same split as google_genai.
- No model-family limits (#151) and no provider_enforced capabilities: none
  was measured on this endpoint.

The wire shapes come from the Interactions API reference and the typed models
in google-genai 2.33.0. The scitix gateway does not proxy `/interactions` (404
on v1 and v1beta, while generateContent answers 200 on the same key), so this
is not live-verified.

Closes #152

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ethan-scitix ethan-scitix mentioned this pull request Oct 27, 2026
7 tasks done
@ethan-scitix

Copy link
Copy Markdown
Collaborator Author

Superseded by #263, which covers everything here (same pre-I/O refusals, store: false guard, stateless opaque continuation, usage split, and the incomplete truncation spelling) and adds hosted tools (Google Search, URL context), live validation against generativelanguage.googleapis.com, and the body.stream normalization in request_definition that this PR was missing (streaming and non-streaming Interactions requests would otherwise hash to the same request definition).

Note: this PR said Closes #152; #263 only says Refs #152, so #152 needs to be closed by #263 or manually.

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.

[Feature]: google_interactions dialect for the Gemini Interactions API

1 participant