diff --git a/docs/agents/custom-agents.md b/docs/agents/custom-agents.md index affcef6164..84cd2d4013 100644 --- a/docs/agents/custom-agents.md +++ b/docs/agents/custom-agents.md @@ -323,5 +323,5 @@ if __name__ == "__main__": ```python # Full runnable code for the StoryFlowAgent example ---8<-- "examples/python/snippets/agents/custom-agent/storyflow-agent.py" -``` \ No newline at end of file +--8<-- "examples/python/snippets/agents/custom-agent/storyflow_agent.py" +``` diff --git a/docs/agents/llm-agents.md b/docs/agents/llm-agents.md index 0d06ebdb44..31a7fe9d1f 100644 --- a/docs/agents/llm-agents.md +++ b/docs/agents/llm-agents.md @@ -94,7 +94,6 @@ capital_agent = LlmAgent( Learn more about Tools in the [Tools](../tools/index.md) section. - ## Advanced Configuration & Control Beyond the core parameters, `LlmAgent` offers several options for finer control: diff --git a/docs/agents/models.md b/docs/agents/models.md index 0439f2d28d..826b1f2fe7 100644 --- a/docs/agents/models.md +++ b/docs/agents/models.md @@ -22,30 +22,36 @@ The `google-genai` library, used internally by ADK for Gemini, can connect throu 1. **Google AI Studio:** * **Use Case:** Best for rapid prototyping and development. * **Setup:** Typically requires an API key set as an environment variable: - + ```shell export GOOGLE_API_KEY="YOUR_GOOGLE_API_KEY" export GOOGLE_GENAI_USE_VERTEXAI=FALSE ``` - + * **Models:** Find available models on the [Google AI for Developers site](https://ai.google.dev/gemini-api/docs/models). 2. **Vertex AI:** * **Use Case:** Recommended for production applications, leveraging Google Cloud infrastructure. * **Setup:** * Authenticate using Application Default Credentials (ADC): + ```shell gcloud auth application-default login ``` + * Set your Google Cloud project and location: + ```shell export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID" export GOOGLE_CLOUD_LOCATION="YOUR_VERTEX_AI_LOCATION" # e.g., us-central1 ``` + * Explicitly tell the library to use Vertex AI: + ```shell export GOOGLE_GENAI_USE_VERTEXAI=TRUE ``` + * **Models:** Find available model IDs in the [Vertex AI documentation](https://cloud.google.com/vertex-ai/generative-ai/docs/learn/models). **Example:** @@ -92,13 +98,17 @@ To access a vast range of LLMs from providers like OpenAI, Anthropic (non-Vertex 2. **Set Provider API Keys:** Configure API keys as environment variables for the specific providers you intend to use. * *Example for OpenAI:* + ```shell export OPENAI_API_KEY="YOUR_OPENAI_API_KEY" ``` + * *Example for Anthropic (non-Vertex AI):* + ```shell export ANTHROPIC_API_KEY="YOUR_ANTHROPIC_API_KEY" ``` + * *Consult the [LiteLLM Providers Documentation](https://docs.litellm.ai/docs/providers) for the correct environment variable names for other providers.* **Example:** @@ -126,7 +136,6 @@ To access a vast range of LLMs from providers like OpenAI, Anthropic (non-Vertex ) ``` - ## Using Open & Local Models via LiteLLM For maximum control, cost savings, privacy, or offline use cases, you can run open-source models locally or self-host them and integrate them using LiteLLM. @@ -141,9 +150,11 @@ For maximum control, cost savings, privacy, or offline use cases, you can run op 1. Install Ollama. 2. Pull the desired model (e.g., Google's Gemma): + ```shell ollama pull gemma:2b ``` + 3. Ensure the Ollama server is running (usually happens automatically after installation or by running `ollama serve`). **Example:** @@ -168,9 +179,9 @@ Tools like [vLLM](https://github.com/vllm-project/vllm) allow you to host models **Setup:** -1. **Deploy Model:** Deploy your chosen model using vLLM (or a similar tool). Note the API base URL (e.g., `https://your-vllm-endpoint.run.app/v1`). - * *Important for ADK Tools:* When deploying, ensure the serving tool supports and enables OpenAI-compatible tool/function calling. For vLLM, this might involve flags like `--enable-auto-tool-choice` and potentially a specific `--tool-call-parser`, depending on the model. Refer to the vLLM documentation on Tool Use. -2. **Authentication:** Determine how your endpoint handles authentication (e.g., API key, bearer token). +1. **Deploy Model:** Deploy your chosen model using vLLM (or a similar tool). Note the API base URL (e.g., `https://your-vllm-endpoint.run.app/v1`). + * *Important for ADK Tools:* When deploying, ensure the serving tool supports and enables OpenAI-compatible tool/function calling. For vLLM, this might involve flags like `--enable-auto-tool-choice` and potentially a specific `--tool-call-parser`, depending on the model. Refer to the vLLM documentation on Tool Use. +2. **Authentication:** Determine how your endpoint handles authentication (e.g., API key, bearer token). **Integration Example:** @@ -223,16 +234,21 @@ For enterprise-grade scalability, reliability, and integration with Google Cloud Ensure your environment is configured for Vertex AI: -1. **Authentication:** Use Application Default Credentials (ADC): +1. **Authentication:** Use Application Default Credentials (ADC): + ```shell gcloud auth application-default login ``` -2. **Environment Variables:** Set your project and location: + +2. **Environment Variables:** Set your project and location: + ```shell export GOOGLE_CLOUD_PROJECT="YOUR_PROJECT_ID" export GOOGLE_CLOUD_LOCATION="YOUR_ENDPOINT_LOCATION" # e.g., us-central1 ``` -3. **Enable Vertex Backend:** Crucially, ensure the `google-genai` library targets Vertex AI: + +3. **Enable Vertex Backend:** Crucially, ensure the `google-genai` library targets Vertex AI: + ```shell export GOOGLE_GENAI_USE_VERTEXAI=TRUE ``` @@ -293,12 +309,15 @@ Some providers, like Anthropic, make their models available directly through Ver **Setup:** -1. **Vertex AI Environment:** Ensure the consolidated Vertex AI setup (ADC, Env Vars, `GOOGLE_GENAI_USE_VERTEXAI=TRUE`) is complete. -2. **Install Provider Library:** Install the necessary client library configured for Vertex AI. +1. **Vertex AI Environment:** Ensure the consolidated Vertex AI setup (ADC, Env Vars, `GOOGLE_GENAI_USE_VERTEXAI=TRUE`) is complete. +2. **Install Provider Library:** Install the necessary client library configured for Vertex AI. + ```shell pip install "anthropic[vertex]" ``` -3. **Register Model Class:** Add this code near the start of your application, *before* creating an agent using the Claude model string: + +3. **Register Model Class:** Add this code near the start of your application, *before* creating an agent using the Claude model string: + ```python # Required for using Claude model strings directly via Vertex AI with LlmAgent from google.adk.models.anthropic_llm import Claude @@ -330,4 +349,4 @@ Some providers, like Anthropic, make their models available directly through Ver generate_content_config=types.GenerateContentConfig(max_output_tokens=4096), # ... other agent parameters ) - ``` \ No newline at end of file + ``` diff --git a/docs/agents/multi-agents.md b/docs/agents/multi-agents.md index ceb31a396c..c7b4b74d16 100644 --- a/docs/agents/multi-agents.md +++ b/docs/agents/multi-agents.md @@ -269,8 +269,8 @@ data_pipeline = SequentialAgent( * **Structure:** A [`ParallelAgent`](workflow-agents/parallel-agents.md) runs multiple `sub_agents` concurrently, often followed by a later agent (in a `SequentialAgent`) that aggregates results. * **Goal:** Execute independent tasks simultaneously to reduce latency, then combine their outputs. * **ADK Primitives Used:** - * **Workflow:** `ParallelAgent` for concurrent execution (Fan-Out). Often nested within a `SequentialAgent` to handle the subsequent aggregation step (Gather). - * **Communication:** Sub-agents write results to distinct keys in **Shared Session State**. The subsequent "Gather" agent reads multiple state keys. + * **Workflow:** `ParallelAgent` for concurrent execution (Fan-Out). Often nested within a `SequentialAgent` to handle the subsequent aggregation step (Gather). + * **Communication:** Sub-agents write results to distinct keys in **Shared Session State**. The subsequent "Gather" agent reads multiple state keys. ```python # Conceptual Code: Parallel Information Gathering @@ -302,8 +302,8 @@ overall_workflow = SequentialAgent( * **Structure:** A multi-level tree of agents where higher-level agents break down complex goals and delegate sub-tasks to lower-level agents. * **Goal:** Solve complex problems by recursively breaking them down into simpler, executable steps. * **ADK Primitives Used:** - * **Hierarchy:** Multi-level `parent_agent`/`sub_agents` structure. - * **Interaction:** Primarily **LLM-Driven Delegation** or **Explicit Invocation (`AgentTool`)** used by parent agents to assign tasks to children. Results are returned up the hierarchy (via tool responses or state). + * **Hierarchy:** Multi-level `parent_agent`/`sub_agents` structure. + * **Interaction:** Primarily **LLM-Driven Delegation** or **Explicit Invocation (`AgentTool`)** used by parent agents to assign tasks to children. Results are returned up the hierarchy (via tool responses or state). ```python # Conceptual Code: Hierarchical Research Task @@ -341,8 +341,8 @@ report_writer = LlmAgent( * **Structure:** Typically involves two agents within a [`SequentialAgent`](workflow-agents/sequential-agents.md): a Generator and a Critic/Reviewer. * **Goal:** Improve the quality or validity of generated output by having a dedicated agent review it. * **ADK Primitives Used:** - * **Workflow:** `SequentialAgent` ensures generation happens before review. - * **Communication:** **Shared Session State** (Generator uses `output_key` to save output; Reviewer reads that state key). The Reviewer might save its feedback to another state key for subsequent steps. + * **Workflow:** `SequentialAgent` ensures generation happens before review. + * **Communication:** **Shared Session State** (Generator uses `output_key` to save output; Reviewer reads that state key). The Reviewer might save its feedback to another state key for subsequent steps. ```python # Conceptual Code: Generator-Critic @@ -419,13 +419,13 @@ refinement_loop = LoopAgent( ### Human-in-the-Loop Pattern -* **Structure:** Integrates human intervention points within an agent workflow. -* **Goal:** Allow for human oversight, approval, correction, or tasks that AI cannot perform. -* **ADK Primitives Used (Conceptual):** - * **Interaction:** Can be implemented using a custom **Tool** that pauses execution and sends a request to an external system (e.g., a UI, ticketing system) waiting for human input. The tool then returns the human's response to the agent. - * **Workflow:** Could use **LLM-Driven Delegation** (`transfer_to_agent`) targeting a conceptual "Human Agent" that triggers the external workflow, or use the custom tool within an `LlmAgent`. - * **State/Callbacks:** State can hold task details for the human; callbacks can manage the interaction flow. - * **Note:** ADK doesn't have a built-in "Human Agent" type, so this requires custom integration. +* **Structure:** Integrates human intervention points within an agent workflow. +* **Goal:** Allow for human oversight, approval, correction, or tasks that AI cannot perform. +* **ADK Primitives Used (Conceptual):** + * **Interaction:** Can be implemented using a custom **Tool** that pauses execution and sends a request to an external system (e.g., a UI, ticketing system) waiting for human input. The tool then returns the human's response to the agent. + * **Workflow:** Could use **LLM-Driven Delegation** (`transfer_to_agent`) targeting a conceptual "Human Agent" that triggers the external workflow, or use the custom tool within an `LlmAgent`. + * **State/Callbacks:** State can hold task details for the human; callbacks can manage the interaction flow. + * **Note:** ADK doesn't have a built-in "Human Agent" type, so this requires custom integration. ```python # Conceptual Code: Using a Tool for Human Approval diff --git a/docs/agents/workflow-agents/parallel-agents.md b/docs/agents/workflow-agents/parallel-agents.md index 880ce9699e..306ab3706c 100644 --- a/docs/agents/workflow-agents/parallel-agents.md +++ b/docs/agents/workflow-agents/parallel-agents.md @@ -4,11 +4,11 @@ The `ParallelAgent` is a [workflow agent](index.md) that executes its sub-agents *concurrently*. This dramatically speeds up workflows where tasks can be performed independently. -Use `ParallelAgent` when: For scenarios prioritizing speed and involving independent, resource-intensive tasks, a `ParallelAgent` facilitates efficient parallel execution. **When sub-agents operate without dependencies, their tasks can be performed concurrently**, significantly reducing overall processing time. +Use `ParallelAgent` when: For scenarios prioritizing speed and involving independent, resource-intensive tasks, a `ParallelAgent` facilitates efficient parallel execution. **When sub-agents operate without dependencies, their tasks can be performed concurrently**, significantly reducing overall processing time. As with other [workflow agents](index.md), the `ParallelAgent` is not powered by an LLM, and is thus deterministic in how it executes. That being said, workflow agents are only concerned only with their execution (i.e. in parallel), and not their internal logic; the tools or sub-agents of a workflow agent may or may not utilize LLMs. -#### Example: +### Example This approach is particularly beneficial for operations like multi-source data retrieval or heavy computations, where parallelization yields substantial performance gains. Importantly, this strategy assumes no inherent need for shared state or direct information exchange between the concurrently executing agents. @@ -38,14 +38,14 @@ Imagine researching multiple topics simultaneously: 2. **Researcher Agent 2:** An `LlmAgent` that researches "electric vehicle technology." 3. **Researcher Agent 3:** An `LlmAgent` that researches "carbon capture methods." - ``` + ```py ParallelAgent(sub_agents=[ResearcherAgent1, ResearcherAgent2, ResearcherAgent3]) ``` These research tasks are independent. Using a `ParallelAgent` allows them to run concurrently, potentially reducing the total research time significantly compared to running them sequentially. The results from each agent would be collected separately after they finish. -**Full code** +### Full code ```py --8<-- "examples/python/snippets/agents/workflow-agents/parallel_agent_web_research.py" -``` \ No newline at end of file +``` diff --git a/docs/deploy/local-testing.md b/docs/deploy/local-testing.md index 45aa06b517..fab50180bf 100644 --- a/docs/deploy/local-testing.md +++ b/docs/deploy/local-testing.md @@ -5,7 +5,7 @@ working as intended. The easiest way is to test your a local agent is to use the ADK CLI with `adk api_server`, which launches a local Fast API server, where you can run cURL commands to test your agent. -#### Working directory +## Working directory First, ensure you are in the correct working directory: @@ -34,7 +34,7 @@ INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) ``` -Your server is now running locally at http://0.0.0.0:8000. +Your server is now running locally at `http://0.0.0.0:8000`. ### Creating a new session for your agent diff --git a/docs/get-started/quickstart-streaming.md b/docs/get-started/quickstart-streaming.md index bc0111a7ef..0c2f697afc 100644 --- a/docs/get-started/quickstart-streaming.md +++ b/docs/get-started/quickstart-streaming.md @@ -78,7 +78,7 @@ To run your agent, you'll need to set up a Gemini API Key. **.env** -``` +```shell GOOGLE_API_KEY=YOUR_API_KEY_HERE # Replace with your API Key GOOGLE_GENAI_USE_VERTEXAI=0 ``` @@ -87,13 +87,13 @@ GOOGLE_GENAI_USE_VERTEXAI=0 Now it's ready to try the agent. Run the following command to launch the **dev UI**. First, make sure to set the current directory to `app`: -``` +```shell cd app ``` Then, run the dev UI: -``` +```shell adk web ``` @@ -128,7 +128,7 @@ We have checked that our basic search agent works with the ADK Streaming. In the Add `static` directory under `app`, and add `main.py` and `index.html` as empty files, as in the following structure: -``` +```console adk-streaming/ # Project folder └── app/ # the web app folder ├── main.py # FastAPI web app @@ -426,16 +426,15 @@ This HTML file sets up a basic webpage with: 1\. **Navigate to the Correct Directory:** - To run your agent effectively, you need to be in the **app folder (`adk-streaming/app`)** + To run your agent effectively, you need to be in the **app folder (`adk-streaming/app`)** 2\. **Start the Fast API**: Run the following command to start CLI interface with -``` +```console uvicorn main:app --reload ``` 3\. **Access the UI:** Once the UI server starts, the terminal will display a local URL (e.g., [http://localhost:8000](http://localhost:8501)). Click this link to open the UI in your browser. - Now you should see the UI like this: diff --git a/docs/get-started/running-the-agent.md b/docs/get-started/running-the-agent.md deleted file mode 100644 index 9aa877b03d..0000000000 --- a/docs/get-started/running-the-agent.md +++ /dev/null @@ -1,220 +0,0 @@ -# Running your Agent - -Different methods for running your agent - -This page outlines the different methods for interacting with your ADK agents offering different levels of control and integration. - -ADK offers four primary ways to interact with your agents: - -| Interaction Method | What it is | When to Use | -| :---- |:---------------------------------------------------------------------------------------------------------------------------------------------------------| :---- | -| Command-Line Interface (CLI) | Use terminal commands to interact directly with your agent. | Quick tasks, scripting, automation, developers comfortable with terminal commands. | -| ADK dev UI | Interact with your agent through a user-friendly web browser. | Visual interaction, monitoring agent behavior, users less familiar with the command line. | -| API Server | Run your agent as a REST API, allowing other applications to communicate with it. | Integration with other applications, building services that use the agent, remote access to the agent. | -| Programmatic Interface | Integrate ADK directly into your applications (Python, Java, etc.) or notebooks (Jupyter, Colab). This provides full control over agent execution. | Deep integration within applications, custom workflows, notebooks, fine-grained control over agent execution. | - -**Note:** The way you *define* your agent (the core logic within `agent.py`) is the *same* regardless of how you choose to interact with it. The difference lies in how you *initiate* and *manage* the interaction. - -### Project Structure (for CLI, dev UI and API Server) - -To build an agent for use with the CLI, dev UI or API commands, you need to organize your code within a specific folder structure - -**Note:** This folder structure is required when using the adk command-line tools (adk cli, adk web, adk api_server). If you are using ADK directly within a Jupyter Notebook or integrating it into an existing Python project, you do not need to follow this structure. You can create and interact with Agent objects directly in your code. - -* **Create a Directory:** Create a directory for your agent, named after the agent (e.g., `my_search_agent`). - -* **Required Files:** Within this folder, you *must* include the following files: - - * `agent.py`: Inside the agent directory, create a file named `agent.py`. This file will contain your agent's definition (using the `Agent` class). You *must* define a variable named `root_agent` within this file; this serves as the entry point for the ADK. - * `__init__.py`: This is a standard Python module file. At a minimum, it must contain the line `from . import agent` to import the necessary class. It's also where you can import and make available other modules within your agent's folder. - - - *Why is this necessary?* This file makes your agent directory a Python package. The ADK CLI relies on Python's module discovery mechanisms. By including this line, you make your agent's class accessible when the CLI imports your agent's package. - - -* **Optional Files:** You are encouraged to add these files for better organization and documentation: - - * `requirements.txt`: Lists the Python packages required by your agent. This makes it easy to install dependencies. - * `README.md`: A Markdown file describing your agent, how to set it up, and how to use it. - -**Example Structure:** - -``` -my_search_agent/ - __init__.py - agent.py - requirements.txt (Optional) - README.md (Optional) -``` - -### 1\) CLI (`adk run`) - -1. **Navigate:** Open your terminal and use `cd` to navigate to the directory *containing* your agent folder (e.g., the directory containing `my_search_agent`). -2. **Run:** Execute the following command: - -``` -adk run my_search_agent # Replace with your agent's folder name -``` - - This will start the agent, and you can interact with it directly in the terminal. - -### 2) Dev UI (`adk web`) - -1. **Navigate:** Open your terminal and `cd` to the directory containing your agent folder. Note you should be in the parent directory of the agent folder, not in the agent folder itself. -2. **Run:** Execute: - -``` -adk web -``` - - This will start a local web server and open a new tab in your browser, providing a visual interface for interacting with your agent. - -### 3\) API Server (`adk api_server`) - -1. **Navigate:** Open your terminal and `cd` to the directory containing your agent folder. -2. **Run:** Execute: - -``` -adk api_server my_search_agent # Replace with your agent's folder name -``` - - - This will start a local API server (using Flask) on port 8000\. You can then interact with your agent via REST API calls. - -1. Start a new session: - -``` -curl -X POST "http://127.0.0.1:8000/apps/{app_123}/users/{user_123}/sessions/{session_123}" -``` - -2. Send a message to a session: - -``` -curl -X POST "http://127.0.0.1:8000/agent/run" \ - -H "Content-Type: application/json" \ - -d '{"session_id": "{session_123}", "app_name": "{app_123}", "user_id": "{user_123}", "new_message": {"role": "user", "parts": [{"text": "What can you do?"}]}}' -``` - -3. Retrieve a session: - -``` -curl -X GET "http://127.0.0.1:8000/apps/{app_123}/users/{user_123}/sessions/{session_123}" -``` - -4. Delete a session: - -``` -curl -X DELETE "http://127.0.0.1:8000/apps/{app_123}/users/{user_123}/sessions/{session_123}" -``` - - - -### 4\) Programmatic Interface (Apps and Notebooks) - -The Programmatic Interface allows you to integrate ADK directly into your Python applications or interactive notebooks (like Jupyter and Colab). Unlike the CLI, dev UI, and API server, you *don't* need the specific project structure as described above. Instead you’ll be using a Session and Runner. You can define and interact with your agent within the same file or notebook cell. - -Here's a breakdown of the steps and a complete code example: - -1. **Define Your Agent:** Create an `Agent` object, just like you would for the CLI or dev UI. You can do this directly in your application code or notebook cell. - -2. **Create a Session :** Think of **Sessions** as the "memory" of your agent. They allow your agent to remember the ongoing conversation. Just like in a real conversation, the agent needs to track what's been said before. `InMemorySessionService` manages this history of interactions, so your agent has context. - -```py -from agents import Agent -from agents.sessions import InMemorySessionService - -# Step 1: Define your agent: -root_agent = Agent(name="my_agent", - model="gemini-2.0-flash-exp", - instruction="Answer questions.") - -# Step 2: Initiate Session -session_service = InMemorySessionService() - -#Step 3: Create a new session. -session = session_service.create_session(app_name="my_app", user_id="user1") -``` - -Note: Data stored in-memory is fast to access but **disappears when your session ends or disconnects.** For example, if you restart your Colab runtime or re-initialize `session_service`, you will lose the conversation history. For real-world applications, you'd use more persistent storages (like databases), but for learning, in-memory is perfect\! - -3. **Create a Runner:** - - -The **Runner** is the **core component** in the ADK responsible for **executing an agent** in response to a user query. It **orchestrates the agent's processing flow** by managing an **event loop** and interacting with other components in the agent. The Runner also utilizes various **services** for session management, and memory. It **processes generated events** and returns a **stream of events**. The Runner provides different execution methods such as `run`, `run_async`, and `run_live`. - -```py -from agents.runners import Runner - -runner = Runner(agent=root_agent, session_service=session_service, app_name="my_app") -``` - -In this example, we're passing in: - -* `agent=root_agent`: **Crucially**, we tell the `Runner` to use our `root_agent` object – the agent we defined in Step 2\! -* `app_name`, `session_service`: These link the runner to our session management, ensuring everything is connected and tracked within our application. - -**Important Note:** For every interaction with your agent (every time you ask it a question), you'll use **the same `runner` object** and a **specific `session` ID**. The `runner` knows *how* to run the agent, and the `session` tells it *which conversation* to continue. - -4. **Run the Agent:** Use the `runner.run()` method to send a message to the agent and process its response. - -```py -from google.genai import types - -query = "What is the capital of France?" # question to agent. -content = types.Content(role='user', parts=[types.Part(text=query)]) -events = runner.run(session=session, new_message=content) - -for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response:", final_response) -``` - -Let’s explore what’s happening here: - -* `content = types.Content(role='user', parts=[types.Part(text=query)]):` This line constructs a Content object, which represents a message within a conversation with the agent. - * The `role='user'` parameter specifies that this \`Content\` originates from the end-user. - * The `parts` parameter is a list containing one or more \`Part\` objects. In this case, it contains a single \`Part\` with the user's query embedded as text. -* `events = runner.run(...)`: **This sends the content object to the agent\!** The `runner` takes our message and the `session` and tells the agent to process the query. The agent does its magic (using its tools and model), and the `runner` gives us back a list of `events`. -* `for event in events:`: We look through the `events` to find the agent's final answer (`event.is_final_response()`). -* `print("Agent Response: ", final_response)`: We simply print the agent's final answer to the screen. - -**Complete Example:** - -```py -from agents import Agent -from agents.runners import Runner -from agents import types -from agents.memory.local import InMemorySessionService, InMemoryArtifactService - -# 1. Define Your Agent -root_agent = Agent(name="my_agent", instruction="Answer questions.") - -# 2. Create a Session -session_service = InMemorySessionService() -artifact_service = InMemoryArtifactService() -session = session_service.create_session(app_name="my_app", user_id="user1") - -# 3. Create a Runner -runner = Runner(agent=root_agent, artifact_service=artifact_service, session_service=session_service, app_name="my_app") - -# 4. Run the Agent -query = "What is the capital of France?" -content = types.Content(role='user', parts=[types.Part(text=query)]) -events = runner.run(session=session, new_message=content) - -for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response:", final_response) - -``` - -* **Full Tutorial:** For a complete, step-by-step guide to using the Programmatic Interface, including code examples and advanced techniques, see the quickstart on building a Weather Agent. **\[placeholder-link\]** - -You should now have a solid understanding of how to install ADK, configure your LLM, and run your agents using different interaction methods. - -## Next steps - -* Learn how to define tools for your Agent: **\[placeholder-link\]** -* Read to build your first Multi-agent? Follow the tutorial here. **\[placeholder-link\]** diff --git a/docs/guides/evaluate-agents.md b/docs/guides/evaluate-agents.md index acfad42b28..22525bcb08 100644 --- a/docs/guides/evaluate-agents.md +++ b/docs/guides/evaluate-agents.md @@ -1,4 +1,4 @@ -## Why to Evaluate Agents +# Why Evaluate Agents In traditional software development, unit tests and integration tests provide confidence that code functions as expected and remains stable through changes. These tests provide a clear "pass/fail" signal, guiding further development. However, LLM agents introduce a level of variability that makes traditional testing approaches insufficient. @@ -58,14 +58,12 @@ This approach involves creating individual test files, each representing a singl * `query:` This is the user query. * `expected_tool_use`: The tool call(s) that we expect the agent to make in order to respond correctly to the user `query`. -* `expected_intermediate_agent_responses`: This field contains the natural language responses produced by the agent as it progresses towards a final answer. These responses are typical in multi-agent systems where a root agent relies on child agents to accomplish a task. While generally not directly relevant to end-users, these intermediate responses are valuable for developers. They provide insight into the agent's reasoning path and help verify that it followed the correct steps to generate the final response. +* `expected_intermediate_agent_responses`: This field contains the natural language responses produced by the agent as it progresses towards a final answer. These responses are typical in multi-agent systems where a root agent relies on child agents to accomplish a task. While generally not directly relevant to end-users, these intermediate responses are valuable for developers. They provide insight into the agent's reasoning path and help verify that it followed the correct steps to generate the final response. * `reference`: The expected final response from the model. - You can give the file any name for example `evaluation.test.json`.The framework only checks for the `.test.json` suffix, and the preceding part of the filename is not constrained. Here is a test file with a few examples: -``` - +```json [ { "query": "hi", @@ -104,8 +102,7 @@ An evalset file contains multiple "evals," each representing a distinct session. Creating evalsets manually can be complex, therefore UI tools are provided to help capture relevant sessions and easily convert them into evals within your evalset. Learn more about using the web UI for evaluation below. Here is an example evalset containing two sessions. -``` - +```json [ { "name": "roll_16_sided_dice_and_then_check_if_6151953_is_prime", @@ -203,7 +200,7 @@ If no evaluation criteria are provided, the following default configuration is u Here is an example of a `test_config.json` file specifying custom evaluation criteria: -``` +```json { "criteria": { "tool_trajectory_avg_score": 1.0, @@ -212,7 +209,7 @@ Here is an example of a `test_config.json` file specifying custom evaluation cri } ``` -## How to run Evaluation with the ADK +## How to run Evaluation with the ADK As a developer, you can evaluate your agents using the ADK in the following ways: @@ -240,14 +237,13 @@ Steps to run evaluation via the web ui: You can also use **`pytest`** to run test files as part of your integration tests. -#### Example Command: - -``` +#### Example Command +```shell pytest tests/integration/ ``` -#### Example Test Code: +#### Example Test Code Here is an example of a `pytest` test case that runs a single test file: @@ -264,7 +260,7 @@ This approach allows you to integrate agent evaluations into your CI/CD pipeline Here is a sample session json file: -``` +```json { "id": "test_id", "app_name": "trip_planner_agent", @@ -300,7 +296,7 @@ You can also run evaluation of an eval set file through the command line interfa Here is the command: -``` +```shell adk eval \ \ \ @@ -310,7 +306,7 @@ adk eval \ For example: -``` +```shell adk eval \ samples_for_testing/hello_world \ samples_for_testing/hello_world/hello_world_eval_set_001.evalset.json @@ -319,7 +315,7 @@ adk eval \ Here are the details for each command line argument: * `AGENT_MODULE_FILE_PATH`: The path to the `init.py` file that contains a module by the name "agent". "agent" module contains a `root_agent`. -* `EVAL_SET_FILE_PATH`: The path to evaluations file(s). You can specify one or more eval set file paths. For each file, all evals will be run by default. If you want to run only specific evals from a eval set, first create a comma separated list of eval names and then add that as a suffix to the eval set file name, demarcated by a colon `:` . +* `EVAL_SET_FILE_PATH`: The path to evaluations file(s). You can specify one or more eval set file paths. For each file, all evals will be run by default. If you want to run only specific evals from a eval set, first create a comma separated list of eval names and then add that as a suffix to the eval set file name, demarcated by a colon `:` . * For example: `sample_eval_set_file.json:eval_1,eval_2,eval_3` `This will only run eval_1, eval_2 and eval_3 from sample_eval_set_file.json` * `CONFIG_FILE_PATH`: The path to the config file. diff --git a/docs/tools/authentication.md b/docs/tools/authentication.md index fdc4e710a6..9ee9852c6e 100644 --- a/docs/tools/authentication.md +++ b/docs/tools/authentication.md @@ -4,21 +4,24 @@ Many tools, especially those interacting with external APIs (like Google Workspace, Salesforce, etc.), require authentication. ADK provides mechanisms to handle this securely. The key components are: -1. **`AuthScheme`**: Defines *what kind* of authentication the target API needs (e.g., OAuth 2.0 Bearer token, API Key). This usually corresponds to OpenAPI `securitySchemes`. -2. **`AuthCredential`**: Holds the *initial* information to start the authentication process (e.g., OAuth Client ID/Secret, API Key value, Service Account details). +1. **`AuthScheme`**: Defines *what kind* of authentication the target API needs (e.g., OAuth 2.0 Bearer token, API Key). This usually corresponds to OpenAPI `securitySchemes`. +2. **`AuthCredential`**: Holds the *initial* information to start the authentication process (e.g., OAuth Client ID/Secret, API Key value, Service Account details). ## Configuring Authentication on Tools You set up authentication when defining your tool: -* **`RestApiTool` / `OpenAPIToolset`**: Pass `auth_scheme` and `auth_credential` during initialization or use `.configure_auth_scheme()` or `.configure_auth_credential()`. -* **`GoogleApiToolSet` Tools**: ADK has [built-in 1st party tools](../tools/built-in-tools.md) like Google Calendar, BigQuery etc,. Use the toolset's specific method. +* **`RestApiTool` / `OpenAPIToolset`**: Pass `auth_scheme` and `auth_credential` during initialization or use `.configure_auth_scheme()` or `.configure_auth_credential()`. +* **`GoogleApiToolSet` Tools**: ADK has [built-in 1st party tools](../tools/built-in-tools.md) like Google Calendar, BigQuery etc,. Use the toolset's specific method. + ```py tool.configure_auth(client_id=..., client_secret=...) ``` -* **Custom `FunctionTool`**: Handle authentication logic *inside* your function using the `ToolContext`. + +* **Custom `FunctionTool`**: Handle authentication logic *inside* your function using the `ToolContext`. ## Supported Initial Credential Types + * API_KEY: For simple key/value authentication. Usually requires no exchange. * HTTP: Can represent Basic Auth (not recommended/supported for exchange) or already obtained Bearer tokens. If it's a Bearer token, no exchange is needed. * OAUTH2: For standard OAuth 2.0 flows. Requires configuration (client ID, secret, scopes) and often triggers the interactive flow for user consent. @@ -27,17 +30,17 @@ You set up authentication when defining your tool: ## The Authentication Flow (General) -1. **Initial Credential Provided:** You configure the tool with the starting credential. -2. **Exchange (if needed):** ADK automatically tries to exchange the initial credential for one usable in an API request (e.g., Service Account key -> Bearer token). This uses internal `CredentialExchanger`. API Keys or existing Bearer tokens usually skip this. -3. **Interactive Flow (if needed):** If user interaction (login/consent) is required (common for OAuth 2.0/OIDC), the specific interactive flow (detailed below) is triggered. -4. **API Call:** The final credential (e.g., Bearer token) is injected into the API request by tools like `RestApiTool`. Custom `FunctionTool`s must manually use the obtained credential from the `ToolContext`. +1. **Initial Credential Provided:** You configure the tool with the starting credential. +2. **Exchange (if needed):** ADK automatically tries to exchange the initial credential for one usable in an API request (e.g., Service Account key -> Bearer token). This uses internal `CredentialExchanger`. API Keys or existing Bearer tokens usually skip this. +3. **Interactive Flow (if needed):** If user interaction (login/consent) is required (common for OAuth 2.0/OIDC), the specific interactive flow (detailed below) is triggered. +4. **API Call:** The final credential (e.g., Bearer token) is injected into the API request by tools like `RestApiTool`. Custom `FunctionTool`s must manually use the obtained credential from the `ToolContext`. -!!! tip "WARNING" +!!! tip "WARNING" Storing sensitive credentials like access tokens and especially refresh tokens directly in the session state might pose security risks depending on your session storage backend (`SessionService`) and overall application security posture. - * **`InMemorySessionService`:** Suitable for testing and development, but data is lost when the process ends. Less risk as it's transient. - * **Database/Persistent Storage:** **Strongly consider encrypting** the token data before storing it in the database using a robust encryption library (like `cryptography`) and managing encryption keys securely (e.g., using a key management service). - * **Secure Secret Stores:** For production environments, storing sensitive credentials in a dedicated secret manager (like Google Cloud Secret Manager or HashiCorp Vault) is the **most recommended approach**. Your tool could potentially store only short-lived access tokens or secure references (not the refresh token itself) in the session state, fetching the necessary secrets from the secure store when needed. + * **`InMemorySessionService`:** Suitable for testing and development, but data is lost when the process ends. Less risk as it's transient. + * **Database/Persistent Storage:** **Strongly consider encrypting** the token data before storing it in the database using a robust encryption library (like `cryptography`) and managing encryption keys securely (e.g., using a key management service). + * **Secure Secret Stores:** For production environments, storing sensitive credentials in a dedicated secret manager (like Google Cloud Secret Manager or HashiCorp Vault) is the **most recommended approach**. Your tool could potentially store only short-lived access tokens or secure references (not the refresh token itself) in the session state, fetching the necessary secrets from the secure store when needed. Always prioritize secure handling of credentials according to your application's security requirements and compliance standards. Avoid storing raw refresh tokens in plain text in persistent storage accessible by the application server. @@ -47,23 +50,23 @@ This flow requires coordination between your Tool code, the ADK Framework, and y ![Authentication](../assets/auth_part1.svg) -**Step 1: (Tool Function) Check for Cached Credentials** +### Step 1: (Tool Function) Check for Cached Credentials Inside your tool function, first check if valid credentials (e.g., access/refresh tokens) are already stored from a previous run in this session. Use `tool_context.state` for this. -**Step 2: (Tool Function) Check for Auth Response from Client** +### Step 2: (Tool Function) Check for Auth Response from Client If no valid cached credentials exist, check if the user just completed the external OAuth flow and the client sent the results back in this turn. Use `tool_context.get_auth_response()`. -**Step 3: (Tool Function) Initiate Authentication Request** +### Step 3: (Tool Function) Initiate Authentication Request If no valid credentials (Step 1) and no auth response (Step 2) are found, the tool needs to start the OAuth flow. Define the `AuthScheme` and initial `AuthCredential` and call `tool_context.request_credential()`. Return a status indicating authorization is needed. -**Step 4: (ADK Framework) Generate Auth Event** +### Step 4: (ADK Framework) Generate Auth Event ADK intercepts the `request_credential` action. It uses the provided scheme and credential to generate the appropriate authorization URL (and potentially state parameter). It then stops the tool and yields a special long-running function call event. -**Step 5: (Agent Client) Handle Auth Request & Redirect User** +### Step 5: (Agent Client) Handle Auth Request & Redirect User Your application (UI, Spark job, etc.) receives the `af_request_euc` event. @@ -73,7 +76,7 @@ Your application (UI, Spark job, etc.) receives the `af_request_euc` event. * Redirect the user to the `auth_uri` (e.g., open a new browser tab). -**Step 6: (User & OAuth Provider) User Authorizes** +### Step 6: (User & OAuth Provider) User Authorizes * The user interacts with the OAuth provider (e.g., logs into Google, grants permissions). @@ -81,7 +84,7 @@ Your application (UI, Spark job, etc.) receives the `af_request_euc` event. ![Authentication](../assets/auth_part2.svg) -**Step 7: (Agent Client) Capture Callback & Send Response** +### Step 7: (Agent Client) Capture Callback & Send Response * Your Agent Client application must be listening on the **REDIRECT_URI**. @@ -89,7 +92,7 @@ Your application (UI, Spark job, etc.) receives the `af_request_euc` event. * Construct a types.FunctionResponse part: - * name: Must be "af_request_euc". + * name: Must be `af_request_euc`. * id: Must match the id received in Step 4 (af-generated-uuid in the example). @@ -97,7 +100,7 @@ Your application (UI, Spark job, etc.) receives the `af_request_euc` event. * Call `runner.run_async()` again, passing only this FunctionResponse within a `types.Content` object as the new_message. -**Step 8 & 9: (ADK & Tool Function) Receive Response & Retry Tool** +### Step 8 & 9: (ADK & Tool Function) Receive Response & Retry Tool * ADK receives the FunctionResponse, processes it, and makes the response data (the callback URL) available via `tool_context.get_auth_response()`. @@ -105,18 +108,18 @@ Your application (UI, Spark job, etc.) receives the `af_request_euc` event. * This time, inside your tool function, the check in Step 2 [`tool_context.get_auth_response()`] will succeed and return the dictionary ```{'response': 'https://your-redirect-uri/callback?code=XYZ...'}```. -**Step 10: (Tool Function) Exchange Code for Tokens** +### Step 10: (Tool Function) Exchange Code for Tokens Your tool function now extracts the `authorization_code` from the callback URL received in `get_auth_response()`. It uses this code (along with client ID/secret) to make a request to the OAuth provider's token endpoint to get the access token and refresh token. Use appropriate libraries like **google-auth-oauthlib**. -**Step 11: (Tool Function) Cache Credentials** +### Step 11: (Tool Function) Cache Credentials Store the newly obtained Credentials object (containing access and refresh tokens) in `tool_context.state` for future use within the session. Remember the security warning about storing tokens. -**Step 12: (Tool Function) Make Authenticated API Call** +### Step 12: (Tool Function) Make Authenticated API Call Use the now valid Credentials object (creds) to make the authenticated call to the target API (e.g., Google Calendar API). -**Step 13: (Tool Function) Return Result** +### Step 13: (Tool Function) Return Result Return the actual result from the API call as a dictionary, including a success status. diff --git a/docs/tools/built-in-tools.md b/docs/tools/built-in-tools.md index 43c5f4fa72..79e7d82ccf 100644 --- a/docs/tools/built-in-tools.md +++ b/docs/tools/built-in-tools.md @@ -17,7 +17,7 @@ Once added to an agent, the agent can decide to use the tool based on the **user `google_search`: Allows the agent to perform web searches using Google Search. You simply add this tool to the agent's tools list. It is compatible with Gemini 2 models. ```py ---8<-- "examples/python/snippets/tools/built-in-tools/google-search.py" +--8<-- "examples/python/snippets/tools/built-in-tools/google_search.py" ``` ### Code Execution @@ -25,7 +25,7 @@ Once added to an agent, the agent can decide to use the tool based on the **user `built_in_code_execution`: Enables the agent to execute code, specifically when using Gemini 2 models. This allows the model to perform tasks like calculations, data manipulation, or running small scripts. This capability is built-in and automatically activated for compatible models, requiring no explicit configuration. ````py ---8<-- "examples/python/snippets/tools/built-in-tools/code-execution.py" +--8<-- "examples/python/snippets/tools/built-in-tools/code_execution.py" ```` ### Retrieval tools @@ -37,5 +37,5 @@ This is a category of tools designed to fetch information from various sources. `built_in_vertexai_search`: Leverages Google Cloud's Vertex AI Search, enabling the agent to search across your private, configured data stores (e.g., internal documents, company policies, knowledge bases). This built-in tool requires you to provide the specific data store ID during configuration. ```py ---8<-- "examples/python/snippets/tools/built-in-tools/vertexai-search.py" +--8<-- "examples/python/snippets/tools/built-in-tools/vertexai_search.py" ``` diff --git a/docs/tools/function-tools.md b/docs/tools/function-tools.md index 529e2aa277..e6cf402e07 100644 --- a/docs/tools/function-tools.md +++ b/docs/tools/function-tools.md @@ -37,7 +37,7 @@ This tool is a python function which obtains the Stock price of a given Stock ti Note: You need to `pip install yfinance` library before using this tool. ```py ---8<-- "examples/python/snippets/tools/function-tools/func-tool.py" +--8<-- "examples/python/snippets/tools/function-tools/func_tool.py" ``` The return value from this tool will be wrapped into a dictionary. @@ -113,7 +113,7 @@ The Python object your generator function returns is considered the final result ### Example: File Processing Simulation ```py ---8<-- "examples/python/snippets/tools/function-tools/file-processor.py" +--8<-- "examples/python/snippets/tools/function-tools/file_processor.py" ``` #### Key aspects of this example @@ -158,7 +158,7 @@ The `AgentTool` class provides the following attributes for customizing its beha --8<-- "examples/python/snippets/tools/function-tools/summarizer.py" ``` -**How it works** +### How it works 1. When the `main_agent` receives the long text, its instruction tells it to use the 'summarize' tool for long texts. 2. The framework recognizes 'summarize' as an `AgentTool` that wraps the `summary_agent`. diff --git a/docs/tools/google-cloud-tools.md b/docs/tools/google-cloud-tools.md index bced94f115..e2bc016668 100644 --- a/docs/tools/google-cloud-tools.md +++ b/docs/tools/google-cloud-tools.md @@ -20,7 +20,7 @@ Google Cloud tools make it easier to connect your agents to Google Cloud’s pro 3. [Apigee API hub](https://cloud.google.com/apigee/docs/apihub/what-is-api-hub) instance with documented (i.e. OpenAPI spec) APIs 4. Set up your project structure and create required files -``` +```console project_root_folder | `-- my_agent @@ -32,7 +32,7 @@ project_root_folder ### Create an API Hub Toolset and add it to your agent -Note: this tutorial includes an agent creation. If you already have an agent, you can only follow subset of these steps. +Note: this tutorial includes an agent creation. If you already have an agent, you can only follow subset of these steps. 1. Get your access token, so that APIHubToolset can fetch spec from API Hub API. In your terminal run the following command @@ -72,7 +72,7 @@ Note: this tutorial includes an agent creation. If you already have an agent, yo ) ``` - For production deployment we recommend using a service account instead of an access token. In the code snippet above, use `service_account_json=service_account_cred_json_str` and provide your security account credentials instead of the token. + For production deployment we recommend using a service account instead of an access token. In the code snippet above, use `service_account_json=service_account_cred_json_str` and provide your security account credentials instead of the token. For apihub\_resource\_name, if you know the specific ID of the OpenAPI Spec being used for your API, use `` `projects/my-project-id/locations/us-west1/apis/my-api-id/versions/version-id/specs/spec-id` ``. If you would like the Toolset to automatically pull the first available spec from the API, use `` `projects/my-project-id/locations/us-west1/apis/my-api-id` `` @@ -109,25 +109,24 @@ Note: this tutorial includes an agent creation. If you already have an agent, yo ## 2. Connect to Enterprise Applications and Integration workflows With **ApplicationIntegrationToolset** you can seamlessly give your agents a secure and governed to enterprise applications using Integration Connector’s 100+ pre-built connectors for systems like Salesforce, ServiceNow, JIRA, SAP, and more. Support for both on-prem and SaaS applications. -In addition you can turn your existing Application Integration process automations into agentic workflows by providing application integration workflows as tools to your ADK agents. +In addition you can turn your existing Application Integration process automations into agentic workflows by providing application integration workflows as tools to your ADK agents. ## Prerequisites 1. [Install ADK](../get-started/installation.md) 2. An existing [Application Integration](https://cloud.google.com/application-integration/docs/overview) workflow or [Integrations Connector](https://cloud.google.com/integration-connectors/docs/overview) connection you want to use with your agent -3. To use tool with default credentials: have Google Cloud CLI installed. See [installation guide](https://cloud.google.com/sdk/docs/install#installation_instructions)*.* +3. To use tool with default credentials: have Google Cloud CLI installed. See [installation guide](https://cloud.google.com/sdk/docs/install#installation_instructions)*.* *Run :* - ``` + ```shell gcloud config set project gcloud auth application-default login gcloud auth application-default set-quota-project ``` 4. Set up your project structure and create required files - - ``` + ```console project_root_folder |-- .env `-- my_agent @@ -136,8 +135,6 @@ In addition you can turn your existing Application Integration process automati `__ tools.py ``` - - When running the agent, make sure to run adk web in project\_root\_folder ### Connect your agent to enterprise applications using [Integration Connectors](https://cloud.google.com/integration-connectors/docs/overview) @@ -165,7 +162,7 @@ When running the agent, make sure to run adk web in project\_root\_folder To find the list of supported entities and actions for a connection, use the connectors apis: [listActions](https://cloud.google.com/integration-connectors/docs/reference/rest/v1/projects.locations.connections.connectionSchemaMetadata/listActions), [listEntityTypes](https://cloud.google.com/integration-connectors/docs/reference/rest/v1/projects.locations.connections.connectionSchemaMetadata/listEntityTypes) -3. Add the tool to your agent. Update your agent.py file +3. Add the tool to your agent. Update your agent.py file ```py from google.adk.agents.llm_agent import LlmAgent @@ -213,7 +210,7 @@ When running the agent, make sure to run adk web in project\_root\_folder Note: You can provide service account to be used instead of using default credentials -2. Add the tool to your agent. Update your agent.py file +2. Add the tool to your agent. Update your agent.py file ```py from google.adk.agents.llm_agent import LlmAgent @@ -249,7 +246,7 @@ When running the agent, make sure to run adk web in project\_root\_folder [MCP Toolbox for Databases](https://github.com/googleapis/genai-toolbox) is an open source MCP server for databases. It was designed with enterprise-grade and production-quality in mind. It enables you to develop tools easier, faster, and more securely by handling the complexities such as connection pooling, authentication, and more. -Google’s Agent Development Kit (ADK) has built in support for Toolbox. For more information on [getting started](https://googleapis.github.io/genai-toolbox/getting-started) or [configuring](https://googleapis.github.io/genai-toolbox/getting-started/configure/) Toolbox, see the [documentation](https://googleapis.github.io/genai-toolbox/getting-started/introduction/). +Google’s Agent Development Kit (ADK) has built in support for Toolbox. For more information on [getting started](https://googleapis.github.io/genai-toolbox/getting-started) or [configuring](https://googleapis.github.io/genai-toolbox/getting-started/configure/) Toolbox, see the [documentation](https://googleapis.github.io/genai-toolbox/getting-started/introduction/). ![GenAI Toolbox](../assets/mcp_db_toolbox.svg) @@ -266,7 +263,7 @@ Toolbox is an open source server that you deploy and manage yourself. For more i ADK relies on the \``toolbox-langchain`\` python package to use Toolbox. Install the package before getting started: -``` +```shell pip install toolbox-langchain ``` @@ -291,8 +288,8 @@ tools = toolbox.get_toolset(tool_name='my-tool-name'), root_agent = Agent( ## Advanced Toolbox Features -Toolbox has a variety of features to make developing Gen AI tools for databases. For more information, read more about the following features:: +Toolbox has a variety of features to make developing Gen AI tools for databases. For more information, read more about the following features:: * [Authenticated Parameters](https://googleapis.github.io/genai-toolbox/resources/tools/#authenticated-parameters): bind tool inputs to values from OIDC tokens automatically, making it easy to run sensitive queries without potentially leaking data * [Authorized Invocations:](https://googleapis.github.io/genai-toolbox/resources/tools/#authorized-invocations) restrict access to use a tool based on the users Auth token -* [OpenTelemetry](https://googleapis.github.io/genai-toolbox/how-to/export_telemetry/): get metrics and tracing from Toolbox with OpenTelemetry \ No newline at end of file +* [OpenTelemetry](https://googleapis.github.io/genai-toolbox/how-to/export_telemetry/): get metrics and tracing from Toolbox with OpenTelemetry diff --git a/docs/tools/index.md b/docs/tools/index.md index b31a24ee96..fa9e28bce4 100644 --- a/docs/tools/index.md +++ b/docs/tools/index.md @@ -70,7 +70,7 @@ Furthermore, ADK supports the sequential use of tools, where the output of one t The following example showcases how an agent can use tools by **referencing their function names in its instructions**. It also demonstrates how to guide the agent to **handle different return values from tools**, such as success or error messages, and how to orchestrate the **sequential use of multiple tools** to accomplish a task. ```py ---8<-- "examples/python/snippets/tools/overview/weather-sentiment.py" +--8<-- "examples/python/snippets/tools/overview/weather_sentiment.py" ``` ## Tool Context @@ -110,7 +110,7 @@ The `tool_context.state` attribute provides direct read and write access to the * `temp:*`: Temporary, not persisted across invocations (useful for passing data within a single run call but generally less useful inside a tool context which operates between LLM calls). ```py ---8<-- "examples/python/snippets/tools/overview/user-preference.py" +--8<-- "examples/python/snippets/tools/overview/user_preference.py" ``` ### **Controlling Agent Flow** @@ -126,7 +126,7 @@ The `tool_context.actions` attribute holds an **EventActions** object. Modifying #### Example ```py ---8<-- "examples/python/snippets/tools/overview/customer-support-agent.py" +--8<-- "examples/python/snippets/tools/overview/customer_support_agent.py" ``` ##### Explanation @@ -167,7 +167,7 @@ These methods provide convenient ways for your tool to interact with persistent #### Example ```py ---8<-- "examples/python/snippets/tools/overview/doc-analysis.py" +--8<-- "examples/python/snippets/tools/overview/doc_analysis.py" ``` By leveraging the **ToolContext**, developers can create more sophisticated and context-aware custom tools that seamlessly integrate with ADK's architecture and enhance the overall capabilities of their agents. diff --git a/docs/tools/openapi-tools.md b/docs/tools/openapi-tools.md index 88950a9bfe..efcd7d470c 100644 --- a/docs/tools/openapi-tools.md +++ b/docs/tools/openapi-tools.md @@ -84,5 +84,5 @@ Follow these steps to integrate an OpenAPI spec into your agent: This example demonstrates generating tools from a simple Pet Store OpenAPI spec (using `httpbin.org` for mock responses) and interacting with them via an agent. ```python title="openapi_example.py" ---8<-- "examples/python/snippets/tools/openapi-tool.py" +--8<-- "examples/python/snippets/tools/openapi_tool.py" ``` diff --git a/docs/tools/third-party-tools.md b/docs/tools/third-party-tools.md index 7c3aa50447..8333ed82ab 100644 --- a/docs/tools/third-party-tools.md +++ b/docs/tools/third-party-tools.md @@ -67,7 +67,7 @@ ADK provides the `LangchainTool` wrapper to integrate tools from the LangChain e Here's the full code combining the steps above to create and run an agent using the LangChain Tavily search tool. ```py ---8<-- "examples/python/snippets/tools/third-party/langchain-tavily-search.py" +--8<-- "examples/python/snippets/tools/third-party/langchain_tavily_search.py" ``` ## 2. Using CrewAI tools @@ -137,5 +137,5 @@ ADK provides the `CrewaiTool` wrapper to integrate tools from the CrewAI library Here's the full code combining the steps above to create and run an agent using the CrewAI Serper API search tool. ```py ---8<-- "examples/python/snippets/tools/third-party/crewai-serper-search.py" +--8<-- "examples/python/snippets/tools/third-party/crewai_serper_search.py" ``` diff --git a/examples/python/snippets/agents/custom-agent/storyflow-agent.py b/examples/python/snippets/agents/custom-agent/storyflow_agent.py similarity index 100% rename from examples/python/snippets/agents/custom-agent/storyflow-agent.py rename to examples/python/snippets/agents/custom-agent/storyflow_agent.py diff --git a/examples/python/snippets/agents/llm-agent/capital_agent.py b/examples/python/snippets/agents/llm-agent/capital_agent.py index a90ed8090d..9bd393c171 100644 --- a/examples/python/snippets/agents/llm-agent/capital_agent.py +++ b/examples/python/snippets/agents/llm-agent/capital_agent.py @@ -144,4 +144,4 @@ async def main(): await call_agent_and_print(structured_runner, structured_info_agent_schema, SESSION_ID_SCHEMA_AGENT, '{"country": "Japan"}') if __name__ == "__main__": - await main() \ No newline at end of file + await main() diff --git a/examples/python/snippets/get-started/multi_tool_agent/agent.py b/examples/python/snippets/get-started/multi_tool_agent/agent.py index f6d61e7ea2..69def702a9 100644 --- a/examples/python/snippets/get-started/multi_tool_agent/agent.py +++ b/examples/python/snippets/get-started/multi_tool_agent/agent.py @@ -1,58 +1,57 @@ +import datetime +from zoneinfo import ZoneInfo from google.adk.agents import Agent - def get_weather(city: str) -> dict: - """Retrieves the current weather report for a specified city. + """Retrieves the current weather report for a specified city. - Args: - city (str): The name of the city for which to retrieve the weather report. + Args: + city (str): The name of the city for which to retrieve the weather report. - Returns: - dict: status and result or error msg. - """ - if city.lower() == "new york": - return { - "status": "success", - "report": ( - "The weather in New York is sunny with a temperature of 25 degrees" - " Celsius (41 degrees Fahrenheit)." - ), - } - else: - return { - "status": "error", - "error_message": f"Weather information for '{city}' is not available.", - } + Returns: + dict: status and result or error msg. + """ + if city.lower() == "new york": + return { + "status": "success", + "report": ( + "The weather in New York is sunny with a temperature of 25 degrees" + " Celsius (41 degrees Fahrenheit)." + ), + } + else: + return { + "status": "error", + "error_message": f"Weather information for '{city}' is not available.", + } def get_current_time(city: str) -> dict: - """Returns the current time in a specified city. + """Returns the current time in a specified city. - Args: - city (str): The name of the city for which to retrieve the current time. + Args: + city (str): The name of the city for which to retrieve the current time. - Returns: - dict: status and result or error msg. - """ - import datetime - from zoneinfo import ZoneInfo + Returns: + dict: status and result or error msg. + """ - if city.lower() == "new york": - tz_identifier = "America/New_York" - else: - return { - "status": "error", - "error_message": ( - f"Sorry, I don't have timezone information for {city}." - ), - } + if city.lower() == "new york": + tz_identifier = "America/New_York" + else: + return { + "status": "error", + "error_message": ( + f"Sorry, I don't have timezone information for {city}." + ), + } - tz = ZoneInfo(tz_identifier) - now = datetime.datetime.now(tz) - report = ( - f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}' - ) - return {"status": "success", "report": report} + tz = ZoneInfo(tz_identifier) + now = datetime.datetime.now(tz) + report = ( + f'The current time in {city} is {now.strftime("%Y-%m-%d %H:%M:%S %Z%z")}' + ) + return {"status": "success", "report": report} root_agent = Agent( @@ -65,4 +64,4 @@ def get_current_time(city: str) -> dict: "I can answer your questions about the time and weather in a city." ), tools=[get_weather, get_current_time], -) \ No newline at end of file +) diff --git a/examples/python/snippets/tools/built-in-tools/code-execution.py b/examples/python/snippets/tools/built-in-tools/code_execution.py similarity index 75% rename from examples/python/snippets/tools/built-in-tools/code-execution.py rename to examples/python/snippets/tools/built-in-tools/code_execution.py index ac5c2637ce..d14393d1c1 100644 --- a/examples/python/snippets/tools/built-in-tools/code-execution.py +++ b/examples/python/snippets/tools/built-in-tools/code_execution.py @@ -52,17 +52,17 @@ async def call_agent_async(query): has_specific_part = True # Also print any text parts found in any event for debugging elif part.text and not part.text.isspace(): - print(f" Text: '{part.text.strip()}'") - # Do not set has_specific_part=True here, as we want the final response logic below + print(f" Text: '{part.text.strip()}'") + # Do not set has_specific_part=True here, as we want the final response logic below # --- Check for final response AFTER specific parts --- # Only consider it final if it doesn't have the specific code parts we just handled if not has_specific_part and event.is_final_response(): - if event.content and event.content.parts and event.content.parts[0].text: - final_response_text = event.content.parts[0].text.strip() - print(f"==> Final Agent Response: {final_response_text}") - else: - print(f"==> Final Agent Response: [No text content in final event]") + if event.content and event.content.parts and event.content.parts[0].text: + final_response_text = event.content.parts[0].text.strip() + print(f"==> Final Agent Response: {final_response_text}") + else: + print("==> Final Agent Response: [No text content in final event]") except Exception as e: @@ -79,11 +79,11 @@ async def main(): try: asyncio.run(main()) except RuntimeError as e: - # Handle specific error when running asyncio.run in an already running loop (like Jupyter/Colab) - if "cannot be called from a running event loop" in str(e): - print("\nRunning in an existing event loop (like Colab/Jupyter).") - print("Please run `await main()` in a notebook cell instead.") - # If in an interactive environment like a notebook, you might need to run: - # await main() - else: - raise e # Re-raise other runtime errors \ No newline at end of file + # Handle specific error when running asyncio.run in an already running loop (like Jupyter/Colab) + if "cannot be called from a running event loop" in str(e): + print("\nRunning in an existing event loop (like Colab/Jupyter).") + print("Please run `await main()` in a notebook cell instead.") + # If in an interactive environment like a notebook, you might need to run: + # await main() + else: + raise e # Re-raise other runtime errors diff --git a/examples/python/snippets/tools/built-in-tools/google-search.py b/examples/python/snippets/tools/built-in-tools/google_search.py similarity index 100% rename from examples/python/snippets/tools/built-in-tools/google-search.py rename to examples/python/snippets/tools/built-in-tools/google_search.py diff --git a/examples/python/snippets/tools/built-in-tools/vertexai-search.py b/examples/python/snippets/tools/built-in-tools/vertexai_search.py similarity index 60% rename from examples/python/snippets/tools/built-in-tools/vertexai-search.py rename to examples/python/snippets/tools/built-in-tools/vertexai_search.py index 6e33918963..fee6ffccd2 100644 --- a/examples/python/snippets/tools/built-in-tools/vertexai-search.py +++ b/examples/python/snippets/tools/built-in-tools/vertexai_search.py @@ -9,7 +9,7 @@ # Replace with your actual Vertex AI Search Datastore ID # Format: projects//locations//collections/default_collection/dataStores/ # e.g., "projects/12345/locations/us-central1/collections/default_collection/dataStores/my-datastore-123" -YOUR_DATASTORE_ID = "YOUR_DATASTORE_ID_HERE" +YOUR_DATASTORE_ID = "YOUR_DATASTORE_ID_HERE" # Constants APP_NAME_VSEARCH = "vertex_search_app" @@ -45,31 +45,31 @@ # Agent Interaction Function async def call_vsearch_agent_async(query): - print(f"\n--- Running Vertex AI Search Agent ---") - print(f"Query: {query}") - if "YOUR_DATASTORE_ID_HERE" in YOUR_DATASTORE_ID: - print("Skipping execution: Please replace YOUR_DATASTORE_ID_HERE with your actual datastore ID.") - print("-" * 30) - return + print("\n--- Running Vertex AI Search Agent ---") + print(f"Query: {query}") + if "YOUR_DATASTORE_ID_HERE" in YOUR_DATASTORE_ID: + print("Skipping execution: Please replace YOUR_DATASTORE_ID_HERE with your actual datastore ID.") + print("-" * 30) + return - content = types.Content(role='user', parts=[types.Part(text=query)]) - final_response_text = "No response received." - try: - async for event in runner_vsearch.run_async( - user_id=USER_ID_VSEARCH, session_id=SESSION_ID_VSEARCH, new_message=content - ): - # Like Google Search, results are often embedded in the model's response. - if event.is_final_response() and event.content and event.content.parts: - final_response_text = event.content.parts[0].text.strip() - print(f"Agent Response: {final_response_text}") - # You can inspect event.grounding_metadata for source citations - if event.grounding_metadata: - print(f" (Grounding metadata found with {len(event.grounding_metadata.grounding_attributions)} attributions)") + content = types.Content(role='user', parts=[types.Part(text=query)]) + final_response_text = "No response received." + try: + async for event in runner_vsearch.run_async( + user_id=USER_ID_VSEARCH, session_id=SESSION_ID_VSEARCH, new_message=content + ): + # Like Google Search, results are often embedded in the model's response. + if event.is_final_response() and event.content and event.content.parts: + final_response_text = event.content.parts[0].text.strip() + print(f"Agent Response: {final_response_text}") + # You can inspect event.grounding_metadata for source citations + if event.grounding_metadata: + print(f" (Grounding metadata found with {len(event.grounding_metadata.grounding_attributions)} attributions)") - except Exception as e: - print(f"An error occurred: {e}") - print("Ensure your datastore ID is correct and the service account has permissions.") - print("-" * 30) + except Exception as e: + print(f"An error occurred: {e}") + print("Ensure your datastore ID is correct and the service account has permissions.") + print("-" * 30) # --- Run Example --- async def run_vsearch_example(): @@ -84,7 +84,7 @@ async def run_vsearch_example(): try: asyncio.run(run_vsearch_example()) except RuntimeError as e: - if "cannot be called from a running event loop" in str(e): - print("Skipping execution in running event loop (like Colab/Jupyter). Run locally.") - else: - raise e + if "cannot be called from a running event loop" in str(e): + print("Skipping execution in running event loop (like Colab/Jupyter). Run locally.") + else: + raise e diff --git a/examples/python/snippets/tools/function-tools/file-processor.py b/examples/python/snippets/tools/function-tools/file_processor.py similarity index 85% rename from examples/python/snippets/tools/function-tools/file-processor.py rename to examples/python/snippets/tools/function-tools/file_processor.py index 36a78a587d..8827219b1f 100644 --- a/examples/python/snippets/tools/function-tools/file-processor.py +++ b/examples/python/snippets/tools/function-tools/file_processor.py @@ -59,12 +59,12 @@ def process_large_file(file_path: str) -> dict: # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -call_agent("Replace with a path to your file...") \ No newline at end of file +call_agent("Replace with a path to your file...") diff --git a/examples/python/snippets/tools/function-tools/func-tool.py b/examples/python/snippets/tools/function-tools/func_tool.py similarity index 83% rename from examples/python/snippets/tools/function-tools/func-tool.py rename to examples/python/snippets/tools/function-tools/func_tool.py index 15dd8fa310..abf5edae13 100644 --- a/examples/python/snippets/tools/function-tools/func-tool.py +++ b/examples/python/snippets/tools/function-tools/func_tool.py @@ -50,12 +50,12 @@ def get_stock_price(symbol: str): # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -call_agent("stock price of GOOG") \ No newline at end of file +call_agent("stock price of GOOG") diff --git a/examples/python/snippets/tools/function-tools/summarizer.py b/examples/python/snippets/tools/function-tools/summarizer.py index 278de5a917..81d82c5b6f 100644 --- a/examples/python/snippets/tools/function-tools/summarizer.py +++ b/examples/python/snippets/tools/function-tools/summarizer.py @@ -30,16 +30,16 @@ # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -long_text="""Quantum computing represents a fundamentally different approach to computation, +long_text = """Quantum computing represents a fundamentally different approach to computation, leveraging the bizarre principles of quantum mechanics to process information. Unlike classical computers that rely on bits representing either 0 or 1, quantum computers use qubits which can exist in a state of superposition - effectively being 0, 1, or a combination of both simultaneously. Furthermore, qubits can become entangled, @@ -49,4 +49,4 @@ def call_agent(query): faster than even the most powerful classical supercomputers could ever achieve, although the technology is still largely in its developmental stages.""" -call_agent(long_text) \ No newline at end of file +call_agent(long_text) diff --git a/examples/python/snippets/tools/openapi-tool.py b/examples/python/snippets/tools/openapi_tool.py similarity index 75% rename from examples/python/snippets/tools/openapi-tool.py rename to examples/python/snippets/tools/openapi_tool.py index b1cafd53c9..c0b2347198 100644 --- a/examples/python/snippets/tools/openapi-tool.py +++ b/examples/python/snippets/tools/openapi_tool.py @@ -1,5 +1,4 @@ import asyncio -import json import uuid # For unique session IDs from google.adk.agents import LlmAgent from google.adk.runners import Runner @@ -167,39 +166,39 @@ # --- Agent Interaction Function --- async def call_openapi_agent_async(query): - print(f"\n--- Running OpenAPI Pet Store Agent ---") - print(f"Query: {query}") - if not generated_tools_list: - print("Skipping execution: No tools were generated.") - print("-" * 30) - return + print("\n--- Running OpenAPI Pet Store Agent ---") + print(f"Query: {query}") + if not generated_tools_list: + print("Skipping execution: No tools were generated.") + print("-" * 30) + return - content = types.Content(role='user', parts=[types.Part(text=query)]) - final_response_text = "Agent did not provide a final text response." - try: - async for event in runner_openapi.run_async( - user_id=USER_ID_OPENAPI, session_id=SESSION_ID_OPENAPI, new_message=content - ): - # Optional: Detailed event logging for debugging - # print(f" DEBUG Event: Author={event.author}, Type={'Final' if event.is_final_response() else 'Intermediate'}, Content={str(event.content)[:100]}...") - if event.get_function_calls(): - call = event.get_function_calls()[0] - print(f" Agent Action: Called function '{call.name}' with args {call.args}") - elif event.get_function_responses(): - response = event.get_function_responses()[0] - print(f" Agent Action: Received response for '{response.name}'") - # print(f" Tool Response Snippet: {str(response.response)[:200]}...") # Uncomment for response details - elif event.is_final_response() and event.content and event.content.parts: - # Capture the last final text response - final_response_text = event.content.parts[0].text.strip() + content = types.Content(role='user', parts=[types.Part(text=query)]) + final_response_text = "Agent did not provide a final text response." + try: + async for event in runner_openapi.run_async( + user_id=USER_ID_OPENAPI, session_id=SESSION_ID_OPENAPI, new_message=content + ): + # Optional: Detailed event logging for debugging + # print(f" DEBUG Event: Author={event.author}, Type={'Final' if event.is_final_response() else 'Intermediate'}, Content={str(event.content)[:100]}...") + if event.get_function_calls(): + call = event.get_function_calls()[0] + print(f" Agent Action: Called function '{call.name}' with args {call.args}") + elif event.get_function_responses(): + response = event.get_function_responses()[0] + print(f" Agent Action: Received response for '{response.name}'") + # print(f" Tool Response Snippet: {str(response.response)[:200]}...") # Uncomment for response details + elif event.is_final_response() and event.content and event.content.parts: + # Capture the last final text response + final_response_text = event.content.parts[0].text.strip() - print(f"Agent Final Response: {final_response_text}") + print(f"Agent Final Response: {final_response_text}") - except Exception as e: - print(f"An error occurred during agent run: {e}") - import traceback - traceback.print_exc() # Print full traceback for errors - print("-" * 30) + except Exception as e: + print(f"An error occurred during agent run: {e}") + import traceback + traceback.print_exc() # Print full traceback for errors + print("-" * 30) # --- Run Examples --- async def run_openapi_example(): @@ -217,10 +216,11 @@ async def run_openapi_example(): try: asyncio.run(run_openapi_example()) except RuntimeError as e: - if "cannot be called from a running event loop" in str(e): - print("Info: Cannot run asyncio.run from a running event loop (e.g., Jupyter/Colab).") - # If in Jupyter/Colab, you might need to run like this: - # await run_openapi_example() - else: - raise e - print("OpenAPI example finished.") \ No newline at end of file + if "cannot be called from a running event loop" in str(e): + print("Info: Cannot run asyncio.run from a running event loop (e.g., Jupyter/Colab).") + # If in Jupyter/Colab, you might need to run like this: + # await run_openapi_example() + else: + raise e + print("OpenAPI example finished.") + \ No newline at end of file diff --git a/examples/python/snippets/tools/overview/customer-support-agent.py b/examples/python/snippets/tools/overview/customer_support_agent.py similarity index 82% rename from examples/python/snippets/tools/overview/customer-support-agent.py rename to examples/python/snippets/tools/overview/customer_support_agent.py index 451c24e457..a4670c02b0 100644 --- a/examples/python/snippets/tools/overview/customer-support-agent.py +++ b/examples/python/snippets/tools/overview/customer_support_agent.py @@ -44,12 +44,12 @@ def check_and_transfer(query: str, tool_context: ToolContext) -> str: # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -call_agent("this is urgent, i cant login") \ No newline at end of file +call_agent("this is urgent, i cant login") diff --git a/examples/python/snippets/tools/overview/doc-analysis.py b/examples/python/snippets/tools/overview/doc_analysis.py similarity index 95% rename from examples/python/snippets/tools/overview/doc-analysis.py rename to examples/python/snippets/tools/overview/doc_analysis.py index 5618bbfaf2..7fed29b4d6 100644 --- a/examples/python/snippets/tools/overview/doc-analysis.py +++ b/examples/python/snippets/tools/overview/doc_analysis.py @@ -25,7 +25,7 @@ def process_document(document_name: str, analysis_query: str, tool_context: Tool print("Tool: Performed analysis.") # 4. Save the analysis result as a new artifact - analysis_part = types.Part.from_text(analysis_result) + analysis_part = types.Part.from_text(text=analysis_result) new_artifact_name = f"analysis_{document_name}" version = tool_context.save_artifact(new_artifact_name, analysis_part) print(f"Tool: Saved analysis result as '{new_artifact_name}' version {version}.") @@ -37,4 +37,4 @@ def process_document(document_name: str, analysis_query: str, tool_context: Tool # In an Agent: # Assume artifact 'report.txt' was previously saved. # Assume memory service is configured and has relevant past data. -# my_agent = Agent(..., tools=[doc_analysis_tool], artifact_service=..., memory_service=...) \ No newline at end of file +# my_agent = Agent(..., tools=[doc_analysis_tool], artifact_service=..., memory_service=...) diff --git a/examples/python/snippets/tools/overview/user-preference.py b/examples/python/snippets/tools/overview/user_preference.py similarity index 94% rename from examples/python/snippets/tools/overview/user-preference.py rename to examples/python/snippets/tools/overview/user_preference.py index 44fb91d26c..3c4032fa9b 100644 --- a/examples/python/snippets/tools/overview/user-preference.py +++ b/examples/python/snippets/tools/overview/user_preference.py @@ -18,4 +18,4 @@ def update_user_preference(preference: str, value: str, tool_context: ToolContex # When the LLM calls update_user_preference(preference='theme', value='dark', ...): # The tool_context.state will be updated, and the change will be part of the -# resulting tool response event's actions.state_delta. \ No newline at end of file +# resulting tool response event's actions.state_delta. diff --git a/examples/python/snippets/tools/overview/weather-sentiment.py b/examples/python/snippets/tools/overview/weather_sentiment.py similarity index 89% rename from examples/python/snippets/tools/overview/weather-sentiment.py rename to examples/python/snippets/tools/overview/weather_sentiment.py index 4ba4f4fdfd..db84109336 100644 --- a/examples/python/snippets/tools/overview/weather-sentiment.py +++ b/examples/python/snippets/tools/overview/weather_sentiment.py @@ -64,12 +64,12 @@ def analyze_sentiment(text: str) -> dict: # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -call_agent("weather in london?") \ No newline at end of file +call_agent("weather in london?") diff --git a/examples/python/snippets/tools/third-party/crewai-serper-search.py b/examples/python/snippets/tools/third-party/crewai_serper_search.py similarity index 74% rename from examples/python/snippets/tools/third-party/crewai-serper-search.py rename to examples/python/snippets/tools/third-party/crewai_serper_search.py index 636c994d8b..98114268dc 100644 --- a/examples/python/snippets/tools/third-party/crewai-serper-search.py +++ b/examples/python/snippets/tools/third-party/crewai_serper_search.py @@ -2,8 +2,9 @@ from google.adk import Agent, Runner from google.adk.sessions import InMemorySessionService from google.adk.tools.crewai_tool import CrewaiTool -from crewai_tools import SerperDevTool from google.genai import types +from crewai_tools import SerperDevTool + # Constants APP_NAME = "news_app" @@ -12,7 +13,7 @@ # Ensure SERPER_API_KEY is set in your environment if not os.getenv("SERPER_API_KEY"): - print("Warning: SERPER_API_KEY environment variable not set.") + print("Warning: SERPER_API_KEY environment variable not set.") serper_tool_instance = SerperDevTool( n_results=10, @@ -43,12 +44,12 @@ # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -call_agent("what's the latest news on AI Agents?") \ No newline at end of file +call_agent("what's the latest news on AI Agents?") diff --git a/examples/python/snippets/tools/third-party/langchain-tavily-search.py b/examples/python/snippets/tools/third-party/langchain_tavily_search.py similarity index 74% rename from examples/python/snippets/tools/third-party/langchain-tavily-search.py rename to examples/python/snippets/tools/third-party/langchain_tavily_search.py index 67e8add8b4..81c20ebcf7 100644 --- a/examples/python/snippets/tools/third-party/langchain-tavily-search.py +++ b/examples/python/snippets/tools/third-party/langchain_tavily_search.py @@ -2,12 +2,12 @@ from google.adk import Agent, Runner from google.adk.sessions import InMemorySessionService from google.adk.tools.langchain_tool import LangchainTool -from langchain_community.tools import TavilySearchResults from google.genai import types +from langchain_community.tools import TavilySearchResults # Ensure TAVILY_API_KEY is set in your environment if not os.getenv("TAVILY_API_KEY"): - print("Warning: TAVILY_API_KEY environment variable not set.") + print("Warning: TAVILY_API_KEY environment variable not set.") APP_NAME = "news_app" USER_ID = "1234" @@ -41,12 +41,12 @@ # Agent Interaction def call_agent(query): - content = types.Content(role='user', parts=[types.Part(text=query)]) - events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) + content = types.Content(role='user', parts=[types.Part(text=query)]) + events = runner.run(user_id=USER_ID, session_id=SESSION_ID, new_message=content) - for event in events: - if event.is_final_response(): - final_response = event.content.parts[0].text - print("Agent Response: ", final_response) + for event in events: + if event.is_final_response(): + final_response = event.content.parts[0].text + print("Agent Response: ", final_response) -call_agent("stock price of GOOG") \ No newline at end of file +call_agent("stock price of GOOG") diff --git a/mkdocs.yml b/mkdocs.yml index 6194b39e18..5503031257 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -139,11 +139,9 @@ nav: - Local testing: deploy/local-testing.md - Agent Engine: deploy/agent-engine.md - Cloud Run: deploy/cloud-run.md - - Docker: deploy/docker.md - Guides: - Evaluate agents: guides/evaluate-agents.md - Responsible Agents: guides/responsible-agents.md - - Troubleshooting: guides/troubleshooting.md - API Reference: - API Reference: api-reference/index.md - Resources: