Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions google/genai/_interactions/_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
RequestOptions,
not_given,
)
from ._utils import is_given
from ._utils import is_given, is_mapping_t
from ._compat import cached_property
from ._models import FinalRequestOptions
from ._version import __version__
Expand Down Expand Up @@ -348,7 +348,6 @@ def __init__(
if base_url is None:
base_url = f"https://generativelanguage.googleapis.com"

self.client_adapter = client_adapter

super().__init__(
version=__version__,
Expand Down
2 changes: 1 addition & 1 deletion google/genai/_interactions/_files.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ async def async_to_httpx_files(files: RequestFiles | None) -> HttpxRequestFiles
elif is_sequence_t(files):
files = [(key, await _async_transform_file(file)) for key, file in files]
else:
raise TypeError("Unexpected file type input {type(files)}, expected mapping or sequence")
raise TypeError(f"Unexpected file type input {type(files)}, expected mapping or sequence")

return files

Expand Down
80 changes: 80 additions & 0 deletions google/genai/_interactions/_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
ClassVar,
Protocol,
Required,
Annotated,
ParamSpec,
TypeAlias,
TypedDict,
TypeGuard,
final,
Expand Down Expand Up @@ -95,7 +97,15 @@
from ._constants import RAW_RESPONSE_HEADER

if TYPE_CHECKING:
from pydantic import GetCoreSchemaHandler, ValidatorFunctionWrapHandler
from pydantic_core import CoreSchema, core_schema
from pydantic_core.core_schema import ModelField, ModelSchema, LiteralSchema, ModelFieldsSchema
else:
try:
from pydantic_core import CoreSchema, core_schema
except ImportError:
CoreSchema = None
core_schema = None

__all__ = ["BaseModel", "GenericModel"]

Expand Down Expand Up @@ -412,6 +422,76 @@ def model_dump_json(
)


class _EagerIterable(list[_T], Generic[_T]):
"""
Accepts any Iterable[T] input (including generators), consumes it
eagerly, and validates all items upfront.

Validation preserves the original container type where possible
(e.g. a set[T] stays a set[T]). Serialization (model_dump / JSON)
always emits a list — round-tripping through model_dump() will not
restore the original container type.
"""

@classmethod
def __get_pydantic_core_schema__(
cls,
source_type: Any,
handler: GetCoreSchemaHandler,
) -> CoreSchema:
(item_type,) = get_args(source_type) or (Any,)
item_schema: CoreSchema = handler.generate_schema(item_type)
list_of_items_schema: CoreSchema = core_schema.list_schema(item_schema)

return core_schema.no_info_wrap_validator_function(
cls._validate,
list_of_items_schema,
serialization=core_schema.plain_serializer_function_ser_schema(
cls._serialize,
info_arg=False,
),
)

@staticmethod
def _validate(v: Iterable[_T], handler: "ValidatorFunctionWrapHandler") -> Any:
original_type: type[Any] = type(v)

# Normalize to list so list_schema can validate each item
if isinstance(v, list):
items: list[_T] = v
else:
try:
items = list(v)
except TypeError as e:
raise TypeError("Value is not iterable") from e

# Validate items against the inner schema
validated: list[_T] = handler(items)

# Reconstruct original container type
if original_type is list:
return validated
# str(list) produces the list's repr, not a string built from items,
# so skip reconstruction for str and its subclasses.
if issubclass(original_type, str):
return validated
try:
return original_type(validated)
except (TypeError, ValueError):
# If the type cannot be reconstructed, just return the validated list
return validated

@staticmethod
def _serialize(v: Iterable[_T]) -> list[_T]:
"""Always serialize as a list so Pydantic's JSON encoder is happy."""
if isinstance(v, list):
return v
return list(v)


EagerIterable: TypeAlias = Annotated[Iterable[_T], _EagerIterable]


def _construct_field(value: object, field: FieldInfo, key: str) -> object:
if value is None:
return field_get_default(field)
Expand Down
2 changes: 2 additions & 0 deletions google/genai/_interactions/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
from .url_context_result_step import URLContextResultStep as URLContextResultStep
from .webhook_delete_response import WebhookDeleteResponse as WebhookDeleteResponse
from .code_execution_call_step import CodeExecutionCallStep as CodeExecutionCallStep
from .code_mender_agent_config import CodeMenderAgentConfig as CodeMenderAgentConfig
from .function_call_step_param import FunctionCallStepParam as FunctionCallStepParam
from .tool_choice_config_param import ToolChoiceConfigParam as ToolChoiceConfigParam
from .google_search_result_step import GoogleSearchResultStep as GoogleSearchResultStep
Expand Down Expand Up @@ -134,6 +135,7 @@
from .google_search_call_step_param import GoogleSearchCallStepParam as GoogleSearchCallStepParam
from .url_context_result_step_param import URLContextResultStepParam as URLContextResultStepParam
from .code_execution_call_step_param import CodeExecutionCallStepParam as CodeExecutionCallStepParam
from .code_mender_agent_config_param import CodeMenderAgentConfigParam as CodeMenderAgentConfigParam
from .google_search_result_step_param import GoogleSearchResultStepParam as GoogleSearchResultStepParam
from .mcp_server_tool_call_step_param import MCPServerToolCallStepParam as MCPServerToolCallStepParam
from .code_execution_result_step_param import CodeExecutionResultStepParam as CodeExecutionResultStepParam
Expand Down
8 changes: 3 additions & 5 deletions google/genai/_interactions/types/agent_list_params.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,16 @@

from __future__ import annotations

from typing_extensions import Annotated, TypedDict

from .._utils import PropertyInfo
from typing_extensions import TypedDict

__all__ = ["AgentListParams"]


class AgentListParams(TypedDict, total=False):
api_version: str

page_size: Annotated[int, PropertyInfo(alias="pageSize")]
page_size: int

page_token: Annotated[str, PropertyInfo(alias="pageToken")]
page_token: str

parent: str
4 changes: 1 addition & 3 deletions google/genai/_interactions/types/agent_list_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,6 @@

from typing import List, Optional

from pydantic import Field as FieldInfo

from .agent import Agent
from .._models import BaseModel

Expand All @@ -28,4 +26,4 @@
class AgentListResponse(BaseModel):
agents: Optional[List[Agent]] = None

next_page_token: Optional[str] = FieldInfo(alias="nextPageToken", default=None)
next_page_token: Optional[str] = None
132 changes: 132 additions & 0 deletions google/genai/_interactions/types/code_mender_agent_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import List, Optional
from typing_extensions import Literal

from .._models import BaseModel

__all__ = [
"CodeMenderAgentConfig",
"FindRequest",
"FindRequestSourceFile",
"FixRequest",
"FixRequestSourceFile",
"SessionConfig",
]


class FindRequestSourceFile(BaseModel):
"""Content of a single file in the codebase."""

content: Optional[str] = None
"""The UTF-8 encoded text content of the file."""

path: Optional[str] = None
"""The relative path of the file from the project root."""


class FindRequest(BaseModel):
"""Parameters for finding vulnerabilities."""

description: Optional[str] = None
"""
Additional context or custom instructions provided by the user to guide the
vulnerability analysis.
"""

finding_id: Optional[str] = None
"""The identifier of a specific finding to verify.

This is primarily used in VERIFY mode to focus the agent's execution-based
validation on a single vulnerability.
"""

source_files: Optional[List[FindRequestSourceFile]] = None
"""A list of source files to provide as context for the scan."""


class FixRequestSourceFile(BaseModel):
"""Content of a single file in the codebase."""

content: Optional[str] = None
"""The UTF-8 encoded text content of the file."""

path: Optional[str] = None
"""The relative path of the file from the project root."""


class FixRequest(BaseModel):
"""Parameters for fixing vulnerabilities."""

description: Optional[str] = None
"""
Additional context or custom instructions provided by the user to guide the
patch generation process.
"""

finding_id: Optional[str] = None
"""The identifier of the specific security finding to be remediated.

This ID maps to a previously discovered vulnerability.
"""

source_files: Optional[List[FixRequestSourceFile]] = None
"""A list of source files providing context for the remediation.

These files are typically the ones containing the identified vulnerability.
"""


class SessionConfig(BaseModel):
"""
Optional session-specific configurations to override default agent
behavior.
"""

max_rounds: Optional[int] = None
"""
The maximum number of interaction rounds the agent is allowed to perform before
reaching a timeout.
"""

pipeline_mode: Optional[Literal["scan", "verify"]] = None
"""The pipeline mode of a CodeMender session.

It can only be used for a find session.
"""

topology: Optional[str] = None
"""The cognitive architecture or "thinking" topology used by the agent (e.g.

"default", "deep").
"""


class CodeMenderAgentConfig(BaseModel):
"""Configuration for the CodeMender agent."""

type: Literal["code-mender"]

find_request: Optional[FindRequest] = None
"""Parameters for finding vulnerabilities."""

fix_request: Optional[FixRequest] = None
"""Parameters for fixing vulnerabilities."""

session_config: Optional[SessionConfig] = None
"""Optional session-specific configurations to override default agent behavior."""
Loading
Loading