mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-12 08:42:18 +00:00
feat(interactions): forward continuation_token and type requires_continuation so callers can resume a long decode (#50151)
* feat(interactions): continue requires_continuation long decodes with continuation_token hops A foreground Interactions request stops at Google's per-hop output cap with status requires_continuation and a continuation_token. litellm now re-posts the request with previous_interaction_id and continuation_token until the status moves on, merging the hops into one interaction (last id, every hop's steps, summed usage with initial_input_tokens from hop 1), for non-streaming and streaming calls. continuation_token is accepted as a request param, and requires_continuation is a known status for billing. * refactor(gemini interactions): validate streaming chunks with model_validate * fix(interactions): keep the held completion across stream hops, stop on a repeated continuation_token, follow the spec redirect * fix(interactions): add grounding_tool_count per tool type, stop on any seen continuation_token, keep streaming past a [DONE] frame when a hop is pending * ci(interactions): point the spec canary at aistudio.google.com, where Google moved the Interactions OpenAPI spec * test(interactions): scripted Google ends each long decode hop with a [DONE] frame * refactor(interactions): pass requires_continuation and continuation_token through instead of looping hops in the proxy The caller drives the continuation, the same as against Google directly. /interactions accepts continuation_token in place of input so a resume request needs no input. * test(proxy): assert the accepted /interactions bodies pass the required-param check * fix(proxy): keep the router default fallback for input on /interactions, continuation_token stands in for it --------- Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
parent
4679b9f642
commit
3b20b48473
13 changed files with 547 additions and 260 deletions
|
|
@ -49,9 +49,9 @@ jobs:
|
|||
id: compliance
|
||||
run: |
|
||||
uv run --no-sync pytest tests/unit/interactions/test_openapi_compliance.py \
|
||||
--interactions-spec-url=https://ai.google.dev/static/api/interactions.openapi.json \
|
||||
--interactions-spec-url=https://aistudio.google.com/api-reference/interactions.openapi.json \
|
||||
--tb=short -vv -p no:rerunfailures -p no:pytest-retry \
|
||||
--allow-hosts=127.0.0.1,::1,localhost,ai.google.dev
|
||||
--allow-hosts=127.0.0.1,::1,localhost,ai.google.dev,aistudio.google.com
|
||||
|
||||
tracking-issue:
|
||||
name: tracking-issue
|
||||
|
|
|
|||
|
|
@ -71,12 +71,12 @@ if TYPE_CHECKING:
|
|||
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
|
||||
|
||||
_TERMINAL_STATUSES: Final = frozenset(
|
||||
{"completed", "failed", "cancelled", "incomplete", "budget_exceeded", "requires_action"}
|
||||
{"completed", "failed", "cancelled", "incomplete", "budget_exceeded", "requires_action", "requires_continuation"}
|
||||
)
|
||||
|
||||
_POLLABLE_STATUSES: Final = frozenset({"in_progress", "queued"})
|
||||
|
||||
_STATUSES_THAT_PRODUCED_OUTPUT: Final = frozenset({"completed", "requires_action"})
|
||||
_STATUSES_THAT_PRODUCED_OUTPUT: Final = frozenset({"completed", "requires_action", "requires_continuation"})
|
||||
|
||||
SettlementOutcome: TypeAlias = Literal["billed", "released", "unsettled"]
|
||||
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ async def acreate(
|
|||
response_mime_type: str | None = None,
|
||||
# Continuation
|
||||
previous_interaction_id: str | None = None,
|
||||
continuation_token: str | None = None,
|
||||
# Extra params
|
||||
extra_headers: dict[str, str] | None = None,
|
||||
extra_body: Mapping[str, object] | None = None,
|
||||
|
|
@ -129,6 +130,7 @@ async def acreate(
|
|||
response_format: JSON schema for response format
|
||||
response_mime_type: MIME type of the response
|
||||
previous_interaction_id: ID of previous interaction for continuation
|
||||
continuation_token: Token from a `requires_continuation` interaction to resume its long decode
|
||||
extra_headers: Additional headers
|
||||
extra_body: Additional body parameters
|
||||
timeout: Request timeout
|
||||
|
|
@ -164,6 +166,7 @@ async def acreate(
|
|||
response_format=response_format,
|
||||
response_mime_type=response_mime_type,
|
||||
previous_interaction_id=previous_interaction_id,
|
||||
continuation_token=continuation_token,
|
||||
extra_headers=extra_headers,
|
||||
extra_body=extra_body,
|
||||
timeout=timeout,
|
||||
|
|
@ -224,6 +227,7 @@ def create(
|
|||
response_mime_type: str | None = None,
|
||||
# Continuation
|
||||
previous_interaction_id: str | None = None,
|
||||
continuation_token: str | None = None,
|
||||
# Extra params
|
||||
extra_headers: dict[str, str] | None = None,
|
||||
extra_body: Mapping[str, object] | None = None,
|
||||
|
|
@ -262,6 +266,7 @@ def create(
|
|||
response_format: JSON schema for response format
|
||||
response_mime_type: MIME type of the response
|
||||
previous_interaction_id: ID of previous interaction for continuation
|
||||
continuation_token: Token from a `requires_continuation` interaction to resume its long decode
|
||||
extra_headers: Additional headers
|
||||
extra_body: Additional body parameters
|
||||
timeout: Request timeout
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ INTERACTIONS_API_OPTIONAL_PARAMS: Final = {
|
|||
"response_format",
|
||||
"response_mime_type",
|
||||
"previous_interaction_id",
|
||||
"continuation_token",
|
||||
"agent_config",
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ class GoogleAIStudioInteractionsConfig(BaseInteractionsAPIConfig):
|
|||
"response_format",
|
||||
"response_mime_type",
|
||||
"previous_interaction_id",
|
||||
"continuation_token",
|
||||
]
|
||||
|
||||
def validate_environment(
|
||||
|
|
@ -206,6 +207,7 @@ class GoogleAIStudioInteractionsConfig(BaseInteractionsAPIConfig):
|
|||
"environment",
|
||||
"response_modalities",
|
||||
"previous_interaction_id",
|
||||
"continuation_token",
|
||||
]
|
||||
dropped_keys: Final = (
|
||||
frozenset({"agent_config"})
|
||||
|
|
@ -301,7 +303,7 @@ class GoogleAIStudioInteractionsConfig(BaseInteractionsAPIConfig):
|
|||
) -> InteractionsAPIStreamingResponse:
|
||||
"""Parse streaming chunk."""
|
||||
verbose_logger.debug("Google AI Interactions streaming chunk: %s", parsed_chunk)
|
||||
return InteractionsAPIStreamingResponse(**parsed_chunk)
|
||||
return InteractionsAPIStreamingResponse.model_validate(parsed_chunk)
|
||||
|
||||
# GET / DELETE / CANCEL - just build URLs, responses match spec directly
|
||||
|
||||
|
|
|
|||
|
|
@ -271,6 +271,10 @@ REQUIRED_ONE_OF_BODY_PARAMS_BY_ROUTE: Final[Mapping[str, tuple[str, str]]] = Map
|
|||
{"acreate_interaction": ("model", "agent"), "acreate_agent": ("id", "name")}
|
||||
)
|
||||
|
||||
BODY_PARAM_ALTERNATIVES_BY_ROUTE: Final[Mapping[str, Mapping[str, tuple[str, ...]]]] = MappingProxyType(
|
||||
{"acreate_interaction": MappingProxyType({"input": ("continuation_token",)})}
|
||||
)
|
||||
|
||||
JSON_OBJECT_ADAPTER: Final[TypeAdapter[dict[str, object]]] = TypeAdapter(dict[str, object])
|
||||
_OPTIONAL_JSON_OBJECT_ADAPTER: Final[TypeAdapter[Mapping[str, object] | None]] = TypeAdapter(
|
||||
Mapping[str, object] | None
|
||||
|
|
@ -320,8 +324,11 @@ def _find_missing_required_body_param(
|
|||
)
|
||||
if missing_merge_base_param is not None:
|
||||
return MissingBodyParam(name=missing_merge_base_param, model_deployments_loaded=True)
|
||||
alternatives: Final = BODY_PARAM_ALTERNATIVES_BY_ROUTE.get(route_type, {})
|
||||
missing_present_params: Final = tuple(
|
||||
param for param in REQUIRED_PRESENT_BODY_PARAMS_BY_ROUTE.get(route_type, ()) if param not in data
|
||||
param
|
||||
for param in REQUIRED_PRESENT_BODY_PARAMS_BY_ROUTE.get(route_type, ())
|
||||
if param not in data and not any(alternative in data for alternative in alternatives.get(param, ()))
|
||||
)
|
||||
if not missing_present_params:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -176,11 +176,16 @@ class Status1(Enum):
|
|||
incomplete = "incomplete"
|
||||
budget_exceeded = "budget_exceeded"
|
||||
queued = "queued"
|
||||
requires_continuation = "requires_continuation"
|
||||
|
||||
|
||||
class InteractionStatusUpdate(LiteLLMBaseModel):
|
||||
interaction_id: str | None = None
|
||||
status: Status1 | None = None
|
||||
continuation_token: str | None = Field(
|
||||
None,
|
||||
description="Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
)
|
||||
event_type: Literal["interaction.status_update"] = "interaction.status_update"
|
||||
event_id: str | None = Field(
|
||||
None,
|
||||
|
|
@ -343,6 +348,7 @@ class Status3(Enum):
|
|||
INCOMPLETE = "incomplete"
|
||||
BUDGET_EXCEEDED = "budget_exceeded"
|
||||
QUEUED = "queued"
|
||||
REQUIRES_CONTINUATION = "requires_continuation"
|
||||
|
||||
|
||||
class ModelOption(RootModel[str]):
|
||||
|
|
@ -604,6 +610,9 @@ class ToolChoice(RootModel[ToolChoiceType | ToolChoiceConfig]):
|
|||
|
||||
class Usage(LiteLLMBaseModel):
|
||||
total_input_tokens: int | None = Field(None, description="Number of tokens in the prompt (context).")
|
||||
initial_input_tokens: int | None = Field(
|
||||
None, description="Number of tokens in the prompt of the first hop of a long decode."
|
||||
)
|
||||
input_tokens_by_modality: list[ModalityTokens] | None = Field(
|
||||
None, description="A breakdown of input token usage by modality."
|
||||
)
|
||||
|
|
@ -625,6 +634,7 @@ class Usage(LiteLLMBaseModel):
|
|||
None, description="A breakdown of tool-use token usage by modality."
|
||||
)
|
||||
total_reasoning_tokens: int | None = Field(None, description="Number of tokens of thoughts for thinking models.")
|
||||
total_thought_tokens: int | None = Field(None, description="Number of tokens of thoughts for thinking models.")
|
||||
total_tokens: int | None = Field(
|
||||
None,
|
||||
description="Total token count for the interaction request (prompt + responses + other\ninternal tokens).",
|
||||
|
|
@ -787,6 +797,10 @@ class Interaction(LiteLLMBaseModel):
|
|||
description="The mime type of the response. This is required if response_format is set.",
|
||||
)
|
||||
previous_interaction_id: str | None = Field(None, description="The ID of the previous interaction, if any.")
|
||||
continuation_token: str | None = Field(
|
||||
None,
|
||||
description="Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
)
|
||||
input: str | list[Content] | list[Turn] | Content | None = Field(
|
||||
None, description="The inputs for the interaction."
|
||||
)
|
||||
|
|
@ -843,6 +857,10 @@ class CreateModelInteractionParams(LiteLLMBaseModel):
|
|||
description="The mime type of the response. This is required if response_format is set.",
|
||||
)
|
||||
previous_interaction_id: str | None = Field(None, description="The ID of the previous interaction, if any.")
|
||||
continuation_token: str | None = Field(
|
||||
None,
|
||||
description="Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
)
|
||||
input: str | list[Content] | list[Turn] | Content = Field(..., description="The inputs for the interaction.")
|
||||
generation_config: GenerationConfig | None = Field(
|
||||
None,
|
||||
|
|
@ -894,6 +912,10 @@ class CreateAgentInteractionParams(LiteLLMBaseModel):
|
|||
description="The mime type of the response. This is required if response_format is set.",
|
||||
)
|
||||
previous_interaction_id: str | None = Field(None, description="The ID of the previous interaction, if any.")
|
||||
continuation_token: str | None = Field(
|
||||
None,
|
||||
description="Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
)
|
||||
input: str | list[Content] | list[Turn] | Content = Field(..., description="The inputs for the interaction.")
|
||||
agent_config: DynamicAgentConfig | DeepResearchAgentConfig | None = Field(
|
||||
None, description="Configuration for the agent.", discriminator="type"
|
||||
|
|
@ -1080,6 +1102,7 @@ class InteractionsAPIResponse(BaseLiteLLMOpenAIResponseObject):
|
|||
# New schema field (Api-Revision: 2026-05-20).
|
||||
steps: list[dict[str, Any]] | None = None
|
||||
usage: dict[str, Any] | None = None
|
||||
continuation_token: str | None = None
|
||||
|
||||
_hidden_params: dict = PrivateAttr(default_factory=dict)
|
||||
|
||||
|
|
@ -1126,6 +1149,7 @@ class InteractionsAPIStreamingResponse(BaseLiteLLMOpenAIResponseObject):
|
|||
step: dict[str, Any] | None = None
|
||||
interaction_id: str | None = None
|
||||
interaction: dict[str, Any] | None = None
|
||||
continuation_token: str | None = None
|
||||
|
||||
_hidden_params: dict = PrivateAttr(default_factory=dict)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import json
|
||||
import uuid
|
||||
from pathlib import Path
|
||||
from typing import Final
|
||||
|
||||
|
|
@ -147,6 +146,7 @@ def test_interaction_forwards_native_body_to_gemini(gateway: Gateway, prefix: st
|
|||
"agent": None,
|
||||
"updated": None,
|
||||
"outputs": None,
|
||||
"continuation_token": None,
|
||||
}, response.text
|
||||
assert [(r.method, r.target) for r in wire.drain()] == [("POST", "/v1beta/interactions")], response.text
|
||||
|
||||
|
|
@ -179,6 +179,7 @@ def test_interaction_authenticates_google_key_header(gateway: Gateway, prefix: s
|
|||
"agent": None,
|
||||
"updated": None,
|
||||
"outputs": None,
|
||||
"continuation_token": None,
|
||||
}, response.text
|
||||
assert [(r.method, r.target) for r in wire.drain()] == [("POST", "/v1beta/interactions")], response.text
|
||||
|
||||
|
|
@ -218,6 +219,7 @@ def test_agent_interaction_uses_env_gemini_credentials(gateway: Gateway, tmp_pat
|
|||
"agent": "deep-research-pro-preview-12-2025",
|
||||
"updated": None,
|
||||
"outputs": None,
|
||||
"continuation_token": None,
|
||||
}, response.text
|
||||
assert [(r.method, r.target) for r in wire.drain()] == [("POST", "/v1beta/interactions")], response.text
|
||||
|
||||
|
|
@ -277,3 +279,78 @@ def test_stream_interaction_ends_without_openai_done_terminator(gateway: Gateway
|
|||
expected: Final = b"".join(_proxy_stream_event(payload, model) for _event_type, payload in _STREAM_EVENTS)
|
||||
assert response.content == expected, response.text
|
||||
assert [(r.method, r.target) for r in wire.drain()] == [("POST", "/v1beta/interactions?alt=sse")]
|
||||
|
||||
|
||||
_LONG_DECODE_MODEL: Final = "gemini/gemini-4-argon"
|
||||
_LONG_DECODE_BODY: Final = {
|
||||
"input": "prove the prime number theorem",
|
||||
"generation_config": {"max_output_tokens": 120000, "thinking_level": "high"},
|
||||
}
|
||||
|
||||
|
||||
def _hop(hop_id: str, status: str, text: str, token: str | None, input_tokens: int, output_tokens: int) -> dict:
|
||||
return {
|
||||
"id": hop_id,
|
||||
"object": "interaction",
|
||||
"model": "gemini-4-argon",
|
||||
"status": status,
|
||||
"created": "2026-11-05T00:00:00Z",
|
||||
"steps": [{"type": "model_output", "content": [{"type": "text", "text": text}]}],
|
||||
"usage": {
|
||||
"total_input_tokens": input_tokens,
|
||||
"total_output_tokens": output_tokens,
|
||||
"total_tokens": input_tokens + output_tokens,
|
||||
"initial_input_tokens": 79,
|
||||
},
|
||||
"continuation_token": token,
|
||||
}
|
||||
|
||||
|
||||
_FIRST_HOP: Final = _hop("interaction-hop-1", "requires_continuation", "Lemma 1.", "tok-1", 79, 32768)
|
||||
_SECOND_HOP: Final = _hop("interaction-hop-2", "completed", " QED.", None, 32847, 1533)
|
||||
|
||||
|
||||
def test_interaction_keeps_requires_continuation_status_and_token_for_the_caller(gateway: Gateway) -> None:
|
||||
def respond(request: Request) -> Reply:
|
||||
assert request.target == "/v1beta/interactions"
|
||||
return Reply(body=json.dumps(_FIRST_HOP).encode())
|
||||
|
||||
with wire_server(respond) as wire, gateway.scenario() as scenario:
|
||||
model: Final = scenario.model(model=_LONG_DECODE_MODEL, api_base=wire.url, api_key=_GEMINI_DEPLOYMENT_KEY)
|
||||
key: Final = scenario.key(models=[model])
|
||||
response: Final = gateway.request(
|
||||
"POST", "/v1beta/interactions", {"model": model, **_LONG_DECODE_BODY}, key=key
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
sent: Final = [json.loads(r.body) for r in wire.drain()]
|
||||
|
||||
assert sent == [{"model": "gemini-4-argon", **_LONG_DECODE_BODY}], sent
|
||||
payload: Final = response.json()
|
||||
assert payload["id"] == "interaction-hop-1", response.text
|
||||
assert payload["status"] == "requires_continuation", response.text
|
||||
assert payload["continuation_token"] == "tok-1", response.text
|
||||
assert payload["usage"]["initial_input_tokens"] == 79, response.text
|
||||
|
||||
|
||||
def test_interaction_forwards_a_caller_continuation_token_to_resume_a_long_decode(gateway: Gateway) -> None:
|
||||
def respond(request: Request) -> Reply:
|
||||
assert request.target == "/v1beta/interactions"
|
||||
return Reply(body=json.dumps(_SECOND_HOP).encode())
|
||||
|
||||
resume: Final = {
|
||||
"generation_config": _LONG_DECODE_BODY["generation_config"],
|
||||
"previous_interaction_id": "interaction-hop-1",
|
||||
"continuation_token": "tok-1",
|
||||
}
|
||||
with wire_server(respond) as wire, gateway.scenario() as scenario:
|
||||
model: Final = scenario.model(model=_LONG_DECODE_MODEL, api_base=wire.url, api_key=_GEMINI_DEPLOYMENT_KEY)
|
||||
key: Final = scenario.key(models=[model])
|
||||
response: Final = gateway.request("POST", "/v1beta/interactions", {"model": model, **resume}, key=key)
|
||||
assert response.status_code == 200, response.text
|
||||
sent: Final = [json.loads(r.body) for r in wire.drain()]
|
||||
|
||||
assert sent == [{"model": "gemini-4-argon", **resume}], sent
|
||||
payload: Final = response.json()
|
||||
assert payload["id"] == "interaction-hop-2", response.text
|
||||
assert payload["status"] == "completed", response.text
|
||||
assert payload["continuation_token"] is None, response.text
|
||||
|
|
|
|||
|
|
@ -756,7 +756,7 @@
|
|||
{
|
||||
"label": "list",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n res, err := client.Environments.ListEnvironments(ctx, operations.ListEnvironmentsRequest{})\n if err != nil {\n log.Fatal(err)\n }\n\n if res.ListEnvironmentsResponse != nil {\n for _, env := range res.ListEnvironmentsResponse.Environments {\n if env.ID != \"\" {\n fmt.Println(env.ID)\n }\n }\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n res, err := client.Environments.ListEnvironments(ctx, operations.ListEnvironmentsRequest{})\n if err != nil {\n log.Fatal(err)\n }\n\n if res.ListEnvironmentsResponse != nil {\n for _, env := range res.ListEnvironmentsResponse.Environments {\n if env.ID != \"\" {\n fmt.Println(env.ID)\n }\n }\n }\n}\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -834,12 +834,12 @@
|
|||
{
|
||||
"label": "create",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n gaos_environments \"google.golang.org/genai/interactions/models/environments\"\n gaos_interactions \"google.golang.org/genai/interactions/models/interactions\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n req := operations.CreateEnvironmentRequest{\n Body: gaos_environments.CreateEnvironmentRequest{\n Sources: []gaos_interactions.Source{\n {\n Type: genai.Ptr(gaos_interactions.SourceTypeInline),\n Target: genai.Ptr(\"main.py\"),\n Content: genai.Ptr(\"print('Hello, World!')\"),\n },\n },\n },\n }\n\n res, err := client.Environments.CreateEnvironment(ctx, req)\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Environment != nil && res.Environment.ID != \"\" {\n fmt.Println(res.Environment.ID)\n\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n gaos_environments \"google.golang.org/genai/interactions/models/environments\"\n gaos_interactions \"google.golang.org/genai/interactions/models/interactions\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n req := operations.CreateEnvironmentRequest{\n Body: gaos_environments.CreateEnvironmentRequest{\n Sources: []gaos_interactions.Source{\n {\n Type: genai.Ptr(gaos_interactions.SourceTypeInline),\n Target: genai.Ptr(\"main.py\"),\n Content: genai.Ptr(\"print('Hello, World!')\"),\n },\n },\n },\n }\n\n res, err := client.Environments.CreateEnvironment(ctx, req)\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Environment != nil && res.Environment.ID != \"\" {\n fmt.Println(res.Environment.ID)\n\n }\n}\n"
|
||||
},
|
||||
{
|
||||
"label": "copy",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n gaos_environments \"google.golang.org/genai/interactions/models/environments\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n\n res, err := client.Environments.CreateEnvironment(ctx, operations.CreateEnvironmentRequest{\n Body: gaos_environments.CreateEnvironmentRequest{\n FromEnvironment: genai.Ptr(sourceEnvID),\n },\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Environment != nil && res.Environment.ID != \"\" {\n fmt.Println(res.Environment.ID)\n\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n gaos_environments \"google.golang.org/genai/interactions/models/environments\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n\n res, err := client.Environments.CreateEnvironment(ctx, operations.CreateEnvironmentRequest{\n Body: gaos_environments.CreateEnvironmentRequest{\n FromEnvironment: genai.Ptr(sourceEnvID),\n },\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Environment != nil && res.Environment.ID != \"\" {\n fmt.Println(res.Environment.ID)\n\n }\n}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -967,12 +967,12 @@
|
|||
{
|
||||
"label": "list_files",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n\n res, err := client.Environments.Files.List(ctx, operations.GetEnvironmentFilesRequest{\n Environment: envID,\n Path: \"src\",\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.GetEnvironmentFilesResponse != nil {\n for _, file := range res.GetEnvironmentFilesResponse.Files {\n name := \"\"\n if file.Name != nil {\n name = *file.Name\n }\n fileType := \"\"\n if file.Type != nil {\n fileType = string(*file.Type)\n }\n var size int64\n if file.SizeBytes != nil {\n size = *file.SizeBytes\n }\n fmt.Println(name, fileType, size)\n }\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n\n res, err := client.Environments.Files.List(ctx, operations.GetEnvironmentFilesRequest{\n Environment: envID,\n Path: \"src\",\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.GetEnvironmentFilesResponse != nil {\n for _, file := range res.GetEnvironmentFilesResponse.Files {\n name := \"\"\n if file.Name != nil {\n name = *file.Name\n }\n fileType := \"\"\n if file.Type != nil {\n fileType = string(*file.Type)\n }\n var size int64\n if file.SizeBytes != nil {\n size = *file.SizeBytes\n }\n fmt.Println(name, fileType, size)\n }\n }\n}\n"
|
||||
},
|
||||
{
|
||||
"label": "get_file",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n\n res, err := client.Environments.Files.List(ctx, operations.GetEnvironmentFilesRequest{\n Environment: envID,\n Path: \"main.py\",\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.GetEnvironmentFilesResponse != nil {\n for _, file := range res.GetEnvironmentFilesResponse.Files {\n name := \"\"\n if file.Name != nil {\n name = *file.Name\n }\n var size int64\n if file.SizeBytes != nil {\n size = *file.SizeBytes\n }\n fmt.Println(name, size)\n }\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n\n res, err := client.Environments.Files.List(ctx, operations.GetEnvironmentFilesRequest{\n Environment: envID,\n Path: \"main.py\",\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.GetEnvironmentFilesResponse != nil {\n for _, file := range res.GetEnvironmentFilesResponse.Files {\n name := \"\"\n if file.Name != nil {\n name = *file.Name\n }\n var size int64\n if file.SizeBytes != nil {\n size = *file.SizeBytes\n }\n fmt.Println(name, size)\n }\n }\n}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1036,7 +1036,7 @@
|
|||
{
|
||||
"label": "delete",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n\n _, err = client.Environments.DeleteEnvironment(ctx, operations.DeleteEnvironmentRequest{\n ID: envID,\n })\n if err != nil {\n log.Fatal(err)\n }\n fmt.Println(\"Environment deleted successfully.\")\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n\n _, err = client.Environments.DeleteEnvironment(ctx, operations.DeleteEnvironmentRequest{\n ID: envID,\n })\n if err != nil {\n log.Fatal(err)\n }\n fmt.Println(\"Environment deleted successfully.\")\n}\n"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -1093,7 +1093,7 @@
|
|||
{
|
||||
"label": "get",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client := interactions.New()\n\n\n res, err := client.Environments.GetEnvironment(ctx, operations.GetEnvironmentRequest{\n ID: envID,\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Environment != nil && res.Environment.ID != \"\" {\n fmt.Println(res.Environment.ID)\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n\n res, err := client.Environments.GetEnvironment(ctx, operations.GetEnvironmentRequest{\n ID: envID,\n })\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Environment != nil && res.Environment.ID != \"\" {\n fmt.Println(res.Environment.ID)\n }\n}\n"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1171,7 +1171,7 @@
|
|||
"deep_research": {
|
||||
"summary": "Deep Research",
|
||||
"value": {
|
||||
"agent": "deep-research-pro-preview-12-2025",
|
||||
"agent": "deep-research-preview-04-2026",
|
||||
"created": "2025-11-26T12:22:47Z",
|
||||
"id": "v1_ChdPU0F4YWFtNkFwS2kxZThQZ05lbXdROBIXT1NBeGFhbTZBcEtpMWU4UGdOZW13UTg",
|
||||
"object": "interaction",
|
||||
|
|
@ -1472,7 +1472,7 @@
|
|||
{
|
||||
"label": "deep_research",
|
||||
"lang": "sh",
|
||||
"source": "curl -X POST https://generativelanguage.googleapis.com/v1beta/interactions \\\n -H \"x-goog-api-key: $GEMINI_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"agent\": \"deep-research-pro-preview-12-2025\",\n \"input\": \"Find a cure to cancer\",\n \"background\": true\n }'\n"
|
||||
"source": "curl -X POST https://generativelanguage.googleapis.com/v1beta/interactions \\\n -H \"x-goog-api-key: $GEMINI_API_KEY\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"agent\": \"deep-research-preview-04-2026\",\n \"input\": \"Find a cure to cancer\",\n \"background\": true\n }'\n"
|
||||
},
|
||||
{
|
||||
"label": "antigravity",
|
||||
|
|
@ -1517,7 +1517,7 @@
|
|||
{
|
||||
"label": "deep_research",
|
||||
"lang": "python",
|
||||
"source": "from google import genai\n\nclient = genai.Client()\ninteraction = client.interactions.create(\n agent=\"deep-research-pro-preview-12-2025\",\n input=\"find a cure to cancer\",\n background=True,\n)\nprint(interaction.status)\n"
|
||||
"source": "from google import genai\n\nclient = genai.Client()\ninteraction = client.interactions.create(\n agent=\"deep-research-preview-04-2026\",\n input=\"find a cure to cancer\",\n background=True,\n)\nprint(interaction.status)\n"
|
||||
},
|
||||
{
|
||||
"label": "antigravity",
|
||||
|
|
@ -1562,7 +1562,7 @@
|
|||
{
|
||||
"label": "deep_research",
|
||||
"lang": "javascript",
|
||||
"source": "import {GoogleGenAI} from '@google/genai';\n\nconst ai = new GoogleGenAI({});\nconst interaction = await ai.interactions.create({\n agent: 'deep-research-pro-preview-12-2025',\n input: 'find a cure to cancer',\n background: true,\n});\nconsole.log(interaction.status);\n"
|
||||
"source": "import {GoogleGenAI} from '@google/genai';\n\nconst ai = new GoogleGenAI({});\nconst interaction = await ai.interactions.create({\n agent: 'deep-research-preview-04-2026',\n input: 'find a cure to cancer',\n background: true,\n});\nconsole.log(interaction.status);\n"
|
||||
},
|
||||
{
|
||||
"label": "antigravity",
|
||||
|
|
@ -1607,7 +1607,7 @@
|
|||
{
|
||||
"label": "deep_research",
|
||||
"lang": "java",
|
||||
"source": "import com.google.genai.gaos.models.interactions.AgentOption;\nimport com.google.genai.Client;\nimport com.google.genai.gaos.models.interactions.CreateAgentInteraction;\nimport com.google.genai.gaos.models.operations.CreateInteractionRequestBody;\nimport com.google.genai.gaos.models.operations.CreateInteractionResponse;\nimport com.google.genai.gaos.models.interactions.Interaction;\nimport com.google.genai.gaos.models.interactions.InteractionStatus;\nimport com.google.genai.gaos.models.interactions.InteractionsInput;\n\nClient client = new Client();\nCreateAgentInteraction params =\n CreateAgentInteraction.builder()\n .agent(AgentOption.of(\"deep-research-pro-preview-12-2025\"))\n .input(InteractionsInput.of(\"find a cure to cancer\"))\n .background(true)\n .build();\nCreateInteractionResponse response =\n client.interactions.create(CreateInteractionRequestBody.of(params));\nInteraction interaction =\n response.interaction().orElseThrow(() -> new RuntimeException(\"No interaction returned\"));\nSystem.out.println(interaction.status().map(InteractionStatus::value).orElse(\"\"));\n"
|
||||
"source": "import com.google.genai.gaos.models.interactions.AgentOption;\nimport com.google.genai.Client;\nimport com.google.genai.gaos.models.interactions.CreateAgentInteraction;\nimport com.google.genai.gaos.models.operations.CreateInteractionRequestBody;\nimport com.google.genai.gaos.models.operations.CreateInteractionResponse;\nimport com.google.genai.gaos.models.interactions.Interaction;\nimport com.google.genai.gaos.models.interactions.InteractionStatus;\nimport com.google.genai.gaos.models.interactions.InteractionsInput;\n\nClient client = new Client();\nCreateAgentInteraction params =\n CreateAgentInteraction.builder()\n .agent(AgentOption.of(\"deep-research-preview-04-2026\"))\n .input(InteractionsInput.of(\"find a cure to cancer\"))\n .background(true)\n .build();\nCreateInteractionResponse response =\n client.interactions.create(CreateInteractionRequestBody.of(params));\nInteraction interaction =\n response.interaction().orElseThrow(() -> new RuntimeException(\"No interaction returned\"));\nSystem.out.println(interaction.status().map(InteractionStatus::value).orElse(\"\"));\n"
|
||||
},
|
||||
{
|
||||
"label": "antigravity",
|
||||
|
|
@ -1652,7 +1652,7 @@
|
|||
{
|
||||
"label": "deep_research",
|
||||
"lang": "go",
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n gaos_interactions \"google.golang.org/genai/interactions/models/interactions\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n body := operations.NewCreateInteractionRequestBody(gaos_interactions.CreateAgentInteraction{\n Agent: gaos_interactions.AgentOption(\"deep-research-pro-preview-12-2025\"),\n Input: genai.Ptr(gaos_interactions.NewInteractionsInput(\"find a cure to cancer\")),\n Background: genai.Ptr(true),\n })\n\n req := operations.CreateInteractionRequest{\n Body: body,\n }\n\n res, err := client.Interactions.Create(ctx, req)\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Interaction != nil {\n fmt.Println(res.Interaction.Status)\n }\n}\n"
|
||||
"source": "package main\n\nimport (\n \"context\"\n \"fmt\"\n \"log\"\n \"google.golang.org/genai\"\n gaos_interactions \"google.golang.org/genai/interactions/models/interactions\"\n \"google.golang.org/genai/interactions/models/operations\"\n)\n\nfunc main() {\n ctx := context.Background()\n client, err := genai.NewClient(ctx, nil)\n if err != nil {\n log.Fatal(err)\n }\n\n body := operations.NewCreateInteractionRequestBody(gaos_interactions.CreateAgentInteraction{\n Agent: gaos_interactions.AgentOption(\"deep-research-preview-04-2026\"),\n Input: genai.Ptr(gaos_interactions.NewInteractionsInput(\"find a cure to cancer\")),\n Background: genai.Ptr(true),\n })\n\n req := operations.CreateInteractionRequest{\n Body: body,\n }\n\n res, err := client.Interactions.Create(ctx, req)\n if err != nil {\n log.Fatal(err)\n }\n\n if res.Interaction != nil {\n fmt.Println(res.Interaction.Status)\n }\n}\n"
|
||||
},
|
||||
{
|
||||
"label": "antigravity",
|
||||
|
|
@ -3041,6 +3041,22 @@
|
|||
"description": "An agent definition for the CreateAgent API.\nThis message is the target for annotation-parser-based JSON parsing.\nNew format:\n {\n \"id\": \"customer-sentinel\",\n \"base_agent\": \"\",\n \"system_instruction\": \"...\",\n \"base_environment\": { \"type\": \"remote\", \"sources\": [...] },\n \"tools\": [ {\"type\": \"code_execution\"} ]\n }",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"description": "The unique identifier for the agent.",
|
||||
"type": "string"
|
||||
},
|
||||
"base_agent": {
|
||||
"description": "The base agent to extend.",
|
||||
"type": "string"
|
||||
},
|
||||
"system_instruction": {
|
||||
"description": "System instruction for the agent.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Agent description for developers to quickly read and understand.",
|
||||
"type": "string"
|
||||
},
|
||||
"agent_config": {
|
||||
"description": "Configuration parameters for the agent.",
|
||||
"oneOf": [
|
||||
|
|
@ -3060,22 +3076,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "The unique identifier for the agent.",
|
||||
"type": "string"
|
||||
},
|
||||
"base_agent": {
|
||||
"description": "The base agent to extend.",
|
||||
"type": "string"
|
||||
},
|
||||
"system_instruction": {
|
||||
"description": "System instruction for the agent.",
|
||||
"type": "string"
|
||||
},
|
||||
"description": {
|
||||
"description": "Agent description for developers to quickly read and understand.",
|
||||
"type": "string"
|
||||
},
|
||||
"tools": {
|
||||
"description": "The tools available to the agent.",
|
||||
"type": "array",
|
||||
|
|
@ -3091,13 +3091,11 @@
|
|||
"description": "The agent to interact with.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"deep-research-pro-preview-12-2025",
|
||||
"deep-research-preview-04-2026",
|
||||
"deep-research-max-preview-04-2026",
|
||||
"antigravity-preview-05-2026"
|
||||
],
|
||||
"x-speakeasy-enum-descriptions": [
|
||||
"Gemini Deep Research Agent",
|
||||
"Gemini Deep Research Agent",
|
||||
"Gemini Deep Research Max Agent",
|
||||
"Use the Antigravity managed agent to perform multi-step tasks that require reasoning, file operations, and tool use."
|
||||
|
|
@ -3330,14 +3328,6 @@
|
|||
"type": {
|
||||
"const": "audio"
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -3371,6 +3361,14 @@
|
|||
"WEBM audio format"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"rate": {
|
||||
"description": "Deprecated. Use sample_rate instead. The value is ignored.",
|
||||
"type": "integer",
|
||||
|
|
@ -3817,32 +3815,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"response_format": {
|
||||
"description": "Enforces that the generated response is a JSON object that complies with\nthe JSON schema specified in this field.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
},
|
||||
{
|
||||
"title": "ResponseFormatList",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment": {
|
||||
"description": "The environment configuration for the interaction. Can be an object\nspecifying remote environment sources or a string referencing an existing\nenvironment ID.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnvironmentConfig"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "Required. Output only. A unique identifier for the interaction completion.",
|
||||
"type": "string",
|
||||
|
|
@ -3858,7 +3830,8 @@
|
|||
"failed",
|
||||
"cancelled",
|
||||
"incomplete",
|
||||
"budget_exceeded"
|
||||
"budget_exceeded",
|
||||
"requires_continuation"
|
||||
],
|
||||
"readOnly": true,
|
||||
"x-google-enum-deprecated": [
|
||||
|
|
@ -3868,7 +3841,8 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
false
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"The interaction is in progress.",
|
||||
|
|
@ -3877,7 +3851,8 @@
|
|||
"The interaction failed.",
|
||||
"The interaction was cancelled.",
|
||||
"The interaction is completed, but contains incomplete results (e.g.\nhitting max_tokens).",
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11)."
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11).",
|
||||
"The interaction requires at least one more request for it to be\ncompleted. The next request should set the continuation_token to the one\nreturned by this request."
|
||||
]
|
||||
},
|
||||
"created": {
|
||||
|
|
@ -3909,6 +3884,21 @@
|
|||
"$ref": "#/components/schemas/ResponseModality"
|
||||
}
|
||||
},
|
||||
"response_format": {
|
||||
"description": "Enforces that the generated response is a JSON object that complies with\nthe JSON schema specified in this field.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
},
|
||||
{
|
||||
"title": "ResponseFormatList",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"response_mime_type": {
|
||||
"description": "The mime type of the response. This is required if response_format is set.",
|
||||
"type": "string",
|
||||
|
|
@ -3918,6 +3908,17 @@
|
|||
"description": "The ID of the previous interaction, if any.",
|
||||
"type": "string"
|
||||
},
|
||||
"environment": {
|
||||
"description": "The environment configuration for the interaction. Can be an object\nspecifying remote environment sources or a string referencing an existing\nenvironment ID.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnvironmentConfig"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment_id": {
|
||||
"description": "Output only. The environment ID for the interaction. Only populated if environment\nconfig is set in the request.",
|
||||
"type": "string",
|
||||
|
|
@ -3945,6 +3946,12 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"continuation_token": {
|
||||
"description": "Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"stream": {
|
||||
"description": "Input only. Whether the interaction will be streamed.",
|
||||
"type": "boolean",
|
||||
|
|
@ -4018,32 +4025,6 @@
|
|||
"$ref": "#/components/schemas/GenerationConfig",
|
||||
"writeOnly": true
|
||||
},
|
||||
"response_format": {
|
||||
"description": "Enforces that the generated response is a JSON object that complies with\nthe JSON schema specified in this field.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
},
|
||||
{
|
||||
"title": "ResponseFormatList",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment": {
|
||||
"description": "The environment configuration for the interaction. Can be an object\nspecifying remote environment sources or a string referencing an existing\nenvironment ID.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnvironmentConfig"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"id": {
|
||||
"description": "Required. Output only. A unique identifier for the interaction completion.",
|
||||
"type": "string",
|
||||
|
|
@ -4059,7 +4040,8 @@
|
|||
"failed",
|
||||
"cancelled",
|
||||
"incomplete",
|
||||
"budget_exceeded"
|
||||
"budget_exceeded",
|
||||
"requires_continuation"
|
||||
],
|
||||
"readOnly": true,
|
||||
"x-google-enum-deprecated": [
|
||||
|
|
@ -4069,7 +4051,8 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
false
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"The interaction is in progress.",
|
||||
|
|
@ -4078,7 +4061,8 @@
|
|||
"The interaction failed.",
|
||||
"The interaction was cancelled.",
|
||||
"The interaction is completed, but contains incomplete results (e.g.\nhitting max_tokens).",
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11)."
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11).",
|
||||
"The interaction requires at least one more request for it to be\ncompleted. The next request should set the continuation_token to the one\nreturned by this request."
|
||||
]
|
||||
},
|
||||
"created": {
|
||||
|
|
@ -4110,6 +4094,21 @@
|
|||
"$ref": "#/components/schemas/ResponseModality"
|
||||
}
|
||||
},
|
||||
"response_format": {
|
||||
"description": "Enforces that the generated response is a JSON object that complies with\nthe JSON schema specified in this field.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
},
|
||||
{
|
||||
"title": "ResponseFormatList",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResponseFormat"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"response_mime_type": {
|
||||
"description": "The mime type of the response. This is required if response_format is set.",
|
||||
"type": "string",
|
||||
|
|
@ -4119,6 +4118,17 @@
|
|||
"description": "The ID of the previous interaction, if any.",
|
||||
"type": "string"
|
||||
},
|
||||
"environment": {
|
||||
"description": "The environment configuration for the interaction. Can be an object\nspecifying remote environment sources or a string referencing an existing\nenvironment ID.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnvironmentConfig"
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"environment_id": {
|
||||
"description": "Output only. The environment ID for the interaction. Only populated if environment\nconfig is set in the request.",
|
||||
"type": "string",
|
||||
|
|
@ -4146,6 +4156,12 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"continuation_token": {
|
||||
"description": "Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"stream": {
|
||||
"description": "Input only. Whether the interaction will be streamed.",
|
||||
"type": "boolean",
|
||||
|
|
@ -4348,11 +4364,31 @@
|
|||
"type": "string",
|
||||
"enum": [
|
||||
"application/pdf",
|
||||
"text/csv"
|
||||
"text/csv",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/vnd.oasis.opendocument.presentation",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.oasis.opendocument.spreadsheet"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"PDF document format",
|
||||
"CSV document format"
|
||||
"CSV document format",
|
||||
"PPTX presentation format",
|
||||
"PPT presentation format",
|
||||
"ODP presentation format",
|
||||
"DOCX document format",
|
||||
"DOC document format",
|
||||
"DOTX document template format",
|
||||
"ODT document format",
|
||||
"XLSX spreadsheet format",
|
||||
"XLS spreadsheet format",
|
||||
"ODS spreadsheet format"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
|
@ -4379,6 +4415,37 @@
|
|||
"type": {
|
||||
"const": "document"
|
||||
},
|
||||
"mime_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"application/pdf",
|
||||
"text/csv",
|
||||
"application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
||||
"application/vnd.ms-powerpoint",
|
||||
"application/vnd.oasis.opendocument.presentation",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
||||
"application/msword",
|
||||
"application/vnd.openxmlformats-officedocument.wordprocessingml.template",
|
||||
"application/vnd.oasis.opendocument.text",
|
||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||
"application/vnd.ms-excel",
|
||||
"application/vnd.oasis.opendocument.spreadsheet"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"PDF document format",
|
||||
"CSV document format",
|
||||
"PPTX presentation format",
|
||||
"PPT presentation format",
|
||||
"ODP presentation format",
|
||||
"DOCX document format",
|
||||
"DOC document format",
|
||||
"DOTX document template format",
|
||||
"ODT document format",
|
||||
"XLSX spreadsheet format",
|
||||
"XLS spreadsheet format",
|
||||
"ODS spreadsheet format"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
|
|
@ -4386,17 +4453,6 @@
|
|||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"application/pdf",
|
||||
"text/csv"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"PDF document format",
|
||||
"CSV document format"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
@ -4474,23 +4530,6 @@
|
|||
"type": "string",
|
||||
"readOnly": true
|
||||
},
|
||||
"network": {
|
||||
"description": "Network configuration for the environment.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnvironmentNetworkEgressAllowlist"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"All network egress is blocked."
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"sources": {
|
||||
"description": "Sources to be mounted into the environment.",
|
||||
"type": "array",
|
||||
|
|
@ -4526,6 +4565,23 @@
|
|||
""
|
||||
]
|
||||
},
|
||||
"network": {
|
||||
"description": "Network configuration for the environment.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/EnvironmentNetworkEgressAllowlist"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"disabled"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"All network egress is blocked."
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"file_count": {
|
||||
"description": "Output only. The number of files in the environment, output only.",
|
||||
"type": "string",
|
||||
|
|
@ -4551,6 +4607,12 @@
|
|||
"type": {
|
||||
"const": "remote"
|
||||
},
|
||||
"sources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Source"
|
||||
}
|
||||
},
|
||||
"network": {
|
||||
"description": "Network configuration for the environment.",
|
||||
"oneOf": [
|
||||
|
|
@ -4568,12 +4630,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"sources": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Source"
|
||||
}
|
||||
},
|
||||
"environment_id": {
|
||||
"description": "Optional. The environment ID for the interaction. If specified, the request will\nupdate the existing environment instead of creating a new one.",
|
||||
"type": "string"
|
||||
|
|
@ -5347,30 +5403,6 @@
|
|||
"description": "Configuration parameters for model interactions.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"tool_choice": {
|
||||
"description": "The tool choice configuration.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolChoiceConfig"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"any",
|
||||
"none",
|
||||
"validated"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"Auto tool choice.",
|
||||
"Any tool choice.",
|
||||
"No tool choice.",
|
||||
"Validated tool choice."
|
||||
],
|
||||
"x-speakeasy-model-namespace": "interactions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"temperature": {
|
||||
"description": "Controls the randomness of the output.",
|
||||
"type": "number",
|
||||
|
|
@ -5395,6 +5427,30 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"tool_choice": {
|
||||
"description": "The tool choice configuration.",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ToolChoiceConfig"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"auto",
|
||||
"any",
|
||||
"none",
|
||||
"validated"
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"Auto tool choice.",
|
||||
"Any tool choice.",
|
||||
"No tool choice.",
|
||||
"Validated tool choice."
|
||||
],
|
||||
"x-speakeasy-model-namespace": "interactions"
|
||||
}
|
||||
]
|
||||
},
|
||||
"thinking_level": {
|
||||
"description": "The level of thought tokens that the model should generate.",
|
||||
"$ref": "#/components/schemas/ThinkingLevel"
|
||||
|
|
@ -6211,14 +6267,6 @@
|
|||
"type": {
|
||||
"const": "image"
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -6242,6 +6290,14 @@
|
|||
"TIFF image format"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"resolution": {
|
||||
"description": "The resolution of the media.",
|
||||
"$ref": "#/components/schemas/MediaResolution"
|
||||
|
|
@ -6385,7 +6441,8 @@
|
|||
"failed",
|
||||
"cancelled",
|
||||
"incomplete",
|
||||
"budget_exceeded"
|
||||
"budget_exceeded",
|
||||
"requires_continuation"
|
||||
],
|
||||
"readOnly": true,
|
||||
"x-google-enum-deprecated": [
|
||||
|
|
@ -6395,7 +6452,8 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
false
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"The interaction is in progress.",
|
||||
|
|
@ -6404,7 +6462,8 @@
|
|||
"The interaction failed.",
|
||||
"The interaction was cancelled.",
|
||||
"The interaction is completed, but contains incomplete results (e.g.\nhitting max_tokens).",
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11)."
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11).",
|
||||
"The interaction requires at least one more request for it to be\ncompleted. The next request should set the continuation_token to the one\nreturned by this request."
|
||||
]
|
||||
},
|
||||
"created": {
|
||||
|
|
@ -6434,9 +6493,33 @@
|
|||
"$ref": "#/components/schemas/GenerationConfig",
|
||||
"writeOnly": true
|
||||
},
|
||||
"system_instruction": {
|
||||
"description": "System instruction for the interaction.",
|
||||
"type": "string"
|
||||
},
|
||||
"tools": {
|
||||
"description": "A list of tool declarations the model may call during interaction.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Tool"
|
||||
}
|
||||
},
|
||||
"input": {
|
||||
"$ref": "#/components/schemas/InteractionsInput"
|
||||
},
|
||||
"usage": {
|
||||
"description": "Output only. Statistics on the interaction request's token usage.",
|
||||
"$ref": "#/components/schemas/Usage",
|
||||
"readOnly": true
|
||||
},
|
||||
"response_modalities": {
|
||||
"description": "The requested modalities of the response (TEXT, IMAGE, AUDIO).",
|
||||
"type": "array",
|
||||
"deprecated": true,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResponseModality"
|
||||
}
|
||||
},
|
||||
"response_format": {
|
||||
"description": "Enforces that the generated response is a JSON object that complies with\nthe JSON schema specified in this field.",
|
||||
"oneOf": [
|
||||
|
|
@ -6452,6 +6535,15 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"response_mime_type": {
|
||||
"description": "The mime type of the response. This is required if response_format is set.",
|
||||
"type": "string",
|
||||
"deprecated": true
|
||||
},
|
||||
"previous_interaction_id": {
|
||||
"description": "The ID of the previous interaction, if any.",
|
||||
"type": "string"
|
||||
},
|
||||
"environment": {
|
||||
"description": "The environment configuration for the interaction. Can be an object\nspecifying remote environment sources or a string referencing an existing\nenvironment ID.",
|
||||
"oneOf": [
|
||||
|
|
@ -6463,39 +6555,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"system_instruction": {
|
||||
"description": "System instruction for the interaction.",
|
||||
"type": "string"
|
||||
},
|
||||
"tools": {
|
||||
"description": "A list of tool declarations the model may call during interaction.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/Tool"
|
||||
}
|
||||
},
|
||||
"usage": {
|
||||
"description": "Output only. Statistics on the interaction request's token usage.",
|
||||
"$ref": "#/components/schemas/Usage",
|
||||
"readOnly": true
|
||||
},
|
||||
"response_modalities": {
|
||||
"description": "The requested modalities of the response (TEXT, IMAGE, AUDIO).",
|
||||
"type": "array",
|
||||
"deprecated": true,
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/ResponseModality"
|
||||
}
|
||||
},
|
||||
"response_mime_type": {
|
||||
"description": "The mime type of the response. This is required if response_format is set.",
|
||||
"type": "string",
|
||||
"deprecated": true
|
||||
},
|
||||
"previous_interaction_id": {
|
||||
"description": "The ID of the previous interaction, if any.",
|
||||
"type": "string"
|
||||
},
|
||||
"environment_id": {
|
||||
"description": "Output only. The environment ID for the interaction. Only populated if environment\nconfig is set in the request.",
|
||||
"type": "string",
|
||||
|
|
@ -6531,6 +6590,12 @@
|
|||
},
|
||||
"readOnly": true
|
||||
},
|
||||
"continuation_token": {
|
||||
"description": "Opaque token to resume a long decode. Output: set when status is\nREQUIRES_CONTINUATION and decoding can be resumed. Input: pass the latest\ntoken back unchanged in CreateInteraction to continue decoding.",
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"stream": {
|
||||
"description": "Input only. Whether the interaction will be streamed.",
|
||||
"type": "boolean",
|
||||
|
|
@ -6813,16 +6878,16 @@
|
|||
},
|
||||
"readOnly": true
|
||||
},
|
||||
"agent": {
|
||||
"description": "The agent to interact with.",
|
||||
"type": "string"
|
||||
},
|
||||
"continuation_token": {
|
||||
"description": "Opaque token to resume a long decode.\nOutput: set when status is INCOMPLETE and decoding can be resumed.\nInput: pass the latest token back unchanged in CreateInteraction to\ncontinue decoding.",
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"agent": {
|
||||
"description": "The agent to interact with.",
|
||||
"type": "string"
|
||||
},
|
||||
"object": {
|
||||
"description": "Output only. The resource type.",
|
||||
"type": "string",
|
||||
|
|
@ -6863,7 +6928,8 @@
|
|||
"failed",
|
||||
"cancelled",
|
||||
"incomplete",
|
||||
"budget_exceeded"
|
||||
"budget_exceeded",
|
||||
"requires_continuation"
|
||||
],
|
||||
"x-google-enum-deprecated": [
|
||||
false,
|
||||
|
|
@ -6872,7 +6938,8 @@
|
|||
false,
|
||||
false,
|
||||
false,
|
||||
true
|
||||
true,
|
||||
false
|
||||
],
|
||||
"x-google-enum-descriptions": [
|
||||
"The interaction is in progress.",
|
||||
|
|
@ -6881,7 +6948,8 @@
|
|||
"The interaction failed.",
|
||||
"The interaction was cancelled.",
|
||||
"The interaction is completed, but contains incomplete results (e.g.\nhitting max_tokens).",
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11)."
|
||||
"Deprecated: Token and execution budget exhaustion returns INCOMPLETE\n(11).",
|
||||
"The interaction requires at least one more request for it to be\ncompleted. The next request should set the continuation_token to the one\nreturned by this request."
|
||||
]
|
||||
},
|
||||
"event_type": {
|
||||
|
|
@ -7076,14 +7144,14 @@
|
|||
"type": {
|
||||
"const": "mcp_server"
|
||||
},
|
||||
"url": {
|
||||
"description": "The full URL for the MCPServer endpoint.\nExample: \"https://api.example.com/mcp\"",
|
||||
"type": "string"
|
||||
},
|
||||
"name": {
|
||||
"description": "The name of the MCPServer.",
|
||||
"type": "string"
|
||||
},
|
||||
"url": {
|
||||
"description": "The full URL for the MCPServer endpoint.\nExample: \"https://api.example.com/mcp\"",
|
||||
"type": "string"
|
||||
},
|
||||
"headers": {
|
||||
"description": "Optional: Fields for authentication headers, timeouts, etc., if needed.",
|
||||
"type": "object",
|
||||
|
|
@ -7362,7 +7430,7 @@
|
|||
},
|
||||
"ModelOption": {
|
||||
"title": "Model",
|
||||
"description": "The model that will complete your prompt.\\n\\nSee [models](https://ai.google.dev/gemini-api/docs/models) for additional details.",
|
||||
"description": "The model that will complete your prompt.\\n\\nSee [models](https://aistudio.google.com/docs/models) for additional details.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"gemma-4-26b-a4b-it",
|
||||
|
|
@ -8695,6 +8763,20 @@
|
|||
"description": "Configuration for speech recognition (transcription).",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"language_codes": {
|
||||
"description": "Optional. BCP-47 language codes providing hints about the languages present in the\naudio. If omitted or empty, defaults to automatic language detection.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"custom_vocabulary": {
|
||||
"description": "Optional. A list of custom vocabulary phrases to bias the speech recognition model\ntoward recognizing specific terms.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"mode": {
|
||||
"description": "Discriminated transcription mode options or enum.",
|
||||
"oneOf": [
|
||||
|
|
@ -8714,20 +8796,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"language_codes": {
|
||||
"description": "Optional. BCP-47 language codes providing hints about the languages present in the\naudio. If omitted or empty, defaults to automatic language detection.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"custom_vocabulary": {
|
||||
"description": "Optional. A list of custom vocabulary phrases to bias the speech recognition model\ntoward recognizing specific terms.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"timestamp_granularities": {
|
||||
"description": "Optional. The granularity of timestamps to include in the transcription output.\nSupported values: \"word\". If empty, no timestamps are generated.",
|
||||
"type": "array",
|
||||
|
|
@ -9332,6 +9400,11 @@
|
|||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"initial_input_tokens": {
|
||||
"description": "Number of input tokens used in the first turn of this interaction.",
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"input_tokens_by_modality": {
|
||||
"description": "A breakdown of input token usage by modality.",
|
||||
"type": "array",
|
||||
|
|
@ -9497,6 +9570,10 @@
|
|||
"description": "The URI of the video.",
|
||||
"type": "string"
|
||||
},
|
||||
"resolution": {
|
||||
"description": "The resolution of the media.",
|
||||
"$ref": "#/components/schemas/MediaResolution"
|
||||
},
|
||||
"processing": {
|
||||
"description": "How the model processes this video for understanding.",
|
||||
"oneOf": [
|
||||
|
|
@ -9516,10 +9593,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"resolution": {
|
||||
"description": "The resolution of the media.",
|
||||
"$ref": "#/components/schemas/MediaResolution"
|
||||
},
|
||||
"name": {
|
||||
"description": "A user-defined name for this content block. Can be referenced by the model\nin the final response.",
|
||||
"type": "string"
|
||||
|
|
@ -9573,14 +9646,6 @@
|
|||
"type": {
|
||||
"const": "video"
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"mime_type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
|
|
@ -9608,6 +9673,14 @@
|
|||
"JPEG 2000 video format"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "string",
|
||||
"format": "byte",
|
||||
"x-speakeasy-base64-input-mode": "file"
|
||||
},
|
||||
"uri": {
|
||||
"type": "string"
|
||||
},
|
||||
"resolution": {
|
||||
"description": "The resolution of the media.",
|
||||
"$ref": "#/components/schemas/MediaResolution"
|
||||
|
|
|
|||
|
|
@ -559,28 +559,34 @@ class TestInteractionsAcreateOffline:
|
|||
|
||||
@pytest.mark.usefixtures("fake_provider_credentials")
|
||||
@pytest.mark.asyncio
|
||||
async def test_acreate_gemini_keeps_continuation_token_out_of_the_request(self, respx_mock: MockRouter) -> None:
|
||||
async def test_acreate_gemini_sends_a_caller_continuation_token_to_resume_a_decode(
|
||||
self, respx_mock: MockRouter
|
||||
) -> None:
|
||||
route: Final = respx_mock.post("https://generativelanguage.googleapis.com/v1beta/interactions").mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
json={
|
||||
"id": "interaction-offline",
|
||||
"object": "interaction",
|
||||
"model": "gemini-3.8-flash",
|
||||
"model": "gemini-4-argon",
|
||||
"status": "completed",
|
||||
"steps": [{"type": "model_output", "content": [{"type": "text", "text": "Hi"}]}],
|
||||
"usage": {"input_tokens": 6, "output_tokens": 3},
|
||||
"usage": {"total_input_tokens": 6, "total_output_tokens": 3},
|
||||
},
|
||||
)
|
||||
)
|
||||
response: Final = await interactions.acreate(
|
||||
model="gemini/gemini-3.8-flash",
|
||||
input="Prove it",
|
||||
model="gemini/gemini-4-argon",
|
||||
previous_interaction_id="interaction-hop-1",
|
||||
continuation_token="dG9rLTE=",
|
||||
api_key="gemini-offline",
|
||||
)
|
||||
# The Interactions API answered 400 "Unknown parameter 'continuation_token'." on 2026-10-13
|
||||
assert json.loads(route.calls.last.request.content) == {"model": "gemini-3.8-flash", "input": "Prove it"}
|
||||
# Google's spec (2026-11-05) takes continuation_token on CreateModelInteractionParams; a 2026-10-13 400 is gone
|
||||
assert json.loads(route.calls.last.request.content) == {
|
||||
"model": "gemini-4-argon",
|
||||
"previous_interaction_id": "interaction-hop-1",
|
||||
"continuation_token": "dG9rLTE=",
|
||||
}
|
||||
assert response.status == "completed"
|
||||
|
||||
@pytest.mark.usefixtures("fake_provider_credentials")
|
||||
|
|
@ -746,9 +752,7 @@ def test_create_with_system_instruction_for_google_and_responses(
|
|||
def test_create_streaming_returns_interaction_events(
|
||||
respx_mock: MockRouter,
|
||||
) -> None:
|
||||
route: Final = respx_mock.post(
|
||||
"https://generativelanguage.googleapis.com/v1beta/interactions?alt=sse"
|
||||
).mock(
|
||||
route: Final = respx_mock.post("https://generativelanguage.googleapis.com/v1beta/interactions?alt=sse").mock(
|
||||
return_value=httpx.Response(
|
||||
200,
|
||||
headers={"content-type": "text/event-stream"},
|
||||
|
|
@ -856,3 +860,65 @@ def test_create_streaming_hands_completed_interaction_to_success_callback(
|
|||
)
|
||||
|
||||
assert recorder.logged == (_GEMINI_COMPLETED_INTERACTION,)
|
||||
|
||||
|
||||
_GEMINI_URL: Final = "https://generativelanguage.googleapis.com/v1beta/interactions"
|
||||
_LONG_DECODE_REQUEST: Final = {
|
||||
"model": "gemini/gemini-4-argon",
|
||||
"input": "Prove the prime number theorem.",
|
||||
"generation_config": {"max_output_tokens": 120000, "thinking_level": "high"},
|
||||
}
|
||||
_FIRST_HOP: Final = {
|
||||
"id": "hop-1",
|
||||
"object": "interaction",
|
||||
"model": "gemini-4-argon",
|
||||
"status": "requires_continuation",
|
||||
"steps": [{"type": "model_output", "content": [{"type": "text", "text": "Lemma 1."}]}],
|
||||
"usage": {
|
||||
"total_input_tokens": 79,
|
||||
"total_output_tokens": 32668,
|
||||
"total_thought_tokens": 100,
|
||||
"total_tokens": 32847,
|
||||
"initial_input_tokens": 79,
|
||||
},
|
||||
"continuation_token": "tok-1",
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("fake_provider_credentials")
|
||||
def test_create_keeps_requires_continuation_status_and_token_for_the_caller(respx_mock: MockRouter) -> None:
|
||||
route: Final = respx_mock.post(_GEMINI_URL).mock(return_value=httpx.Response(200, json=_FIRST_HOP))
|
||||
|
||||
response: Final = interactions.create(**_LONG_DECODE_REQUEST, api_key="gemini-offline")
|
||||
|
||||
assert route.call_count == 1
|
||||
assert response.status == "requires_continuation"
|
||||
assert response.continuation_token == "tok-1"
|
||||
assert response.usage == _FIRST_HOP["usage"]
|
||||
|
||||
|
||||
@pytest.mark.usefixtures("fake_provider_credentials")
|
||||
def test_create_sends_a_caller_continuation_token_to_resume_a_long_decode(respx_mock: MockRouter) -> None:
|
||||
route: Final = respx_mock.post(_GEMINI_URL).mock(
|
||||
return_value=httpx.Response(
|
||||
200, json={**_FIRST_HOP, "id": "hop-2", "status": "completed", "continuation_token": None}
|
||||
)
|
||||
)
|
||||
|
||||
response: Final = interactions.create(
|
||||
model="gemini/gemini-4-argon",
|
||||
previous_interaction_id="hop-1",
|
||||
continuation_token="tok-1",
|
||||
generation_config=_LONG_DECODE_REQUEST["generation_config"],
|
||||
api_key="gemini-offline",
|
||||
)
|
||||
|
||||
sent: Final = json.loads(route.calls.last.request.content)
|
||||
assert sent == {
|
||||
"model": "gemini-4-argon",
|
||||
"previous_interaction_id": "hop-1",
|
||||
"continuation_token": "tok-1",
|
||||
"generation_config": _LONG_DECODE_REQUEST["generation_config"],
|
||||
}, sent
|
||||
assert response.status == "completed"
|
||||
assert response.continuation_token is None
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
OpenAPI compliance tests for Google Interactions API.
|
||||
|
||||
Validates that our SDK requests/responses match the OpenAPI spec snapshot in
|
||||
interactions.openapi.json, taken from https://ai.google.dev/static/api/interactions.openapi.json
|
||||
interactions.openapi.json, taken from https://aistudio.google.com/api-reference/interactions.openapi.json
|
||||
(litellm/types/interactions/README.md says how to refresh it). The scheduled
|
||||
interactions-spec-canary workflow runs the same tests against the live spec by passing
|
||||
--interactions-spec-url, so a change Google makes shows up there, not in every PR.
|
||||
|
|
@ -23,7 +23,7 @@ import pytest
|
|||
from openapi_core import OpenAPI
|
||||
from pydantic import BaseModel, TypeAdapter
|
||||
|
||||
OPENAPI_SPEC_URL = "https://ai.google.dev/static/api/interactions.openapi.json"
|
||||
OPENAPI_SPEC_URL = "https://aistudio.google.com/api-reference/interactions.openapi.json"
|
||||
OPENAPI_SPEC_SNAPSHOT: Final = Path(__file__).with_name("interactions.openapi.json")
|
||||
SPEC_URL_OPTION: Final = TypeAdapter(str | None)
|
||||
|
||||
|
|
@ -47,10 +47,10 @@ def _requested_spec_url(request: pytest.FixtureRequest) -> str | None:
|
|||
def _load_openapi_spec(live_url: str | None) -> LoadedSpec:
|
||||
if live_url is None:
|
||||
return LoadedSpec(source=str(OPENAPI_SPEC_SNAPSHOT), spec=json.loads(OPENAPI_SPEC_SNAPSHOT.read_text()))
|
||||
with httpx.Client(transport=httpx.HTTPTransport(retries=3), timeout=30.0) as client:
|
||||
with httpx.Client(transport=httpx.HTTPTransport(retries=3), timeout=30.0, follow_redirects=True) as client:
|
||||
response: Final = client.get(live_url)
|
||||
response.raise_for_status()
|
||||
return LoadedSpec(source=str(response.url), spec=response.json())
|
||||
return LoadedSpec(source=live_url, spec=response.json())
|
||||
|
||||
|
||||
def _model_create_request_schema(spec_dict: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
|
|
|||
|
|
@ -1939,6 +1939,7 @@ async def test_callback_handles_every_status_the_interactions_api_can_return():
|
|||
assert released == {
|
||||
"completed",
|
||||
"requires_action",
|
||||
"requires_continuation",
|
||||
"failed",
|
||||
"cancelled",
|
||||
"incomplete",
|
||||
|
|
|
|||
|
|
@ -1522,6 +1522,37 @@ def test_raise_if_required_body_param_missing_rejects_missing_param(route_type,
|
|||
assert exc_info.value.message == f"{route}: Missing required parameter: '{param}'."
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data",
|
||||
[
|
||||
{"model": "gemini-4-argon", "input": "prove the prime number theorem"},
|
||||
{"model": "gemini-4-argon", "previous_interaction_id": "v1_abc", "continuation_token": "tok-1"},
|
||||
{"model": "gemini-4-argon", "input": "prove it again", "continuation_token": "tok-1"},
|
||||
],
|
||||
)
|
||||
def test_create_interaction_accepts_input_or_a_continuation_token(data: dict[str, object]) -> None:
|
||||
from litellm.proxy.route_llm_request import raise_if_required_body_param_missing
|
||||
|
||||
assert raise_if_required_body_param_missing(route_type="acreate_interaction", data=data, llm_router=None) is None
|
||||
|
||||
|
||||
def test_create_interaction_without_input_or_continuation_token_names_input() -> None:
|
||||
from litellm.proxy.route_llm_request import (
|
||||
ProxyMissingRequiredParamError,
|
||||
raise_if_required_body_param_missing,
|
||||
)
|
||||
|
||||
with pytest.raises(ProxyMissingRequiredParamError) as exc_info:
|
||||
raise_if_required_body_param_missing(
|
||||
route_type="acreate_interaction",
|
||||
data={"model": "gemini-4-argon", "previous_interaction_id": "v1_abc"},
|
||||
llm_router=None,
|
||||
)
|
||||
|
||||
assert exc_info.value.param == "input"
|
||||
assert exc_info.value.message == "/interactions: Missing required parameter: 'input'."
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"data, param",
|
||||
[
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue