Compare commits

...

44 Commits

Author SHA1 Message Date
Google Team Member c8059428a2 chore: add contributing spanner sample
PiperOrigin-RevId: 795154839
2025-08-14 12:41:28 -07:00
Xuan Yang e63e2a7106 fix: add the missing required tool parameters for Anthropic models
Fixes #1692

PiperOrigin-RevId: 795125801
2025-08-14 11:31:00 -07:00
Wei Sun (Jack) 9ba8eec220 feat(tracing): Adds more OpenTelemetry convention attributes: gen_ai.request.max_tokens, gen_ai.request.top_p and gen_ai.response.finish_reasons
Fixes #1234

PiperOrigin-RevId: 795082815
2025-08-14 09:52:50 -07:00
Kacper Jawoszek 9cfe43334a fix: Uncomment OTel tracing in base_llm_flow.py
It was mistakenly commented out in the previous change.

PiperOrigin-RevId: 795048873
2025-08-14 08:20:07 -07:00
Xiang (Sean) Zhou 52284b1bae fix: A2A RPC URL got overriden by host and port param of adk api server
PiperOrigin-RevId: 794708721
2025-08-13 13:20:26 -07:00
George Weale a74d3344bc chore: Added upper version bounds to dependencies in "pyproject.toml"
This change keeps dependencies to their major versions, but for the pre 1.0.0 releases pinned to minor releases as they could have breaking changes.

PyYAML: Version 7.0 is in development and could have breaking changes

absolufy-imports: The package is archived and no longer maintained.

anyio: Follows SemVer, so version 5.0 could have breaking changes.

authlib: Follows a SemVer-like pattern, so version 2.0 could have breaking changes.

click: A mature library, version 9.0 is the expected boundary for breaking changes.

fastapi: As a pre-1.0 library, the next minor release could have breaking changes.

google-api-python-client: Although in maintenance, version 3.0 could still have breaking changes.

google-cloud-aiplatform: Follows SemVer, so breaking changes are expected in version 2.0.

google-cloud-secret-manager: A stable Google library, version 3.0 could lead to breaking changes.

google-cloud-speech: A stable Google library, version 3.0 could lead to breaking changes.

google-cloud-storage: A stable Google library.

google-genai: As an official Google SDK, version 2.0 is the expected boundary for breaking changes.

graphviz: As a pre-1.0 library, the next minor release could have breaking changes.

mcp: As an SDK, version 2.0 is the boundary for potential breaking changes.

opentelemetry-api: Follows SemVer; version 2.0 could have breaking changes.

opentelemetry-exporter-gcp-trace: It's tied to the v1 OpenTelemetry API, so version 2.0 would likely be a breaking change.

opentelemetry-sdk: It's coupled to the v1 API, so version 2.0 would likely be a breaking change.

pydantic: This stops upgrades to the incompatible version 3.0 after its major 2.0 rewrite.

python-dateutil: Follows to SemVer, making version 3.0 the boundary for potential breaking changes.

python-dotenv: Locks to stable version 1.0 major release.

requests: As a more mature library, version 3.0 is boundary for breaking changes.

sqlalchemy: This locks the dependency to the stable version 2.0 API after its major rewrite.

starlette: As a pre-1.0 library, the next minor release could have breaking changes.

tenacity: This is a mature library, version 9.0 is boundary for breaking changes.

typing-extensions: Major versions are tied to large typing changes in Python itself.

tzlocal: The library has a history of introducing breaking API changes between major versions.

uvicorn: As a pre-1.0 library, the next minor release could have breaking changes.

watchdog: As a stable library, version 7.0 could have breaking changes.

websockets: Follows SemVer, so version 16.0 is the boundary for breaking changes.
PiperOrigin-RevId: 794677571
2025-08-13 12:03:47 -07:00
George Weale ddf2e2194b chore: Update python-version in .github/workflows/python-unit-tests.yml to ["3.9", "3.10", "3.11", "3.12", "3.13"]
Verified with uv on Python 3.12 and 3.13 using the same ignores as CI.
3.12:
uv python install 3.12 && uv venv --python 3.12 .venv && source .venv/bin/activate
uv sync --extra test --extra eval --extra a2a
python -m pytest tests/unittests --ignore=tests/unittests/artifacts/test_artifact_service.py --ignore=tests/unittests/tools/google_api_tool/test_googleapi_to_openapi_converter.py
3.13: repeated the above with 3.13 (separate env)
Result: All unit tests passed

PiperOrigin-RevId: 794669437
2025-08-13 11:43:24 -07:00
Kacper Jawoszek a30c63c593 fix: aclose all async generators to fix OTel tracing context
See https://github.com/google/adk-python/issues/1670#issuecomment-3115891100

PiperOrigin-RevId: 794659547
2025-08-13 11:18:26 -07:00
Wei Sun (Jack) c5af44cfc0 docs(config): Fixes tool_functions, which is a config-based sample for using tools
PiperOrigin-RevId: 794652291
2025-08-13 11:01:52 -07:00
Google Team Member c52f956433 chore: Update comment to reference "Streamable HTTP Client"
Corrects a typo in the `StreamableHTTPConnectionParams` docstring, changing "SSE" to "Streamable HTTP" to accurately reflect the referenced client.

PiperOrigin-RevId: 794424727
2025-08-12 23:45:23 -07:00
Xuan Yang 585141e0b7 fix: Use PreciseTimestamp for create and update time in database session service to improve precision
PiperOrigin-RevId: 794422113
2025-08-12 23:36:53 -07:00
Google Team Member 114db93d70 ADK changes
PiperOrigin-RevId: 794403729
2025-08-12 22:29:23 -07:00
Hangfei Lin e2518dc371 fix: Ignore AsyncGenerator return types in function declarations
For Vertex model backend, we send response back. This doesn't work for streaming tools that the return type is AsyncGenerator. So the fix here is to ignore the return type when it's AsyncGenerator.

We can't distinguish streaming vs non-streaming tool with AsyncGenerator though as LiveRequestQueue is optional in streaming tool.

