Files
2026-07-13 13:30:30 +08:00

842 lines
32 KiB
Plaintext

{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "yFeds7eiwI6x"
},
"outputs": [],
"source": [
"# Copyright 2025 Google LLC\n",
"#\n",
"# Licensed under the Apache License, Version 2.0 (the \"License\");\n",
"# you may not use this file except in compliance with the License.\n",
"# You may obtain a copy of the License at\n",
"#\n",
"# https://www.apache.org/licenses/LICENSE-2.0\n",
"#\n",
"# Unless required by applicable law or agreed to in writing, software\n",
"# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
"# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
"# See the License for the specific language governing permissions and\n",
"# limitations under the License."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4ircZQgHwRdy"
},
"source": [
"# Intro to Computer Use with Gemini\n",
"\n",
"<table align=\"left\">\n",
" <td style=\"text-align: center\">\n",
" <a href=\"https://colab.research.google.com/github/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\">\n",
" <img width=\"32px\" src=\"https://www.gstatic.com/pantheon/images/bigquery/welcome_page/colab-logo.svg\" alt=\"Google Colaboratory logo\"><br> Open in Colab\n",
" </a>\n",
" </td>\n",
" <td style=\"text-align: center\">\n",
" <a href=\"https://console.cloud.google.com/agent-platform/colab/import/https:%2F%2Fraw.githubusercontent.com%2FGoogleCloudPlatform%2Fgenerative-ai%2Fmain%2Fgemini%2Fcomputer-use%2Fintro_computer_use.ipynb\">\n",
" <img width=\"32px\" src=\"https://lh3.googleusercontent.com/JmcxdQi-qOpctIvWKgPtrzZdJJK-J3sWE1RsfjZNwshCFgE_9fULcNpuXYTilIR2hjwN\" alt=\"Google Cloud Colab Enterprise logo\"><br> Open in Colab Enterprise\n",
" </a>\n",
" </td>\n",
" <td style=\"text-align: center\">\n",
" <a href=\"https://console.cloud.google.com/agent-platform/workbench/instances?download_url=https://raw.githubusercontent.com/GoogleCloudPlatform/generative-ai/main/gemini/computer-use/intro_computer_use.ipynb\">\n",
" <img width=\"32px\" src=\"https://storage.googleapis.com/github-repo/workbench-icon.svg\" alt=\"Workbench logo\"><br> Open in Workbench\n",
" </a>\n",
" </td>\n",
" <td style=\"text-align: center\">\n",
" <a href=\"https://github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\">\n",
" <img width=\"32px\" src=\"https://raw.githubusercontent.com/primer/octicons/refs/heads/main/icons/mark-github-24.svg\" alt=\"GitHub logo\"><br> View on GitHub\n",
" </a>\n",
" </td>\n",
"</table>\n",
"\n",
"<div style=\"clear: both;\"></div>\n",
"\n",
"<p>\n",
"<b>Share to:</b>\n",
"\n",
"<a href=\"https://www.linkedin.com/sharing/share-offsite/?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\" target=\"_blank\">\n",
" <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/8/81/LinkedIn_icon.svg\" alt=\"LinkedIn logo\">\n",
"</a>\n",
"\n",
"<a href=\"https://bsky.app/intent/compose?text=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\" target=\"_blank\">\n",
" <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/7/7a/Bluesky_Logo.svg\" alt=\"Bluesky logo\">\n",
"</a>\n",
"\n",
"<a href=\"https://twitter.com/intent/tweet?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\" target=\"_blank\">\n",
" <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/5a/X_icon_2.svg\" alt=\"X logo\">\n",
"</a>\n",
"\n",
"<a href=\"https://reddit.com/submit?url=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\" target=\"_blank\">\n",
" <img width=\"20px\" src=\"https://redditinc.com/hubfs/Reddit%20Inc/Brand/Reddit_Logo.png\" alt=\"Reddit logo\">\n",
"</a>\n",
"\n",
"<a href=\"https://www.facebook.com/sharer/sharer.php?u=https%3A//github.com/GoogleCloudPlatform/generative-ai/blob/main/gemini/computer-use/intro_computer_use.ipynb\" target=\"_blank\">\n",
" <img width=\"20px\" src=\"https://upload.wikimedia.org/wikipedia/commons/5/51/Facebook_f_logo_%282019%29.svg\" alt=\"Facebook logo\">\n",
"</a>\n",
"</p>"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "MJDxNAGItD51"
},
"source": [
"| Authors |\n",
"| --- |\n",
"| [Eric Dong](https://github.com/gericdong) |\n",
"| [Holt Skinner](https://github.com/holtskinner) |"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "896Uhs2Ww6_E"
},
"source": [
"## Overview\n",
"\n",
"The **Gemini Computer Use** tool lets you create agents that can automate tasks on a computer. It works by \"seeing\" the screen with screenshots and then \"acting\" with mouse clicks and keyboard inputs.\n",
"\n",
"This is useful for tasks like:\n",
"\n",
"- Automatically filling out forms on websites.\n",
"- Testing web applications.\n",
"- Researching information, like comparing prices, across different sites.\n",
"\n",
"Learn more about [computer use](https://cloud.google.com/vertex-ai/generative-ai/docs/computer-use).\n",
"\n",
"\n",
"## Objective\n",
"\n",
"In this tutorial, you will build a simple web automation agent using the Gemini Computer Use tool. By the end, you will understand the complete workflow: from sending an initial prompt with a screenshot to executing browser actions and looping until a task is complete."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gPiTOAHURvTM"
},
"source": [
"## Getting Started"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "CHRZUpfWSEpp"
},
"source": [
"### Install the Gen AI SDK and required libraries"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "sG3_LKsWSD3A"
},
"outputs": [],
"source": [
"%pip install --upgrade --quiet google-genai playwright"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "msiBxrk0ATzB"
},
"source": [
"> ⚠️ Note: You can ignore the pip's dependency errors."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "WiZkhIF41qhY"
},
"source": [
"### Set up Playwright\n",
"\n",
"Playwright is a tool for browser automation. It enables browser control over web browsers like Chromium, Firefox, and WebKit.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "zL7fxJtq1cWT"
},
"outputs": [],
"source": [
"%%capture\n",
"\n",
"# Installs Playwright and browsers\n",
"!playwright install\n",
"\n",
"# Additional command, mandatory for Linux only\n",
"!playwright install-deps"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "rK3jJDR5lfiT"
},
"source": [
"### Import libraries\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "T6DyDoNclVEn"
},
"outputs": [],
"source": [
"import logging\n",
"import os\n",
"import sys\n",
"import time\n",
"from types import SimpleNamespace\n",
"\n",
"from google import genai\n",
"from google.genai.types import (\n",
" ComputerUse,\n",
" Content,\n",
" Environment,\n",
" FunctionCall,\n",
" FunctionResponse,\n",
" FunctionResponseBlob,\n",
" GenerateContentConfig,\n",
" Part,\n",
" ThinkingConfig,\n",
" Tool,\n",
")\n",
"from playwright.async_api import async_playwright\n",
"\n",
"logging.getLogger(\"google_genai._common\").setLevel(logging.ERROR)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "HlMVjiAWSMNX"
},
"source": [
"### Authenticate your notebook environment\n",
"\n",
"If you are running this notebook on Google Colab, run the cell below to authenticate your environment."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "12fnq4V0SNV3"
},
"outputs": [],
"source": [
"if \"google.colab\" in sys.modules:\n",
" from google.colab import auth\n",
"\n",
" auth.authenticate_user()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "be18ac9c5ec8"
},
"source": [
"### Set your project information\n",
"\n",
"Update the following variables with your Google Cloud project details, and connect to the Gen AI service on Vertex AI."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "6wXh1aH7BlPl"
},
"outputs": [],
"source": [
"# fmt: off\n",
"PROJECT_ID = \"[your-project-id]\" # @param {type: \"string\", placeholder: \"[your-project-id]\", isTemplate: true}\n",
"# fmt: on\n",
"LOCATION = \"global\" # @param {type: \"string\"}\n",
"\n",
"if not PROJECT_ID or PROJECT_ID == \"[your-project-id]\":\n",
" PROJECT_ID = str(os.environ.get(\"GOOGLE_CLOUD_PROJECT\"))\n",
"\n",
"# Connect to the Gen AI service on Vertex AI\n",
"client = genai.Client(enterprise=True, project=PROJECT_ID, location=LOCATION)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "n4yRkFg6BBu4"
},
"source": [
"### Supported Models\n",
"\n",
"This tutorial uses the `gemini-3.5-flash` model."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "-coEslfWPrxo"
},
"outputs": [],
"source": [
"# fmt: off\n",
"MODEL_ID = \"gemini-3.5-flash\" # @param [\"gemini-3.5-flash\", \"gemini-2.5-computer-use-preview-10-2025\"]\n",
"# fmt: on"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "KqjCltg20IgR"
},
"source": [
"## Computer Use: Agent Loop\n",
"\n",
"To build a browser control agent, you implement an \"agent loop\" that continuously cycles through four key steps. This process allows the agent to perform a sequence of actions to achieve a goal.\n",
"\n",
"1. **Send Request to the Model**. Your app sends the goal (e.g., \"Find me a flight\") and a current screenshot of the screen to the model.\n",
"\n",
"2. **Receive the Model Response**. The model analyzes the screen and sends back a suggested action, like navigate to a URL. It may also include a safety warning for risky actions.\n",
"\n",
"3. **Execute the Received Action**. Your code runs the suggested action. If there's a safety warning, your code must ask the user for confirmation before proceeding.\n",
"\n",
"\n",
"4. **Capture the New Environment State**. After the action, your code takes a new screenshot. This new screenshot is sent back to the model in the next turn, starting the cycle over again."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "L85sHbJv9cpF"
},
"source": [
"## Prerequisites: Setting Up Your Environment\n",
"\n",
"Before you begin, you need to set up two key components:\n",
"\n",
"- **Secure Execution Environment**: For safety, you must run your Computer Use agent in a secure and controlled environment. Good options include a sandboxed virtual machine, a container, or a dedicated browser profile with limited permissions.\n",
"\n",
"- **Client-Side Action Handler**: You need to write client-side logic to execute the actions generated by the model (e.g., clicking a button) and capture screenshots.\n",
"\n",
"In this tutorial, we use Playwright to start a browser environment for demonstration purpose."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "vU5s-EBxCGiN"
},
"outputs": [],
"source": [
"# Start the Playwright session\n",
"playwright = await async_playwright().start()\n",
"\n",
"# Launch the browser in headless mode, which is required for this environment\n",
"browser = await playwright.chromium.launch(headless=True)\n",
"\n",
"# Create a new page\n",
"page = await browser.new_page()\n",
"screen_width, screen_height = 1920, 1080\n",
"await page.set_viewport_size({\"width\": screen_width, \"height\": screen_height})\n",
"\n",
"print(\"Playwright session started.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nNhzdiH3-str"
},
"source": [
"## A Single Turn: Step-by-Step Walkthrough\n",
"\n",
"Now, let's walk through the code for a single turn of the agent loop, from sending the first request to preparing for the next one.\n",
"\n",
"### **1. Send a Request to the Model**\n",
"First, you configure your API request. In the request, you add the Computer Use tool and send a prompt that includes the user's goal and an initial screenshot.\n",
"\n",
"You can also include optional parameters like `excluded_predefined_functions` to prevent the model from using certain actions."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "M8CdwkdPAC8e"
},
"outputs": [],
"source": [
"# Configure Computer Use tool with browser environment\n",
"# Base configuration for the Computer Use tool\n",
"config_kwargs = {\n",
" \"tools\": [\n",
" Tool(\n",
" computer_use=ComputerUse(\n",
" environment=Environment.ENVIRONMENT_BROWSER,\n",
" # Optional: Exclude specific predefined functions\n",
" excluded_predefined_functions=[\"drag_and_drop\"],\n",
" )\n",
" )\n",
" ]\n",
"}\n",
"\n",
"# Conditionally add thinking_config only for the Gemini 3 models\n",
"model_version = float(MODEL_ID.split(\"-\")[1])\n",
"if model_version >= 3:\n",
" config_kwargs[\"thinking_config\"] = ThinkingConfig(include_thoughts=True)\n",
"\n",
"config = GenerateContentConfig(**config_kwargs)\n",
"\n",
"# Create the content with user message and initial screenshot\n",
"screenshot = await page.screenshot()\n",
"\n",
"contents = [\n",
" Content(\n",
" role=\"user\",\n",
" parts=[\n",
" Part(\n",
" text=\"Find me a flight from SF to Hawaii on next Monday, coming back on next Friday. Start by navigating directly to flights.google.com\"\n",
" ),\n",
" # Optional: include a screenshot of the initial state\n",
" Part.from_bytes(\n",
" data=screenshot,\n",
" mime_type=\"image/png\",\n",
" ),\n",
" ],\n",
" )\n",
"]\n",
"\n",
"# Generate content with the configured settings\n",
"response = client.models.generate_content(\n",
" model=MODEL_ID,\n",
" contents=contents,\n",
" config=config,\n",
")\n",
"\n",
"print(response)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "M8ymc2GH_xxs"
},
"source": [
"### **2. Receive the Model Response**\n",
"The model responds with one or more `FunctionCalls` that represent the UI actions it wants to perform. Let's inspect the response from our first API call."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "aC4wcsEBJ9vt"
},
"outputs": [],
"source": [
"response.function_calls"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2vj9YwsxKvdg"
},
"source": [
"### **3. Execute the Received Actions**\n",
"\n",
"Next, our application's client-side code needs to parse the response and execute the requested actions using Playwright. We'll use the `execute_function_calls` helper function for this.\n",
"\n",
"The following example implements some most common UI actions. For a production use case, you would need to implement all supported actions unless you explicitly exclude them."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "tQqZqdTCf1YH"
},
"outputs": [],
"source": [
"def normalize_x(x: int, screen_width: int) -> int:\n",
" \"\"\"Convert normalized x coordinate (0-1000) to actual pixel coordinate.\"\"\"\n",
" return int(x / 1000 * screen_width)\n",
"\n",
"\n",
"def normalize_y(y: int, screen_height: int) -> int:\n",
" \"\"\"Convert normalized y coordinate (0-1000) to actual pixel coordinate.\"\"\"\n",
" return int(y / 1000 * screen_height)\n",
"\n",
"\n",
"async def execute_function_calls(\n",
" response, page, screen_width, screen_height\n",
") -> list[tuple[str, str]]:\n",
" \"\"\"Extracts and executes function calls from the model response.\"\"\"\n",
" candidate = response.candidates[0]\n",
" function_calls = []\n",
" thoughts = []\n",
"\n",
" for part in candidate.content.parts:\n",
" if hasattr(part, \"function_call\") and part.function_call:\n",
" function_calls.append(part.function_call)\n",
" elif hasattr(part, \"text\") and part.text:\n",
" thoughts.append(part.text)\n",
"\n",
" if thoughts:\n",
" print(f\" Model Reasoning: {' '.join(thoughts)}\")\n",
"\n",
" if not function_calls:\n",
" return \"NO_ACTION\", []\n",
"\n",
" results = []\n",
" for function_call in function_calls:\n",
" result = None\n",
" print(f\"⚡ Executing Action: {function_call.name}\")\n",
" try:\n",
" if function_call.name == \"open_web_browser\":\n",
" result = \"success\"\n",
" elif function_call.name == \"navigate\":\n",
" await page.goto(function_call.args[\"url\"])\n",
" result = \"success\"\n",
" elif function_call.name == \"click_at\":\n",
" actual_x = normalize_x(function_call.args[\"x\"], screen_width)\n",
" actual_y = normalize_y(function_call.args[\"y\"], screen_height)\n",
" await page.mouse.click(actual_x, actual_y)\n",
" result = \"success\"\n",
" elif function_call.name == \"type_text_at\":\n",
" actual_x = normalize_x(function_call.args[\"x\"], screen_width)\n",
" actual_y = normalize_y(function_call.args[\"y\"], screen_height)\n",
" await page.mouse.click(actual_x, actual_y)\n",
" time.sleep(0.1)\n",
" await page.keyboard.type(function_call.args[\"text\"])\n",
" if function_call.args.get(\"press_enter\", False):\n",
" await page.keyboard.press(\"Enter\")\n",
" result = \"success\"\n",
" else:\n",
" result = \"unknown_function\"\n",
" except Exception as e:\n",
" print(f\"❗️ Error executing {function_call.name}: {e}\")\n",
" result = f\"error: {e!s}\"\n",
" results.append((function_call.name, result))\n",
" return \"CONTINUE\", results"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "_SP2x-IjMSzr"
},
"outputs": [],
"source": [
"results = await execute_function_calls(response, page, screen_width, screen_height)\n",
"print(results)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "y287MbtSJ7bs"
},
"source": [
"Here is an example action for navigating a URL. In this case, we create a simple mock response object.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AubneGmKA2bw"
},
"outputs": [],
"source": [
"mock_response = SimpleNamespace(\n",
" candidates=[\n",
" SimpleNamespace(\n",
" content=SimpleNamespace(\n",
" parts=[\n",
" SimpleNamespace(\n",
" function_call=FunctionCall(\n",
" name=\"navigate\", args={\"url\": \"https://flights.google.com\"}\n",
" ),\n",
" )\n",
" ]\n",
" )\n",
" )\n",
" ]\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "OW9N3x6kC-kc"
},
"outputs": [],
"source": [
"print(f\"Current page URL: {page.url}\")\n",
"\n",
"print(\"Calling execute_function_calls with a sample response\")\n",
"results = await execute_function_calls(mock_response, page, screen_width, screen_height)\n",
"print(f\"Results from execution:\\n{results}\\n\")\n",
"\n",
"print(f\"Navigated to: {page.url}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "dkndDAPXNLQx"
},
"source": [
"### **4. Capture the New State and Respond**\n",
"\n",
"Finally, after executing the actions, we capture a new screenshot and the current URL. This state information is then formatted as a `FunctionResponse` and added to our conversation history, making it ready for the next turn in the loop."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8QcMbBE5NUHU"
},
"outputs": [],
"source": [
"status, action_results_list = results\n",
"\n",
"function_response_parts = []\n",
"\n",
"for name, result in action_results_list:\n",
" # After each action, capture a new screenshot and the current URL\n",
" screenshot = await page.screenshot()\n",
" current_url = page.url\n",
"\n",
" # Create a FunctionResponse for each action that was executed\n",
" # This is required even if multiple actions were called in parallel\n",
" function_response_parts.append(\n",
" Part(\n",
" function_response=FunctionResponse(\n",
" name=name,\n",
" response={\"url\": current_url},\n",
" parts=[\n",
" Part(\n",
" inline_data=FunctionResponseBlob(\n",
" mime_type=\"image/png\", data=screenshot\n",
" )\n",
" )\n",
" ],\n",
" )\n",
" )\n",
" )\n",
"\n",
"# Package all the function responses into a single 'user' message\n",
"user_feedback_content = Content(role=\"user\", parts=function_response_parts)\n",
"\n",
"# Append this new message to your conversation history\n",
"contents.append(user_feedback_content)\n",
"\n",
"print(\"Step 4 Complete: New state captured and added to conversation history.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YAZBbH3hD1y8"
},
"source": [
"The `contents` list is now ready for the next call to the model."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "O3LJGCkHD640"
},
"source": [
"#### Clean up by closing the browser and stopping the session\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "GKoItatcCqrV"
},
"outputs": [],
"source": [
"await browser.close()\n",
"await playwright.stop()\n",
"\n",
"print(\"Browser closed and Playwright session stopped.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "sZR7UOfgOdji"
},
"source": [
"## Build an Agent Loop\n",
"\n",
"To enable multi-step interactions, combine the four steps from the How to implement Computer Use section into a loop. The loop must handle parallel function calls, and safety decisions. Remember to manage the conversation history correctly by appending both model responses and your function responses."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "m5mYV8CbZE05"
},
"outputs": [],
"source": [
"async def agent_loop(initial_prompt, max_turns=20):\n",
" \"\"\"Main agent loop\"\"\"\n",
" playwright_loop = await async_playwright().start()\n",
" browser_loop = await playwright_loop.chromium.launch(headless=True)\n",
" page_loop = await browser_loop.new_page()\n",
" sw, sh = 1920, 1080\n",
" await page_loop.set_viewport_size({\"width\": sw, \"height\": sh})\n",
"\n",
" print(f\"Starting Agent Loop with prompt: '{initial_prompt}'\")\n",
"\n",
" screenshot = await page_loop.screenshot()\n",
" contents = [\n",
" Content(\n",
" role=\"user\",\n",
" parts=[\n",
" Part(text=initial_prompt),\n",
" Part.from_bytes(data=screenshot, mime_type=\"image/png\"),\n",
" ],\n",
" )\n",
" ]\n",
"\n",
" for turn in range(max_turns):\n",
" print(f\"\\n Turn {turn + 1}\")\n",
"\n",
" response = client.models.generate_content(\n",
" model=MODEL_ID, contents=contents, config=config\n",
" )\n",
"\n",
" # Handle cases where the model returns no candidates (e.g., due to safety filters)\n",
" if not response.candidates:\n",
" print(\"Model returned no candidates. This may be due to a safety filter.\")\n",
" print(\"Full Response:\", response)\n",
" print(\"Terminating loop.\")\n",
" break\n",
"\n",
" contents.append(response.candidates[0].content)\n",
"\n",
" function_calls = [\n",
" part.function_call\n",
" for part in response.candidates[0].content.parts\n",
" if hasattr(part, \"function_call\") and part.function_call\n",
" ]\n",
"\n",
" # Finish the agent loop if no function call in the response.\n",
" if not function_calls:\n",
" final_text = \"\".join(\n",
" part.text\n",
" for part in response.candidates[0].content.parts\n",
" if hasattr(part, \"text\") and part.text is not None\n",
" )\n",
" if final_text:\n",
" print(f\"Agent Finished: {final_text}\")\n",
" break\n",
"\n",
" status, execution_results = await execute_function_calls(\n",
" response, page_loop, sw, sh\n",
" )\n",
"\n",
" if status == \"NO_ACTION\":\n",
" continue\n",
"\n",
" function_response_parts = []\n",
" for name, result in execution_results:\n",
" screenshot = await page_loop.screenshot()\n",
" current_url = page_loop.url\n",
" function_response_parts.append(\n",
" Part(\n",
" function_response=FunctionResponse(\n",
" name=name,\n",
" response={\"url\": current_url},\n",
" parts=[\n",
" Part(\n",
" inline_data=FunctionResponseBlob(\n",
" mime_type=\"image/png\", data=screenshot\n",
" )\n",
" )\n",
" ],\n",
" )\n",
" )\n",
" )\n",
" contents.append(Content(role=\"user\", parts=function_response_parts))\n",
" print(f\"State captured. History now has {len(contents)} messages.\")\n",
"\n",
" print(\"\\n Agent loop finished. Closing browser.\")\n",
" await browser_loop.close()\n",
" await playwright_loop.stop()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "hX30dnPKnXYK"
},
"outputs": [],
"source": [
"# RUN THE AGENT LOOP\n",
"prompt = \"Navigate to the Google Store and find the 'Pixel' category.\"\n",
"\n",
"await agent_loop(prompt)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gj9KyrqG3n3s"
},
"source": [
"## Next Steps\n",
"\n",
"- Explore a [Computer Use web agent reference implementation](https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/computer-use/web-agent).\n",
"- Check out the [Computer Use documentation](https://ai.google.dev/gemini-api/docs/computer-use) for detailed guides, parameter references, and best practices.\n"
]
}
],
"metadata": {
"colab": {
"name": "intro_computer_use.ipynb",
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
}
},
"nbformat": 4,
"nbformat_minor": 0
}