0
import subprocess, sys
subprocess.check_call(
(sys.executable, "-m", "pip", "install", "-qU", "google-genai"),
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
)
import getpass, json, textwrap, os, time
from google import genai
from google.genai import types
if "GOOGLE_API_KEY" not in os.environ:
os.environ("GOOGLE_API_KEY") = getpass.getpass("Enter your Gemini API key: ")
client = genai.Client(api_key=os.environ("GOOGLE_API_KEY"))
TOOL_COMBO_MODEL = "gemini-3-flash-preview"
MAPS_MODEL = "gemini-2.5-flash"
DIVIDER = "=" * 72
def heading(title: str):
print(f"n{DIVIDER}")
print(f" {title}")
print(DIVIDER)
def wrap(text: str, width: int = 80):
for line in text.splitlines():
print(textwrap.fill(line, width=width) if line.strip() else "")
def describe_parts(response):
parts = response.candidates(0).content.parts
fc_ids = {}
for i, part in enumerate(parts):
prefix = f" Part {i:2d}:"
if hasattr(part, "tool_call") and part.tool_call:
tc = part.tool_call
print(f"{prefix} (toolCall) type={tc.tool_type} id={tc.id}")
if hasattr(part, "tool_response") and part.tool_response:
tr = part.tool_response
print(f"{prefix} (toolResponse) type={tr.tool_type} id={tr.id}")
if hasattr(part, "executable_code") and part.executable_code:
code = part.executable_code.code(:90).replace("n", " ↵ ")
print(f"{prefix} (executableCode) {code}...")
if hasattr(part, "code_execution_result") and part.code_execution_result:
out = (part.code_execution_result.output or "")(:90)
print(f"{prefix} (codeExecResult) {out}")
if hasattr(part, "function_call") and part.function_call:
fc = part.function_call
fc_ids(fc.name) = fc.id
print(f"{prefix} (functionCall) name={fc.name} id={fc.id}")
print(f" └─ args: {dict(fc.args)}")
if hasattr(part, "text") and part.text:
snippet = part.text(:110).replace("n", " ")
print(f"{prefix} (text) {snippet}...")
if hasattr(part, "thought_signature") and part.thought_signature:
print(f" └─ thought_signature present ✓")
return fc_ids
heading("DEMO 1: Combine Google Search + Custom Function in One Request")
print("""
This demo shows the flagship new feature: passing BOTH a built-in tool
(Google Search) and a custom function declaration in a single API call.
Gemini will:
Turn 1 → Search the web for real-time info, then request our custom
function to get weather data.
Turn 2 → We supply the function response; Gemini synthesizes everything.
Key points:
• google_search and function_declarations go in the SAME Tool object
• include_server_side_tool_invocations must be True (on ToolConfig)
• Return ALL parts (incl. thought_signatures) in subsequent turns
""")
get_weather_func = types.FunctionDeclaration(
name="getWeather",
description="Gets the current weather for a requested city.",
parameters=types.Schema(
type="OBJECT",
properties={
"city": types.Schema(
type="STRING",
description="The city and state, e.g. Utqiagvik, Alaska",
),
},
required=("city"),
),
)
print("â–¶ Turn 1: Sending prompt with Google Search + getWeather tools...n")
response_1 = client.models.generate_content(
model=TOOL_COMBO_MODEL,
contents=(
"What is the northernmost city in the United States? "
"What's the weather like there today?"
),
config=types.GenerateContentConfig(
tools=(
types.Tool(
google_search=types.GoogleSearch(),
function_declarations=(get_weather_func),
),
),
tool_config=types.ToolConfig(
include_server_side_tool_invocations=True,
),
),
)
print(" Parts returned by the model:n")
fc_ids = describe_parts(response_1)
function_call_id = fc_ids.get("getWeather")
print(f"n ✅ Captured function_call id for getWeather: {function_call_id}")
print("nâ–¶ Turn 2: Returning function result & requesting final synthesis...n")
history = (
types.Content(
role="user",
parts=(
types.Part(
text=(
"What is the northernmost city in the United States? "
"What's the weather like there today?"
)
)
),
),
response_1.candidates(0).content,
types.Content(
role="user",
parts=(
types.Part(
function_response=types.FunctionResponse(
name="getWeather",
response={"response": "Very cold. 22°F / -5.5°C with strong Arctic winds."},
id=function_call_id,
)
)
),
),
)
response_2 = client.models.generate_content(
model=TOOL_COMBO_MODEL,
contents=history,
config=types.GenerateContentConfig(
tools=(
types.Tool(
google_search=types.GoogleSearch(),
function_declarations=(get_weather_func),
),
),
tool_config=types.ToolConfig(
include_server_side_tool_invocations=True,
),
),
)
print(" ✅ Final synthesized response:n")
for part in response_2.candidates(0).content.parts:
if hasattr(part, "text") and part.text:
wrap(part.text)