Adds an `ignore_response` option to `build_function_declaration` to skip including the return type in the function declaration. This is enabled for tools that return `AsyncGenerator`, as the model does not yet support understanding these return types, while streaming tools can still handle them. Also, removes redundant return statements in `_get_mandatory_params`.

PiperOrigin-RevId: 794392846
2025-08-12 21:45:52 -07:00
Xiang (Sean) Zhou 8c65967cdc fix: Make all subclass of BaseToolset to call parent constructor
So that all member field are created / initialized in the base toolset.

PiperOrigin-RevId: 794388671
2025-08-12 21:32:24 -07:00
Xiang (Sean) Zhou ebd726f1f5 feat: Support adding prefix to tool names returned by toolset
This is to address the name conflict issue of tools returned by different toolset. Mainly it's to give each toolset a namespace.

We have a flag `add_tool_name_prefix` to decide whether to apply this behavior
We have a `tool_name_prefix` to let client specify a custom prefix, if not set , toolset name will be used as prefix.

PiperOrigin-RevId: 794306796
2025-08-12 16:17:53 -07:00
Goldy 54680edf3c fix: path parameter extraction for complex Google API endpoints
Merge https://github.com/google/adk-python/pull/1815

fix: path parameter extraction for complex Google API endpoints

- Fix GoogleApiToOpenApiConverter to handle path parameters in complex endpoints like /v1/documents/{documentId}:batchUpdate
- Use Google Discovery Document 'location' field
- Add comprehensive test suite for Google Docs batchUpdate functionality
- Verify parameter location handling for complex endpoint patterns
- Test schema validation for BatchUpdateDocumentRequest/Response

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/1815 from goldylocks87:fix-issue-1814-path-parameter-extraction af5508ec6975b1ccbc34931a0041e422ee259c16
PiperOrigin-RevId: 794301898
2025-08-12 16:02:45 -07:00
Shangjie Chen bb3735c9ca chore: Remove logging that contains full event data from DatabaseSessionService
Resolves https://github.com/google/adk-python/issues/2153

PiperOrigin-RevId: 794288546
2025-08-12 15:19:52 -07:00
Xuan Yang a09a5e67aa chore: add the missing env variables in discussion_answering.yml
PiperOrigin-RevId: 794285985
2025-08-12 15:12:03 -07:00
Google Team Member 7e0880869b feat: Expose print_detailed_results param to AgentEvaluator.evaluate
Currently `print_detailed_results` is available only in `AgentEvaluator.evaluate_eval_set` while the adk-samples data science agent uses `AgentEvaluator.evaluate` https://github.com/google/adk-samples/blob/c230c3ddc16a3f9fc7edff409b567bdd65ebd9da/python/agents/data-science/eval/test_eval.py#L32.

PiperOrigin-RevId: 794262781
2025-08-12 14:07:17 -07:00
Google Team Member 1fc8d20ae8 feat: add Spanner first-party toolset (breaking change to BigQueryTool, consolidating into generic GoogleTool)
Spanner toolset support basic operations to interact with Spanner table metadata and query results.

Consolidate BigQueryTool into generic GoogleTool, so that BigQueryToolset and SpannerToolset can share.

PiperOrigin-RevId: 794259782
2025-08-12 13:59:37 -07:00
Google Team Member 10e3dfab1a feat: remove load_dotenv() in feature_decorator.py
PiperOrigin-RevId: 794249376
2025-08-12 13:35:49 -07:00
Xuan Yang 5fba1963c3 chore: add Gemini API docs as a new datastore for the ADK Answering Agent
PiperOrigin-RevId: 794247007
2025-08-12 13:30:00 -07:00
Xuan Yang 7d2cb654f0 chore: add the missing license header for some sample agents' files
PiperOrigin-RevId: 794165986
2025-08-12 10:24:36 -07:00
Xiang (Sean) Zhou 88f759a941 fix: docstring concatenation in 3.13
The issue was caused by a breaking change in Python 3.13's inspect.cleandoc() function that made it more conservative about whitespace handling:

Root Cause:

- Python 3.12-: inspect.cleandoc() used line.lstrip() - strips all whitespace (spaces, tabs, etc.)
- Python 3.13+: inspect.cleandoc() uses line.lstrip(' ') - strips only space characters

PiperOrigin-RevId: 793921360
2025-08-11 21:26:25 -07:00
Wei Sun (Jack) e295feb4c6 docs: Add workflow_triage sample for multi-agent request orchestration
Demonstrates intelligent triage system with root planning agent and parallel
execution agents.

Use session state to store the execution plan and coordinate with other specialized agents.

Check out README.md for more details.

