mirror of
https://github.com/googleapis/genai-toolbox.git
synced 2026-01-30 01:38:38 -05:00
Compare commits
107 Commits
processing
...
sts-py-sh-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10532bebc2 | ||
|
|
d93a23b35a | ||
|
|
c323dc4618 | ||
|
|
feadcfbef0 | ||
|
|
e06e802f5e | ||
|
|
5b7bcf0715 | ||
|
|
71dd32de60 | ||
|
|
5615f4636d | ||
|
|
68a85b80e7 | ||
|
|
b44bfec6cc | ||
|
|
55635cedf6 | ||
|
|
a9b84d6165 | ||
|
|
c23c5c9e8f | ||
|
|
beb524de67 | ||
|
|
c3257fe912 | ||
|
|
4fa243063c | ||
|
|
7b69829a4b | ||
|
|
ea9e4f323a | ||
|
|
aded6630b6 | ||
|
|
674e98875a | ||
|
|
82e901b193 | ||
|
|
6f43a283fa | ||
|
|
51f6c4a946 | ||
|
|
577e094330 | ||
|
|
3399f4ed61 | ||
|
|
bed5ce5d71 | ||
|
|
6db2fcbcfa | ||
|
|
05bb6820e2 | ||
|
|
b754ce9e34 | ||
|
|
2a9138dd01 | ||
|
|
a366f99524 | ||
|
|
37eb54d693 | ||
|
|
8e5908251e | ||
|
|
fd814cdf27 | ||
|
|
7df5d8975c | ||
|
|
d09dd1ac76 | ||
|
|
4e022ef3ef | ||
|
|
2b9710ffef | ||
|
|
653a9f0f46 | ||
|
|
8df929fcd4 | ||
|
|
7280065c23 | ||
|
|
ce83384393 | ||
|
|
34c4edf1ae | ||
|
|
6ae1039f4a | ||
|
|
d85ae4fb78 | ||
|
|
8f77e081b5 | ||
|
|
a5bc7d8110 | ||
|
|
3a1814f9e6 | ||
|
|
9e45500df6 | ||
|
|
b80a4d8612 | ||
|
|
69fcd51966 | ||
|
|
e7708ef17e | ||
|
|
1cd05b6fc1 | ||
|
|
e195a5bc74 | ||
|
|
54827c46c8 | ||
|
|
f28074285c | ||
|
|
2355ca5a96 | ||
|
|
9160aad696 | ||
|
|
46eb49245e | ||
|
|
ff31de5eb2 | ||
|
|
a3c4306897 | ||
|
|
a295585367 | ||
|
|
1571daa145 | ||
|
|
371f03e0ed | ||
|
|
39e3250a70 | ||
|
|
b462583ccf | ||
|
|
06042e6731 | ||
|
|
94adbbd992 | ||
|
|
7abec9e53e | ||
|
|
577c37f0df | ||
|
|
a07a8aa2d7 | ||
|
|
05662f1410 | ||
|
|
7c7b3b6305 | ||
|
|
3bae22efcf | ||
|
|
9bde22bfce | ||
|
|
8c1467d8a9 | ||
|
|
623b91af84 | ||
|
|
e1cc144e72 | ||
|
|
1a0386b360 | ||
|
|
7dfdede4be | ||
|
|
25e116584a | ||
|
|
e0d6c1f6d8 | ||
|
|
7ffb0e2d82 | ||
|
|
0e23d73ea2 | ||
|
|
79adf9d70b | ||
|
|
c97b89555e | ||
|
|
018edb5d61 | ||
|
|
a5beea5756 | ||
|
|
1130354ac5 | ||
|
|
28021d760e | ||
|
|
ff7f34bba6 | ||
|
|
a93ab0c25a | ||
|
|
921db2a546 | ||
|
|
5b7cc83472 | ||
|
|
e5922a69ec | ||
|
|
faa79cd3c1 | ||
|
|
959941d4ae | ||
|
|
7dc77fec19 | ||
|
|
061f38382e | ||
|
|
64e64a0d51 | ||
|
|
5e0a1b03ab | ||
|
|
b7cf0562ed | ||
|
|
8309816f44 | ||
|
|
114a0c91d8 | ||
|
|
5f1e4b940c | ||
|
|
e0b6d2d26b | ||
|
|
590bfaf4d3 |
107
.ci/quickstart_py.sh
Normal file
107
.ci/quickstart_py.sh
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -u
|
||||||
|
|
||||||
|
TABLE_NAME="hotels"
|
||||||
|
QUICKSTART_PYTHON_DIR="docs/en/getting-started/quickstart/python"
|
||||||
|
TOOLBOX_SETUP_DIR="/workspace/toolbox_setup"
|
||||||
|
|
||||||
|
apt-get update && apt-get install -y postgresql-client python3-venv curl wget
|
||||||
|
|
||||||
|
if [ ! -d "$QUICKSTART_PYTHON_DIR" ]; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
wget https://storage.googleapis.com/cloud-sql-connectors/cloud-sql-proxy/v2.10.0/cloud-sql-proxy.linux.amd64 -O /usr/local/bin/cloud-sql-proxy
|
||||||
|
chmod +x /usr/local/bin/cloud-sql-proxy
|
||||||
|
|
||||||
|
cloud-sql-proxy "${CLOUD_SQL_INSTANCE}" &
|
||||||
|
PROXY_PID=$!
|
||||||
|
|
||||||
|
export PGHOST=127.0.0.1
|
||||||
|
export PGPORT=5432
|
||||||
|
export PGPASSWORD="$DB_PASSWORD"
|
||||||
|
export GOOGLE_API_KEY="$GOOGLE_API_KEY"
|
||||||
|
|
||||||
|
mkdir -p "${TOOLBOX_SETUP_DIR}"
|
||||||
|
echo "${TOOLS_YAML_CONTENT}" > "${TOOLBOX_SETUP_DIR}/tools.yaml"
|
||||||
|
if [ ! -f "${TOOLBOX_SETUP_DIR}/tools.yaml" ]; then echo "Failed to create tools.yaml"; exit 1; fi
|
||||||
|
|
||||||
|
curl -L "https://storage.googleapis.com/genai-toolbox/v${VERSION}/linux/amd64/toolbox" -o "${TOOLBOX_SETUP_DIR}/toolbox"
|
||||||
|
chmod +x "${TOOLBOX_SETUP_DIR}/toolbox"
|
||||||
|
if [ ! -f "${TOOLBOX_SETUP_DIR}/toolbox" ]; then echo "Failed to download toolbox"; exit 1; fi
|
||||||
|
|
||||||
|
echo "--- Starting Toolbox Server ---"
|
||||||
|
cd "${TOOLBOX_SETUP_DIR}"
|
||||||
|
./toolbox --tools-file ./tools.yaml &
|
||||||
|
TOOLBOX_PID=$!
|
||||||
|
cd "/workspace"
|
||||||
|
sleep 5
|
||||||
|
|
||||||
|
cleanup_all() {
|
||||||
|
kill $TOOLBOX_PID || true
|
||||||
|
kill $PROXY_PID || true
|
||||||
|
}
|
||||||
|
trap cleanup_all EXIT
|
||||||
|
|
||||||
|
|
||||||
|
for ORCH_DIR in "$QUICKSTART_PYTHON_DIR"/*/; do
|
||||||
|
if [ ! -d "$ORCH_DIR" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
(
|
||||||
|
set -e
|
||||||
|
ORCH_NAME=$(basename "$ORCH_DIR")
|
||||||
|
|
||||||
|
cleanup_orch() {
|
||||||
|
psql -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DATABASE_NAME" -c "DROP TABLE IF EXISTS $TABLE_NAME;"
|
||||||
|
|
||||||
|
if [ -d ".venv" ]; then
|
||||||
|
rm -rf ".venv"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
trap cleanup_orch EXIT
|
||||||
|
|
||||||
|
cd "$ORCH_DIR"
|
||||||
|
|
||||||
|
psql -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DATABASE_NAME" <<EOF
|
||||||
|
CREATE TABLE $TABLE_NAME (
|
||||||
|
id INTEGER NOT NULL PRIMARY KEY,
|
||||||
|
name VARCHAR NOT NULL,
|
||||||
|
location VARCHAR NOT NULL,
|
||||||
|
price_tier VARCHAR NOT NULL,
|
||||||
|
checkin_date DATE NOT NULL,
|
||||||
|
checkout_date DATE NOT NULL,
|
||||||
|
booked BIT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO $TABLE_NAME (id, name, location, price_tier, checkin_date, checkout_date, booked)
|
||||||
|
VALUES
|
||||||
|
(1, 'Hilton Basel', 'Basel', 'Luxury', '2024-04-22', '2024-04-20', B'0'),
|
||||||
|
(2, 'Marriott Zurich', 'Zurich', 'Upscale', '2024-04-14', '2024-04-21', B'0'),
|
||||||
|
(3, 'Hyatt Regency Basel', 'Basel', 'Upper Upscale', '2024-04-02', '2024-04-20', B'0'),
|
||||||
|
(4, 'Radisson Blu Lucerne', 'Lucerne', 'Midscale', '2024-04-24', '2024-04-05', B'0'),
|
||||||
|
(5, 'Best Western Bern', 'Bern', 'Upper Midscale', '2024-04-23', '2024-04-01', B'0'),
|
||||||
|
(6, 'InterContinental Geneva', 'Geneva', 'Luxury', '2024-04-23', '2024-04-28', B'0'),
|
||||||
|
(7, 'Sheraton Zurich', 'Zurich', 'Upper Upscale', '2024-04-27', '2024-04-02', B'0'),
|
||||||
|
(8, 'Holiday Inn Basel', 'Basel', 'Upper Midscale', '2024-04-24', '2024-04-09', B'0'),
|
||||||
|
(9, 'Courtyard Zurich', 'Zurich', 'Upscale', '2024-04-03', '2024-04-13', B'0'),
|
||||||
|
(10, 'Comfort Inn Bern', 'Bern', 'Midscale', '2024-04-04', '2024-04-16', B'0');
|
||||||
|
EOF
|
||||||
|
|
||||||
|
VENV_DIR=".venv"
|
||||||
|
python3 -m venv "$VENV_DIR"
|
||||||
|
source "$VENV_DIR/bin/activate"
|
||||||
|
|
||||||
|
if [ -f "requirements.txt" ]; then
|
||||||
|
pip install -r requirements.txt
|
||||||
|
else
|
||||||
|
echo "Warning: requirements.txt not found. Skipping."
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Running tests for $ORCH_NAME..."
|
||||||
|
pytest
|
||||||
|
|
||||||
|
)
|
||||||
|
done
|
||||||
57
.ci/quickstart_py.yaml
Normal file
57
.ci/quickstart_py.yaml
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
substitutions:
|
||||||
|
_GCP_PROJECT: "your-project-id"
|
||||||
|
_CLOUD_SQL_INSTANCE: "project-id:region:instance-name"
|
||||||
|
_DATABASE_NAME: "db-name"
|
||||||
|
_DB_USER: "db-user"
|
||||||
|
_TOOLS_YAML_SECRET: "tools yaml secret"
|
||||||
|
_API_KEY_SECRET: "api key secret"
|
||||||
|
_DB_PASS_SECRET: "db pass secret"
|
||||||
|
_GCP_PROJECT_NUMBER: "your-project-number"
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
|
||||||
|
id: 'run-psql-commands'
|
||||||
|
entrypoint: 'bash'
|
||||||
|
args:
|
||||||
|
- -c
|
||||||
|
- |
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
export VERSION=$(cat ./cmd/version.txt)
|
||||||
|
chmod +x .ci/quickstart_py.sh
|
||||||
|
.ci/quickstart_py.sh
|
||||||
|
|
||||||
|
env:
|
||||||
|
- 'CLOUD_SQL_INSTANCE=${_CLOUD_SQL_INSTANCE}'
|
||||||
|
- 'GCP_PROJECT=${_GCP_PROJECT}'
|
||||||
|
- 'DATABASE_NAME=${_DATABASE_NAME}'
|
||||||
|
- 'DB_USER=${_DB_USER}'
|
||||||
|
secretEnv: ['TOOLS_YAML_CONTENT', 'GOOGLE_API_KEY', 'DB_PASSWORD']
|
||||||
|
|
||||||
|
availableSecrets:
|
||||||
|
secretManager:
|
||||||
|
- versionName: projects/${_GCP_PROJECT}/secrets/${_TOOLS_YAML_SECRET}/versions/latest
|
||||||
|
env: 'TOOLS_YAML_CONTENT'
|
||||||
|
- versionName: projects/${_GCP_PROJECT_NUMBER}/secrets/${_API_KEY_SECRET}/versions/latest
|
||||||
|
env: 'GOOGLE_API_KEY'
|
||||||
|
- versionName: projects/${_GCP_PROJECT}/secrets/${_DB_PASS_SECRET}/versions/latest
|
||||||
|
env: 'DB_PASSWORD'
|
||||||
|
|
||||||
|
timeout: 1800s
|
||||||
|
|
||||||
|
options:
|
||||||
|
logging: CLOUD_LOGGING_ONLY
|
||||||
3
docs/en/getting-started/quickstart/golden.txt
Normal file
3
docs/en/getting-started/quickstart/golden.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Hilton Basel
|
||||||
|
Hyatt Regency
|
||||||
|
book
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
|
||||||
from google.adk.agents import Agent
|
from google.adk.agents import Agent
|
||||||
from google.adk.runners import Runner
|
from google.adk.runners import Runner
|
||||||
from google.adk.sessions import InMemorySessionService
|
from google.adk.sessions import InMemorySessionService
|
||||||
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
|
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
|
||||||
from google.genai import types
|
from google.genai import types
|
||||||
from toolbox_core import ToolboxSyncClient
|
from toolbox_core import ToolboxSyncClient # Corrected import
|
||||||
|
|
||||||
import asyncio
|
|
||||||
import os
|
|
||||||
|
|
||||||
# TODO(developer): replace this with your Google API key
|
# TODO(developer): replace this with your Google API key
|
||||||
|
os.environ['GOOGLE_API_KEY']
|
||||||
os.environ['GOOGLE_API_KEY'] = 'your-api-key'
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox_client:
|
host = os.environ.get("TOOLBOX_HOST", "127.0.0.1")
|
||||||
|
toolbox_url = f"http://{host}:5000"
|
||||||
|
|
||||||
|
with ToolboxSyncClient(toolbox_url) as toolbox_client:
|
||||||
|
|
||||||
prompt = """
|
prompt = """
|
||||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||||
@@ -35,7 +37,7 @@ async def main():
|
|||||||
|
|
||||||
session_service = InMemorySessionService()
|
session_service = InMemorySessionService()
|
||||||
artifacts_service = InMemoryArtifactService()
|
artifacts_service = InMemoryArtifactService()
|
||||||
session = await session_service.create_session(
|
session = session_service.create_session(
|
||||||
state={}, app_name='hotel_agent', user_id='123'
|
state={}, app_name='hotel_agent', user_id='123'
|
||||||
)
|
)
|
||||||
runner = Runner(
|
runner = Runner(
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
import asyncio
|
||||||
|
from quickstart import main
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def golden_keywords():
|
||||||
|
"""Loads expected keywords from the golden.txt file."""
|
||||||
|
golden_file_path = Path("../../golden.txt")
|
||||||
|
if not golden_file_path.exists():
|
||||||
|
pytest.fail(f"Golden file not found: {golden_file_path}")
|
||||||
|
try:
|
||||||
|
with open(golden_file_path, 'r') as f:
|
||||||
|
return [line.strip() for line in f.readlines() if line.strip()]
|
||||||
|
except Exception as e:
|
||||||
|
pytest.fail(f"Could not read golden.txt: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Execution Tests ---
|
||||||
|
class TestADKExecution:
|
||||||
|
"""Test ADK framework execution and output validation."""
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def script_output(self, capsys):
|
||||||
|
"""Run the quickstart function and return its output."""
|
||||||
|
asyncio.run(main())
|
||||||
|
return capsys.readouterr()
|
||||||
|
|
||||||
|
def test_script_runs_without_errors(self, script_output):
|
||||||
|
"""Test that the script runs and produces no stderr."""
|
||||||
|
assert script_output.err == "", f"Script produced stderr: {script_output.err}"
|
||||||
|
|
||||||
|
def test_keywords_in_output(self, script_output, golden_keywords):
|
||||||
|
"""Test that expected keywords are present in the script's output."""
|
||||||
|
output = script_output.out
|
||||||
|
missing_keywords = [kw for kw in golden_keywords if kw not in output]
|
||||||
|
assert not missing_keywords, f"Missing keywords in output: {missing_keywords}"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
google-adk==0.1.0
|
||||||
|
toolbox-core==0.5.0
|
||||||
|
pytest==7.0.0
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
import os
|
||||||
from google import genai
|
from google import genai
|
||||||
from google.genai.types import (
|
from google.genai.types import (
|
||||||
Content,
|
Content,
|
||||||
@@ -30,7 +30,9 @@ queries = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
async with ToolboxClient("http://127.0.0.1:5000") as toolbox_client:
|
host = os.environ.get("TOOLBOX_HOST", "127.0.0.1")
|
||||||
|
toolbox_url = f"http://{host}:5000"
|
||||||
|
async with ToolboxClient(toolbox_url) as toolbox_client:
|
||||||
|
|
||||||
# The toolbox_tools list contains Python callables (functions/methods) designed for LLM tool-use
|
# The toolbox_tools list contains Python callables (functions/methods) designed for LLM tool-use
|
||||||
# integration. While this example uses Google's genai client, these callables can be adapted for
|
# integration. While this example uses Google's genai client, these callables can be adapted for
|
||||||
@@ -39,7 +41,7 @@ async def main():
|
|||||||
# provided wrapper packages, which handle framework-specific boilerplate.
|
# provided wrapper packages, which handle framework-specific boilerplate.
|
||||||
toolbox_tools = await toolbox_client.load_toolset("my-toolset")
|
toolbox_tools = await toolbox_client.load_toolset("my-toolset")
|
||||||
genai_client = genai.Client(
|
genai_client = genai.Client(
|
||||||
vertexai=True, project="project-id", location="us-central1"
|
vertexai=True, project=os.environ.get("GCP_PROJECT"), location="us-central1"
|
||||||
)
|
)
|
||||||
|
|
||||||
genai_tools = [
|
genai_tools = [
|
||||||
@@ -68,41 +70,47 @@ async def main():
|
|||||||
)
|
)
|
||||||
history.append(response.candidates[0].content)
|
history.append(response.candidates[0].content)
|
||||||
function_response_parts = []
|
function_response_parts = []
|
||||||
for function_call in response.function_calls:
|
|
||||||
fn_name = function_call.name
|
if response.function_calls:
|
||||||
# The tools are sorted alphabetically
|
for function_call in response.function_calls:
|
||||||
if fn_name == "search-hotels-by-name":
|
fn_name = function_call.name
|
||||||
function_result = await toolbox_tools[3](**function_call.args)
|
# The tools are sorted alphabetically
|
||||||
elif fn_name == "search-hotels-by-location":
|
if fn_name == "search-hotels-by-name":
|
||||||
function_result = await toolbox_tools[2](**function_call.args)
|
function_result = await toolbox_tools[3](**function_call.args)
|
||||||
elif fn_name == "book-hotel":
|
elif fn_name == "search-hotels-by-location":
|
||||||
function_result = await toolbox_tools[0](**function_call.args)
|
function_result = await toolbox_tools[2](**function_call.args)
|
||||||
elif fn_name == "update-hotel":
|
elif fn_name == "book-hotel":
|
||||||
function_result = await toolbox_tools[4](**function_call.args)
|
function_result = await toolbox_tools[0](**function_call.args)
|
||||||
elif fn_name == "cancel-hotel":
|
elif fn_name == "update-hotel":
|
||||||
function_result = await toolbox_tools[1](**function_call.args)
|
function_result = await toolbox_tools[4](**function_call.args)
|
||||||
else:
|
elif fn_name == "cancel-hotel":
|
||||||
raise ValueError("Function name not present.")
|
function_result = await toolbox_tools[1](**function_call.args)
|
||||||
function_response = {"result": function_result}
|
else:
|
||||||
function_response_part = Part.from_function_response(
|
raise ValueError(f"Function name {fn_name} not present.")
|
||||||
name=function_call.name,
|
|
||||||
response=function_response,
|
function_response = {"result": function_result}
|
||||||
)
|
function_response_part = Part.from_function_response(
|
||||||
function_response_parts.append(function_response_part)
|
name=function_call.name,
|
||||||
|
response=function_response,
|
||||||
|
)
|
||||||
|
function_response_parts.append(function_response_part)
|
||||||
|
|
||||||
if function_response_parts:
|
if function_response_parts:
|
||||||
tool_response_content = Content(role="tool", parts=function_response_parts)
|
tool_response_content = Content(role="tool", parts=function_response_parts)
|
||||||
history.append(tool_response_content)
|
history.append(tool_response_content)
|
||||||
|
|
||||||
response2 = genai_client.models.generate_content(
|
response2 = genai_client.models.generate_content(
|
||||||
model="gemini-2.0-flash-001",
|
model="gemini-2.0-flash-001",
|
||||||
contents=history,
|
contents=history,
|
||||||
config=GenerateContentConfig(
|
config=GenerateContentConfig(
|
||||||
tools=genai_tools,
|
tools=genai_tools,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
final_model_response_content = response2.candidates[0].content
|
final_model_response_content = response2.candidates[0].content
|
||||||
history.append(final_model_response_content)
|
history.append(final_model_response_content)
|
||||||
print(response2.text)
|
print(response2.text)
|
||||||
|
else:
|
||||||
|
print(response.text)
|
||||||
|
|
||||||
asyncio.run(main())
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
import asyncio
|
||||||
|
from quickstart import main
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def golden_keywords():
|
||||||
|
"""Loads expected keywords from the golden.txt file."""
|
||||||
|
golden_file_path = Path("../../golden.txt")
|
||||||
|
if not golden_file_path.exists():
|
||||||
|
pytest.fail(f"Golden file not found: {golden_file_path}")
|
||||||
|
try:
|
||||||
|
with open(golden_file_path, 'r') as f:
|
||||||
|
return [line.strip() for line in f.readlines() if line.strip()]
|
||||||
|
except Exception as e:
|
||||||
|
pytest.fail(f"Could not read golden.txt: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Execution Tests ---
|
||||||
|
class TestADKExecution:
|
||||||
|
"""Test ADK framework execution and output validation."""
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def script_output(self, capsys):
|
||||||
|
"""Run the quickstart function and return its output."""
|
||||||
|
asyncio.run(main())
|
||||||
|
return capsys.readouterr()
|
||||||
|
|
||||||
|
def test_script_runs_without_errors(self, script_output):
|
||||||
|
"""Test that the script runs and produces no stderr."""
|
||||||
|
assert script_output.err == "", f"Script produced stderr: {script_output.err}"
|
||||||
|
|
||||||
|
def test_keywords_in_output(self, script_output, golden_keywords):
|
||||||
|
"""Test that expected keywords are present in the script's output."""
|
||||||
|
output = script_output.out
|
||||||
|
missing_keywords = [kw for kw in golden_keywords if kw not in output]
|
||||||
|
assert not missing_keywords, f"Missing keywords in output: {missing_keywords}"
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
google-genai==1.33.0
|
||||||
|
toolbox-core==0.5.0
|
||||||
|
pytest==7.0.0
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
from langgraph.prebuilt import create_react_agent
|
from langgraph.prebuilt import create_react_agent
|
||||||
|
|
||||||
# TODO(developer): replace this with another import if needed
|
# TODO(developer): replace this with another import if needed
|
||||||
@@ -38,8 +40,10 @@ async def main():
|
|||||||
# model = ChatAnthropic(model="claude-3-5-sonnet-20240620")
|
# model = ChatAnthropic(model="claude-3-5-sonnet-20240620")
|
||||||
|
|
||||||
# Load the tools from the Toolbox server
|
# Load the tools from the Toolbox server
|
||||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
host = os.environ.get("TOOLBOX_HOST", "127.0.0.1")
|
||||||
tools = await client.aload_toolset()
|
toolbox_url = f"http://{host}:5000"
|
||||||
|
async with ToolboxClient(toolbox_url) as toolbox_client:
|
||||||
|
tools = await toolbox_client.aload_toolset()
|
||||||
|
|
||||||
agent = create_react_agent(model, tools, checkpointer=MemorySaver())
|
agent = create_react_agent(model, tools, checkpointer=MemorySaver())
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
import asyncio
|
||||||
|
from quickstart import main
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def golden_keywords():
|
||||||
|
"""Loads expected keywords from the golden.txt file."""
|
||||||
|
golden_file_path = Path("../../golden.txt")
|
||||||
|
if not golden_file_path.exists():
|
||||||
|
pytest.fail(f"Golden file not found: {golden_file_path}")
|
||||||
|
try:
|
||||||
|
with open(golden_file_path, 'r') as f:
|
||||||
|
return [line.strip() for line in f.readlines() if line.strip()]
|
||||||
|
except Exception as e:
|
||||||
|
pytest.fail(f"Could not read golden.txt: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Execution Tests ---
|
||||||
|
class TestADKExecution:
|
||||||
|
"""Test ADK framework execution and output validation."""
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def script_output(self, capsys):
|
||||||
|
"""Run the quickstart function and return its output."""
|
||||||
|
asyncio.run(main())
|
||||||
|
return capsys.readouterr()
|
||||||
|
|
||||||
|
def test_script_runs_without_errors(self, script_output):
|
||||||
|
"""Test that the script runs and produces no stderr."""
|
||||||
|
assert script_output.err == "", f"Script produced stderr: {script_output.err}"
|
||||||
|
|
||||||
|
def test_keywords_in_output(self, script_output, golden_keywords):
|
||||||
|
"""Test that expected keywords are present in the script's output."""
|
||||||
|
output = script_output.out
|
||||||
|
missing_keywords = [kw for kw in golden_keywords if kw not in output]
|
||||||
|
assert not missing_keywords, f"Missing keywords in output: {missing_keywords}"
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
langchain==0.3.27
|
||||||
|
langchain-google-vertexai==2.0.28
|
||||||
|
langgraph==0.6.7
|
||||||
|
toolbox-langchain==0.5.0
|
||||||
|
pytest==8.4.2
|
||||||
@@ -2,13 +2,9 @@ import asyncio
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
from llama_index.core.agent.workflow import AgentWorkflow
|
from llama_index.core.agent.workflow import AgentWorkflow
|
||||||
|
|
||||||
from llama_index.core.workflow import Context
|
from llama_index.core.workflow import Context
|
||||||
|
|
||||||
# TODO(developer): replace this with another import if needed
|
# TODO(developer): replace this with another import if needed
|
||||||
|
|
||||||
from llama_index.llms.google_genai import GoogleGenAI
|
from llama_index.llms.google_genai import GoogleGenAI
|
||||||
|
|
||||||
# from llama_index.llms.anthropic import Anthropic
|
# from llama_index.llms.anthropic import Anthropic
|
||||||
|
|
||||||
from toolbox_llamaindex import ToolboxClient
|
from toolbox_llamaindex import ToolboxClient
|
||||||
@@ -34,7 +30,7 @@ async def main():
|
|||||||
# TODO(developer): replace this with another model if needed
|
# TODO(developer): replace this with another model if needed
|
||||||
llm = GoogleGenAI(
|
llm = GoogleGenAI(
|
||||||
model="gemini-2.0-flash-001",
|
model="gemini-2.0-flash-001",
|
||||||
vertexai_config={"project": "project-id", "location": "us-central1"},
|
vertexai_config={"project": os.environ.get("GCP_PROJECT", "project-id"), "location": "us-central1"},
|
||||||
)
|
)
|
||||||
# llm = GoogleGenAI(
|
# llm = GoogleGenAI(
|
||||||
# api_key=os.getenv("GOOGLE_API_KEY"),
|
# api_key=os.getenv("GOOGLE_API_KEY"),
|
||||||
@@ -46,8 +42,10 @@ async def main():
|
|||||||
# )
|
# )
|
||||||
|
|
||||||
# Load the tools from the Toolbox server
|
# Load the tools from the Toolbox server
|
||||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
host = os.environ.get("TOOLBOX_HOST", "127.0.0.1")
|
||||||
tools = await client.aload_toolset()
|
toolbox_url = f"http://{host}:5000"
|
||||||
|
async with ToolboxClient(toolbox_url) as toolbox_client:
|
||||||
|
tools = await toolbox_client.aload_toolset()
|
||||||
|
|
||||||
agent = AgentWorkflow.from_tools_or_functions(
|
agent = AgentWorkflow.from_tools_or_functions(
|
||||||
tools,
|
tools,
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import os
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
import asyncio
|
||||||
|
from quickstart import main
|
||||||
|
|
||||||
|
@pytest.fixture(scope="module")
|
||||||
|
def golden_keywords():
|
||||||
|
"""Loads expected keywords from the golden.txt file."""
|
||||||
|
golden_file_path = Path("../../golden.txt")
|
||||||
|
if not golden_file_path.exists():
|
||||||
|
pytest.fail(f"Golden file not found: {golden_file_path}")
|
||||||
|
try:
|
||||||
|
with open(golden_file_path, 'r') as f:
|
||||||
|
return [line.strip() for line in f.readlines() if line.strip()]
|
||||||
|
except Exception as e:
|
||||||
|
pytest.fail(f"Could not read golden.txt: {e}")
|
||||||
|
|
||||||
|
|
||||||
|
# --- Execution Tests ---
|
||||||
|
class TestADKExecution:
|
||||||
|
"""Test ADK framework execution and output validation."""
|
||||||
|
|
||||||
|
@pytest.fixture(scope="function")
|
||||||
|
def script_output(self, capsys):
|
||||||
|
"""Run the quickstart function and return its output."""
|
||||||
|
asyncio.run(main())
|
||||||
|
return capsys.readouterr()
|
||||||
|
|
||||||
|
def test_script_runs_without_errors(self, script_output):
|
||||||
|
"""Test that the script runs and produces no stderr."""
|
||||||
|
assert script_output.err == "", f"Script produced stderr: {script_output.err}"
|
||||||
|
|
||||||
|
def test_keywords_in_output(self, script_output, golden_keywords):
|
||||||
|
"""Test that expected keywords are present in the script's output."""
|
||||||
|
output = script_output.out
|
||||||
|
missing_keywords = [kw for kw in golden_keywords if kw not in output]
|
||||||
|
assert not missing_keywords, f"Missing keywords in output: {missing_keywords}"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
llama-index==0.13.6
|
||||||
|
llama-index-llms-google-genai==0.3.0
|
||||||
|
toolbox-llamaindex==0.5.0
|
||||||
|
pytest==8.4.2
|
||||||
Reference in New Issue
Block a user