Compare commits

...

42 Commits

Author SHA1 Message Date
Harsh Jha
12c554df1f chore: fix auth 2025-09-09 19:03:07 +05:30
Harsh Jha
9a4409b5ff chore: added pkg of wget 2025-09-09 19:03:07 +05:30
Harsh Jha
d4c78ade87 chore: fix wget cmd 2025-09-09 19:03:07 +05:30
Harsh Jha
33c9009863 chore: fix of cloudsql 2025-09-09 19:03:07 +05:30
Harsh Jha
865040166a chore: fix toolbox instance 2025-09-09 19:03:07 +05:30
Harsh Jha
c1a9eda0b3 chore: fix toolbox url 2025-09-09 19:03:07 +05:30
Harsh Jha
cf24f5cca6 chore: fix variable name of version of toolbox 2025-09-09 19:03:07 +05:30
Harsh Jha
08c9c9e811 removed log of secret value 2025-09-09 19:03:07 +05:30
Harsh Jha
6ad513a256 chore: removed cloudsql steps 2025-09-09 19:03:07 +05:30
Harsh Jha
c3db65c134 fix: removed extra steps 2025-09-09 19:03:07 +05:30
Harsh Jha
5cc43b3e8a chore: added license for quickstart_py.yaml 2025-09-09 19:03:07 +05:30
Harsh Jha
1a730705b1 updated 2025-09-09 19:03:07 +05:30
Harsh Jha
bba285a5b3 debug for pg password 2025-09-09 19:03:07 +05:30
Harsh Jha
170984706e updated 2025-09-09 19:03:06 +05:30
Harsh Jha
2db6aa3218 updated 2025-09-09 19:03:06 +05:30
Harsh Jha
6d9a22aabd updated 2025-09-09 19:03:06 +05:30
Harsh Jha
6d829ef065 updated 2025-09-09 19:03:06 +05:30
Harsh Jha
6813e6211d update 2025-09-09 19:03:06 +05:30
Harsh Jha
f7f8870a85 fixed: quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
7cc6d4e08d added psql cmd 2025-09-09 19:03:06 +05:30
Harsh Jha
2ea5671fa7 updated 2025-09-09 19:03:06 +05:30
Harsh Jha
19d7a9419a updated quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
ad9137a452 updated quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
106183fae8 updated quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
c32cc78012 chore: updated ci files 2025-09-09 19:03:06 +05:30
Harsh Jha
af2afd47f1 updated quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
84bb5b8078 chore: updated quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
30e2888370 chore(ci): update quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
dba96fa4f8 chore(ci): update _GCP_PROJECT_NUMBER value in quickstart_py.yaml 2025-09-09 19:03:06 +05:30
Harsh Jha
7ff06e1345 feat(ci): add ci files for py sample workflow 2025-09-09 19:03:05 +05:30
Harsh Jha
3e213c110c chore(python/quickstart): address multiple review comments in sample code 2025-09-09 19:01:50 +05:30
Harsh Jha
72d1bf72b9 test: Remove redundant script output check from tests 2025-09-09 18:59:47 +05:30
Harsh Jha
704413f475 fix(python/quickstart): pin exact versions in requirements.txt 2025-09-09 18:59:46 +05:30
Harsh Jha
ef3aa80fac fix(python/quickstart): revert code sample in all python quickstart examples 2025-09-09 18:59:46 +05:30
Harsh Jha
7d16633dc1 feat: Implement language-agnostic snippet shortcode 2025-09-09 18:59:46 +05:30
Harsh Jha
1d9b72a926 refactor(docs): Fix Table of Contents and optimize region include shortcode 2025-09-09 18:59:46 +05:30
Harsh Jha
751142a652 refactor(docs): Replace duplicated content with a shared shortcode 2025-09-09 18:59:46 +05:30
Harsh Jha
d4e6909a5b feat: Add shortcode for including file regions 2025-09-09 18:59:46 +05:30
Harsh Jha
b658710b55 chore(docs/python): remove compile-time test from quickstart samples 2025-09-09 18:59:46 +05:30
Harsh Jha
f1dc359046 refactor(test): update quickstart tests to only check for error-free execution 2025-09-09 18:59:46 +05:30
Harsh Jha
f1c8b2ac87 feat: add pytest-based test infrastructure for Python quickstart frameworks 2025-09-09 18:59:46 +05:30
Harsh Jha
3ebc2879e9 feat(adk): add Python quickstart testing infrastructure with requirements.txt, golden.txt, and quickstart_test.py 2025-09-09 18:59:01 +05:30
13 changed files with 337 additions and 3 deletions

107
.ci/quickstart_py.sh Normal file
View 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
View 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

View File

@@ -0,0 +1,3 @@
Hilton Basel
Hyatt Regency
book

View File

@@ -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}"

View File

@@ -0,0 +1,3 @@
google-adk==0.1.0
toolbox-core==0.5.0
pytest==7.0.0

View File

@@ -29,7 +29,7 @@ queries = [
"My check in dates for my booking would be from April 10, 2024 to April 19, 2024.", "My check in dates for my booking would be from April 10, 2024 to April 19, 2024.",
] ]
async def main(): async def run_application():
async with ToolboxClient("http://127.0.0.1:5000") as toolbox_client: async with ToolboxClient("http://127.0.0.1:5000") 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
@@ -105,4 +105,4 @@ async def main():
history.append(final_model_response_content) history.append(final_model_response_content)
print(response2.text) print(response2.text)
asyncio.run(main()) asyncio.run(run_application())

View File

@@ -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}"

View File

@@ -0,0 +1,3 @@
google-genai==0.6.0
toolbox-core==0.5.0
pytest==7.0.0

View File

@@ -31,7 +31,7 @@ queries = [
"My check in dates would be from April 10, 2024 to April 19, 2024.", "My check in dates would be from April 10, 2024 to April 19, 2024.",
] ]
async def main(): async def run_application():
# TODO(developer): replace this with another model if needed # TODO(developer): replace this with another model if needed
model = ChatVertexAI(model_name="gemini-2.0-flash-001") model = ChatVertexAI(model_name="gemini-2.0-flash-001")
# model = ChatGoogleGenerativeAI(model="gemini-2.0-flash-001") # model = ChatGoogleGenerativeAI(model="gemini-2.0-flash-001")

View File

@@ -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}"

View File

@@ -0,0 +1,5 @@
langchain==0.2.0
langchain-google-vertexai==1.0.0
langgraph==0.2.0
toolbox-langchain==0.5.0
pytest==7.0.0

View File

@@ -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}"

View File

@@ -0,0 +1,4 @@
llama-index==0.10.0
llama-index-llms-google-genai==0.1.0
toolbox-llamaindex==0.5.0
pytest==7.0.0