How to combine Google Search, Google Maps, and custom functions into a single Gemini API call with context circulation, parallel tool IDs, and multi-step agent chains

by ai-intensify
0 comments
How to combine Google Search, Google Maps, and custom functions into a single Gemini API call with context circulation, parallel tool IDs, and multi-step agent chains

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)

Related Articles

Leave a Comment