PiperOrigin-RevId: 793884758
2025-08-11 19:05:53 -07:00
Liang Wu d87feb8ddb docs(config): add examples for config agents
PiperOrigin-RevId: 793871778
2025-08-11 18:09:55 -07:00
Shangjie Chen 88114d7c73 chore: Add docstring to clarify the behavior of preload memory tool
PiperOrigin-RevId: 793840979
2025-08-11 16:33:49 -07:00
Xiang (Sean) Zhou d0b3b5d857 chore: add experimental messages for a2a related API
PiperOrigin-RevId: 793812544
2025-08-11 15:09:08 -07:00
Wei Sun (Jack) d674178a05 chore: Fixes generate_image sample
PiperOrigin-RevId: 793725452
2025-08-11 11:15:06 -07:00
Wei Sun (Jack) dc26aad663 docs: Adds pypi badge to README.md
PiperOrigin-RevId: 793713600
2025-08-11 10:47:57 -07:00
Shangjie Chen 7f12387eb1 chore: Make all FastAPI endpoints async
PiperOrigin-RevId: 792886431
2025-08-08 21:58:34 -07:00
Eugen-Bleck 8f937b5175 docs: update StreamableHTTPConnectionParams docstring to remove SSE references (#1456)
Co-authored-by: Terrence Ryan <tpryan@google.com>
Fixes: google/adk-docs#475
2025-08-08 20:42:43 -07:00
Shangjie Chen c323de5c69 chore: Group FastAPI endpoints with tags
PiperOrigin-RevId: 792816574
2025-08-08 17:20:46 -07:00
Liang Wu b4f1ebea31 chore(config): replace @working_in_progress with @experimental for config agent feature
PiperOrigin-RevId: 792803076
2025-08-08 16:32:50 -07:00
Google Team Member 944e39ec2a chore: allow implementations to skip defining a close method on Toolset
PiperOrigin-RevId: 792760747
2025-08-08 14:22:17 -07:00
Xiang (Sean) Zhou 9478a31bf2 fix: Lazy load retrieval tools and prompt users to install extensions if import failed
PiperOrigin-RevId: 792701550
2025-08-08 11:37:47 -07:00
Xiang (Sean) Zhou f2005a2026 chore: Add sample agent to test support of output_schema and tools at the same time for gemini model
PiperOrigin-RevId: 792694074
2025-08-08 11:16:31 -07:00
Xiang (Sean) Zhou af635674b5 feat: Support both output_schema and tools at the same time in LlmAgent
1. Allow developers to specify output schema and tools together.
2. If both are specified, do the following:
  2.1 Do not set output schema on the model config
  2.2 Add a special tool called set_model_response(result)
  2.3 `result` has the same schema as the requested output_schema
  2.4 Instruct the model to use set_model_response() to output its final result, rather than output text directly.
  2.5 When the set_model_response() is called, ADK will extract its content and put it in a text part, so the client would treat it as the model response.

PiperOrigin-RevId: 792686011
2025-08-08 10:55:22 -07:00
Xiang (Sean) Zhou b4ce3b12d1 fix: incorrect logic in LlmRequest.append_tools and make BaseTool to call it
PiperOrigin-RevId: 792642882
2025-08-08 08:53:57 -07:00
Google Team Member 98a5730115 fix: incorrect logic in LlmRequest.append_tools and make BaseTool to call it
PiperOrigin-RevId: 792518526
2025-08-08 01:29:47 -07:00
Xiang (Sean) Zhou 4b2a8e3186 fix: incorrect logic in LlmRequest.append_tools and make BaseTool to call it
PiperOrigin-RevId: 792474565
2025-08-07 22:53:54 -07:00
Sam Hatfield e4d54b66b3 fix: Creates an InMemoryMemoryService within the EvaluationGenerator
Merge https://github.com/google/adk-python/pull/2263

Addresses #2084

COPYBARA_INTEGRATE_REVIEW=https://github.com/google/adk-python/pull/2263 from sjhatfield:main 8d6fca48437f151c34b2766ea4813a777bafcabd
PiperOrigin-RevId: 792336301
2025-08-07 15:40:42 -07:00
Xuan Yang 5900273455 chore: add Github workflow config for uploading ADK docs to knowledge store
PiperOrigin-RevId: 792272706
2025-08-07 12:52:28 -07:00
Xuan Yang b5a8bad170 chore: update ADK Answering agent to reference doc site instead of adk-docs repo
PiperOrigin-RevId: 792259386
2025-08-07 12:17:09 -07:00
162 changed files with 7658 additions and 1315 deletions
+3 -1
View File
@@ -27,14 +27,16 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install google-adk
pip install google-adk google-cloud-discoveryengine
- name: Run Answering Script
env:
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
ADK_GCP_SA_KEY: ${{ secrets.ADK_GCP_SA_KEY }}
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
VERTEXAI_DATASTORE_ID: ${{ secrets.VERTEXAI_DATASTORE_ID }}
GEMINI_API_DATASTORE_ID: ${{ secrets.GEMINI_API_DATASTORE_ID }}
GOOGLE_GENAI_USE_VERTEXAI: 1
OWNER: 'google'
REPO: 'adk-python'
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11"]
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]
steps:
- name: Checkout code
@@ -0,0 +1,51 @@
name: Upload ADK Docs to Vertex AI Search
on:
# Runs once per day at 16:00 UTC
schedule:
- cron: '00 16 * * *'
# Manual trigger for testing and fixing
workflow_dispatch:
jobs:
upload-adk-docs-to-vertex-ai-search:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Clone adk-docs repository
run: git clone https://github.com/google/adk-docs.git /tmp/adk-docs
- name: Clone adk-python repository
run: git clone https://github.com/google/adk-python.git /tmp/adk-python
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Authenticate to Google Cloud
id: auth
uses: 'google-github-actions/auth@v2'
with:
credentials_json: '${{ secrets.ADK_GCP_SA_KEY }}'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install google-adk markdown google-cloud-storage google-cloud-discoveryengine
- name: Run Answering Script
env:
GITHUB_TOKEN: ${{ secrets.ADK_TRIAGE_AGENT }}
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
VERTEXAI_DATASTORE_ID: ${{ secrets.VERTEXAI_DATASTORE_ID }}
GOOGLE_GENAI_USE_VERTEXAI: 1
GCS_BUCKET_NAME: ${{ secrets.GCS_BUCKET_NAME }}
ADK_DOCS_ROOT_PATH: /tmp/adk-docs
ADK_PYTHON_ROOT_PATH: /tmp/adk-python
PYTHONPATH: contributing/samples
run: python -m adk_answering_agent.upload_docs_to_vertex_ai_search
+2 -1
View File
@@ -1,6 +1,7 @@
# Agent Development Kit (ADK)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)
[![PyPI](https://img.shields.io/pypi/v/google-adk)](https://pypi.org/project/google-adk/)
[![Python Unit Tests](https://github.com/google/adk-python/actions/workflows/python-unit-tests.yml/badge.svg)](https://github.com/google/adk-python/actions/workflows/python-unit-tests.yml)
[![r/agentdevelopmentkit](https://img.shields.io/badge/Reddit-r%2Fagentdevelopmentkit-FF4500?style=flat&logo=reddit&logoColor=white)](https://www.reddit.com/r/agentdevelopmentkit/)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/google/adk-python)
@@ -14,7 +15,7 @@
</h3>
<h3 align="center">
Important Links:
<a href="https://google.github.io/adk-docs/">Docs</a>,
<a href="https://google.github.io/adk-docs/">Docs</a>,
<a href="https://github.com/google/adk-samples">Samples</a>,
<a href="https://github.com/google/adk-java">Java ADK</a> &
<a href="https://github.com/google/adk-web">ADK Web</a>.
+32
View File
@@ -157,12 +157,43 @@ You can extend this sample by:
- Adding audit logging for authentication events
- Implementing multi-tenant OAuth token management
## Deployment to Other Environments
When deploying the remote BigQuery A2A agent to different environments (e.g., Cloud Run, different hosts/ports), you **must** update the `url` field in the agent card JSON file:
### Local Development
```json
{
"url": "http://localhost:8001/a2a/bigquery_agent",
...
}
```
### Cloud Run Example
```json
{
"url": "https://your-bigquery-service-abc123-uc.a.run.app/a2a/bigquery_agent",
...
}
```
### Custom Host/Port Example
```json
{
"url": "https://your-domain.com:9000/a2a/bigquery_agent",
...
}
```
**Important:** The `url` field in `remote_a2a/bigquery_agent/agent.json` must point to the actual RPC endpoint where your remote BigQuery A2A agent is deployed and accessible.
## Troubleshooting
**Connection Issues:**
- Ensure the local ADK web server is running on port 8000
- Ensure the remote A2A server is running on port 8001
- Check that no firewall is blocking localhost connections
- **Verify the `url` field in `remote_a2a/bigquery_agent/agent.json` matches the actual deployed location of your remote A2A server**
- Verify the agent card URL passed to RemoteA2AAgent constructor matches the running A2A server
@@ -182,3 +213,4 @@ You can extend this sample by:
- Check the logs for both the local ADK web server and remote A2A server
- Verify OAuth tokens are properly passed between agents
- Ensure agent instructions are clear about authentication requirements
- **Double-check that the RPC URL in the agent.json file is correct and accessible**
@@ -24,6 +24,6 @@
"tags": ["authentication", "oauth", "security"]
}
],
"url": "http://localhost:8000/a2a/bigquery_agent",
"url": "http://localhost:8001/a2a/bigquery_agent",
"version": "1.0.0"
}
+32
View File
@@ -107,15 +107,47 @@ You can extend this sample by:
- Adding persistent state management
- Integrating with external APIs or databases
## Deployment to Other Environments
When deploying the remote A2A agent to different environments (e.g., Cloud Run, different hosts/ports), you **must** update the `url` field in the agent card JSON file:
### Local Development
```json
{
"url": "http://localhost:8001/a2a/check_prime_agent",
...
}
```
### Cloud Run Example
```json
{
"url": "https://your-service-abc123-uc.a.run.app/a2a/check_prime_agent",
...
}
```
### Custom Host/Port Example
```json
{
"url": "https://your-domain.com:9000/a2a/check_prime_agent",
...
}
```
**Important:** The `url` field in `remote_a2a/check_prime_agent/agent.json` must point to the actual RPC endpoint where your remote A2A agent is deployed and accessible.
## Troubleshooting
**Connection Issues:**
- Ensure the local ADK web server is running on port 8000
- Ensure the remote A2A server is running on port 8001
- Check that no firewall is blocking localhost connections
- **Verify the `url` field in `remote_a2a/check_prime_agent/agent.json` matches the actual deployed location of your remote A2A server**
- Verify the agent card URL passed to RemoteA2AAgent constructor matches the running A2A server
**Agent Not Responding:**
- Check the logs for both the local ADK web server on port 8000 and remote A2A server on port 8001
- Verify the agent instructions are clear and unambiguous
- **Double-check that the RPC URL in the agent.json file is correct and accessible**
@@ -116,18 +116,50 @@ You can extend this sample by:
- Integrating with external approval systems or databases
- Implementing approval timeouts and escalation procedures
## Deployment to Other Environments
When deploying the remote approval A2A agent to different environments (e.g., Cloud Run, different hosts/ports), you **must** update the `url` field in the agent card JSON file:
### Local Development
```json
{
"url": "http://localhost:8001/a2a/human_in_loop",
...
}
```
### Cloud Run Example
```json
{
"url": "https://your-approval-service-abc123-uc.a.run.app/a2a/human_in_loop",
...
}
```
### Custom Host/Port Example
```json
{
"url": "https://your-domain.com:9000/a2a/human_in_loop",
...
}
```
**Important:** The `url` field in `remote_a2a/human_in_loop/agent.json` must point to the actual RPC endpoint where your remote approval A2A agent is deployed and accessible.
## Troubleshooting
**Connection Issues:**
- Ensure the local ADK web server is running on port 8000
- Ensure the remote A2A server is running on port 8001
- Check that no firewall is blocking localhost connections
- **Verify the `url` field in `remote_a2a/human_in_loop/agent.json` matches the actual deployed location of your remote A2A server**
- Verify the agent card URL passed to RemoteA2AAgent constructor matches the running A2A server
**Agent Not Responding:**
- Check the logs for both the local ADK web server on port 8000 and remote A2A server on port 8001
- Verify the agent instructions are clear and unambiguous
- Ensure long-running tool responses are properly formatted with matching IDs
- **Double-check that the RPC URL in the agent.json file is correct and accessible**
**Approval Workflow Issues:**
- Verify that updated tool responses use the same `id` and `name` as the original function call
@@ -24,6 +24,6 @@
"tags": ["expenses", "processing", "employee-services"]
}
],
"url": "http://localhost:8000/a2a/human_in_loop",
"url": "http://localhost:8001/a2a/human_in_loop",
"version": "1.0.0"
}
+16 -208
View File
@@ -12,18 +12,19 @@
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any
from adk_answering_agent.gemini_assistant.agent import root_agent as gemini_assistant_agent
from adk_answering_agent.settings import BOT_RESPONSE_LABEL
from adk_answering_agent.settings import IS_INTERACTIVE
from adk_answering_agent.settings import OWNER
from adk_answering_agent.settings import REPO
from adk_answering_agent.settings import VERTEXAI_DATASTORE_ID
from adk_answering_agent.utils import error_response
from adk_answering_agent.utils import run_graphql_query
from adk_answering_agent.tools import add_comment_to_discussion
from adk_answering_agent.tools import add_label_to_discussion
from adk_answering_agent.tools import convert_gcs_links_to_https
from adk_answering_agent.tools import get_discussion_and_comments
from google.adk.agents.llm_agent import Agent
from google.adk.tools.agent_tool import AgentTool
from google.adk.tools.vertex_ai_search_tool import VertexAiSearchTool
import requests
if IS_INTERACTIVE:
APPROVAL_INSTRUCTION = (
@@ -35,197 +36,6 @@ else:
" comment."
)
def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]:
"""Fetches a discussion and its comments using the GitHub GraphQL API.
Args:
discussion_number: The number of the GitHub discussion.
Returns:
A dictionary with the request status and the discussion details.
"""
print(f"Attempting to get discussion #{discussion_number} and its comments")
query = """
query($owner: String!, $repo: String!, $discussionNumber: Int!) {
repository(owner: $owner, name: $repo) {
discussion(number: $discussionNumber) {
id
title
body
createdAt
closed
author {
login
}
# For each discussion, fetch the latest 20 labels.
labels(last: 20) {
nodes {
id
name
}
}
# For each discussion, fetch the latest 100 comments.
comments(last: 100) {
nodes {
id
body
createdAt
author {
login
}
# For each discussion, fetch the latest 50 replies
replies(last: 50) {
nodes {
id
body
createdAt
author {
login
}
}
}
}
}
}
}
}
"""
variables = {
"owner": OWNER,
"repo": REPO,
"discussionNumber": discussion_number,
}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
discussion_data = (
response.get("data", {}).get("repository", {}).get("discussion")
)
if not discussion_data:
return error_response(f"Discussion #{discussion_number} not found.")
return {"status": "success", "discussion": discussion_data}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def add_comment_to_discussion(
discussion_id: str, comment_body: str
) -> dict[str, Any]:
"""Adds a comment to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
comment_body: The content of the comment in Markdown.
Returns:
The status of the request and the new comment's details.
"""
print(f"Adding comment to discussion {discussion_id}")
query = """
mutation($discussionId: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
comment {
id
body
createdAt
author {
login
}
}
}
}
"""
comment_body = (
"**Response from ADK Answering Agent (experimental, answer may be"
" inaccurate)**\n\n"
+ comment_body
)
variables = {"discussionId": discussion_id, "body": comment_body}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
new_comment = (
response.get("data", {}).get("addDiscussionComment", {}).get("comment")
)
return {"status": "success", "comment": new_comment}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def get_label_id(label_name: str) -> str | None:
"""Helper function to find the GraphQL node ID for a given label name."""
print(f"Finding ID for label '{label_name}'...")
query = """
query($owner: String!, $repo: String!, $labelName: String!) {
repository(owner: $owner, name: $repo) {
label(name: $labelName) {
id
}
}
}
"""
variables = {"owner": OWNER, "repo": REPO, "labelName": label_name}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
print(
f"[Warning] Error from GitHub API response for label '{label_name}':"
f" {response['errors']}"
)
return None
label_info = response["data"].get("repository", {}).get("label")
if label_info:
return label_info.get("id")
print(f"[Warning] Label information for '{label_name}' not found.")
return None
except requests.exceptions.RequestException as e:
print(f"[Warning] Error from GitHub API: {e}")
return None
def add_label_to_discussion(
discussion_id: str, label_name: str
) -> dict[str, Any]:
"""Adds a label to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
label_name: The name of the label to add (e.g., "bug").
Returns:
The status of the request and the label details.
"""
print(
f"Attempting to add label '{label_name}' to discussion {discussion_id}..."
)
# First, get the GraphQL ID of the label by its name
label_id = get_label_id(label_name)
if not label_id:
return error_response(f"Label '{label_name}' not found.")
# Then, perform the mutation to add the label to the discussion
mutation = """
mutation AddLabel($discussionId: ID!, $labelId: ID!) {
addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) {
clientMutationId
}
}
"""
variables = {"discussionId": discussion_id, "labelId": label_id}
try:
response = run_graphql_query(mutation, variables)
if "errors" in response:
return error_response(str(response["errors"]))
return {"status": "success", "label_id": label_id, "label_name": label_name}
except requests.exceptions.RequestException as e:
return error_response(str(e))
root_agent = Agent(
model="gemini-2.5-pro",
name="adk_answering_agent",
@@ -244,10 +54,10 @@ root_agent = Agent(
* The latest comment is not from you or other agents (marked as "Response from XXX Agent").
* The latest comment is asking a question or requesting information.
4. Use the `VertexAiSearchTool` to find relevant information before answering.
* If you need infromation about Gemini API, ask the `gemini_assistant` agent to provide the information and references.
* You can call the `gemini_assistant` agent with multiple queries to find all the relevant information.
5. If you can find relevant information, use the `add_comment_to_discussion` tool to add a comment to the discussion.
6. If you post a commment and the discussion does not have a label named {BOT_RESPONSE_LABEL},
add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
6. If you post a comment, add the label {BOT_RESPONSE_LABEL} to the discussion using the `add_label_to_discussion` tool.
IMPORTANT:
* {APPROVAL_INSTRUCTION}
@@ -255,25 +65,23 @@ root_agent = Agent(
information that is not in the document store. Do not invent citations which are not in the document store.
* **Be Objective**: your answer should be based on the facts you found in the document store, do not be misled by user's assumptions or user's understanding of ADK.
* If you can't find the answer or information in the document store, **do not** respond.
* Inlclude a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
* Start with a short summary of your response in the comment as a TLDR, e.g. "**TLDR**: <your summary>".
* Have a divider line between the TLDR and your detail response.
* Do not respond to any other discussion except the one specified by the user.
* Please include your justification for your decision in your output
to the user who is telling with you.
* If you uses citation from the document store, please provide a footnote
referencing the source document format it as: "[1] URL of the document".
* Replace the "gs://prefix/" part, e.g. "gs://adk-qa-bucket/", to be "https://github.com/google/"
* Add "blob/main/" after the repo name, e.g. "adk-python", "adk-docs", for example:
* If the original URL is "gs://adk-qa-bucket/adk-python/src/google/adk/version.py",
then the citation URL is "https://github.com/google/adk-python/blob/main/src/google/adk/version.py",
* If the original URL is "gs://adk-qa-bucket/adk-docs/docs/index.md",
then the citation URL is "https://github.com/google/adk-docs/blob/main/docs/index.md"
* If the file is a html file, replace the ".html" to be ".md"
referencing the source document format it as: "[1] publicly accessible HTTPS URL of the document".
* You **should always** use the `convert_gcs_links_to_https` tool to convert GCS links (e.g. "gs://...") to HTTPS links.
* **Do not** use the `convert_gcs_links_to_https` tool for non-GCS links.
* Make sure the citation URL is valid. Otherwise do not list this specific citation.
""",
tools=[
VertexAiSearchTool(data_store_id=VERTEXAI_DATASTORE_ID),
AgentTool(gemini_assistant_agent),
get_discussion_and_comments,
add_comment_to_discussion,
add_label_to_discussion,
convert_gcs_links_to_https,
],
)
@@ -0,0 +1,15 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from . import agent
@@ -0,0 +1,94 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import json
from typing import Any
from typing import Dict
from typing import List
from adk_answering_agent.settings import ADK_GCP_SA_KEY
from adk_answering_agent.settings import GEMINI_API_DATASTORE_ID
from adk_answering_agent.utils import error_response
from google.adk.agents.llm_agent import Agent
from google.api_core.exceptions import GoogleAPICallError
from google.cloud import discoveryengine_v1beta as discoveryengine
from google.oauth2 import service_account
def search_gemini_api_docs(queries: List[str]) -> Dict[str, Any]:
"""Searches Gemini API docs using Vertex AI Search.
Args:
queries: The list of queries to search.
Returns:
A dictionary containing the status of the request and the list of search
results, which contains the title, url and snippets.
"""
try:
adk_gcp_sa_key_info = json.loads(ADK_GCP_SA_KEY)
client = discoveryengine.SearchServiceClient(
credentials=service_account.Credentials.from_service_account_info(
adk_gcp_sa_key_info
)
)
except (TypeError, ValueError) as e:
return error_response(f"Error creating Vertex AI Search client: {e}")
serving_config = f"{GEMINI_API_DATASTORE_ID}/servingConfigs/default_config"
results = []
try:
for query in queries:
request = discoveryengine.SearchRequest(
serving_config=serving_config,
query=query,
page_size=20,
)
response = client.search(request=request)
for item in response.results:
snippets = []
for snippet in item.document.derived_struct_data.get("snippets", []):
snippets.append(snippet.get("snippet"))
results.append({
"title": item.document.derived_struct_data.get("title"),
"url": item.document.derived_struct_data.get("link"),
"snippets": snippets,
})
except GoogleAPICallError as e:
return error_response(f"Error from Vertex AI Search: {e}")
return {"status": "success", "results": results}
root_agent = Agent(
model="gemini-2.5-pro",
name="gemini_assistant",
description="Answer questions about Gemini API.",
instruction="""
You are a helpful assistant that responds to questions about Gemini API based on information
found in the document store. You can access the document store using the `search_gemini_api_docs` tool.
When user asks a question, here are the steps:
1. Use the `search_gemini_api_docs` tool to find relevant information before answering.
* You can call the tool with multiple queries to find all the relevant information.
2. Provide a response based on the information you found in the document store. Reference the source document in the response.
IMPORTANT:
* Your response should be based on the information you found in the document store. Do not invent
information that is not in the document store. Do not invent citations which are not in the document store.
* If you can't find the answer or information in the document store, just respond with "I can't find the answer or information in the document store".
* If you uses citation from the document store, please always provide a footnote referencing the source document format it as: "[1] URL of the document".
""",
tools=[search_gemini_api_docs],
)
@@ -13,6 +13,7 @@
# limitations under the License.
import asyncio
import logging
import time
from adk_answering_agent import agent
@@ -21,11 +22,14 @@ from adk_answering_agent.settings import OWNER
from adk_answering_agent.settings import REPO
from adk_answering_agent.utils import call_agent_async
from adk_answering_agent.utils import parse_number_string
from google.adk.cli.utils import logs
from google.adk.runners import InMemoryRunner
APP_NAME = "adk_answering_app"
USER_ID = "adk_answering_user"
logs.setup_adk_logger(level=logging.DEBUG)
async def main():
runner = InMemoryRunner(
@@ -31,6 +31,9 @@ if not VERTEXAI_DATASTORE_ID:
GOOGLE_CLOUD_PROJECT = os.getenv("GOOGLE_CLOUD_PROJECT")
GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME")
GEMINI_API_DATASTORE_ID = os.getenv("GEMINI_API_DATASTORE_ID")
ADK_GCP_SA_KEY = os.getenv("ADK_GCP_SA_KEY")
ADK_DOCS_ROOT_PATH = os.getenv("ADK_DOCS_ROOT_PATH")
ADK_PYTHON_ROOT_PATH = os.getenv("ADK_PYTHON_ROOT_PATH")
@@ -0,0 +1,230 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Any
from typing import Dict
from typing import Optional
from adk_answering_agent.settings import OWNER
from adk_answering_agent.settings import REPO
from adk_answering_agent.utils import convert_gcs_to_https
from adk_answering_agent.utils import error_response
from adk_answering_agent.utils import run_graphql_query
import requests
def get_discussion_and_comments(discussion_number: int) -> dict[str, Any]:
"""Fetches a discussion and its comments using the GitHub GraphQL API.
Args:
discussion_number: The number of the GitHub discussion.
Returns:
A dictionary with the request status and the discussion details.
"""
print(f"Attempting to get discussion #{discussion_number} and its comments")
query = """
query($owner: String!, $repo: String!, $discussionNumber: Int!) {
repository(owner: $owner, name: $repo) {
discussion(number: $discussionNumber) {
id
title
body
createdAt
closed
author {
login
}
# For each discussion, fetch the latest 20 labels.
labels(last: 20) {
nodes {
id
name
}
}
# For each discussion, fetch the latest 100 comments.
comments(last: 100) {
nodes {
id
body
createdAt
author {
login
}
# For each discussion, fetch the latest 50 replies
replies(last: 50) {
nodes {
id
body
createdAt
author {
login
}
}
}
}
}
}
}
}
"""
variables = {
"owner": OWNER,
"repo": REPO,
"discussionNumber": discussion_number,
}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
discussion_data = (
response.get("data", {}).get("repository", {}).get("discussion")
)
if not discussion_data:
return error_response(f"Discussion #{discussion_number} not found.")
return {"status": "success", "discussion": discussion_data}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def add_comment_to_discussion(
discussion_id: str, comment_body: str
) -> dict[str, Any]:
"""Adds a comment to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
comment_body: The content of the comment in Markdown.
Returns:
The status of the request and the new comment's details.
"""
print(f"Adding comment to discussion {discussion_id}")
query = """
mutation($discussionId: ID!, $body: String!) {
addDiscussionComment(input: {discussionId: $discussionId, body: $body}) {
comment {
id
body
createdAt
author {
login
}
}
}
}
"""
if not comment_body.startswith("**Response from ADK Answering Agent"):
comment_body = (
"**Response from ADK Answering Agent (experimental, answer may be"
" inaccurate)**\n\n"
+ comment_body
)
variables = {"discussionId": discussion_id, "body": comment_body}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
return error_response(str(response["errors"]))
new_comment = (
response.get("data", {}).get("addDiscussionComment", {}).get("comment")
)
return {"status": "success", "comment": new_comment}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def get_label_id(label_name: str) -> str | None:
"""Helper function to find the GraphQL node ID for a given label name."""
print(f"Finding ID for label '{label_name}'...")
query = """
query($owner: String!, $repo: String!, $labelName: String!) {
repository(owner: $owner, name: $repo) {
label(name: $labelName) {
id
}
}
}
"""
variables = {"owner": OWNER, "repo": REPO, "labelName": label_name}
try:
response = run_graphql_query(query, variables)
if "errors" in response:
print(
f"[Warning] Error from GitHub API response for label '{label_name}':"
f" {response['errors']}"
)
return None
label_info = response["data"].get("repository", {}).get("label")
if label_info:
return label_info.get("id")
print(f"[Warning] Label information for '{label_name}' not found.")
return None
except requests.exceptions.RequestException as e:
print(f"[Warning] Error from GitHub API: {e}")
return None
def add_label_to_discussion(
discussion_id: str, label_name: str
) -> dict[str, Any]:
"""Adds a label to a specific discussion.
Args:
discussion_id: The GraphQL node ID of the discussion.
label_name: The name of the label to add (e.g., "bug").
Returns:
The status of the request and the label details.
"""
print(
f"Attempting to add label '{label_name}' to discussion {discussion_id}..."
)
# First, get the GraphQL ID of the label by its name
label_id = get_label_id(label_name)
if not label_id:
return error_response(f"Label '{label_name}' not found.")
# Then, perform the mutation to add the label to the discussion
mutation = """
mutation AddLabel($discussionId: ID!, $labelId: ID!) {
addLabelsToLabelable(input: {labelableId: $discussionId, labelIds: [$labelId]}) {
clientMutationId
}
}
"""
variables = {"discussionId": discussion_id, "labelId": label_id}
try:
response = run_graphql_query(mutation, variables)
if "errors" in response:
return error_response(str(response["errors"]))
return {"status": "success", "label_id": label_id, "label_name": label_name}
except requests.exceptions.RequestException as e:
return error_response(str(e))
def convert_gcs_links_to_https(gcs_uris: list[str]) -> Dict[str, Optional[str]]:
"""Converts GCS files link into publicly accessible HTTPS links.
Args:
gcs_uris: A list of GCS files links, in the format
'gs://bucket_name/prefix/relative_path'.
Returns:
A dictionary mapping the original GCS files links to the converted HTTPS
links. If a GCS link is invalid, the corresponding value in the dictionary
will be None.
"""
return {gcs_uri: convert_gcs_to_https(gcs_uri) for gcs_uri in gcs_uris}
@@ -12,8 +12,11 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import os
import sys
from typing import Any
from typing import Optional
from urllib.parse import urljoin
from adk_answering_agent.settings import GITHUB_GRAPHQL_URL
from adk_answering_agent.settings import GITHUB_TOKEN
@@ -58,6 +61,92 @@ def parse_number_string(number_str: str | None, default_value: int = 0) -> int:
return default_value
def _check_url_exists(url: str) -> bool:
"""Checks if a URL exists and is accessible."""
try:
# Set a timeout to prevent the program from waiting indefinitely.
# allow_redirects=True ensures we correctly handle valid links
# after redirection.
response = requests.head(url, timeout=5, allow_redirects=True)
# Status codes 2xx (Success) or 3xx (Redirection) are considered valid.
return response.ok
except requests.RequestException:
# Catch all possible exceptions from the requests library
# (e.g., connection errors, timeouts).
return False
def _generate_github_url(repo_name: str, relative_path: str) -> str:
"""Generates a standard GitHub URL for a repo file."""
return f"https://github.com/google/{repo_name}/blob/main/{relative_path}"
def convert_gcs_to_https(gcs_uri: str) -> Optional[str]:
"""Converts a GCS file link into a publicly accessible HTTPS link.
Args:
gcs_uri: The Google Cloud Storage link, in the format
'gs://bucket_name/prefix/relative_path'.
Returns:
The converted HTTPS link as a string, or None if the input format is
incorrect.
"""
# Parse the GCS link
if not gcs_uri or not gcs_uri.startswith("gs://"):
print(f"Error: Invalid GCS link format: {gcs_uri}")
return None
try:
# Strip 'gs://' and split by '/', requiring at least 3 parts
# (bucket, prefix, path)
parts = gcs_uri[5:].split("/", 2)
if len(parts) < 3:
raise ValueError(
"GCS link must contain a bucket, prefix, and relative_path."
)
_, prefix, relative_path = parts
except (ValueError, IndexError) as e:
print(f"Error: Failed to parse GCS link '{gcs_uri}': {e}")
return None
# Replace .html with .md
if relative_path.endswith(".html"):
relative_path = relative_path.removesuffix(".html") + ".md"
# Convert the links for adk-docs
if prefix == "adk-docs" and relative_path.startswith("docs/"):
path_after_docs = relative_path[len("docs/") :]
if not path_after_docs.endswith(".md"):
# Use the regular github url
return _generate_github_url(prefix, relative_path)
base_url = "https://google.github.io/adk-docs/"
if os.path.basename(path_after_docs) == "index.md":
# Use the directory path if it is a index file
final_path_segment = os.path.dirname(path_after_docs)
else:
# Otherwise, use the file name without extention
final_path_segment = path_after_docs.removesuffix(".md")
if final_path_segment and not final_path_segment.endswith("/"):
final_path_segment += "/"
potential_url = urljoin(base_url, final_path_segment)
# Check if the generated link exists
if _check_url_exists(potential_url):
return potential_url
else:
# If it doesn't exist, fallback to the regular github url
return _generate_github_url(prefix, relative_path)
# Convert the links for other cases, e.g. adk-python
else:
return _generate_github_url(prefix, relative_path)
async def call_agent_async(
runner: Runner, user_id: str, session_id: str, prompt: str
) -> str:
@@ -0,0 +1,7 @@
# Basic Confg-based Agent
This sample only covers:
* name
* description
* model
@@ -0,0 +1,9 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: assistant_agent
model: gemini-2.5-flash
description: A helper agent that can answer users' questions.
instruction: |
You are an agent to help answer users' various questions.
1. If the user's intention is not clear, ask clarifying questions to better understand their needs.
2. Once the intention is clear, provide accurate and helpful answers to the user's questions.
@@ -0,0 +1,79 @@
from google.genai import types
async def before_agent_callback(callback_context):
print('@before_agent_callback')
return None
async def after_agent_callback(callback_context):
print('@after_agent_callback')
return None
async def before_model_callback(callback_context, llm_request):
print('@before_model_callback')
return None
async def after_model_callback(callback_context, llm_response):
print('@after_model_callback')
return None
def after_agent_callback1(callback_context):
print('@after_agent_callback1')
def after_agent_callback2(callback_context):
print('@after_agent_callback2')
# ModelContent (or Content with role set to 'model') must be returned.
# Otherwise, the event will be excluded from the context in the next turn.
return types.ModelContent(
parts=[
types.Part(
text='(stopped) after_agent_callback2',
),
],
)
def after_agent_callback3(callback_context):
print('@after_agent_callback3')
def before_agent_callback1(callback_context):
print('@before_agent_callback1')
def before_agent_callback2(callback_context):
print('@before_agent_callback2')
def before_agent_callback3(callback_context):
print('@before_agent_callback3')
def before_tool_callback1(tool, args, tool_context):
print('@before_tool_callback1')
def before_tool_callback2(tool, args, tool_context):
print('@before_tool_callback2')
def before_tool_callback3(tool, args, tool_context):
print('@before_tool_callback3')
def after_tool_callback1(tool, args, tool_context, tool_response):
print('@after_tool_callback1')
def after_tool_callback2(tool, args, tool_context, tool_response):
print('@after_tool_callback2')
return {'test': 'after_tool_callback2', 'response': tool_response}
def after_tool_callback3(tool, args, tool_context, tool_response):
print('@after_tool_callback3')
@@ -0,0 +1,43 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/google/adk-python/refs/heads/main/src/google/adk/agents/config_schemas/AgentConfig.json
name: hello_world_agent
model: gemini-2.0-flash
description: hello world agent that can roll a dice and check prime numbers.
instruction: |
You roll dice and answer questions about the outcome of the dice rolls.
You can roll dice of different sizes.
You can use multiple tools in parallel by calling functions in parallel(in one request and in one round).
It is ok to discuss previous dice roles, and comment on the dice rolls.
When you are asked to roll a die, you must call the roll_die tool with the number of sides. Be sure to pass in an integer. Do not pass in a string.
You should never roll a die on your own.
When checking prime numbers, call the check_prime tool with a list of integers. Be sure to pass in a list of integers. You should never pass in a string.
You should not check prime numbers before calling the tool.
When you are asked to roll a die and check prime numbers, you should always make the following two function calls:
1. You should first call the roll_die tool to get a roll. Wait for the function response before calling the check_prime tool.
2. After you get the function response from roll_die tool, you should call the check_prime tool with the roll_die result.
2.1 If user asks you to check primes based on previous rolls, make sure you include the previous rolls in the list.
3. When you respond, you must include the roll_die result from step 1.
You should always perform the previous 3 steps when asking for a roll and checking prime numbers.
You should not rely on the previous history on prime results.
tools:
- name: callbacks.tools.roll_die
- name: callbacks.tools.check_prime
before_agent_callbacks:
- name: callbacks.callbacks.before_agent_callback1
- name: callbacks.callbacks.before_agent_callback2
- name: callbacks.callbacks.before_agent_callback3
after_agent_callbacks:
- name: callbacks.callbacks.after_agent_callback1
- name: callbacks.callbacks.after_agent_callback2
- name: callbacks.callbacks.after_agent_callback3
before_model_callbacks:
- name: callbacks.callbacks.before_model_callback
after_model_callbacks:
- name: callbacks.callbacks.after_model_callback
before_tool_callbacks:
- name: callbacks.callbacks.before_tool_callback1
- name: callbacks.callbacks.before_tool_callback2
- name: callbacks.callbacks.before_tool_callback3
after_tool_callbacks:
- name: callbacks.callbacks.after_tool_callback1
- name: callbacks.callbacks.after_tool_callback2
- name: callbacks.callbacks.after_tool_callback3

Some files were not shown because too many files have changed in this diff Show More