Google GenAI Python SDK
The official google-genai package, on plugboard's Gemini API.
Connect
The SDK adds /v1beta itself, so the base URL is the plugboard origin:
python
from google import genai
from google.genai import types
client = genai.Client(api_key=PLUGBOARD_KEY, http_options=types.HttpOptions(base_url="http://127.0.0.1:4010"))Chat
py
response = client.models.generate_content(model=model, contents="Reply with exactly: pong", config=types.GenerateContentConfig(max_output_tokens=1024))Tool calls
Gemini calls carry no id: the function name pairs a functionResponse with its call.
py
tools = [
types.Tool(
function_declarations=[
types.FunctionDeclaration(
name="get_weather",
description="Current weather for a city",
parameters_json_schema={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
)
]
)
]
config = types.GenerateContentConfig(tools=tools, max_output_tokens=1024)
contents = [types.Content(role="user", parts=[types.Part(text="What is the weather in Paris? Use the tool.")])]
first = client.models.generate_content(model=model, contents=contents, config=config)
call = first.function_calls[0] if first.function_calls else None
# Send the model's turn back as it came, then the result as a functionResponse. Gemini calls carry no id: the name pairs them.
turn = list(contents)
if first.candidates and first.candidates[0].content:
turn.append(first.candidates[0].content)
if call:
turn.append(types.Content(role="user", parts=[types.Part.from_function_response(name=call.name, response={"temp_c": 18, "sky": "cloudy"})]))
second = client.models.generate_content(model=model, contents=turn, config=config)Streaming
py
text = ""
finish = None
usage = None
for chunk in client.models.generate_content_stream(model=model, contents="Reply with exactly: pong", config=types.GenerateContentConfig(max_output_tokens=1024)):
text += chunk.text or "" # each chunk carries the next text delta
if chunk.candidates and chunk.candidates[0].finish_reason:
finish = chunk.candidates[0].finish_reason.value.lower()
if chunk.usage_metadata:
usage = chunk.usage_metadata.model_dump(exclude_none=True)A streamed tool call arrives whole, in one chunk:
py
tools = [
types.Tool(
function_declarations=[
types.FunctionDeclaration(
name="get_weather",
description="Current weather for a city",
parameters_json_schema={"type": "object", "properties": {"city": {"type": "string"}}, "required": ["city"]},
)
]
)
]
call = None
finish = None
for chunk in client.models.generate_content_stream(
model=model,
contents="What is the weather in Paris? Use the tool.",
config=types.GenerateContentConfig(tools=tools, max_output_tokens=1024),
):
if chunk.function_calls:
call = chunk.function_calls[0]
if chunk.candidates and chunk.candidates[0].finish_reason:
finish = chunk.candidates[0].finish_reason.value.lower()Images
py
# A 32px red PNG (examples/_shared/red32.png). Part.from_bytes takes the raw bytes and the mime type.
response = client.models.generate_content(
model=model,
contents=[
types.Content(
role="user",
parts=[
types.Part(text="What color is this image? One word."),
types.Part.from_bytes(data=RED_PNG.read_bytes(), mime_type="image/png"),
],
)
],
config=types.GenerateContentConfig(max_output_tokens=1024),
)Structured output
py
# Gemini enforces response_json_schema on the model's output, unlike plugboard's forced-tool route for other APIs.
schema = {
"type": "object",
"properties": {"calories": {"type": "number"}, "protein_g": {"type": "number"}},
"required": ["calories", "protein_g"],
"additionalProperties": False,
}
response = client.models.generate_content(
model=model,
contents="Estimate: 2 boiled eggs and a slice of toast.",
config=types.GenerateContentConfig(response_mime_type="application/json", response_json_schema=schema, max_output_tokens=1024),
)Files
client.files.upload(file="doc.pdf") uploads through plugboard; pass the returned file to generate_content like any other part. See Files.
Model names
A # in a model name must be sent as %23 (openai/gpt-5.6-luna%23low); a / goes as it is. Aliases avoid both. See Gemini model names.
Limits
- Errors raise
ClientErrorwith the HTTP status; the body'sstatusis Google's name (UNAUTHENTICATED,NOT_FOUND). - The schema in structured output is not enforced by the provider. Validate the answer.