mirror of
https://github.com/googleapis/genai-toolbox.git
synced 2026-01-11 16:38:15 -05:00
Compare commits
6 Commits
fix-python
...
blog
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e26368b88e | ||
|
|
1d5a8986e2 | ||
|
|
7b571b17e3 | ||
|
|
c2b3f5df19 | ||
|
|
1dd567f430 | ||
|
|
6c13e8fa9b |
@@ -18,7 +18,7 @@ steps:
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
docker buildx create --name container-builder --driver docker-container --bootstrap --use
|
||||
docker buildx build --platform linux/amd64,linux/arm64 --build-arg COMMIT_SHA=$(git rev-parse --short HEAD) -t ${_DOCKER_URI}:$REF_NAME --push .
|
||||
docker buildx build --platform linux/amd64,linux/arm64 --build-arg COMMIT_SHA=$(git rev-parse HEAD) -t ${_DOCKER_URI}:$REF_NAME --push .
|
||||
|
||||
- id: "install-dependencies"
|
||||
name: golang:1
|
||||
@@ -43,7 +43,7 @@ steps:
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.linux.amd64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.linux.amd64
|
||||
|
||||
- id: "store-linux-amd64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -65,7 +65,7 @@ steps:
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.darwin.arm64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.arm64
|
||||
|
||||
- id: "store-darwin-arm64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -87,7 +87,7 @@ steps:
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.darwin.amd64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.amd64
|
||||
|
||||
- id: "store-darwin-amd64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -109,7 +109,7 @@ steps:
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.windows.amd64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.windows.amd64
|
||||
|
||||
- id: "store-windows-amd64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
|
||||
@@ -33,9 +33,7 @@ steps:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
script: |
|
||||
go test -c -race -cover \
|
||||
-coverpkg=./internal/sources/...,./internal/tools/... ./tests/...
|
||||
chmod +x .ci/test_with_coverage.sh
|
||||
go test -c -race ./tests/...
|
||||
|
||||
- id: "cloud-sql-pg"
|
||||
name: golang:1
|
||||
@@ -56,33 +54,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Cloud SQL Postgres" \
|
||||
cloudsqlpg \
|
||||
postgressql \
|
||||
postgresexecutesql
|
||||
|
||||
- id: "alloydb"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "ALLOYDB_PROJECT=$PROJECT_ID"
|
||||
- "ALLOYDB_CLUSTER=$_ALLOYDB_POSTGRES_CLUSTER"
|
||||
- "ALLOYDB_INSTANCE=$_ALLOYDB_POSTGRES_INSTANCE"
|
||||
- "ALLOYDB_REGION=$_REGION"
|
||||
secretEnv: ["ALLOYDB_POSTGRES_USER"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"AlloyDB" \
|
||||
alloydb \
|
||||
alloydb
|
||||
./cloudsqlpg.test -test.v
|
||||
|
||||
- id: "alloydb-pg"
|
||||
name: golang:1
|
||||
@@ -103,11 +75,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"AlloyDB Postgres" \
|
||||
alloydbpg \
|
||||
postgressql \
|
||||
postgresexecutesql
|
||||
./alloydbpg.test -test.v
|
||||
|
||||
- id: "alloydb-ai-nl"
|
||||
name: golang:1
|
||||
@@ -128,10 +96,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"AlloyDB AI NL" \
|
||||
alloydbainl \
|
||||
alloydbainl
|
||||
./alloydbainl.test -test.v
|
||||
|
||||
- id: "bigtable"
|
||||
name: golang:1
|
||||
@@ -142,17 +107,15 @@ steps:
|
||||
- "BIGTABLE_PROJECT=$PROJECT_ID"
|
||||
- "BIGTABLE_INSTANCE=$_BIGTABLE_INSTANCE"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID"]
|
||||
secretEnv:
|
||||
["CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Bigtable" \
|
||||
bigtable \
|
||||
bigtable
|
||||
./bigtable.test -test.v
|
||||
|
||||
- id: "bigquery"
|
||||
name: golang:1
|
||||
@@ -169,50 +132,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"BigQuery" \
|
||||
bigquery \
|
||||
bigquery
|
||||
|
||||
- id: "dataplex"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "DATAPLEX_PROJECT=$PROJECT_ID"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Dataplex" \
|
||||
dataplex \
|
||||
dataplex
|
||||
|
||||
- id: "dataform"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
secretEnv: ["CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
apt-get update && apt-get install -y npm && \
|
||||
npm install -g @dataform/cli && \
|
||||
.ci/test_with_coverage.sh \
|
||||
"Dataform" \
|
||||
dataform \
|
||||
dataform
|
||||
./bigquery.test -test.v
|
||||
|
||||
- id: "postgres"
|
||||
name: golang:1
|
||||
@@ -231,11 +151,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Postgres" \
|
||||
postgres \
|
||||
postgressql \
|
||||
postgresexecutesql
|
||||
./postgres.test -test.v
|
||||
|
||||
- id: "spanner"
|
||||
name: golang:1
|
||||
@@ -254,10 +170,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Spanner" \
|
||||
spanner \
|
||||
spanner
|
||||
./spanner.test -test.v
|
||||
|
||||
- id: "neo4j"
|
||||
name: golang:1
|
||||
@@ -274,10 +187,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Neo4j" \
|
||||
neo4j \
|
||||
neo4j
|
||||
./neo4j.test -test.v
|
||||
|
||||
- id: "cloud-sql-mssql"
|
||||
name: golang:1
|
||||
@@ -298,10 +208,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Cloud SQL MSSQL" \
|
||||
cloudsqlmssql \
|
||||
mssql
|
||||
./cloudsqlmssql.test -test.v
|
||||
|
||||
- id: "cloud-sql-mysql"
|
||||
name: golang:1
|
||||
@@ -314,17 +221,15 @@ steps:
|
||||
- "CLOUD_SQL_MYSQL_DATABASE=$_DATABASE_NAME"
|
||||
- "CLOUD_SQL_MYSQL_REGION=$_REGION"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLOUD_SQL_MYSQL_USER", "CLOUD_SQL_MYSQL_PASS", "CLIENT_ID"]
|
||||
secretEnv:
|
||||
["CLOUD_SQL_MYSQL_USER", "CLOUD_SQL_MYSQL_PASS", "CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Cloud SQL MySQL" \
|
||||
cloudsqlmysql \
|
||||
mysql || echo "Integration tests failed." # ignore test failures
|
||||
./cloudsqlmysql.test -test.v
|
||||
|
||||
- id: "mysql"
|
||||
name: golang:1
|
||||
@@ -343,10 +248,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"MySQL" \
|
||||
mysql \
|
||||
mysql || echo "Integration tests failed." # ignore test failures
|
||||
./mysql.test -test.v
|
||||
|
||||
- id: "mssql"
|
||||
name: golang:1
|
||||
@@ -365,28 +267,22 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"MSSQL" \
|
||||
mssql \
|
||||
mssql
|
||||
./mssql.test -test.v
|
||||
|
||||
# - id: "dgraph"
|
||||
# name: golang:1
|
||||
# waitFor: ["compile-test-binary"]
|
||||
# entrypoint: /bin/bash
|
||||
# env:
|
||||
# - "GOPATH=/gopath"
|
||||
# - "DGRAPH_URL=$_DGRAPHURL"
|
||||
# volumes:
|
||||
# - name: "go"
|
||||
# path: "/gopath"
|
||||
# args:
|
||||
# - -c
|
||||
# - |
|
||||
# .ci/test_with_coverage.sh \
|
||||
# "Dgraph" \
|
||||
# dgraph \
|
||||
# dgraph
|
||||
- id: "dgraph"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "DGRAPH_URL=$_DGRAPHURL"
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
./dgraph.test -test.v
|
||||
|
||||
- id: "http"
|
||||
name: golang:1
|
||||
@@ -401,10 +297,7 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"HTTP" \
|
||||
http \
|
||||
http
|
||||
./http.test -test.v
|
||||
|
||||
- id: "sqlite"
|
||||
name: golang:1
|
||||
@@ -420,13 +313,10 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"SQLite" \
|
||||
sqlite \
|
||||
sqlite
|
||||
./sqlite.test -test.v
|
||||
|
||||
- id: "couchbase"
|
||||
name: golang:1
|
||||
name : golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
@@ -434,21 +324,17 @@ steps:
|
||||
- "COUCHBASE_SCOPE=$_COUCHBASE_SCOPE"
|
||||
- "COUCHBASE_BUCKET=$_COUCHBASE_BUCKET"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv:
|
||||
["COUCHBASE_CONNECTION", "COUCHBASE_USER", "COUCHBASE_PASS", "CLIENT_ID"]
|
||||
secretEnv: ["COUCHBASE_CONNECTION", "COUCHBASE_USER", "COUCHBASE_PASS", "CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Couchbase" \
|
||||
couchbase \
|
||||
couchbase
|
||||
./couchbase.test -test.v
|
||||
|
||||
- id: "redis"
|
||||
name: golang:1
|
||||
name : golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
@@ -461,13 +347,10 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Redis" \
|
||||
redis \
|
||||
redis
|
||||
|
||||
./redis.test -test.v
|
||||
|
||||
- id: "valkey"
|
||||
name: golang:1
|
||||
name : golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
@@ -481,268 +364,9 @@ steps:
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Valkey" \
|
||||
valkey \
|
||||
valkey
|
||||
./valkey.test -test.v
|
||||
|
||||
|
||||
- id: "oceanbase"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "OCEANBASE_PORT=$_OCEANBASE_PORT"
|
||||
- "OCEANBASE_DATABASE=$_OCEANBASE_DATABASE"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv:
|
||||
["CLIENT_ID", "OCEANBASE_HOST", "OCEANBASE_USER", "OCEANBASE_PASSWORD"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"OceanBase" \
|
||||
oceanbase \
|
||||
oceanbase
|
||||
|
||||
- id: "firestore"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "FIRESTORE_PROJECT=$PROJECT_ID"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Firestore" \
|
||||
firestore \
|
||||
firestore
|
||||
|
||||
- id: "looker"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "FIRESTORE_PROJECT=$PROJECT_ID"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
- "LOOKER_VERIFY_SSL=$_LOOKER_VERIFY_SSL"
|
||||
- "LOOKER_PROJECT=$_LOOKER_PROJECT"
|
||||
- "LOOKER_LOCATION=$_LOOKER_LOCATION"
|
||||
secretEnv:
|
||||
[
|
||||
"CLIENT_ID",
|
||||
"LOOKER_BASE_URL",
|
||||
"LOOKER_CLIENT_ID",
|
||||
"LOOKER_CLIENT_SECRET",
|
||||
]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Looker" \
|
||||
looker \
|
||||
looker
|
||||
|
||||
- id: "cloud-sql"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
secretEnv: ["CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Cloud SQL Wait for Operation" \
|
||||
cloudsql \
|
||||
cloudsql
|
||||
|
||||
- id: "tidb"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "TIDB_DATABASE=$_DATABASE_NAME"
|
||||
- "TIDB_HOST=$_TIDB_HOST"
|
||||
- "TIDB_PORT=$_TIDB_PORT"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID", "TIDB_USER", "TIDB_PASS"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"TiDB" \
|
||||
tidb \
|
||||
tidbsql tidbexecutesql
|
||||
|
||||
- id: "firebird"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "FIREBIRD_DATABASE=$_FIREBIRD_DATABASE_NAME"
|
||||
- "FIREBIRD_HOST=$_FIREBIRD_HOST"
|
||||
- "FIREBIRD_PORT=$_FIREBIRD_PORT"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID", "FIREBIRD_USER", "FIREBIRD_PASS"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Firebird" \
|
||||
firebird \
|
||||
firebirdsql firebirdexecutesql
|
||||
|
||||
- id: "clickhouse"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "CLICKHOUSE_DATABASE=$_CLICKHOUSE_DATABASE"
|
||||
- "CLICKHOUSE_PORT=$_CLICKHOUSE_PORT"
|
||||
- "CLICKHOUSE_PROTOCOL=$_CLICKHOUSE_PROTOCOL"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLICKHOUSE_HOST", "CLICKHOUSE_USER", "CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"ClickHouse" \
|
||||
clickhouse \
|
||||
clickhouse
|
||||
|
||||
- id: "trino"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "TRINO_HOST=$_TRINO_HOST"
|
||||
- "TRINO_PORT=$_TRINO_PORT"
|
||||
- "TRINO_CATALOG=$_TRINO_CATALOG"
|
||||
- "TRINO_SCHEMA=$_TRINO_SCHEMA"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID", "TRINO_USER"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Trino" \
|
||||
trino \
|
||||
trinosql trinoexecutesql
|
||||
|
||||
- id: "yugabytedb"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "YUGABYTEDB_DATABASE=$_YUGABYTEDB_DATABASE"
|
||||
- "YUGABYTEDB_PORT=$_YUGABYTEDB_PORT"
|
||||
- "YUGABYTEDB_LOADBALANCE=$_YUGABYTEDB_LOADBALANCE"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv:
|
||||
["YUGABYTEDB_USER", "YUGABYTEDB_PASS", "YUGABYTEDB_HOST", "CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
./yugabytedb.test -test.v
|
||||
|
||||
|
||||
- id: "cassandra"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
secretEnv: ["CLIENT_ID", "CASSANDRA_USER", "CASSANDRA_PASS", "CASSANDRA_HOST"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Cassandra" \
|
||||
cassandra \
|
||||
cassandra
|
||||
|
||||
- id: "oracle"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "SERVICE_ACCOUNT_EMAIL=$SERVICE_ACCOUNT_EMAIL"
|
||||
- "ORACLE_SERVER_NAME=$_ORACLE_SERVER_NAME"
|
||||
secretEnv: ["CLIENT_ID", "ORACLE_USER", "ORACLE_PASS", "ORACLE_HOST"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Oracle" \
|
||||
oracle \
|
||||
oracle
|
||||
|
||||
- id: "serverless-spark"
|
||||
name: golang:1
|
||||
waitFor: ["compile-test-binary"]
|
||||
entrypoint: /bin/bash
|
||||
env:
|
||||
- "GOPATH=/gopath"
|
||||
- "SERVERLESS_SPARK_PROJECT=$PROJECT_ID"
|
||||
- "SERVERLESS_SPARK_LOCATION=$_REGION"
|
||||
secretEnv: ["CLIENT_ID"]
|
||||
volumes:
|
||||
- name: "go"
|
||||
path: "/gopath"
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
.ci/test_with_coverage.sh \
|
||||
"Serverless Spark" \
|
||||
serverlessspark
|
||||
|
||||
availableSecrets:
|
||||
secretManager:
|
||||
- versionName: projects/$PROJECT_ID/secrets/cloud_sql_pg_user/versions/latest
|
||||
@@ -780,7 +404,7 @@ availableSecrets:
|
||||
- versionName: projects/$PROJECT_ID/secrets/mysql_pass/versions/latest
|
||||
env: MYSQL_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/mssql_user/versions/latest
|
||||
env: MSSQL_USER
|
||||
env: MSSQL_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/mssql_pass/versions/latest
|
||||
env: MSSQL_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/couchbase_connection/versions/latest
|
||||
@@ -795,50 +419,7 @@ availableSecrets:
|
||||
env: REDIS_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/memorystore_valkey_address/versions/latest
|
||||
env: VALKEY_ADDRESS
|
||||
- versionName: projects/$PROJECT_ID/secrets/looker_base_url/versions/latest
|
||||
env: LOOKER_BASE_URL
|
||||
- versionName: projects/$PROJECT_ID/secrets/looker_client_id/versions/latest
|
||||
env: LOOKER_CLIENT_ID
|
||||
- versionName: projects/$PROJECT_ID/secrets/looker_client_secret/versions/latest
|
||||
env: LOOKER_CLIENT_SECRET
|
||||
- versionName: projects/$PROJECT_ID/secrets/tidb_user/versions/latest
|
||||
env: TIDB_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/tidb_pass/versions/latest
|
||||
env: TIDB_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/clickhouse_host/versions/latest
|
||||
env: CLICKHOUSE_HOST
|
||||
- versionName: projects/$PROJECT_ID/secrets/clickhouse_user/versions/latest
|
||||
env: CLICKHOUSE_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/firebird_user/versions/latest
|
||||
env: FIREBIRD_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/firebird_pass/versions/latest
|
||||
env: FIREBIRD_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/trino_user/versions/latest
|
||||
env: TRINO_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/oceanbase_host/versions/latest
|
||||
env: OCEANBASE_HOST
|
||||
- versionName: projects/$PROJECT_ID/secrets/oceanbase_user/versions/latest
|
||||
env: OCEANBASE_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/oceanbase_pass/versions/latest
|
||||
env: OCEANBASE_PASSWORD
|
||||
- versionName: projects/$PROJECT_ID/secrets/yugabytedb_host/versions/latest
|
||||
env: YUGABYTEDB_HOST
|
||||
- versionName: projects/$PROJECT_ID/secrets/yugabytedb_user/versions/latest
|
||||
env: YUGABYTEDB_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/yugabytedb_pass/versions/latest
|
||||
env: YUGABYTEDB_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/cassandra_user/versions/latest
|
||||
env: CASSANDRA_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/cassandra_pass/versions/latest
|
||||
env: CASSANDRA_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/cassandra_host/versions/latest
|
||||
env: CASSANDRA_HOST
|
||||
- versionName: projects/$PROJECT_ID/secrets/oracle_user/versions/latest
|
||||
env: ORACLE_USER
|
||||
- versionName: projects/$PROJECT_ID/secrets/oracle_pass/versions/latest
|
||||
env: ORACLE_PASS
|
||||
- versionName: projects/$PROJECT_ID/secrets/oracle_host/versions/latest
|
||||
env: ORACLE_HOST
|
||||
|
||||
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
@@ -850,7 +431,6 @@ options:
|
||||
|
||||
substitutions:
|
||||
_DATABASE_NAME: test_database
|
||||
_FIREBIRD_DATABASE_NAME: /firebird/test_database.fdb
|
||||
_REGION: "us-central1"
|
||||
_CLOUD_SQL_POSTGRES_INSTANCE: "cloud-sql-pg-testing"
|
||||
_ALLOYDB_POSTGRES_CLUSTER: "alloydb-pg-testing"
|
||||
@@ -870,24 +450,4 @@ substitutions:
|
||||
_MSSQL_PORT: "1433"
|
||||
_DGRAPHURL: "https://play.dgraph.io"
|
||||
_COUCHBASE_BUCKET: "couchbase-bucket"
|
||||
_COUCHBASE_SCOPE: "couchbase-scope"
|
||||
_LOOKER_LOCATION: "us"
|
||||
_LOOKER_PROJECT: "149671255749"
|
||||
_LOOKER_VERIFY_SSL: "true"
|
||||
_TIDB_HOST: 127.0.0.1
|
||||
_TIDB_PORT: "4000"
|
||||
_CLICKHOUSE_DATABASE: "default"
|
||||
_CLICKHOUSE_PORT: "8123"
|
||||
_CLICKHOUSE_PROTOCOL: "http"
|
||||
_FIREBIRD_HOST: 127.0.0.1
|
||||
_FIREBIRD_PORT: "3050"
|
||||
_TRINO_HOST: 127.0.0.1
|
||||
_TRINO_PORT: "8080"
|
||||
_TRINO_CATALOG: "memory"
|
||||
_TRINO_SCHEMA: "default"
|
||||
_OCEANBASE_PORT: "2883"
|
||||
_OCEANBASE_DATABASE: "oceanbase"
|
||||
_YUGABYTEDB_DATABASE: "yugabyte"
|
||||
_YUGABYTEDB_PORT: "5433"
|
||||
_YUGABYTEDB_LOADBALANCE: "false"
|
||||
_ORACLE_SERVER_NAME: "FREEPDB1"
|
||||
_COUCHBASE_SCOPE: "couchbase-scope"
|
||||
@@ -1,47 +0,0 @@
|
||||
# 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.
|
||||
|
||||
steps:
|
||||
- name: 'golang:1.25.1'
|
||||
id: 'go-quickstart-test'
|
||||
entrypoint: 'bash'
|
||||
args:
|
||||
# The '-c' flag tells bash to execute the following string as a command.
|
||||
# The 'set -ex' enables debug output and exits on error for easier troubleshooting.
|
||||
- -c
|
||||
- |
|
||||
set -ex
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
chmod +x .ci/quickstart_test/run_go_tests.sh
|
||||
.ci/quickstart_test/run_go_tests.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/7
|
||||
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: 1000s
|
||||
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
@@ -1,47 +0,0 @@
|
||||
# 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.
|
||||
|
||||
steps:
|
||||
- name: 'node:20'
|
||||
id: 'js-quickstart-test'
|
||||
entrypoint: 'bash'
|
||||
args:
|
||||
# The '-c' flag tells bash to execute the following string as a command.
|
||||
# The 'set -ex' enables debug output and exits on error for easier troubleshooting.
|
||||
- -c
|
||||
- |
|
||||
set -ex
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
chmod +x .ci/quickstart_test/run_js_tests.sh
|
||||
.ci/quickstart_test/run_js_tests.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/6
|
||||
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: 1000s
|
||||
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
@@ -1,47 +0,0 @@
|
||||
# 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.
|
||||
|
||||
steps:
|
||||
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk:537.0.0'
|
||||
id: 'python-quickstart-test'
|
||||
entrypoint: 'bash'
|
||||
args:
|
||||
# The '-c' flag tells bash to execute the following string as a command.
|
||||
# The 'set -ex' enables debug output and exits on error for easier troubleshooting.
|
||||
- -c
|
||||
- |
|
||||
set -ex
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
chmod +x .ci/quickstart_test/run_py_tests.sh
|
||||
.ci/quickstart_test/run_py_tests.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/5
|
||||
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: 1000s
|
||||
|
||||
options:
|
||||
logging: CLOUD_LOGGING_ONLY
|
||||
@@ -1,125 +0,0 @@
|
||||
# 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.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TABLE_NAME="hotels_go"
|
||||
QUICKSTART_GO_DIR="docs/en/getting-started/quickstart/go"
|
||||
SQL_FILE=".ci/quickstart_test/setup_hotels_sample.sql"
|
||||
|
||||
PROXY_PID=""
|
||||
TOOLBOX_PID=""
|
||||
|
||||
install_system_packages() {
|
||||
apt-get update && apt-get install -y \
|
||||
postgresql-client \
|
||||
wget \
|
||||
gettext-base \
|
||||
netcat-openbsd
|
||||
}
|
||||
|
||||
start_cloud_sql_proxy() {
|
||||
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=$!
|
||||
|
||||
for i in {1..30}; do
|
||||
if nc -z 127.0.0.1 5432; then
|
||||
echo "Cloud SQL Proxy is up and running."
|
||||
return
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Cloud SQL Proxy failed to start within the timeout period."
|
||||
exit 1
|
||||
}
|
||||
|
||||
setup_toolbox() {
|
||||
TOOLBOX_YAML="/tools.yaml"
|
||||
echo "${TOOLS_YAML_CONTENT}" > "$TOOLBOX_YAML"
|
||||
if [ ! -f "$TOOLBOX_YAML" ]; then echo "Failed to create tools.yaml"; exit 1; fi
|
||||
wget "https://storage.googleapis.com/genai-toolbox/v${VERSION}/linux/amd64/toolbox" -O "/toolbox"
|
||||
chmod +x "/toolbox"
|
||||
/toolbox --tools-file "$TOOLBOX_YAML" &
|
||||
TOOLBOX_PID=$!
|
||||
sleep 2
|
||||
}
|
||||
|
||||
setup_orch_table() {
|
||||
export TABLE_NAME
|
||||
envsubst < "$SQL_FILE" | psql -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DATABASE_NAME"
|
||||
}
|
||||
|
||||
run_orch_test() {
|
||||
local orch_dir="$1"
|
||||
local orch_name
|
||||
orch_name=$(basename "$orch_dir")
|
||||
|
||||
if [ "$orch_name" == "openAI" ]; then
|
||||
echo -e "\nSkipping framework '${orch_name}': Temporarily excluded."
|
||||
return
|
||||
fi
|
||||
|
||||
(
|
||||
set -e
|
||||
setup_orch_table
|
||||
|
||||
echo "--- Preparing module for $orch_name ---"
|
||||
cd "$orch_dir"
|
||||
|
||||
if [ -f "go.mod" ]; then
|
||||
go mod tidy
|
||||
fi
|
||||
|
||||
cd ..
|
||||
|
||||
export ORCH_NAME="$orch_name"
|
||||
|
||||
echo "--- Running tests for $orch_name ---"
|
||||
go test -v ./...
|
||||
)
|
||||
}
|
||||
|
||||
cleanup_all() {
|
||||
echo "--- Final cleanup: Shutting down processes and dropping table ---"
|
||||
if [ -n "$TOOLBOX_PID" ]; then
|
||||
kill $TOOLBOX_PID || true
|
||||
fi
|
||||
if [ -n "$PROXY_PID" ]; then
|
||||
kill $PROXY_PID || true
|
||||
fi
|
||||
}
|
||||
trap cleanup_all EXIT
|
||||
|
||||
# Main script execution
|
||||
install_system_packages
|
||||
start_cloud_sql_proxy
|
||||
|
||||
export PGHOST=127.0.0.1
|
||||
export PGPORT=5432
|
||||
export PGPASSWORD="$DB_PASSWORD"
|
||||
export GOOGLE_API_KEY="$GOOGLE_API_KEY"
|
||||
|
||||
setup_toolbox
|
||||
|
||||
for ORCH_DIR in "$QUICKSTART_GO_DIR"/*/; do
|
||||
if [ ! -d "$ORCH_DIR" ]; then
|
||||
continue
|
||||
fi
|
||||
run_orch_test "$ORCH_DIR"
|
||||
done
|
||||
@@ -1,123 +0,0 @@
|
||||
# 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.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TABLE_NAME="hotels_js"
|
||||
QUICKSTART_JS_DIR="docs/en/getting-started/quickstart/js"
|
||||
SQL_FILE=".ci/quickstart_test/setup_hotels_sample.sql"
|
||||
|
||||
# Initialize process IDs to empty at the top of the script
|
||||
PROXY_PID=""
|
||||
TOOLBOX_PID=""
|
||||
|
||||
install_system_packages() {
|
||||
apt-get update && apt-get install -y \
|
||||
postgresql-client \
|
||||
wget \
|
||||
gettext-base \
|
||||
netcat-openbsd
|
||||
}
|
||||
|
||||
start_cloud_sql_proxy() {
|
||||
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=$!
|
||||
|
||||
for i in {1..30}; do
|
||||
if nc -z 127.0.0.1 5432; then
|
||||
echo "Cloud SQL Proxy is up and running."
|
||||
return
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Cloud SQL Proxy failed to start within the timeout period."
|
||||
exit 1
|
||||
}
|
||||
|
||||
setup_toolbox() {
|
||||
TOOLBOX_YAML="/tools.yaml"
|
||||
echo "${TOOLS_YAML_CONTENT}" > "$TOOLBOX_YAML"
|
||||
if [ ! -f "$TOOLBOX_YAML" ]; then echo "Failed to create tools.yaml"; exit 1; fi
|
||||
wget "https://storage.googleapis.com/genai-toolbox/v${VERSION}/linux/amd64/toolbox" -O "/toolbox"
|
||||
chmod +x "/toolbox"
|
||||
/toolbox --tools-file "$TOOLBOX_YAML" &
|
||||
TOOLBOX_PID=$!
|
||||
sleep 2
|
||||
}
|
||||
|
||||
setup_orch_table() {
|
||||
export TABLE_NAME
|
||||
envsubst < "$SQL_FILE" | psql -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DATABASE_NAME"
|
||||
}
|
||||
|
||||
run_orch_test() {
|
||||
local orch_dir="$1"
|
||||
local orch_name
|
||||
orch_name=$(basename "$orch_dir")
|
||||
|
||||
(
|
||||
set -e
|
||||
echo "--- Preparing environment for $orch_name ---"
|
||||
setup_orch_table
|
||||
|
||||
cd "$orch_dir"
|
||||
if [ -f "package.json" ]; then
|
||||
echo "Installing dependencies for $orch_name..."
|
||||
npm install
|
||||
fi
|
||||
|
||||
cd ..
|
||||
|
||||
echo "--- Running tests for $orch_name ---"
|
||||
export ORCH_NAME="$orch_name"
|
||||
node --test quickstart.test.js
|
||||
|
||||
echo "--- Cleaning environment for $orch_name ---"
|
||||
rm -rf "${orch_name}/node_modules"
|
||||
)
|
||||
}
|
||||
|
||||
cleanup_all() {
|
||||
echo "--- Final cleanup: Shutting down processes and dropping table ---"
|
||||
if [ -n "$TOOLBOX_PID" ]; then
|
||||
kill $TOOLBOX_PID || true
|
||||
fi
|
||||
if [ -n "$PROXY_PID" ]; then
|
||||
kill $PROXY_PID || true
|
||||
fi
|
||||
}
|
||||
trap cleanup_all EXIT
|
||||
|
||||
# Main script execution
|
||||
install_system_packages
|
||||
start_cloud_sql_proxy
|
||||
|
||||
export PGHOST=127.0.0.1
|
||||
export PGPORT=5432
|
||||
export PGPASSWORD="$DB_PASSWORD"
|
||||
export GOOGLE_API_KEY="$GOOGLE_API_KEY"
|
||||
|
||||
setup_toolbox
|
||||
|
||||
for ORCH_DIR in "$QUICKSTART_JS_DIR"/*/; do
|
||||
if [ ! -d "$ORCH_DIR" ]; then
|
||||
continue
|
||||
fi
|
||||
run_orch_test "$ORCH_DIR"
|
||||
done
|
||||
@@ -1,115 +0,0 @@
|
||||
# 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.
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TABLE_NAME="hotels_python"
|
||||
QUICKSTART_PYTHON_DIR="docs/en/getting-started/quickstart/python"
|
||||
SQL_FILE=".ci/quickstart_test/setup_hotels_sample.sql"
|
||||
|
||||
PROXY_PID=""
|
||||
TOOLBOX_PID=""
|
||||
|
||||
install_system_packages() {
|
||||
apt-get update && apt-get install -y \
|
||||
postgresql-client \
|
||||
python3-venv \
|
||||
wget \
|
||||
gettext-base \
|
||||
netcat-openbsd
|
||||
}
|
||||
|
||||
start_cloud_sql_proxy() {
|
||||
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=$!
|
||||
|
||||
for i in {1..30}; do
|
||||
if nc -z 127.0.0.1 5432; then
|
||||
echo "Cloud SQL Proxy is up and running."
|
||||
return
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Cloud SQL Proxy failed to start within the timeout period."
|
||||
exit 1
|
||||
}
|
||||
|
||||
setup_toolbox() {
|
||||
TOOLBOX_YAML="/tools.yaml"
|
||||
echo "${TOOLS_YAML_CONTENT}" > "$TOOLBOX_YAML"
|
||||
if [ ! -f "$TOOLBOX_YAML" ]; then echo "Failed to create tools.yaml"; exit 1; fi
|
||||
wget "https://storage.googleapis.com/genai-toolbox/v${VERSION}/linux/amd64/toolbox" -O "/toolbox"
|
||||
chmod +x "/toolbox"
|
||||
/toolbox --tools-file "$TOOLBOX_YAML" &
|
||||
TOOLBOX_PID=$!
|
||||
sleep 2
|
||||
}
|
||||
|
||||
setup_orch_table() {
|
||||
export TABLE_NAME
|
||||
envsubst < "$SQL_FILE" | psql -h "$PGHOST" -p "$PGPORT" -U "$DB_USER" -d "$DATABASE_NAME"
|
||||
}
|
||||
|
||||
run_orch_test() {
|
||||
local orch_dir="$1"
|
||||
local orch_name
|
||||
orch_name=$(basename "$orch_dir")
|
||||
(
|
||||
set -e
|
||||
setup_orch_table
|
||||
cd "$orch_dir"
|
||||
local VENV_DIR=".venv"
|
||||
python3 -m venv "$VENV_DIR"
|
||||
source "$VENV_DIR/bin/activate"
|
||||
pip install -r requirements.txt
|
||||
echo "--- Running tests for $orch_name ---"
|
||||
cd ..
|
||||
ORCH_NAME="$orch_name" pytest
|
||||
rm -rf "$VENV_DIR"
|
||||
)
|
||||
}
|
||||
|
||||
cleanup_all() {
|
||||
echo "--- Final cleanup: Shutting down processes and dropping table ---"
|
||||
if [ -n "$TOOLBOX_PID" ]; then
|
||||
kill $TOOLBOX_PID || true
|
||||
fi
|
||||
if [ -n "$PROXY_PID" ]; then
|
||||
kill $PROXY_PID || true
|
||||
fi
|
||||
}
|
||||
trap cleanup_all EXIT
|
||||
|
||||
# Main script execution
|
||||
install_system_packages
|
||||
start_cloud_sql_proxy
|
||||
|
||||
export PGHOST=127.0.0.1
|
||||
export PGPORT=5432
|
||||
export PGPASSWORD="$DB_PASSWORD"
|
||||
export GOOGLE_API_KEY="$GOOGLE_API_KEY"
|
||||
|
||||
setup_toolbox
|
||||
|
||||
for ORCH_DIR in "$QUICKSTART_PYTHON_DIR"/*/; do
|
||||
if [ ! -d "$ORCH_DIR" ]; then
|
||||
continue
|
||||
fi
|
||||
run_orch_test "$ORCH_DIR"
|
||||
done
|
||||
@@ -1,28 +0,0 @@
|
||||
-- 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.
|
||||
|
||||
TRUNCATE TABLE $TABLE_NAME;
|
||||
|
||||
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');
|
||||
@@ -1,62 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Arguments:
|
||||
# $1: Display name for logs (e.g., "Cloud SQL Postgres")
|
||||
# $2: Integration test's package name (e.g., cloudsqlpg)
|
||||
# $3, $4, ...: Tool package names for grep (e.g., postgressql), if the
|
||||
# integration test specifically check a separate package inside a folder, please
|
||||
# specify the full path instead (e.g., postgressql/postgresexecutesql)
|
||||
|
||||
DISPLAY_NAME="$1"
|
||||
SOURCE_PACKAGE_NAME="$2"
|
||||
|
||||
# Construct the test binary name
|
||||
TEST_BINARY="${SOURCE_PACKAGE_NAME}.test"
|
||||
|
||||
# Construct the full source path
|
||||
SOURCE_PATH="sources/${SOURCE_PACKAGE_NAME}/"
|
||||
|
||||
# Shift arguments so that $3 and onwards become the list of tool package names
|
||||
shift 2
|
||||
TOOL_PACKAGE_NAMES=("$@")
|
||||
|
||||
COVERAGE_FILE="${TEST_BINARY%.test}_coverage.out"
|
||||
FILTERED_COVERAGE_FILE="${TEST_BINARY%.test}_filtered_coverage.out"
|
||||
|
||||
export path="github.com/googleapis/genai-toolbox/internal/"
|
||||
|
||||
GREP_PATTERN="^mode:|${path}${SOURCE_PATH}"
|
||||
# Add each tool package path to the grep pattern
|
||||
for tool_name in "${TOOL_PACKAGE_NAMES[@]}"; do
|
||||
if [ -n "$tool_name" ]; then
|
||||
full_tool_path="tools/${tool_name}/"
|
||||
GREP_PATTERN="${GREP_PATTERN}|${path}${full_tool_path}"
|
||||
fi
|
||||
done
|
||||
|
||||
# Run integration test
|
||||
if ! ./"${TEST_BINARY}" -test.v -test.coverprofile="${COVERAGE_FILE}"; then
|
||||
echo "Error: Tests for ${DISPLAY_NAME} failed. Exiting."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Filter source/tool packages
|
||||
if ! grep -E "${GREP_PATTERN}" "${COVERAGE_FILE}" > "${FILTERED_COVERAGE_FILE}"; then
|
||||
echo "Warning: Could not filter coverage for ${DISPLAY_NAME}. Filtered file might be empty or invalid."
|
||||
fi
|
||||
|
||||
# Calculate coverage
|
||||
echo "Calculating coverage for ${DISPLAY_NAME}..."
|
||||
total_coverage=$(go tool cover -func="${FILTERED_COVERAGE_FILE}" 2>/dev/null | grep "total:" | awk '{print $3}')
|
||||
|
||||
|
||||
echo "${DISPLAY_NAME} total coverage: $total_coverage"
|
||||
coverage_numeric=$(echo "$total_coverage" | sed 's/%//')
|
||||
|
||||
# Check coverage threshold
|
||||
if awk -v coverage="$coverage_numeric" 'BEGIN {exit !(coverage < 50)}'; then
|
||||
echo "Coverage failure: ${DISPLAY_NAME} total coverage($total_coverage) is below 50%."
|
||||
exit 1
|
||||
else
|
||||
echo "Coverage for ${DISPLAY_NAME} is sufficient."
|
||||
fi
|
||||
@@ -24,7 +24,7 @@ steps:
|
||||
if [[ $_PUSH_LATEST == 'true' ]]; then
|
||||
export TAGS="$TAGS -t ${_DOCKER_URI}:latest"
|
||||
fi
|
||||
docker buildx build --platform linux/amd64,linux/arm64 --build-arg BUILD_TYPE=container.release --build-arg COMMIT_SHA=$(git rev-parse --short HEAD) $TAGS --push .
|
||||
docker buildx build --platform linux/amd64,linux/arm64 --build-arg BUILD_TYPE=container.release --build-arg COMMIT_SHA=$(git rev-parse HEAD) $TAGS --push .
|
||||
|
||||
- id: "install-dependencies"
|
||||
name: golang:1
|
||||
@@ -50,7 +50,7 @@ steps:
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.linux.amd64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.linux.amd64
|
||||
|
||||
- id: "store-linux-amd64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -61,30 +61,6 @@ steps:
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.linux.amd64 gs://$_BUCKET_NAME/$VERSION/linux/amd64/toolbox
|
||||
|
||||
- id: "build-linux-amd64-geminicli"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
- "install-dependencies"
|
||||
env:
|
||||
- 'GOPATH=/gopath'
|
||||
volumes:
|
||||
- name: 'go'
|
||||
path: '/gopath'
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=geminicli.binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.geminicli.linux.amd64
|
||||
|
||||
- id: "store-linux-amd64-geminicli"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
waitFor:
|
||||
- "build-linux-amd64-geminicli"
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.geminicli.linux.amd64 gs://$_BUCKET_NAME/geminicli/$VERSION/linux/amd64/toolbox
|
||||
|
||||
- id: "build-darwin-arm64"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
@@ -98,7 +74,7 @@ steps:
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.darwin.arm64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.arm64
|
||||
|
||||
- id: "store-darwin-arm64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -109,30 +85,6 @@ steps:
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.darwin.arm64 gs://$_BUCKET_NAME/$VERSION/darwin/arm64/toolbox
|
||||
|
||||
- id: "build-darwin-arm64-geminicli"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
- "install-dependencies"
|
||||
env:
|
||||
- 'GOPATH=/gopath'
|
||||
volumes:
|
||||
- name: 'go'
|
||||
path: '/gopath'
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=arm64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=geminicli.binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.geminicli.darwin.arm64
|
||||
|
||||
- id: "store-darwin-arm64-geminicli"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
waitFor:
|
||||
- "build-darwin-arm64-geminicli"
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.geminicli.darwin.arm64 gs://$_BUCKET_NAME/geminicli/$VERSION/darwin/arm64/toolbox
|
||||
|
||||
- id: "build-darwin-amd64"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
@@ -146,7 +98,7 @@ steps:
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.darwin.amd64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.darwin.amd64
|
||||
|
||||
- id: "store-darwin-amd64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -157,30 +109,6 @@ steps:
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.darwin.amd64 gs://$_BUCKET_NAME/$VERSION/darwin/amd64/toolbox
|
||||
|
||||
- id: "build-darwin-amd64-geminicli"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
- "install-dependencies"
|
||||
env:
|
||||
- 'GOPATH=/gopath'
|
||||
volumes:
|
||||
- name: 'go'
|
||||
path: '/gopath'
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=geminicli.binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.geminicli.darwin.amd64
|
||||
|
||||
- id: "store-darwin-amd64-geminicli"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
waitFor:
|
||||
- "build-darwin-amd64-geminicli"
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.geminicli.darwin.amd64 gs://$_BUCKET_NAME/geminicli/$VERSION/darwin/amd64/toolbox
|
||||
|
||||
- id: "build-windows-amd64"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
@@ -194,7 +122,7 @@ steps:
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.windows.amd64
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse HEAD)" -o toolbox.windows.amd64
|
||||
|
||||
- id: "store-windows-amd64"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
@@ -205,30 +133,6 @@ steps:
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.windows.amd64 gs://$_BUCKET_NAME/$VERSION/windows/amd64/toolbox.exe
|
||||
|
||||
- id: "build-windows-amd64-geminicli"
|
||||
name: golang:1
|
||||
waitFor:
|
||||
- "install-dependencies"
|
||||
env:
|
||||
- 'GOPATH=/gopath'
|
||||
volumes:
|
||||
- name: 'go'
|
||||
path: '/gopath'
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=$(cat ./cmd/version.txt)
|
||||
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=geminicli.binary -X github.com/googleapis/genai-toolbox/cmd.commitSha=$(git rev-parse --short HEAD)" -o toolbox.geminicli.windows.amd64
|
||||
|
||||
- id: "store-windows-amd64-geminicli"
|
||||
name: "gcr.io/cloud-builders/gcloud:latest"
|
||||
waitFor:
|
||||
- "build-windows-amd64-geminicli"
|
||||
script: |
|
||||
#!/usr/bin/env bash
|
||||
export VERSION=v$(cat ./cmd/version.txt)
|
||||
gcloud storage cp toolbox.geminicli.windows.amd64 gs://$_BUCKET_NAME/geminicli/$VERSION/windows/amd64/toolbox.exe
|
||||
|
||||
options:
|
||||
automapSubstitutions: true
|
||||
dynamicSubstitutions: true
|
||||
|
||||
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
22
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,22 +0,0 @@
|
||||
## Description
|
||||
|
||||
> Should include a concise description of the changes (bug or feature), it's
|
||||
> impact, along with a summary of the solution
|
||||
|
||||
## PR Checklist
|
||||
|
||||
> Thank you for opening a Pull Request! Before submitting your PR, there are a
|
||||
> few things you can do to make sure it goes smoothly:
|
||||
|
||||
- [ ] Make sure you reviewed
|
||||
[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
|
||||
- [ ] Make sure to open an issue as a
|
||||
[bug/issue](https://github.com/googleapis/genai-toolbox/issues/new/choose)
|
||||
before writing your code! That way we can discuss the change, evaluate
|
||||
designs, and agree on the general idea
|
||||
- [ ] Ensure the tests and linter pass
|
||||
- [ ] Code coverage does not decrease (if any source code was changed)
|
||||
- [ ] Appropriate docs were updated (if necessary)
|
||||
- [ ] Make sure to add `!` if this involve a breaking change
|
||||
|
||||
🛠️ Fixes #<issue_number_goes_here>
|
||||
25
.github/blunderbuss.yml
vendored
25
.github/blunderbuss.yml
vendored
@@ -1,24 +1,7 @@
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
|
||||
assign_issues:
|
||||
- kurtisvg
|
||||
- Yuan325
|
||||
- duwenxin99
|
||||
- averikitsch
|
||||
- anubhav756
|
||||
- dishaprakash
|
||||
- twishabansal
|
||||
assign_issues_by:
|
||||
- labels:
|
||||
- 'product: bigquery'
|
||||
@@ -26,11 +9,7 @@ assign_issues_by:
|
||||
- Genesis929
|
||||
- shobsi
|
||||
- jiaxunwu
|
||||
- labels:
|
||||
- 'product: looker'
|
||||
to:
|
||||
- drstrangelooker
|
||||
assign_prs:
|
||||
- kurtisvg
|
||||
- Yuan325
|
||||
- duwenxin99
|
||||
- averikitsch
|
||||
|
||||
@@ -14,14 +14,9 @@
|
||||
|
||||
allowedCopyrightHolders:
|
||||
- 'Google LLC'
|
||||
- 'Oracle'
|
||||
allowedLicenses:
|
||||
- 'Apache-2.0'
|
||||
sourceFileExtensions:
|
||||
- 'go'
|
||||
- 'yaml'
|
||||
- 'yml'
|
||||
ignoreFiles:
|
||||
- 'docs/en/getting-started/quickstart/**'
|
||||
- '**/*oracle*'
|
||||
|
||||
32
.github/labels.yaml
vendored
32
.github/labels.yaml
vendored
@@ -50,7 +50,7 @@
|
||||
color: ffffc7
|
||||
description: Desirable enhancement or fix. May not be included in next release.
|
||||
|
||||
- name: 'do not merge'
|
||||
- name: do not merge
|
||||
color: d93f0b
|
||||
description: Indicates a pull request not ready for merge, due to either quality
|
||||
or timing.
|
||||
@@ -65,38 +65,28 @@
|
||||
color: ededed
|
||||
description: Release please has completed a release for this.
|
||||
|
||||
- name: 'blunderbuss: assign'
|
||||
color: 3DED97
|
||||
description: Have blunderbuss assign this to someone new.
|
||||
|
||||
- name: 'tests: run'
|
||||
color: 3DED97
|
||||
description: Label to trigger Github Action tests.
|
||||
|
||||
|
||||
- name: 'docs: deploy-preview'
|
||||
color: BFDADC
|
||||
description: Label to trigger Github Action docs preview.
|
||||
|
||||
- name: 'status: help wanted'
|
||||
- name: 'status: contribution welcome'
|
||||
color: 8befd7
|
||||
description: 'Status: Unplanned work open to contributions from the community.'
|
||||
- name: 'status: feedback wanted'
|
||||
color: 8befd7
|
||||
description: 'Status: waiting for feedback from community or issue author.'
|
||||
description: Status - Contributions welcome.
|
||||
|
||||
- name: 'status: waiting for response'
|
||||
- name: 'status: awaiting response'
|
||||
color: 8befd7
|
||||
description: 'Status: reviewer is awaiting feedback or responses from the author before proceeding.'
|
||||
description: Status - Awaiting response from author.
|
||||
|
||||
- name: 'release candidate'
|
||||
color: 32CD32
|
||||
description: 'Use label to signal PR should be included in the next release.'
|
||||
- name: 'status: awaiting codeowners'
|
||||
color: 8befd7
|
||||
description: Status - Awaiting response from code owners.
|
||||
|
||||
# Product Labels
|
||||
- name: 'product: bigquery'
|
||||
color: 5065c7
|
||||
description: 'Product: Assigned to the BigQuery team.'
|
||||
# Product Labels
|
||||
- name: 'product: looker'
|
||||
color: 5065c7
|
||||
description: 'Product: Assigned to the Looker team.'
|
||||
description: Product - Assigned to the BigQuery team.
|
||||
|
||||
|
||||
24
.github/release-please.yml
vendored
24
.github/release-please.yml
vendored
@@ -18,24 +18,18 @@ releaseType: simple
|
||||
versionFile: "cmd/version.txt"
|
||||
extraFiles: [
|
||||
"README.md",
|
||||
"docs/en/getting-started/colab_quickstart.ipynb",
|
||||
"docs/en/getting-started/introduction/_index.md",
|
||||
"docs/en/getting-started/local_quickstart.md",
|
||||
"docs/en/getting-started/mcp_quickstart/_index.md",
|
||||
"docs/en/getting-started/quickstart/shared/configure_toolbox.md",
|
||||
"docs/en/samples/alloydb/_index.md",
|
||||
"docs/en/samples/alloydb/mcp_quickstart.md",
|
||||
"docs/en/samples/alloydb/ai-nl/alloydb_ai_nl.ipynb",
|
||||
"docs/en/samples/bigquery/local_quickstart.md",
|
||||
"docs/en/samples/bigquery/mcp_quickstart/_index.md",
|
||||
"docs/en/getting-started/colab_quickstart.ipynb",
|
||||
"docs/en/samples/bigquery/colab_quickstart_bigquery.ipynb",
|
||||
"docs/en/samples/looker/looker_gemini.md",
|
||||
"docs/en/samples/looker/looker_gemini_oauth/_index.md",
|
||||
"docs/en/samples/looker/looker_mcp_inspector/_index.md",
|
||||
"docs/en/how-to/connect-ide/looker_mcp.md",
|
||||
"docs/en/how-to/connect-ide/mysql_mcp.md",
|
||||
"docs/en/how-to/connect-ide/mssql_mcp.md",
|
||||
"docs/en/how-to/connect-ide/bigquery_mcp.md",
|
||||
"docs/en/how-to/connect-ide/spanner_mcp.md",
|
||||
"docs/en/how-to/connect-ide/alloydb_pg_mcp.md",
|
||||
"docs/en/how-to/connect-ide/cloud_sql_mysql_mcp.md",
|
||||
"docs/en/how-to/connect-ide/cloud_sql_pg_mcp.md",
|
||||
"docs/en/how-to/connect-ide/postgres_mcp.md",
|
||||
"docs/en/how-to/connect-ide/neo4j_mcp.md",
|
||||
"docs/en/how-to/connect-ide/sqlite_mcp.md",
|
||||
"gemini-extension.json",
|
||||
]
|
||||
"docs/en/how-to/connect-ide/cloud_sql_mssql_mcp.md",
|
||||
]
|
||||
|
||||
@@ -37,7 +37,7 @@ jobs:
|
||||
runs-on: 'ubuntu-latest'
|
||||
|
||||
steps:
|
||||
- uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # v8
|
||||
- uses: 'actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea' # v7
|
||||
with:
|
||||
script: |-
|
||||
// parse test names
|
||||
|
||||
85
.github/workflows/deploy_dev_docs.yaml
vendored
85
.github/workflows/deploy_dev_docs.yaml
vendored
@@ -1,85 +0,0 @@
|
||||
# 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.
|
||||
|
||||
name: "Deploy In-development docs"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'docs/**'
|
||||
- 'github/workflows/docs**'
|
||||
- '.hugo/**'
|
||||
|
||||
# Allow triggering manually.
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-24.04
|
||||
defaults:
|
||||
run:
|
||||
working-directory: .hugo
|
||||
# This shared concurrency group ensures only one docs deployment runs at a time.
|
||||
concurrency:
|
||||
group: docs-deployment
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||
|
||||
- name: Setup Hugo
|
||||
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3
|
||||
with:
|
||||
hugo-version: "0.145.0"
|
||||
extended: true
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
|
||||
- run: npm ci
|
||||
- run: hugo --minify
|
||||
env:
|
||||
HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/dev
|
||||
HUGO_RELATIVEURLS: false
|
||||
|
||||
- name: Create Staging Directory
|
||||
run: |
|
||||
mkdir staging
|
||||
mv public staging/dev
|
||||
mv staging/dev/releases.releases staging/releases.releases
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./.hugo/staging
|
||||
publish_branch: versioned-gh-pages
|
||||
keep_files: true
|
||||
commit_message: "deploy: ${{ github.event.head_commit.message }}"
|
||||
104
.github/workflows/deploy_previous_version_docs.yaml
vendored
104
.github/workflows/deploy_previous_version_docs.yaml
vendored
@@ -1,104 +0,0 @@
|
||||
# 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.
|
||||
|
||||
name: "Deploy Previous Version Docs"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version_tag:
|
||||
description: 'The old version tag to build docs for (e.g., v0.15.0)'
|
||||
required: true
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build_and_deploy:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout main branch (for latest templates and theme)
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
ref: 'main'
|
||||
submodules: 'recursive'
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Checkout old content from tag into a temporary directory
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
ref: ${{ github.event.inputs.version_tag }}
|
||||
path: 'old_version_source' # Checkout into a temp subdir
|
||||
# Sparse checkout to only get the content directory
|
||||
sparse-checkout: |
|
||||
docs
|
||||
|
||||
- name: Replace content with old version
|
||||
run: |
|
||||
# Remove the current content directory from the main branch checkout
|
||||
rm -rf docs/
|
||||
# Move the old content directory into place
|
||||
mv ./old_version_source/docs docs
|
||||
|
||||
- name: Setup Hugo and Node
|
||||
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3
|
||||
with:
|
||||
hugo-version: "0.145.0"
|
||||
extended: true
|
||||
- uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
working-directory: .hugo
|
||||
|
||||
- name: Build Hugo Site for Archived Version
|
||||
run: hugo --minify
|
||||
working-directory: .hugo
|
||||
env:
|
||||
HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ github.event.inputs.version_tag }}/
|
||||
HUGO_RELATIVEURLS: false
|
||||
|
||||
- name: Deploy to gh-pages
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: .hugo/public
|
||||
publish_branch: versioned-gh-pages
|
||||
destination_dir: ./${{ github.event.inputs.version_tag }}
|
||||
keep_files: true
|
||||
allow_empty_commit: true
|
||||
commit_message: "docs(backport): deploy docs for ${{ github.event.inputs.version_tag }}"
|
||||
|
||||
- name: Clean Build Directory
|
||||
run: rm -rf .hugo/public
|
||||
|
||||
- name: Build Hugo Site
|
||||
run: hugo --minify
|
||||
working-directory: .hugo
|
||||
env:
|
||||
HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/
|
||||
HUGO_RELATIVEURLS: false
|
||||
|
||||
- name: Deploy to root
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: .hugo/public
|
||||
publish_branch: versioned-gh-pages
|
||||
keep_files: true
|
||||
allow_empty_commit: true
|
||||
commit_message: "deploy: docs to root for ${{ github.event.inputs.version_tag }}"
|
||||
90
.github/workflows/deploy_versioned_docs.yaml
vendored
90
.github/workflows/deploy_versioned_docs.yaml
vendored
@@ -1,90 +0,0 @@
|
||||
# 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.
|
||||
|
||||
name: "Deploy Versioned Docs"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-24.04
|
||||
# This shared concurrency group ensures only one docs deployment runs at a time.
|
||||
concurrency:
|
||||
group: docs-deployment
|
||||
cancel-in-progress: false
|
||||
steps:
|
||||
- name: Checkout Code at Tag
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
with:
|
||||
ref: ${{ github.event.release.tag_name }}
|
||||
|
||||
- name: Get Version from Release Tag
|
||||
run: echo "VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup Hugo
|
||||
uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3
|
||||
with:
|
||||
hugo-version: "0.145.0"
|
||||
extended: true
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
working-directory: .hugo
|
||||
|
||||
- name: Build Hugo Site
|
||||
run: hugo --minify
|
||||
working-directory: .hugo
|
||||
env:
|
||||
HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/${{ env.VERSION }}/
|
||||
HUGO_RELATIVEURLS: false
|
||||
|
||||
- name: Deploy
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: .hugo/public
|
||||
publish_branch: versioned-gh-pages
|
||||
destination_dir: ./${{ env.VERSION }}
|
||||
keep_files: true
|
||||
commit_message: "deploy: docs for ${{ env.VERSION }}"
|
||||
|
||||
- name: Clean Build Directory
|
||||
run: rm -rf .hugo/public
|
||||
|
||||
- name: Build Hugo Site
|
||||
run: hugo --minify
|
||||
working-directory: .hugo
|
||||
env:
|
||||
HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/
|
||||
HUGO_RELATIVEURLS: false
|
||||
|
||||
- name: Deploy to root
|
||||
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: .hugo/public
|
||||
publish_branch: versioned-gh-pages
|
||||
keep_files: true
|
||||
allow_empty_commit: true
|
||||
commit_message: "deploy: docs to root for ${{ env.VERSION }}"
|
||||
6
.github/workflows/docs_deploy.yaml
vendored
6
.github/workflows/docs_deploy.yaml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||
|
||||
@@ -50,12 +50,12 @@ jobs:
|
||||
extended: true
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
|
||||
8
.github/workflows/docs_preview_clean.yaml
vendored
8
.github/workflows/docs_preview_clean.yaml
vendored
@@ -34,9 +34,9 @@ jobs:
|
||||
group: "preview-${{ github.event.number }}"
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
ref: versioned-gh-pages
|
||||
ref: gh-pages
|
||||
|
||||
- name: Remove Preview
|
||||
run: |
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
git push
|
||||
|
||||
- name: Comment
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
@@ -56,4 +56,4 @@ jobs:
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: "🧨 Preview deployments removed."
|
||||
})
|
||||
})
|
||||
11
.github/workflows/docs_preview_deploy.yaml
vendored
11
.github/workflows/docs_preview_deploy.yaml
vendored
@@ -49,10 +49,8 @@ jobs:
|
||||
group: "preview-${{ github.event.number }}"
|
||||
cancel-in-progress: true
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
# Checkout the PR's HEAD commit (supports forks).
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||
|
||||
- name: Setup Hugo
|
||||
@@ -62,12 +60,12 @@ jobs:
|
||||
extended: true
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6
|
||||
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
@@ -86,12 +84,11 @@ jobs:
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: .hugo/public
|
||||
publish_branch: versioned-gh-pages
|
||||
destination_dir: ./previews/PR-${{ github.event.number }}
|
||||
commit_message: "stage: PR-${{ github.event.number }}: ${{ github.event.head_commit.message }}"
|
||||
|
||||
- name: Comment
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
|
||||
8
.github/workflows/lint.yaml
vendored
8
.github/workflows/lint.yaml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
steps:
|
||||
- name: Remove PR Label
|
||||
if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}"
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
@@ -51,11 +51,11 @@ jobs:
|
||||
console.log('Failed to remove label. Another job may have already removed it!');
|
||||
}
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: "1.25"
|
||||
go-version: "1.22"
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
|
||||
2
.github/workflows/schedule_reporter.yml
vendored
2
.github/workflows/schedule_reporter.yml
vendored
@@ -26,4 +26,4 @@ jobs:
|
||||
contents: 'read'
|
||||
uses: ./.github/workflows/cloud_build_failure_reporter.yml
|
||||
with:
|
||||
trigger_names: "toolbox-test-nightly,toolbox-test-on-merge,toolbox-continuous-release"
|
||||
trigger_names: "toolbox-test-nightly,toolbox-test-on-merge"
|
||||
|
||||
2
.github/workflows/sync-labels.yaml
vendored
2
.github/workflows/sync-labels.yaml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
- uses: micnncim/action-label-syncer@3abd5ab72fda571e69fffd97bd4e0033dd5f495c # v1.3.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
18
.github/workflows/tests.yaml
vendored
18
.github/workflows/tests.yaml
vendored
@@ -16,7 +16,7 @@ name: tests
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "main"
|
||||
- 'main'
|
||||
pull_request:
|
||||
pull_request_target:
|
||||
types: [labeled]
|
||||
@@ -35,13 +35,13 @@ jobs:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
fail-fast: false
|
||||
permissions:
|
||||
contents: "read"
|
||||
issues: "write"
|
||||
pull-requests: "write"
|
||||
contents: 'read'
|
||||
issues: 'write'
|
||||
pull-requests: 'write'
|
||||
steps:
|
||||
- name: Remove PR label
|
||||
if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}"
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
@@ -57,12 +57,12 @@ jobs:
|
||||
}
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0
|
||||
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
|
||||
with:
|
||||
go-version: "1.24"
|
||||
go-version: "1.22"
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
repository: ${{ github.event.pull_request.head.repo.full_name }}
|
||||
@@ -76,8 +76,6 @@ jobs:
|
||||
|
||||
- name: Run tests with coverage
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
env:
|
||||
GOTOOLCHAIN: go1.25.0+auto
|
||||
run: |
|
||||
source_dir="./internal/sources/*"
|
||||
tool_dir="./internal/tools/*"
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -4,9 +4,6 @@
|
||||
# vscode
|
||||
.vscode/
|
||||
|
||||
# idea
|
||||
.idea/
|
||||
|
||||
# npm
|
||||
node_modules
|
||||
|
||||
@@ -17,7 +14,3 @@ node_modules
|
||||
|
||||
# coverage
|
||||
.coverage
|
||||
|
||||
# executable
|
||||
genai-toolbox
|
||||
toolbox
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
@import 'td/code-dark';
|
||||
@@ -1,5 +1,5 @@
|
||||
title = 'MCP Toolbox for Databases'
|
||||
relativeURLs = false
|
||||
relativeURLs = true
|
||||
|
||||
languageCode = 'en-us'
|
||||
defaultContentLanguage = "en"
|
||||
@@ -8,8 +8,6 @@ defaultContentLanguageInSubdir = false
|
||||
enableGitInfo = true
|
||||
enableRobotsTXT = true
|
||||
|
||||
ignoreFiles = ["quickstart/shared", "quickstart/python", "quickstart/js", "quickstart/go"]
|
||||
|
||||
[languages]
|
||||
[languages.en]
|
||||
languageName ="English"
|
||||
@@ -36,7 +34,6 @@ ignoreFiles = ["quickstart/shared", "quickstart/python", "quickstart/js", "quick
|
||||
github_project_repo = "https://github.com/googleapis/genai-toolbox"
|
||||
github_subdir = "docs"
|
||||
offlineSearch = true
|
||||
version_menu = "Releases"
|
||||
[params.ui]
|
||||
ul_show = 100
|
||||
showLightDarkModeMenu = true
|
||||
@@ -44,58 +41,6 @@ ignoreFiles = ["quickstart/shared", "quickstart/python", "quickstart/js", "quick
|
||||
sidebar_menu_foldable = true
|
||||
sidebar_menu_compact = false
|
||||
|
||||
[[params.versions]]
|
||||
version = "Dev"
|
||||
url = "https://googleapis.github.io/genai-toolbox/dev/"
|
||||
|
||||
# Add a new version block here before every release
|
||||
# The order of versions in this file is mirrored into the dropdown
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.18.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.18.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.17.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.17.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.16.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.16.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.15.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.15.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.14.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.14.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.13.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.13.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.12.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.12.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.11.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.11.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.10.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.10.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.9.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.9.0/"
|
||||
|
||||
[[params.versions]]
|
||||
version = "v0.8.0"
|
||||
url = "https://googleapis.github.io/genai-toolbox/v0.8.0/"
|
||||
|
||||
|
||||
[[menu.main]]
|
||||
name = "GitHub"
|
||||
weight = 50
|
||||
@@ -103,11 +48,7 @@ ignoreFiles = ["quickstart/shared", "quickstart/python", "quickstart/js", "quick
|
||||
pre = "<i class='fa-brands fa-github'></i>"
|
||||
|
||||
[markup.goldmark.renderer]
|
||||
unsafe= true
|
||||
|
||||
[markup.highlight]
|
||||
noClasses = false
|
||||
style = "tango"
|
||||
unsafe= true
|
||||
|
||||
[outputFormats]
|
||||
[outputFormats.LLMS]
|
||||
@@ -120,13 +61,6 @@ ignoreFiles = ["quickstart/shared", "quickstart/python", "quickstart/js", "quick
|
||||
baseName = "llms-full"
|
||||
isPlainText = true
|
||||
root = true
|
||||
[outputFormats.releases]
|
||||
baseName = 'releases'
|
||||
isPlainText = true
|
||||
mediaType = 'text/releases'
|
||||
|
||||
[mediaTypes."text/releases"]
|
||||
suffixes = ["releases"]
|
||||
|
||||
[outputs]
|
||||
home = ["HTML", "RSS", "LLMS", "LLMS-FULL", "releases"]
|
||||
home = ["HTML", "RSS", "LLMS", "LLMS-FULL"]
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{{ if .Site.Params.versions -}}
|
||||
{{ $path := "" -}}
|
||||
{{ if .Site.Params.version_menu_pagelinks -}}
|
||||
{{ $path = .Page.RelPermalink -}}
|
||||
{{ end -}}
|
||||
{{ range .Site.Params.versions -}}
|
||||
<a class="dropdown-item" href="{{ .url }}{{ $path }}">{{ .version }}</a>
|
||||
{{ end -}}
|
||||
{{ end -}}
|
||||
@@ -1 +0,0 @@
|
||||
<script src='{{ .Site.BaseURL }}js/w3.js' type="application/x-javascript"></script>
|
||||
@@ -1,12 +0,0 @@
|
||||
{{ if .Site.Params.versions -}}
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
|
||||
{{ .Site.Params.version_menu }}
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<div w3-include-html="/genai-toolbox/releases.releases" w3-include-html-default='<a class="dropdown-item" href="/genai-toolbox/dev/">Dev</a>'></div>
|
||||
<script>
|
||||
// This must run after the w3.js script has loaded.
|
||||
w3.includeHTML();
|
||||
</script>
|
||||
</div>
|
||||
{{ end -}}
|
||||
@@ -1,2 +0,0 @@
|
||||
{{ $file := .Get 0 }}
|
||||
{{ (printf "%s%s" .Page.File.Dir $file) | readFile | replaceRE "^---[\\s\\S]+?---" "" | safeHTML }}
|
||||
@@ -1,47 +0,0 @@
|
||||
{{ $notebookFile := .Get 0 }}
|
||||
{{ with .Page.Resources.Get $notebookFile }}
|
||||
|
||||
{{ $content := .Content | transform.Unmarshal }}
|
||||
{{ range $content.cells }}
|
||||
|
||||
{{ if eq .cell_type "markdown" }}
|
||||
<div class="notebook-markdown">
|
||||
{{ $markdown := "" }}
|
||||
{{ range .source }}{{ $markdown = print $markdown . }}{{ end }}
|
||||
{{ $markdown | markdownify }}
|
||||
</div>
|
||||
{{ end }}
|
||||
|
||||
{{ if eq .cell_type "code" }}
|
||||
<div class="notebook-code">
|
||||
{{ $code := "" }}
|
||||
{{ range .source }}{{ $code = print $code . }}{{ end }}
|
||||
{{ highlight $code "python" "" }}
|
||||
|
||||
{{ range .outputs }}
|
||||
<div class="notebook-output">
|
||||
{{ with .text }}
|
||||
<pre class="notebook-stream"><code>{{- range . }}{{ . }}{{ end -}}</code></pre>
|
||||
{{ end }}
|
||||
|
||||
{{ with .data }}
|
||||
{{ with index . "image/png" }}
|
||||
<img src="data:image/png;base64,{{ . }}" alt="Notebook output image">
|
||||
{{ end }}
|
||||
{{ with index . "image/jpeg" }}
|
||||
<img src="data:image/jpeg;base64,{{ . }}" alt="Notebook output image">
|
||||
{{ end }}
|
||||
{{ with index . "text/html" }}
|
||||
{{ $html := "" }}
|
||||
{{ range . }}{{ $html = print $html . }}{{ end }}
|
||||
{{ $html | safeHTML }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
</div>
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
{{ else }}
|
||||
<p style="color: red;">Error: Notebook '{{ $notebookFile }}' not found in page resources.</p>
|
||||
{{ end }}
|
||||
@@ -1,49 +0,0 @@
|
||||
{{/*
|
||||
snippet.html
|
||||
Usage:
|
||||
{{< regionInclude "filename.md" "region_name" >}}
|
||||
{{< regionInclude "filename.python" "region_name" "python" >}}
|
||||
*/}}
|
||||
|
||||
{{ $file := .Get 0 }}
|
||||
{{ $region := .Get 1 }}
|
||||
{{ $lang := .Get 2 | default "text" }}
|
||||
{{ $path := printf "%s%s" .Page.File.Dir $file }}
|
||||
|
||||
{{ if or (not $file) (eq $file "") }}
|
||||
{{ errorf "The file parameter (first argument) is required and must be non-empty in %s" .Page.File.Path }}
|
||||
{{ end }}
|
||||
{{ if or (not $region) (eq $region "") }}
|
||||
{{ errorf "The region parameter (second argument) is required and must be non-empty in %s" .Page.File.Path }}
|
||||
{{ end }}
|
||||
{{ if not (fileExists $path) }}
|
||||
{{ errorf "File %q not found (referenced in %s)" $path .Page.File.Path }}
|
||||
{{ end }}
|
||||
|
||||
{{ $content := readFile $path }}
|
||||
{{ $start_tag := printf "[START %s]" $region }}
|
||||
{{ $end_tag := printf "[END %s]" $region }}
|
||||
|
||||
{{ $snippet := "" }}
|
||||
{{ $in_snippet := false }}
|
||||
{{ range split $content "\n" }}
|
||||
{{ if $in_snippet }}
|
||||
{{ if in . $end_tag }}
|
||||
{{ $in_snippet = false }}
|
||||
{{ else }}
|
||||
{{ $snippet = printf "%s%s\n" $snippet . }}
|
||||
{{ end }}
|
||||
{{ else if in . $start_tag }}
|
||||
{{ $in_snippet = true }}
|
||||
{{ end }}
|
||||
{{ end }}
|
||||
|
||||
{{ if eq (trim $snippet "") "" }}
|
||||
{{ errorf "Region %q not found or empty in file %s (referenced in %s)" $region $file .Page.File.Path }}
|
||||
{{ end }}
|
||||
|
||||
{{ if eq $lang "text" }}
|
||||
{{ $snippet | markdownify }}
|
||||
{{ else }}
|
||||
{{ highlight (trim $snippet "\n") $lang "" }}
|
||||
{{ end }}
|
||||
@@ -1,405 +0,0 @@
|
||||
/* W3.JS 1.04 April 2019 by w3schools.com */
|
||||
"use strict";
|
||||
var w3 = {};
|
||||
w3.hide = function (sel) {
|
||||
w3.hideElements(w3.getElements(sel));
|
||||
};
|
||||
w3.hideElements = function (elements) {
|
||||
var i, l = elements.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
w3.hideElement(elements[i]);
|
||||
}
|
||||
};
|
||||
w3.hideElement = function (element) {
|
||||
w3.styleElement(element, "display", "none");
|
||||
};
|
||||
w3.show = function (sel, a) {
|
||||
var elements = w3.getElements(sel);
|
||||
if (a) {w3.hideElements(elements);}
|
||||
w3.showElements(elements);
|
||||
};
|
||||
w3.showElements = function (elements) {
|
||||
var i, l = elements.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
w3.showElement(elements[i]);
|
||||
}
|
||||
};
|
||||
w3.showElement = function (element) {
|
||||
w3.styleElement(element, "display", "block");
|
||||
};
|
||||
w3.addStyle = function (sel, prop, val) {
|
||||
w3.styleElements(w3.getElements(sel), prop, val);
|
||||
};
|
||||
w3.styleElements = function (elements, prop, val) {
|
||||
var i, l = elements.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
w3.styleElement(elements[i], prop, val);
|
||||
}
|
||||
};
|
||||
w3.styleElement = function (element, prop, val) {
|
||||
element.style.setProperty(prop, val);
|
||||
};
|
||||
w3.toggleShow = function (sel) {
|
||||
var i, x = w3.getElements(sel), l = x.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
if (x[i].style.display == "none") {
|
||||
w3.styleElement(x[i], "display", "block");
|
||||
} else {
|
||||
w3.styleElement(x[i], "display", "none");
|
||||
}
|
||||
}
|
||||
};
|
||||
w3.addClass = function (sel, name) {
|
||||
w3.addClassElements(w3.getElements(sel), name);
|
||||
};
|
||||
w3.addClassElements = function (elements, name) {
|
||||
var i, l = elements.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
w3.addClassElement(elements[i], name);
|
||||
}
|
||||
};
|
||||
w3.addClassElement = function (element, name) {
|
||||
var i, arr1, arr2;
|
||||
arr1 = element.className.split(" ");
|
||||
arr2 = name.split(" ");
|
||||
for (i = 0; i < arr2.length; i++) {
|
||||
if (arr1.indexOf(arr2[i]) == -1) {element.className += " " + arr2[i];}
|
||||
}
|
||||
};
|
||||
w3.removeClass = function (sel, name) {
|
||||
w3.removeClassElements(w3.getElements(sel), name);
|
||||
};
|
||||
w3.removeClassElements = function (elements, name) {
|
||||
var i, l = elements.length, arr1, arr2, j;
|
||||
for (i = 0; i < l; i++) {
|
||||
w3.removeClassElement(elements[i], name);
|
||||
}
|
||||
};
|
||||
w3.removeClassElement = function (element, name) {
|
||||
var i, arr1, arr2;
|
||||
arr1 = element.className.split(" ");
|
||||
arr2 = name.split(" ");
|
||||
for (i = 0; i < arr2.length; i++) {
|
||||
while (arr1.indexOf(arr2[i]) > -1) {
|
||||
arr1.splice(arr1.indexOf(arr2[i]), 1);
|
||||
}
|
||||
}
|
||||
element.className = arr1.join(" ");
|
||||
};
|
||||
w3.toggleClass = function (sel, c1, c2) {
|
||||
w3.toggleClassElements(w3.getElements(sel), c1, c2);
|
||||
};
|
||||
w3.toggleClassElements = function (elements, c1, c2) {
|
||||
var i, l = elements.length;
|
||||
for (i = 0; i < l; i++) {
|
||||
w3.toggleClassElement(elements[i], c1, c2);
|
||||
}
|
||||
};
|
||||
w3.toggleClassElement = function (element, c1, c2) {
|
||||
var t1, t2, t1Arr, t2Arr, j, arr, allPresent;
|
||||
t1 = (c1 || "");
|
||||
t2 = (c2 || "");
|
||||
t1Arr = t1.split(" ");
|
||||
t2Arr = t2.split(" ");
|
||||
arr = element.className.split(" ");
|
||||
if (t2Arr.length == 0) {
|
||||
allPresent = true;
|
||||
for (j = 0; j < t1Arr.length; j++) {
|
||||
if (arr.indexOf(t1Arr[j]) == -1) {allPresent = false;}
|
||||
}
|
||||
if (allPresent) {
|
||||
w3.removeClassElement(element, t1);
|
||||
} else {
|
||||
w3.addClassElement(element, t1);
|
||||
}
|
||||
} else {
|
||||
allPresent = true;
|
||||
for (j = 0; j < t1Arr.length; j++) {
|
||||
if (arr.indexOf(t1Arr[j]) == -1) {allPresent = false;}
|
||||
}
|
||||
if (allPresent) {
|
||||
w3.removeClassElement(element, t1);
|
||||
w3.addClassElement(element, t2);
|
||||
} else {
|
||||
w3.removeClassElement(element, t2);
|
||||
w3.addClassElement(element, t1);
|
||||
}
|
||||
}
|
||||
};
|
||||
w3.getElements = function (id) {
|
||||
if (typeof id == "object") {
|
||||
return [id];
|
||||
} else {
|
||||
return document.querySelectorAll(id);
|
||||
}
|
||||
};
|
||||
w3.filterHTML = function(id, sel, filter) {
|
||||
var a, b, c, i, ii, iii, hit;
|
||||
a = w3.getElements(id);
|
||||
for (i = 0; i < a.length; i++) {
|
||||
b = a[i].querySelectorAll(sel);
|
||||
for (ii = 0; ii < b.length; ii++) {
|
||||
hit = 0;
|
||||
if (b[ii].innerText.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
|
||||
hit = 1;
|
||||
}
|
||||
c = b[ii].getElementsByTagName("*");
|
||||
for (iii = 0; iii < c.length; iii++) {
|
||||
if (c[iii].innerText.toUpperCase().indexOf(filter.toUpperCase()) > -1) {
|
||||
hit = 1;
|
||||
}
|
||||
}
|
||||
if (hit == 1) {
|
||||
b[ii].style.display = "";
|
||||
} else {
|
||||
b[ii].style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
w3.sortHTML = function(id, sel, sortvalue) {
|
||||
var a, b, i, ii, y, bytt, v1, v2, cc, j;
|
||||
a = w3.getElements(id);
|
||||
for (i = 0; i < a.length; i++) {
|
||||
for (j = 0; j < 2; j++) {
|
||||
cc = 0;
|
||||
y = 1;
|
||||
while (y == 1) {
|
||||
y = 0;
|
||||
b = a[i].querySelectorAll(sel);
|
||||
for (ii = 0; ii < (b.length - 1); ii++) {
|
||||
bytt = 0;
|
||||
if (sortvalue) {
|
||||
v1 = b[ii].querySelector(sortvalue).innerText;
|
||||
v2 = b[ii + 1].querySelector(sortvalue).innerText;
|
||||
} else {
|
||||
v1 = b[ii].innerText;
|
||||
v2 = b[ii + 1].innerText;
|
||||
}
|
||||
v1 = v1.toLowerCase();
|
||||
v2 = v2.toLowerCase();
|
||||
if ((j == 0 && (v1 > v2)) || (j == 1 && (v1 < v2))) {
|
||||
bytt = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (bytt == 1) {
|
||||
b[ii].parentNode.insertBefore(b[ii + 1], b[ii]);
|
||||
y = 1;
|
||||
cc++;
|
||||
}
|
||||
}
|
||||
if (cc > 0) {break;}
|
||||
}
|
||||
}
|
||||
};
|
||||
w3.slideshow = function (sel, ms, func) {
|
||||
var i, ss, x = w3.getElements(sel), l = x.length;
|
||||
ss = {};
|
||||
ss.current = 1;
|
||||
ss.x = x;
|
||||
ss.ondisplaychange = func;
|
||||
if (!isNaN(ms) || ms == 0) {
|
||||
ss.milliseconds = ms;
|
||||
} else {
|
||||
ss.milliseconds = 1000;
|
||||
}
|
||||
ss.start = function() {
|
||||
ss.display(ss.current)
|
||||
if (ss.ondisplaychange) {ss.ondisplaychange();}
|
||||
if (ss.milliseconds > 0) {
|
||||
window.clearTimeout(ss.timeout);
|
||||
ss.timeout = window.setTimeout(ss.next, ss.milliseconds);
|
||||
}
|
||||
};
|
||||
ss.next = function() {
|
||||
ss.current += 1;
|
||||
if (ss.current > ss.x.length) {ss.current = 1;}
|
||||
ss.start();
|
||||
};
|
||||
ss.previous = function() {
|
||||
ss.current -= 1;
|
||||
if (ss.current < 1) {ss.current = ss.x.length;}
|
||||
ss.start();
|
||||
};
|
||||
ss.display = function (n) {
|
||||
w3.styleElements(ss.x, "display", "none");
|
||||
w3.styleElement(ss.x[n - 1], "display", "block");
|
||||
}
|
||||
ss.start();
|
||||
return ss;
|
||||
};
|
||||
w3.includeHTML = function(cb) {
|
||||
var z, i, elmnt, file, xhttp;
|
||||
z = document.getElementsByTagName("*");
|
||||
for (i = 0; i < z.length; i++) {
|
||||
elmnt = z[i];
|
||||
file = elmnt.getAttribute("w3-include-html");
|
||||
if (file) {
|
||||
xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4) {
|
||||
if (this.status == 200) {elmnt.innerHTML = this.responseText;}
|
||||
if (this.status == 404) {
|
||||
if (elmnt.getAttribute("w3-include-html-default")) {
|
||||
elmnt.innerHTML = elmnt.getAttribute("w3-include-html-default");
|
||||
}
|
||||
else { elmnt.innerHTML = "Page not found."; }
|
||||
}
|
||||
elmnt.removeAttribute("w3-include-html");
|
||||
w3.includeHTML(cb);
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", file, true);
|
||||
xhttp.send();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (cb) cb();
|
||||
};
|
||||
w3.getHttpData = function (file, func) {
|
||||
w3.http(file, function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
func(this.responseText);
|
||||
}
|
||||
});
|
||||
};
|
||||
w3.getHttpObject = function (file, func) {
|
||||
w3.http(file, function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
func(JSON.parse(this.responseText));
|
||||
}
|
||||
});
|
||||
};
|
||||
w3.displayHttp = function (id, file) {
|
||||
w3.http(file, function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
w3.displayObject(id, JSON.parse(this.responseText));
|
||||
}
|
||||
});
|
||||
};
|
||||
w3.http = function (target, readyfunc, xml, method) {
|
||||
var httpObj;
|
||||
if (!method) {method = "GET"; }
|
||||
if (window.XMLHttpRequest) {
|
||||
httpObj = new XMLHttpRequest();
|
||||
} else if (window.ActiveXObject) {
|
||||
httpObj = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
if (httpObj) {
|
||||
if (readyfunc) {httpObj.onreadystatechange = readyfunc;}
|
||||
httpObj.open(method, target, true);
|
||||
httpObj.send(xml);
|
||||
}
|
||||
};
|
||||
w3.getElementsByAttribute = function (x, att) {
|
||||
var arr = [], arrCount = -1, i, l, y = x.getElementsByTagName("*"), z = att.toUpperCase();
|
||||
l = y.length;
|
||||
for (i = -1; i < l; i += 1) {
|
||||
if (i == -1) {y[i] = x;}
|
||||
if (y[i].getAttribute(z) !== null) {arrCount += 1; arr[arrCount] = y[i];}
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
w3.dataObject = {},
|
||||
w3.displayObject = function (id, data) {
|
||||
var htmlObj, htmlTemplate, html, arr = [], a, l, rowClone, x, j, i, ii, cc, repeat, repeatObj, repeatX = "";
|
||||
htmlObj = document.getElementById(id);
|
||||
htmlTemplate = init_template(id, htmlObj);
|
||||
html = htmlTemplate.cloneNode(true);
|
||||
arr = w3.getElementsByAttribute(html, "w3-repeat");
|
||||
l = arr.length;
|
||||
for (j = (l - 1); j >= 0; j -= 1) {
|
||||
cc = arr[j].getAttribute("w3-repeat").split(" ");
|
||||
if (cc.length == 1) {
|
||||
repeat = cc[0];
|
||||
} else {
|
||||
repeatX = cc[0];
|
||||
repeat = cc[2];
|
||||
}
|
||||
arr[j].removeAttribute("w3-repeat");
|
||||
repeatObj = data[repeat];
|
||||
if (repeatObj && typeof repeatObj == "object" && repeatObj.length != "undefined") {
|
||||
i = 0;
|
||||
for (x in repeatObj) {
|
||||
i += 1;
|
||||
rowClone = arr[j];
|
||||
rowClone = w3_replace_curly(rowClone, "element", repeatX, repeatObj[x]);
|
||||
a = rowClone.attributes;
|
||||
for (ii = 0; ii < a.length; ii += 1) {
|
||||
a[ii].value = w3_replace_curly(a[ii], "attribute", repeatX, repeatObj[x]).value;
|
||||
}
|
||||
(i === repeatObj.length) ? arr[j].parentNode.replaceChild(rowClone, arr[j]) : arr[j].parentNode.insertBefore(rowClone, arr[j]);
|
||||
}
|
||||
} else {
|
||||
console.log("w3-repeat must be an array. " + repeat + " is not an array.");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
html = w3_replace_curly(html, "element");
|
||||
htmlObj.parentNode.replaceChild(html, htmlObj);
|
||||
function init_template(id, obj) {
|
||||
var template;
|
||||
template = obj.cloneNode(true);
|
||||
if (w3.dataObject.hasOwnProperty(id)) {return w3.dataObject[id];}
|
||||
w3.dataObject[id] = template;
|
||||
return template;
|
||||
}
|
||||
function w3_replace_curly(elmnt, typ, repeatX, x) {
|
||||
var value, rowClone, pos1, pos2, originalHTML, lookFor, lookForARR = [], i, cc, r;
|
||||
rowClone = elmnt.cloneNode(true);
|
||||
pos1 = 0;
|
||||
while (pos1 > -1) {
|
||||
originalHTML = (typ == "attribute") ? rowClone.value : rowClone.innerHTML;
|
||||
pos1 = originalHTML.indexOf("{{", pos1);
|
||||
if (pos1 === -1) {break;}
|
||||
pos2 = originalHTML.indexOf("}}", pos1 + 1);
|
||||
lookFor = originalHTML.substring(pos1 + 2, pos2);
|
||||
lookForARR = lookFor.split("||");
|
||||
value = undefined;
|
||||
for (i = 0; i < lookForARR.length; i += 1) {
|
||||
lookForARR[i] = lookForARR[i].replace(/^\s+|\s+$/gm, ''); //trim
|
||||
if (x) {value = x[lookForARR[i]];}
|
||||
if (value == undefined && data) {value = data[lookForARR[i]];}
|
||||
if (value == undefined) {
|
||||
cc = lookForARR[i].split(".");
|
||||
if (cc[0] == repeatX) {value = x[cc[1]]; }
|
||||
}
|
||||
if (value == undefined) {
|
||||
if (lookForARR[i] == repeatX) {value = x;}
|
||||
}
|
||||
if (value == undefined) {
|
||||
if (lookForARR[i].substr(0, 1) == '"') {
|
||||
value = lookForARR[i].replace(/"/g, "");
|
||||
} else if (lookForARR[i].substr(0,1) == "'") {
|
||||
value = lookForARR[i].replace(/'/g, "");
|
||||
}
|
||||
}
|
||||
if (value != undefined) {break;}
|
||||
}
|
||||
if (value != undefined) {
|
||||
r = "{{" + lookFor + "}}";
|
||||
if (typ == "attribute") {
|
||||
rowClone.value = rowClone.value.replace(r, value);
|
||||
} else {
|
||||
w3_replace_html(rowClone, r, value);
|
||||
}
|
||||
}
|
||||
pos1 = pos1 + 1;
|
||||
}
|
||||
return rowClone;
|
||||
}
|
||||
function w3_replace_html(a, r, result) {
|
||||
var b, l, i, a, x, j;
|
||||
if (a.hasAttributes()) {
|
||||
b = a.attributes;
|
||||
l = b.length;
|
||||
for (i = 0; i < l; i += 1) {
|
||||
if (b[i].value.indexOf(r) > -1) {b[i].value = b[i].value.replace(r, result);}
|
||||
}
|
||||
}
|
||||
x = a.getElementsByTagName("*");
|
||||
l = x.length;
|
||||
a.innerHTML = a.innerHTML.replace(r, result);
|
||||
}
|
||||
};
|
||||
338
CHANGELOG.md
338
CHANGELOG.md
@@ -1,343 +1,5 @@
|
||||
# Changelog
|
||||
|
||||
## [0.18.0](https://github.com/googleapis/genai-toolbox/compare/v0.17.0...v0.18.0) (2025-10-23)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Support `allowedValues`, `escape`, `minValue` and `maxValue` for parameters ([#1770](https://github.com/googleapis/genai-toolbox/issues/1770)) ([eaf7740](https://github.com/googleapis/genai-toolbox/commit/eaf77406fd386c12315d67eb685dc69e0415c516))
|
||||
* **tools/looker:** Tools to allow the agent to retrieve, create, modify, and delete LookML project files. ([#1673](https://github.com/googleapis/genai-toolbox/issues/1673)) ([089081f](https://github.com/googleapis/genai-toolbox/commit/089081feb0e32f9eb65d00df5987392d413a4081))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **sources/mysql:** Escape mysql user agent ([#1707](https://github.com/googleapis/genai-toolbox/issues/1707)) ([eeb694c](https://github.com/googleapis/genai-toolbox/commit/eeb694c20facc40a38bfa67073c4cb1f3dd657ff))
|
||||
* **sources/mysql:** Escape program_name for MySQL ([#1717](https://github.com/googleapis/genai-toolbox/issues/1717)) ([02f7f8a](https://github.com/googleapis/genai-toolbox/commit/02f7f8af979057efe99fd138cb1b958130355b68))
|
||||
* **tools/http:** Allow 2xx status code on tool invocation ([#1761](https://github.com/googleapis/genai-toolbox/issues/1761)) ([a06d0d8](https://github.com/googleapis/genai-toolbox/commit/a06d0d8735fbec29bea97457248845a8c6b4aa3c))
|
||||
* **tools/http:** Omit optional nil query parameters ([#1762](https://github.com/googleapis/genai-toolbox/issues/1762)) ([bd16ba3](https://github.com/googleapis/genai-toolbox/commit/bd16ba3921e6177065780e5f29870859b8e18e4f))
|
||||
* **tools/looker:** Looker file content calls should not use url.QueryEscape ([#1758](https://github.com/googleapis/genai-toolbox/issues/1758)) ([336de1b](https://github.com/googleapis/genai-toolbox/commit/336de1bd04b869d322c0fd1f4667eb652159d791))
|
||||
|
||||
|
||||
## [0.17.0](https://github.com/googleapis/genai-toolbox/compare/v0.16.0...v0.17.0) (2025-10-10)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **tools/bigquery-get-table-info:** add allowed dataset support ([#1093](https://github.com/googleapis/genai-toolbox/issues/1093))
|
||||
* **tools/bigquery-list-dataset-ids:** add allowed datasets support ([#1573](https://github.com/googleapis/genai-toolbox/issues/1573))
|
||||
|
||||
### Features
|
||||
|
||||
* Add configs and workflows for docs versioning ([#1611](https://github.com/googleapis/genai-toolbox/issues/1611)) ([21ac98b](https://github.com/googleapis/genai-toolbox/commit/21ac98bc065e95bde911d66185c67d8380891bf8))
|
||||
* Add metadata in MCP Manifest for Toolbox auth ([#1395](https://github.com/googleapis/genai-toolbox/issues/1395)) ([0b3dac4](https://github.com/googleapis/genai-toolbox/commit/0b3dac41322f7aaa5a19df571686fa8fd4338ca5))
|
||||
* Add program name to MySQL connections ([#1617](https://github.com/googleapis/genai-toolbox/issues/1617)) ([c4a22b8](https://github.com/googleapis/genai-toolbox/commit/c4a22b8d3bd0307325215ebd2f30ba37927cd37e))
|
||||
* **source/bigquery:** Add optional write mode config ([#1157](https://github.com/googleapis/genai-toolbox/issues/1157)) ([63adc78](https://github.com/googleapis/genai-toolbox/commit/63adc78beae949dfe5e300c50e5ceef073e9652c))
|
||||
* **sources/alloydb,cloudsqlpg,cloudsqlmysql,cloudsqlmssql:** Support PSC connection ([#1686](https://github.com/googleapis/genai-toolbox/issues/1686)) ([9d2bf79](https://github.com/googleapis/genai-toolbox/commit/9d2bf79becfda104ef77f34b8d4b22cbedbc4bf3))
|
||||
* **sources/mssql:** Add app name to MSSQL ([#1620](https://github.com/googleapis/genai-toolbox/issues/1620)) ([1536d1f](https://github.com/googleapis/genai-toolbox/commit/1536d1fdabb9d7f73dbdeebeb05a83d9a3b78e1c))
|
||||
* **sources/oracle:** Add Oracle Source and Tool ([#1456](https://github.com/googleapis/genai-toolbox/issues/1456)) ([3a19a50](https://github.com/googleapis/genai-toolbox/commit/3a19a50ff211e33429de1d05338d353359a52987))
|
||||
* **sources/oracle:** Switch Oracle driver from godror to go-ora ([#1685](https://github.com/googleapis/genai-toolbox/issues/1685)) ([8faf376](https://github.com/googleapis/genai-toolbox/commit/8faf37667e371b4ed88ebb892e8784b67611ba64))
|
||||
* **tool/bigquery-list-dataset-ids:** Add allowed datasets support ([#1573](https://github.com/googleapis/genai-toolbox/issues/1573)) ([1a44c67](https://github.com/googleapis/genai-toolbox/commit/1a44c671ec593e764a2d2f67f70a98ceec20a168))
|
||||
* **tools/bigquery-get-table-info:** Add allowed dataset support ([#1093](https://github.com/googleapis/genai-toolbox/issues/1093)) ([acb205c](https://github.com/googleapis/genai-toolbox/commit/acb205ca4761d59ce97b804827230978c8c98ede))
|
||||
* **tools/dataform:** Add dataform compile tool ([#1470](https://github.com/googleapis/genai-toolbox/issues/1470)) ([3be9b7b](https://github.com/googleapis/genai-toolbox/commit/3be9b7b3bdf112fe7303706e56e9f39935cde661))
|
||||
* **tools/looker:** Add support for pulse, vacuum and analyze audit and performance functions on a Looker instance ([#1581](https://github.com/googleapis/genai-toolbox/issues/1581)) ([5aed4e1](https://github.com/googleapis/genai-toolbox/commit/5aed4e136d0091731d2ded10ec076ee789e1987c))
|
||||
* **tools/looker:** Enable access to the Conversational Analytics API for Looker ([#1596](https://github.com/googleapis/genai-toolbox/issues/1596)) ([2d5a93e](https://github.com/googleapis/genai-toolbox/commit/2d5a93e312990c8a9f3170c7e9c655f97cf11712))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Added google_ml_integration extension to use alloydb ai-nl support api ([#1445](https://github.com/googleapis/genai-toolbox/issues/1445)) ([dbc477a](https://github.com/googleapis/genai-toolbox/commit/dbc477ab0f832495cf51f73ea16ae363472d6eed))
|
||||
* Fix broken links ([#1625](https://github.com/googleapis/genai-toolbox/issues/1625)) ([36c6584](https://github.com/googleapis/genai-toolbox/commit/36c658472ccdeb6cddd8a4452a8b3438aeb0a744))
|
||||
* Remove duplicated build type in Dockerfile ([#1598](https://github.com/googleapis/genai-toolbox/issues/1598)) ([b43c945](https://github.com/googleapis/genai-toolbox/commit/b43c94575d86aa65b0528d59f9b41d30b439fee5))
|
||||
* **source/bigquery:** Allowed datasets project id issue with client oauth ([#1663](https://github.com/googleapis/genai-toolbox/issues/1663)) ([f4cf486](https://github.com/googleapis/genai-toolbox/commit/f4cf486fa929299fef076cf71689776e5dec19c1))
|
||||
* **sources/looker:** Allow Looker to be configured without setting a Client Id or Secret ([#1496](https://github.com/googleapis/genai-toolbox/issues/1496)) ([67d8221](https://github.com/googleapis/genai-toolbox/commit/67d8221a2e780df54a81f0f7e8f7e41e4bf1a82e))
|
||||
* **tools/looker:** Refactor run-inline-query logic to helper function ([#1497](https://github.com/googleapis/genai-toolbox/issues/1497)) ([62af39d](https://github.com/googleapis/genai-toolbox/commit/62af39d751443eb758586663969b162c868a233f))
|
||||
* **tools/mysql-list-tables:** Update sql query to resolve subquery scope error ([#1629](https://github.com/googleapis/genai-toolbox/issues/1629)) ([94e19d8](https://github.com/googleapis/genai-toolbox/commit/94e19d87e54e831b80eb766572e48bc7370305d8))
|
||||
|
||||
## [0.16.0](https://github.com/googleapis/genai-toolbox/compare/v0.15.0...v0.16.0) (2025-09-25)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **tool/bigquery-execute-sql:** add allowed datasets support ([#1443](https://github.com/googleapis/genai-toolbox/issues/1443))
|
||||
* **tool/bigquery-forecast:** add allowed datasets support ([#1412](https://github.com/googleapis/genai-toolbox/issues/1412))
|
||||
|
||||
### Features
|
||||
|
||||
* **cassandra:** Add Cassandra Source and Tool ([#1012](https://github.com/googleapis/genai-toolbox/issues/1012)) ([6e42053](https://github.com/googleapis/genai-toolbox/commit/6e420534ee894da4a8d226acb6cdb63d0d5d9ce5))
|
||||
* **sources/postgres:** Add application_name ([#1504](https://github.com/googleapis/genai-toolbox/issues/1504)) ([72a2366](https://github.com/googleapis/genai-toolbox/commit/72a2366b28870aa6f81c4f890f4770ec5ecffdba))
|
||||
* **tool/bigquery-execute-sql:** Add allowed datasets support ([#1443](https://github.com/googleapis/genai-toolbox/issues/1443)) ([9501ebb](https://github.com/googleapis/genai-toolbox/commit/9501ebbdbcba871b98663185c690308dda1729b5))
|
||||
* **tool/bigquery-forecast:** Add allowed datasets support ([#1412](https://github.com/googleapis/genai-toolbox/issues/1412)) ([88bac7e](https://github.com/googleapis/genai-toolbox/commit/88bac7e36f5ebb6ad18773bff30b85ef678431e7))
|
||||
* **tools/clickhouse-list-tables:** Add list-tables tool ([#1446](https://github.com/googleapis/genai-toolbox/issues/1446)) ([69a3caf](https://github.com/googleapis/genai-toolbox/commit/69a3cafabec5a40e2776d71de3587c0d16c722a2))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tool/mongodb-find:** Fix find tool `limit` field ([#1570](https://github.com/googleapis/genai-toolbox/issues/1570)) ([4166bf7](https://github.com/googleapis/genai-toolbox/commit/4166bf7ab85732f64b877d5f20235057df919049))
|
||||
* **tools/mongodb:** Concat filter params only once in mongodb update tools ([#1545](https://github.com/googleapis/genai-toolbox/issues/1545)) ([295f9dc](https://github.com/googleapis/genai-toolbox/commit/295f9dc41a43f0a4bdbd99e465bf2be01249084e))
|
||||
|
||||
## [0.15.0](https://github.com/googleapis/genai-toolbox/compare/v0.14.0...v0.15.0) (2025-09-18)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **prebuilt:** update prebuilt tool names to use consistent guidance ([#1421](https://github.com/googleapis/genai-toolbox/issues/1421))
|
||||
* **tools/alloydb-wait-for-operation:** Add `alloydb-admin` source to `alloydb-wait-for-operation` tool ([#1449](https://github.com/googleapis/genai-toolbox/issues/1449))
|
||||
|
||||
### Features
|
||||
|
||||
* Add AlloyDB admin source ([#1369](https://github.com/googleapis/genai-toolbox/issues/1369)) ([33beb71](https://github.com/googleapis/genai-toolbox/commit/33beb7187d2e0f968fc949a00c780073d1bc7cdd))
|
||||
* Add Cloud monitoring source and tool ([#1311](https://github.com/googleapis/genai-toolbox/issues/1311)) ([d661f53](https://github.com/googleapis/genai-toolbox/commit/d661f5343f2ad28fbf0481db16440aec823eece6))
|
||||
* Add YugabyteDB Source and Tool ([#732](https://github.com/googleapis/genai-toolbox/issues/732)) ([664711f](https://github.com/googleapis/genai-toolbox/commit/664711f4b35409bd1c57af92f625b70a0dc9a4e6))
|
||||
* **prebuilt:** Update default values for prebuilt tools ([#1355](https://github.com/googleapis/genai-toolbox/issues/1355)) ([70e832b](https://github.com/googleapis/genai-toolbox/commit/70e832bd08a98a95b925e590f31c8d3f2d8b6aa0))
|
||||
* **prebuilt/cloud-sql:** Add list instances tool for cloudsql ([#1310](https://github.com/googleapis/genai-toolbox/issues/1310)) ([0171228](https://github.com/googleapis/genai-toolbox/commit/01712284b480774ffa68930affae290ee2e3fcfd))
|
||||
* **prebuilt/cloud-sql:** Add cloud sql create database tool. ([#1453](https://github.com/googleapis/genai-toolbox/issues/1453)) ([a1bc044](https://github.com/googleapis/genai-toolbox/commit/a1bc04477b0f822ffaab039098682f1776b8a472))
|
||||
* **prebuilt/cloud-sql:** Add `cloud-sql-get-instances` tool ([#1383](https://github.com/googleapis/genai-toolbox/issues/1383)) ([77919c7](https://github.com/googleapis/genai-toolbox/commit/77919c7d8e4aac16eeb703c0cc61ca774dc4f94e))
|
||||
* **prebuilt/cloud-sql:** Add create user tool for cloud sql ([#1406](https://github.com/googleapis/genai-toolbox/issues/1406)) ([3a6b517](https://github.com/googleapis/genai-toolbox/commit/3a6b51752f077b225b8c2e2e7308a69a68eec3c0))
|
||||
* **prebuilt/cloud-sql:** Add list databases tool for cloud sql ([#1454](https://github.com/googleapis/genai-toolbox/issues/1454)) ([e6a6c61](https://github.com/googleapis/genai-toolbox/commit/e6a6c615d5480e8930ad173d44d243f5bd99eebc))
|
||||
* **prebuilt/cloud-sql:** Package cloud sql tools ([#1455](https://github.com/googleapis/genai-toolbox/issues/1455)) ([bf6266b](https://github.com/googleapis/genai-toolbox/commit/bf6266ba1131bd1c5829ac112a8c45c8a5919fea))
|
||||
* **prebuilt/cloud-sql-mssql:** Add create instance tool for mssql ([#1440](https://github.com/googleapis/genai-toolbox/issues/1440)) ([b176523](https://github.com/googleapis/genai-toolbox/commit/b17652309d8a02b1f20c6c576b1617b23c8e481f))
|
||||
* **prebuilt/cloud-sql-mysql:** Add create instance tool for Cloud SQL MySQL ([#1434](https://github.com/googleapis/genai-toolbox/issues/1434)) ([15b628d](https://github.com/googleapis/genai-toolbox/commit/15b628d2d2feb2ecdd418394b9265a6c77c77f6d))
|
||||
* **prebuilt/cloud-sql-mysql:** Add env var support for IP Type ([#1232](https://github.com/googleapis/genai-toolbox/issues/1232)) ([#1347](https://github.com/googleapis/genai-toolbox/issues/1347)) ([0cd3f16](https://github.com/googleapis/genai-toolbox/commit/0cd3f16f877f426b45e35625ba0af03789459591))
|
||||
* **prebuilt/cloudsqlpg:** Add cloud sql pg create instance tool ([#1403](https://github.com/googleapis/genai-toolbox/issues/1403)) ([d302499](https://github.com/googleapis/genai-toolbox/commit/d30249961b5a2ddc2c3809b481085d1ca034ead0))
|
||||
* **prebuilt/mysql:** Add a new tool to show query plan of a given query in MySQL ([#1474](https://github.com/googleapis/genai-toolbox/issues/1474)) ([1a42e05](https://github.com/googleapis/genai-toolbox/commit/1a42e05675645ac4f1b89edef7a71ac61b637a76))
|
||||
* **prebuilt/mysql:** Add `queryParams` field in MySQL prebuilt config ([#1318](https://github.com/googleapis/genai-toolbox/issues/1318)) ([4b32c2a](https://github.com/googleapis/genai-toolbox/commit/4b32c2a7701ce5ccc56d019055283e73e7046372))
|
||||
* **prebuilt/neo4j:** Add prebuiltconfig support for neo4j ([#1352](https://github.com/googleapis/genai-toolbox/issues/1352)) ([f819e26](https://github.com/googleapis/genai-toolbox/commit/f819e2644315a589ec283494f244c1b8407cae59))
|
||||
* **prebuilt/observability:** Add cloud sql observability tools ([#1425](https://github.com/googleapis/genai-toolbox/issues/1425)) ([236be89](https://github.com/googleapis/genai-toolbox/commit/236be89961fe423c1ec992d3d1f699f77a6e5b29))
|
||||
* **prebuilt/postgres:** Add postgres prebuilt tools ([#1473](https://github.com/googleapis/genai-toolbox/issues/1473)) ([edca9dc](https://github.com/googleapis/genai-toolbox/commit/edca9dc7d772baf1a234485020fa69d76f71bfcc))
|
||||
* **prebuilt/sqlite:** Prebuilt tools for the sqlite. ([#1227](https://github.com/googleapis/genai-toolbox/issues/1227)) ([681c2b4](https://github.com/googleapis/genai-toolbox/commit/681c2b4f3a65837d972c138c623c08fb6b1f1785))
|
||||
* **source/alloydb-admin:** Add user agent and attach alloydb api in `alloydb-admin` source ([#1448](https://github.com/googleapis/genai-toolbox/issues/1448)) ([9710014](https://github.com/googleapis/genai-toolbox/commit/971001400f25796784f8aeb3ec5cb1a2df2e4c69))
|
||||
* **source/bigquery:** Add support for datasets selection ([#1313](https://github.com/googleapis/genai-toolbox/issues/1313)) ([aa39724](https://github.com/googleapis/genai-toolbox/commit/aa3972470fd0f6f5901c5d85dd05f1e2ae973e7b))
|
||||
* **source/cloud-monitoring:** Add support for user agent in cloud monitoring source ([#1472](https://github.com/googleapis/genai-toolbox/issues/1472)) ([92680b1](https://github.com/googleapis/genai-toolbox/commit/92680b18d6159300ae66f80ddb4c6bf0547d45a1))
|
||||
* **source/cloud-sql-admin:** Add User agent and attach sqldmin in `cloud-sql-admin` source. ([#1441](https://github.com/googleapis/genai-toolbox/issues/1441)) ([56b6574](https://github.com/googleapis/genai-toolbox/commit/56b6574fc2c506c7c7df7f2a25686e3e4aae0e8a))
|
||||
* **source/cloudsqladmin:** Add cloud sql admin source ([#1408](https://github.com/googleapis/genai-toolbox/issues/1408)) ([4f46782](https://github.com/googleapis/genai-toolbox/commit/4f4678292762507494515ce61188cd0310805c40))
|
||||
* **tool/cloudsql:** Add cloud sql wait for operation tool with exponential backoff ([#1306](https://github.com/googleapis/genai-toolbox/issues/1306)) ([3aef2bb](https://github.com/googleapis/genai-toolbox/commit/3aef2bb7be8274bb4718739faeaa5f97b50dbf19))
|
||||
* **tools/alloydb-create-cluster:** Add custom tool kind for AlloyDB create cluster ([#1331](https://github.com/googleapis/genai-toolbox/issues/1331)) ([76bb876](https://github.com/googleapis/genai-toolbox/commit/76bb876d546780908c1a69ef3b1a92781af28a3b))
|
||||
* **tools/alloydb-create-instance:** Add new custom tool kind for AlloyDB ([#1379](https://github.com/googleapis/genai-toolbox/issues/1379)) ([091cd9a](https://github.com/googleapis/genai-toolbox/commit/091cd9aa1aabe1cb3de2ce2be5c707a8f77ad647))
|
||||
* **tools/alloydb-create-user:** Add new custom tool kind for AlloyDB create user ([#1380](https://github.com/googleapis/genai-toolbox/issues/1380)) ([ab3fd26](https://github.com/googleapis/genai-toolbox/commit/ab3fd261af373dcdaf4555292c63d7095d7a02df))
|
||||
* **tools/alloydb-get-cluster:** Add new tool for AlloyDB ([#1420](https://github.com/googleapis/genai-toolbox/issues/1420)) ([c181dab](https://github.com/googleapis/genai-toolbox/commit/c181dabc91bdc1c24c89a3c7bba0049d9af4cf2b))
|
||||
* **tools/alloydb-get-instance:** Add new for AlloyDB ([#1435](https://github.com/googleapis/genai-toolbox/issues/1435)) ([f2d9e3b](https://github.com/googleapis/genai-toolbox/commit/f2d9e3b57963082f0db70880d5c02b1cbe3eb75d))
|
||||
* **tools/alloydb-get-user:** Add new tool for AlloyDB ([#1436](https://github.com/googleapis/genai-toolbox/issues/1436)) ([677254e](https://github.com/googleapis/genai-toolbox/commit/677254e6d9c532fa9f0fb0b0e4062446640ab75f))
|
||||
* **tools/alloydb-list-cluster:** Add custom tool kind for AlloyDB ([#1319](https://github.com/googleapis/genai-toolbox/issues/1319)) ([d4a9eb0](https://github.com/googleapis/genai-toolbox/commit/d4a9eb0ce217c7969aff61868e53c7dc7757d28d))
|
||||
* **tools/alloydb-list-instances:** Add custom tool kind for AlloyDB ([#1357](https://github.com/googleapis/genai-toolbox/issues/1357)) ([93c1b30](https://github.com/googleapis/genai-toolbox/commit/93c1b30fced113d6721ade9fdcfb92b5ed6c0ad6))
|
||||
* **tools/alloydb-list-users:** Add new custom tool kind for AlloyDB ([#1377](https://github.com/googleapis/genai-toolbox/issues/1377)) ([3a8a65c](https://github.com/googleapis/genai-toolbox/commit/3a8a65ceaa92368563e237087c4a38ed7c0d3fd5))
|
||||
* **tools/bigquery-analyze-contribution:** Add analyze contribution tool ([#1223](https://github.com/googleapis/genai-toolbox/issues/1223)) ([81d239b](https://github.com/googleapis/genai-toolbox/commit/81d239b053a6978250878a6809905dcc9424909e))
|
||||
* **tools/bigquery-conversational-analytics:** Add allowed datasets support ([#1411](https://github.com/googleapis/genai-toolbox/issues/1411)) ([345bd6a](https://github.com/googleapis/genai-toolbox/commit/345bd6af520bb9ce8a43834951e68fea7bbe6a02))
|
||||
* **tools/bigquery-search-catalog:** Add new tool to BigQuery ([#1382](https://github.com/googleapis/genai-toolbox/issues/1382)) ([bffb39d](https://github.com/googleapis/genai-toolbox/commit/bffb39dea3cc946a1e611e3523241443b1e4f047))
|
||||
* **tools/bigquery:** Add `useClientOAuth` to BigQuery prebuilt source config ([#1431](https://github.com/googleapis/genai-toolbox/issues/1431)) ([fe2999a](https://github.com/googleapis/genai-toolbox/commit/fe2999a691ac92b2bf35cb7cfd504df2f3ce84b3))
|
||||
* **tools/clickhouse-list-databases:** Add `list-databases` tool to clickhouse source ([#1274](https://github.com/googleapis/genai-toolbox/issues/1274)) ([e515d92](https://github.com/googleapis/genai-toolbox/commit/e515d9254f3b8e89f89322d490eb3cedce85d2bb))
|
||||
* **tools/firestore-get-rules:** Add `databaseId` to the Firestore source and `firestore-get-rules` tool ([#1505](https://github.com/googleapis/genai-toolbox/issues/1505)) ([7450482](https://github.com/googleapis/genai-toolbox/commit/7450482bb2479eab7d1c8f0d40755a8d11aa3b26))
|
||||
* **tools/firestore:** Add `firestore-query` tool ([#1305](https://github.com/googleapis/genai-toolbox/issues/1305)) ([cce602f](https://github.com/googleapis/genai-toolbox/commit/cce602f28097353f6a3017cec1fa5f75283f111d))
|
||||
* **tools/looker:** Query tracking for MCP Toolbox in Looker System Activity views ([#1410](https://github.com/googleapis/genai-toolbox/issues/1410)) ([2036c8e](https://github.com/googleapis/genai-toolbox/commit/2036c8efd2fb9edc26df599629d3131c6c367f4b))
|
||||
* **tools/mssql-list-tables:** Add new tool for sql server ([#1433](https://github.com/googleapis/genai-toolbox/issues/1433)) ([b036047](https://github.com/googleapis/genai-toolbox/commit/b036047a21f63265c9d9637ac1a671792c9c2e80))
|
||||
* **tools/mysql-list-active-queries:** Add a new tool to list ongoing queries in a MySQL instance ([#1471](https://github.com/googleapis/genai-toolbox/issues/1471)) ([ed54cd6](https://github.com/googleapis/genai-toolbox/commit/ed54cd6cfd17a3bdd84025d4eb8264763da36a98))
|
||||
* **tools/mysql-list-table-fragmentation:** Add a new tool to list table fragmentation in a MySQL instance ([#1479](https://github.com/googleapis/genai-toolbox/issues/1479)) ([fe651d8](https://github.com/googleapis/genai-toolbox/commit/fe651d822f88832833e869ec049c6c084eae7e51))
|
||||
* **tools/mysql-list-tables-missing-index:** Add a new tool to list tables that do not have primary or unique keys in a MySQL instance ([#1493](https://github.com/googleapis/genai-toolbox/issues/1493)) ([9eb821a](https://github.com/googleapis/genai-toolbox/commit/9eb821a6dca408ba993f904aa42b5b4f70674ba7))
|
||||
* **tools/mysql-list-tables:** Add new tool for MySQL ([#1287](https://github.com/googleapis/genai-toolbox/issues/1287)) ([6c8460b](https://github.com/googleapis/genai-toolbox/commit/6c8460b0e507315d407c91ba1c821f4820cc1620))
|
||||
* **tools/postgres-list-active-queries:** Add new `postgres-list-active-queries` tool ([#1400](https://github.com/googleapis/genai-toolbox/issues/1400)) ([b2b06c7](https://github.com/googleapis/genai-toolbox/commit/b2b06c72c29fd99a0c7118b85e6f7bcf6853d173))
|
||||
* **tools/postgres-list-tables:** Add new tool to postgres source ([#1284](https://github.com/googleapis/genai-toolbox/issues/1284)) ([71f360d](https://github.com/googleapis/genai-toolbox/commit/71f360d31522f429a646b705ce7d1d11dac4cf68))
|
||||
* **tools/spanner-list-tables:** Add new tool `spanner-list-tables` ([#1404](https://github.com/googleapis/genai-toolbox/issues/1404)) ([7d384dc](https://github.com/googleapis/genai-toolbox/commit/7d384dc28f8c37dddc2f6cefc0bbeb4c201e3167))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bigquery:** Add `Bearer` parsing to auth token ([#1386](https://github.com/googleapis/genai-toolbox/issues/1386)) ([b5f9780](https://github.com/googleapis/genai-toolbox/commit/b5f9780a59e15eca2591dee32f5da42435e03039))
|
||||
* **source/alloydb-admin, source/cloudsql-admin:** Post append new user agent ([#1494](https://github.com/googleapis/genai-toolbox/issues/1494)) ([30f1d3a](https://github.com/googleapis/genai-toolbox/commit/30f1d3a983aa317f1e1a98f9fe753005b56c52bd))
|
||||
* **tools/alloydb:** Update parameter names and set default description for AlloyDB control plane tools ([#1468](https://github.com/googleapis/genai-toolbox/issues/1468)) ([6c140d7](https://github.com/googleapis/genai-toolbox/commit/6c140d718a66b45c7ec2d5a267331adb7680f689))
|
||||
* **tools/bigquery-conversational-analytics:** Fix authentication scope error in Cloud Run ([#1381](https://github.com/googleapis/genai-toolbox/issues/1381)) ([80b7488](https://github.com/googleapis/genai-toolbox/commit/80b7488ad248ab1d98ee6713e1f6737f67f6754b))
|
||||
* **tools/mysql-list-tables:** Update `mysql-list-tables` table_names parameter with default value ([#1439](https://github.com/googleapis/genai-toolbox/issues/1439)) ([da24661](https://github.com/googleapis/genai-toolbox/commit/da246610e105df10a9dc1bce19fa35d408c039f3))
|
||||
* **tools/neo4j:** Implement value conversion for Neo4j types to JSON-compatible ([#1428](https://github.com/googleapis/genai-toolbox/issues/1428)) ([4babc4e](https://github.com/googleapis/genai-toolbox/commit/4babc4e11b3b64db8d8c9d6b65e47744f5174f7f))
|
||||
|
||||
## [0.14.0](https://github.com/googleapis/genai-toolbox/compare/v0.13.0...v0.14.0) (2025-09-05)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **bigquery:** Move `useClientOAuth` config from tool to source ([#1279](https://github.com/googleapis/genai-toolbox/issues/1279)) ([8d20a48](https://github.com/googleapis/genai-toolbox/commit/8d20a48f13bcda853d41bdf80a162de12b076d1b))
|
||||
* **tools/bigquerysql:** remove `useClientOAuth` from tools config ([#1312](https://github.com/googleapis/genai-toolbox/issues/1312))
|
||||
|
||||
### Features
|
||||
|
||||
* **clickhouse:** Add ClickHouse Source and Tools ([#1088](https://github.com/googleapis/genai-toolbox/issues/1088)) ([75a04a5](https://github.com/googleapis/genai-toolbox/commit/75a04a55dd2259bed72fe95119a7a51a906c0b21))
|
||||
* **prebuilt/alloydb-postgres:** Support ipType and IAM users ([#1324](https://github.com/googleapis/genai-toolbox/issues/1324)) ([0b2121e](https://github.com/googleapis/genai-toolbox/commit/0b2121ea72eb81348dcd9c740a62ccd32e71fe37))
|
||||
* **server/mcp:** Support toolbox auth in mcp ([#1140](https://github.com/googleapis/genai-toolbox/issues/1140)) ([ca353e0](https://github.com/googleapis/genai-toolbox/commit/ca353e0b66fedc00e9110df57db18632aef49018))
|
||||
* **source/mysql:** Support `queryParams` in MySQL source ([#1299](https://github.com/googleapis/genai-toolbox/issues/1299)) ([3ae2526](https://github.com/googleapis/genai-toolbox/commit/3ae2526e0fe36b57b05a9b54f1d99f3fc68d9657))
|
||||
* **tools/bigquery:** Support end-user credential passthrough on multiple BQ tools ([#1314](https://github.com/googleapis/genai-toolbox/issues/1314)) ([88f4b30](https://github.com/googleapis/genai-toolbox/commit/88f4b3028df3b6a400936cdf8a035bf55021924c))
|
||||
* **tools/looker:** Add description for looker-get-models tool ([#1266](https://github.com/googleapis/genai-toolbox/issues/1266)) ([89af3a4](https://github.com/googleapis/genai-toolbox/commit/89af3a4ca332f029615b2a739d1f6cd50519638d))
|
||||
* **tools/looker:** Authenticate via end user credentials ([#1257](https://github.com/googleapis/genai-toolbox/issues/1257)) ([8755e3d](https://github.com/googleapis/genai-toolbox/commit/8755e3db3476abb35629b3cca9c78db7366757a4))
|
||||
* **tools/looker:** Report field suggestions to agent ([#1267](https://github.com/googleapis/genai-toolbox/issues/1267)) ([2cad82e](https://github.com/googleapis/genai-toolbox/commit/2cad82e5107566dd6c9b75e34e9976af63af0bb5))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Do not print usage on runtime error ([#1315](https://github.com/googleapis/genai-toolbox/issues/1315)) ([afba7a5](https://github.com/googleapis/genai-toolbox/commit/afba7a57cdd4fe7c1b0741dbf8f8c78b14a68089))
|
||||
* Update env var to allow empty string ([#1260](https://github.com/googleapis/genai-toolbox/issues/1260)) ([03aa9fa](https://github.com/googleapis/genai-toolbox/commit/03aa9fabacda06f860c9f178485126bddb7d5782))
|
||||
* **tools/firestore:** Add document/collection path validation ([#1229](https://github.com/googleapis/genai-toolbox/issues/1229)) ([14c2249](https://github.com/googleapis/genai-toolbox/commit/14c224939a2f9bb349fa00a7d5227877198530c2))
|
||||
* **tools/looker-get-dashboards:** Fix Looker client OAuth check ([#1338](https://github.com/googleapis/genai-toolbox/issues/1338)) ([36225aa](https://github.com/googleapis/genai-toolbox/commit/36225aa6db7f8426ad87930866530fde4e9bf0cd))
|
||||
* **tools/oceanbase:** Fix encoded text with mysql driver ([#1283](https://github.com/googleapis/genai-toolbox/issues/1283)) ([d16f89f](https://github.com/googleapis/genai-toolbox/commit/d16f89fbb6e49c03998f114ef7dc2b584b5e4967)), closes [#1161](https://github.com/googleapis/genai-toolbox/issues/1161)
|
||||
|
||||
## [0.13.0](https://github.com/googleapis/genai-toolbox/compare/v0.12.0...v0.13.0) (2025-08-27)
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **prebuilt/alloydb:** Add bearer token support for alloydb-wait-for-operation ([#1183](https://github.com/googleapis/genai-toolbox/issues/1183))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add capability to set default for environment variable in config ([#1248](https://github.com/googleapis/genai-toolbox/issues/1248)) ([5bcd52e](https://github.com/googleapis/genai-toolbox/commit/5bcd52e7dcd0773ded723585f4abe29d044e1540))
|
||||
* **firebird:** Add Firebird SQL 2.5+ source and tool ([#1011](https://github.com/googleapis/genai-toolbox/issues/1011)) ([4f6b806](https://github.com/googleapis/genai-toolbox/commit/4f6b806de947efc4e12bdb50dff7781aedb7b966))
|
||||
* **oceanbase:** Add Oceanbase source and tool ([#895](https://github.com/googleapis/genai-toolbox/issues/895)) ([6fc4982](https://github.com/googleapis/genai-toolbox/commit/6fc49826d43f46c84028e752ebebddf3d94b3d13))
|
||||
* **server/mcp:** Support `ping` mechanism ([#1178](https://github.com/googleapis/genai-toolbox/issues/1178)) ([5dcc66c](https://github.com/googleapis/genai-toolbox/commit/5dcc66c84fa72c75ec50a9ac5198018212ec2979))
|
||||
* **server:** Fail-fast on environment variable substitution ([#1177](https://github.com/googleapis/genai-toolbox/issues/1177)) ([212aaba](https://github.com/googleapis/genai-toolbox/commit/212aaba74c8b431de8a5f7b9822a0af4afcaaa0e))
|
||||
* **server:** Implement Tool call auth error propagation ([#1235](https://github.com/googleapis/genai-toolbox/issues/1235)) ([b94a021](https://github.com/googleapis/genai-toolbox/commit/b94a021ca11c6637cf8038449483b5e75f2012b3))
|
||||
* **sources/bigquery:** Add support for user-credential passthrough ([#1067](https://github.com/googleapis/genai-toolbox/issues/1067)) ([650e2e2](https://github.com/googleapis/genai-toolbox/commit/650e2e26f51bff75ce66343f64944d0a89a58b69))
|
||||
* **tool/looker:** Add support for `description` field in looker tool ([#1199](https://github.com/googleapis/genai-toolbox/issues/1199)) ([97f0dd2](https://github.com/googleapis/genai-toolbox/commit/97f0dd2acf26caf28ecad65abea8779c196a27f1))
|
||||
* **tools/bigquery-ask-data-insights:** Add bigquery `ask-data-insights` tool ([#932](https://github.com/googleapis/genai-toolbox/issues/932)) ([7651357](https://github.com/googleapis/genai-toolbox/commit/7651357d424a2b6656d8b6818cebc5c8a86ed053))
|
||||
* **tools/bigquery-forecast:** Add bigqueryforecast tool ([#1148](https://github.com/googleapis/genai-toolbox/issues/1148)) ([2ad0ccf](https://github.com/googleapis/genai-toolbox/commit/2ad0ccf83df542340087742468d6762f81eedee6))
|
||||
* **tools/firestore-add-documents:** Add firestore-add-documents tool ([#1107](https://github.com/googleapis/genai-toolbox/issues/1107)) ([ee4a70a](https://github.com/googleapis/genai-toolbox/commit/ee4a70a0e82b346b07b5b4c60dfa060da2273f50))
|
||||
* **tools/firestore-update-document:** Add firestore-update-document tool ([#1191](https://github.com/googleapis/genai-toolbox/issues/1191)) ([0010123](https://github.com/googleapis/genai-toolbox/commit/00101232a39c70288aac5715649c184858d351e3))
|
||||
* **tools/looker:** Control over whether hidden objects are surfaced ([#1222](https://github.com/googleapis/genai-toolbox/issues/1222)) ([bc91559](https://github.com/googleapis/genai-toolbox/commit/bc91559cc4e5b20385b84cc562b624fabf7e47a8))
|
||||
* **trino:** Add Trino source and tools ([#948](https://github.com/googleapis/genai-toolbox/issues/948)) ([7dd123b](https://github.com/googleapis/genai-toolbox/commit/7dd123b3d76b8eb2b74b5d960959c1f90684b37e))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tools/looker:** Lookergetdashboards uses proper Authorized helper func ([#1255](https://github.com/googleapis/genai-toolbox/issues/1255)) ([00866bc](https://github.com/googleapis/genai-toolbox/commit/00866bc7fc33115c547213e60316ae889735fdbb))
|
||||
* **tools/mongodb-find-one:** ProjectPayload unmarshaling ([#1167](https://github.com/googleapis/genai-toolbox/issues/1167)) ([8ea6a98](https://github.com/googleapis/genai-toolbox/commit/8ea6a98bd9096ba97722e5f807366887e864004f))
|
||||
* **tools/mysql:** Fix encoded text for mysql ([#1161](https://github.com/googleapis/genai-toolbox/issues/1161)) ([a37cfa8](https://github.com/googleapis/genai-toolbox/commit/a37cfa841d151b9995d4fab73cfc5e4d30d2cc57)), closes [#840](https://github.com/googleapis/genai-toolbox/issues/840)
|
||||
|
||||
## [0.12.0](https://github.com/googleapis/genai-toolbox/compare/v0.11.0...v0.12.0) (2025-08-14)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **prebuiltconfig:** Introduce additional parameter to limit context in list_tables ([#1151](https://github.com/googleapis/genai-toolbox/issues/1151)) ([497d3b1](https://github.com/googleapis/genai-toolbox/commit/497d3b126da252a4b59806ca2ca3c56e78efc13d))
|
||||
* **prebuiltconfig/alloydb-admin:** Add list cluster, instance and users ([#1126](https://github.com/googleapis/genai-toolbox/issues/1126)) ([b42c139](https://github.com/googleapis/genai-toolbox/commit/b42c139158650fb1f3b696965e840c52e2016bf0))
|
||||
* **prebuiltconfig/alloydb-admin:** Add tool to create user via Built in user type or IAM ([#1130](https://github.com/googleapis/genai-toolbox/issues/1130)) ([f5bcb9c](https://github.com/googleapis/genai-toolbox/commit/f5bcb9c755a2c1747d0beeda568b6217d7420e7a))
|
||||
* **source/http:** Add User Agent to `http` invocations ([#1102](https://github.com/googleapis/genai-toolbox/issues/1102)) ([6f55b78](https://github.com/googleapis/genai-toolbox/commit/6f55b78e96b8c7aa9aca601cfae4d62f3e1eb42b))
|
||||
* **sources/postgres:** Add support for `queryParams` ([#1047](https://github.com/googleapis/genai-toolbox/issues/1047)) ([7b57251](https://github.com/googleapis/genai-toolbox/commit/7b5725140279de21fece45e860945b7a7d23e7d0)), closes [#963](https://github.com/googleapis/genai-toolbox/issues/963)
|
||||
* **tools/bigquery-execute-sql:** Add dry run support ([#1057](https://github.com/googleapis/genai-toolbox/issues/1057)) ([1cac9b5](https://github.com/googleapis/genai-toolbox/commit/1cac9b5b378153c7dc65ff3dfb4ebd852b715a10))
|
||||
* **tools/dataplex-search-aspect-types:** Add support for `dataplex-search-aspect-types` tool ([#1061](https://github.com/googleapis/genai-toolbox/issues/1061)) ([d940187](https://github.com/googleapis/genai-toolbox/commit/d940187c851666cc201f519665fb4f2e1478465c))
|
||||
* **tools/looker:** Add `looker-make-look` tool to create Looks ([#1099](https://github.com/googleapis/genai-toolbox/issues/1099)) ([61d9489](https://github.com/googleapis/genai-toolbox/commit/61d94893448f633a5f2b9d7f0744ab40704af824))
|
||||
* **tools/looker:** Add visualizations to `query-url` tool ([#1090](https://github.com/googleapis/genai-toolbox/issues/1090)) ([5bf2758](https://github.com/googleapis/genai-toolbox/commit/5bf275846a268a8d305d6392fa4e8e79e365f00d))
|
||||
* **tools/looker:** New Looker tools for dashboards ([#1118](https://github.com/googleapis/genai-toolbox/issues/1118)) ([42be3f5](https://github.com/googleapis/genai-toolbox/commit/42be3f550ceab34baf43fe2a246ded7a09cff8e3))
|
||||
* **ui:** Add login with google button for automatic id token retrieval ([#1044](https://github.com/googleapis/genai-toolbox/issues/1044)) ([d91bdfc](https://github.com/googleapis/genai-toolbox/commit/d91bdfcbdcbf5fcae6e17770c88c5ffba4115d67))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Correct the capitalization of `map` manifests ([#1139](https://github.com/googleapis/genai-toolbox/issues/1139)) ([0b0457c](https://github.com/googleapis/genai-toolbox/commit/0b0457c8e6b78f53a2f1929c05d46fb31421fbca))
|
||||
* Remove unnecessary fields from `map` parameter manifests ([#1138](https://github.com/googleapis/genai-toolbox/issues/1138)) ([fbe8c1a](https://github.com/googleapis/genai-toolbox/commit/fbe8c1a9c0f28797443bf9cb32d63bfbc1072881))
|
||||
* **tools/looker:** Add authorized invocation feature to all Looker tools ([#1091](https://github.com/googleapis/genai-toolbox/issues/1091)) ([3b1cce7](https://github.com/googleapis/genai-toolbox/commit/3b1cce72e7ff4f6b3a0a31db0564dc45b8302caa))
|
||||
* Update ui info log to reflect port ([#1125](https://github.com/googleapis/genai-toolbox/issues/1125)) ([6d691d5](https://github.com/googleapis/genai-toolbox/commit/6d691d582f18137de504d39f372c5104b7392bff))
|
||||
|
||||
## [0.11.0](https://github.com/googleapis/genai-toolbox/compare/v0.11.0...v0.11.0) (2025-08-05)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **tools/bigquery-sql:** Ensure invoke always returns a non-null value ([#1020](https://github.com/googleapis/genai-toolbox/issues/1020)) ([9af55b6](https://github.com/googleapis/genai-toolbox/commit/9af55b651d836f268eda342ea27380e7c9967c94))
|
||||
* **tools/bigquery-execute-sql:** Update the return messages ([#1034](https://github.com/googleapis/genai-toolbox/issues/1034)) ([051e686](https://github.com/googleapis/genai-toolbox/commit/051e686476a781ca49f7617764d507916a1188b8))
|
||||
|
||||
### Features
|
||||
|
||||
* Add TiDB source and tool ([#829](https://github.com/googleapis/genai-toolbox/issues/829)) ([6eaf36a](https://github.com/googleapis/genai-toolbox/commit/6eaf36ac8505d523fa4f5a4ac3c97209fd688cef))
|
||||
* Interactive web UI for Toolbox ([#1065](https://github.com/googleapis/genai-toolbox/issues/1065)) ([8749b03](https://github.com/googleapis/genai-toolbox/commit/8749b030035e65361047c4ead13dfacb8e9a9b59))
|
||||
* **prebuiltconfigs/cloud-sql-postgres:** Introduce additional parameter to limit context in list tables ([#1062](https://github.com/googleapis/genai-toolbox/issues/1062)) ([c3a58e1](https://github.com/googleapis/genai-toolbox/commit/c3a58e1d1678dc14d8de5006511df597fd75faa3))
|
||||
* **tools/looker-query-url:** Add support for `looker-query-url` tool ([#1015](https://github.com/googleapis/genai-toolbox/issues/1015)) ([327ddf0](https://github.com/googleapis/genai-toolbox/commit/327ddf0439058aa5ecd2c7ae8251fcde6aeff18c))
|
||||
* **tools/dataplex-lookup-entry:** Add support for `dataplex-lookup-entry` tool ([#1009](https://github.com/googleapis/genai-toolbox/issues/1009)) ([5fa1660](https://github.com/googleapis/genai-toolbox/commit/5fa1660fc8631989b4d13abea205b6426bb506a5))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **tools/bigquery,mssql,mysql,postgres,spanner,tidb:** Add query logging to execute-sql tools ([#1069](https://github.com/googleapis/genai-toolbox/issues/1069)) ([0527532]([https://github.com/googleapis/genai-toolbox/commit/0527532bd7085ef9eb8f9c30f430a2f2f35cef32))
|
||||
|
||||
## [0.10.0](https://github.com/googleapis/genai-toolbox/compare/v0.9.0...v0.10.0) (2025-07-25)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Add `Map` parameters support ([#928](https://github.com/googleapis/genai-toolbox/issues/928)) ([4468bc9](https://github.com/googleapis/genai-toolbox/commit/4468bc920bbf27dce4ab160197587b7c12fcd20f))
|
||||
* Add Dataplex source and tool ([#847](https://github.com/googleapis/genai-toolbox/issues/847)) ([30c16a5](https://github.com/googleapis/genai-toolbox/commit/30c16a559e8d49a9a717935269e69b97ec25519a))
|
||||
* Add Looker source and tool ([#923](https://github.com/googleapis/genai-toolbox/issues/923)) ([c67e01b](https://github.com/googleapis/genai-toolbox/commit/c67e01bcf998e7b884be30ebb1fd277c89ed6ffc))
|
||||
* Add support for null optional parameter ([#802](https://github.com/googleapis/genai-toolbox/issues/802)) ([a817b12](https://github.com/googleapis/genai-toolbox/commit/a817b120ca5e09ce80eb8d7544ebbe81fc28b082)), closes [#736](https://github.com/googleapis/genai-toolbox/issues/736)
|
||||
* **prebuilt/alloydb-admin-config:** Add alloydb control plane as a prebuilt config ([#937](https://github.com/googleapis/genai-toolbox/issues/937)) ([0b28b72](https://github.com/googleapis/genai-toolbox/commit/0b28b72aa0ca2cdc87afbddbeb7f4dbb9688593d))
|
||||
* **prebuilt/mysql,prebuilt/mssql:** Add generic mysql and mssql prebuilt tools ([#983](https://github.com/googleapis/genai-toolbox/issues/983)) ([c600c30](https://github.com/googleapis/genai-toolbox/commit/c600c30374443b6106c1f10b60cd334fd202789b))
|
||||
* **server/mcp:** Support MCP version 2025-06-18 ([#898](https://github.com/googleapis/genai-toolbox/issues/898)) ([313d3ca](https://github.com/googleapis/genai-toolbox/commit/313d3ca0d084a3a6e7ac9a21a862aa31bf3edadd))
|
||||
* **sources/mssql:** Add support for encrypt connection parameter ([#874](https://github.com/googleapis/genai-toolbox/issues/874)) ([14a868f](https://github.com/googleapis/genai-toolbox/commit/14a868f2a0780b94c2ca104419b2ff098778303b))
|
||||
* **sources/firestore:** Add Firestore as Source ([#786](https://github.com/googleapis/genai-toolbox/issues/786)) ([2bb790e](https://github.com/googleapis/genai-toolbox/commit/2bb790e4f8194b677fe0ba40122d409d0e3e687e))
|
||||
* **sources/mongodb:** Add MongoDB Source ([#969](https://github.com/googleapis/genai-toolbox/issues/969)) ([74dbd61](https://github.com/googleapis/genai-toolbox/commit/74dbd6124daab6192dd880dbd1d15f36861abf74))
|
||||
* **tools/alloydb-wait-for-operation:** Add wait for operation tool with exponential backoff ([#920](https://github.com/googleapis/genai-toolbox/issues/920)) ([3f6ec29](https://github.com/googleapis/genai-toolbox/commit/3f6ec2944ede18ee02b10157cc048145bdaec87a))
|
||||
* **tools/mongodb-aggregate:** Add MongoDB `aggregate` Tools ([#977](https://github.com/googleapis/genai-toolbox/issues/977)) ([bd399bb](https://github.com/googleapis/genai-toolbox/commit/bd399bb0fb7134469345ed9a1111ea4209440867))
|
||||
* **tools/mongodb-delete:** Add MongoDB `delete` Tools ([#974](https://github.com/googleapis/genai-toolbox/issues/974)) ([78e9752](https://github.com/googleapis/genai-toolbox/commit/78e9752f620e065246f3e7b9d37062e492247c8a))
|
||||
* **tools/mongodb-find:** Add MongoDB `find` Tools ([#970](https://github.com/googleapis/genai-toolbox/issues/970)) ([a747475](https://github.com/googleapis/genai-toolbox/commit/a7474752d8d7ea7af1e80a3c4533d2fd4154d897))
|
||||
* **tools/mongodb-insert:** Add MongoDB `insert` Tools ([#975](https://github.com/googleapis/genai-toolbox/issues/975)) ([4c63f0c](https://github.com/googleapis/genai-toolbox/commit/4c63f0c1e402817a0c8fec611635e99290308d0e))
|
||||
* **tools/mongodb-update:** Add MongoDB `update` Tools ([#972](https://github.com/googleapis/genai-toolbox/issues/972)) ([dfde52c](https://github.com/googleapis/genai-toolbox/commit/dfde52ca9a8e25e2f3944f52b4c2e307072b6c37))
|
||||
* **tools/neo4j-execute-cypher:** Add neo4j-execute-cypher for Neo4j sources ([#946](https://github.com/googleapis/genai-toolbox/issues/946)) ([81d0505](https://github.com/googleapis/genai-toolbox/commit/81d05053b2e08338fd6eabe4849c309064f76b6b))
|
||||
* **tools/neo4j-schema:** Add neo4j-schema tool ([#978](https://github.com/googleapis/genai-toolbox/issues/978)) ([be7db3d](https://github.com/googleapis/genai-toolbox/commit/be7db3dff263625ce64fdb726e81164996b7a708))
|
||||
* **tools/wait:** Create wait for tool ([#885](https://github.com/googleapis/genai-toolbox/issues/885)) ([ed5ef4c](https://github.com/googleapis/genai-toolbox/commit/ed5ef4caea10ba1dbc49c0fc0a0d2b91cf341d3b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Fix document preview pipeline for forked PRs ([#950](https://github.com/googleapis/genai-toolbox/issues/950)) ([481cc60](https://github.com/googleapis/genai-toolbox/commit/481cc608bae807d9e92497bc8863066916f7ef21))
|
||||
* **prebuilt/firestore:** Mark database field as required in the firestore prebuilt tools ([#959](https://github.com/googleapis/genai-toolbox/issues/959)) ([15417d4](https://github.com/googleapis/genai-toolbox/commit/15417d4e0c7b173e81edbbeb672e53884d186104))
|
||||
* **prebuilt/cloud-sql-mssql:** Correct source reference for execute_sql tool in cloud-sql-mssql.yaml prebuilt config ([#938](https://github.com/googleapis/genai-toolbox/issues/938)) ([d16728e](https://github.com/googleapis/genai-toolbox/commit/d16728e5c603eab37700876a6ddacbf709fd5823))
|
||||
* **prebuilt/cloud-sql-mysql:** Update list_table tool ([#924](https://github.com/googleapis/genai-toolbox/issues/924)) ([2083ba5](https://github.com/googleapis/genai-toolbox/commit/2083ba50483951e9ee6101bb832aa68823cd96a5))
|
||||
* Replace 'float' with 'number' in McpManifest ([#985](https://github.com/googleapis/genai-toolbox/issues/985)) ([59e23e1](https://github.com/googleapis/genai-toolbox/commit/59e23e17250a516e3931996114f32ac6526a4f8e))
|
||||
* **server/api:** Add logger to context in tool invoke handler ([#891](https://github.com/googleapis/genai-toolbox/issues/891)) ([8ce311f](https://github.com/googleapis/genai-toolbox/commit/8ce311f256481e8f11ecb4aa505b95a562f394ef))
|
||||
* **sources/looker:** Add agent tag to Looker API calls. ([#966](https://github.com/googleapis/genai-toolbox/issues/966)) ([f55dd6f](https://github.com/googleapis/genai-toolbox/commit/f55dd6fcd099f23bd89df62b268c4a53d16f3bac))
|
||||
* **tools/bigquery-execute-sql:** Ensure invoke always returns a non-null value ([#925](https://github.com/googleapis/genai-toolbox/issues/925)) ([9a55b80](https://github.com/googleapis/genai-toolbox/commit/9a55b804821a6ccfcd157bcfaee7e599c4a5cb63))
|
||||
* **tools/mysqlsql:** Unmarshal json data from database during invoke ([#979](https://github.com/googleapis/genai-toolbox/issues/979)) ([ccc3498](https://github.com/googleapis/genai-toolbox/commit/ccc3498cf0a4c43eb909e3850b9e6f582cd48f2a)), closes [#840](https://github.com/googleapis/genai-toolbox/issues/840)
|
||||
|
||||
## [0.9.0](https://github.com/googleapis/genai-toolbox/compare/v0.8.0...v0.9.0) (2025-07-11)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* Dynamic reloading for toolbox config ([#800](https://github.com/googleapis/genai-toolbox/issues/800)) ([4c240ac](https://github.com/googleapis/genai-toolbox/commit/4c240ac3c961cd14738c998ba2d10d5235ef523e))
|
||||
* **sources/mysql:** Add queryTimeout support to MySQL source ([#830](https://github.com/googleapis/genai-toolbox/issues/830)) ([391cb5b](https://github.com/googleapis/genai-toolbox/commit/391cb5bfe845e554411240a1d9838df5331b25fa))
|
||||
* **tools/bigquery:** Add optional projectID parameter to bigquery tools ([#799](https://github.com/googleapis/genai-toolbox/issues/799)) ([c6ab74c](https://github.com/googleapis/genai-toolbox/commit/c6ab74c5dad53a0e7885a18438ab3be36b9b7cb3))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Cleanup unassigned err log ([#857](https://github.com/googleapis/genai-toolbox/issues/857)) ([c081ace](https://github.com/googleapis/genai-toolbox/commit/c081ace46bb24cb3fd2adb21d519489be0d3f3c3))
|
||||
* Fix docs preview deployment pipeline ([#787](https://github.com/googleapis/genai-toolbox/issues/787)) ([0a93b04](https://github.com/googleapis/genai-toolbox/commit/0a93b0482c8d3c64b324e67408d408f5576ecaf3))
|
||||
* **tools:** Nil parameter error when arrays are used ([#801](https://github.com/googleapis/genai-toolbox/issues/801)) ([2bdcc08](https://github.com/googleapis/genai-toolbox/commit/2bdcc0841ab37d18e2f0d6fe63fb6f10da3e302b))
|
||||
* Trigger reload on additional fsnotify operations ([#854](https://github.com/googleapis/genai-toolbox/issues/854)) ([aa8dbec](https://github.com/googleapis/genai-toolbox/commit/aa8dbec97095cf0d7ac771c8084a84e2d3d8ce4e))
|
||||
|
||||
## [0.8.0](https://github.com/googleapis/genai-toolbox/compare/v0.7.0...v0.8.0) (2025-07-02)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **postgres,mssql,cloudsqlmssql:** encode source connection url for sources ([#727](https://github.com/googleapis/genai-toolbox/issues/727))
|
||||
|
||||
### Features
|
||||
|
||||
* Add support for multiple YAML configuration files ([#760](https://github.com/googleapis/genai-toolbox/issues/760)) ([40679d7](https://github.com/googleapis/genai-toolbox/commit/40679d700eded50d19569923e2a71c51e907a8bf))
|
||||
* Add support for optional parameters ([#617](https://github.com/googleapis/genai-toolbox/issues/617)) ([4827771](https://github.com/googleapis/genai-toolbox/commit/4827771b78dee9a1284a898b749509b472061527)), closes [#475](https://github.com/googleapis/genai-toolbox/issues/475)
|
||||
* **mcp:** Support MCP version 2025-03-26 ([#755](https://github.com/googleapis/genai-toolbox/issues/755)) ([474df57](https://github.com/googleapis/genai-toolbox/commit/474df57d62de683079f8d12c31db53396a545fd1))
|
||||
* **sources/http:** Support disable SSL verification for HTTP Source ([#674](https://github.com/googleapis/genai-toolbox/issues/674)) ([4055b0c](https://github.com/googleapis/genai-toolbox/commit/4055b0c3569c527560d7ad34262963b3dd4e282d))
|
||||
* **tools/bigquery:** Add templateParameters field for bigquery ([#699](https://github.com/googleapis/genai-toolbox/issues/699)) ([f5f771b](https://github.com/googleapis/genai-toolbox/commit/f5f771b0f3d159630ff602ff55c6c66b61981446))
|
||||
* **tools/bigtable:** Add templateParameters field for bigtable ([#692](https://github.com/googleapis/genai-toolbox/issues/692)) ([1c06771](https://github.com/googleapis/genai-toolbox/commit/1c067715fac06479eb0060d7067b73dba099ed92))
|
||||
* **tools/couchbase:** Add templateParameters field for couchbase ([#723](https://github.com/googleapis/genai-toolbox/issues/723)) ([9197186](https://github.com/googleapis/genai-toolbox/commit/9197186b8bea1ac4ec1b39c9c5c110807c8b2ba9))
|
||||
* **tools/http:** Add support for HTTP Tool pathParams ([#726](https://github.com/googleapis/genai-toolbox/issues/726)) ([fd300dc](https://github.com/googleapis/genai-toolbox/commit/fd300dc606d88bf9f7bba689e2cee4e3565537dd))
|
||||
* **tools/redis:** Add Redis Source and Tool ([#519](https://github.com/googleapis/genai-toolbox/issues/519)) ([f0aef29](https://github.com/googleapis/genai-toolbox/commit/f0aef29b0c2563e2a00277fbe2784f39f16d2835))
|
||||
* **tools/spanner:** Add templateParameters field for spanner ([#691](https://github.com/googleapis/genai-toolbox/issues/691)) ([075dfa4](https://github.com/googleapis/genai-toolbox/commit/075dfa47e1fd92be4847bd0aec63296146b66455))
|
||||
* **tools/sqlitesql:** Add templateParameters field for sqlitesql ([#687](https://github.com/googleapis/genai-toolbox/issues/687)) ([75e254c](https://github.com/googleapis/genai-toolbox/commit/75e254c0a4ce690ca5fa4d1741550ce54734b226))
|
||||
* **tools/valkey:** Add Valkey Source and Tool ([#532](https://github.com/googleapis/genai-toolbox/issues/532)) ([054ec19](https://github.com/googleapis/genai-toolbox/commit/054ec198b97ba9f36f67dd12b2eff0cc6bc4d080))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **bigquery,mssql:** Fix panic on tools with array param ([#722](https://github.com/googleapis/genai-toolbox/issues/722)) ([7a6644c](https://github.com/googleapis/genai-toolbox/commit/7a6644cf0c5413e5c803955c88a2cfd0a2233ed3))
|
||||
* **postgres,mssql,cloudsqlmssql:** Encode source connection url for sources ([#727](https://github.com/googleapis/genai-toolbox/issues/727)) ([67964d9](https://github.com/googleapis/genai-toolbox/commit/67964d939f27320b63b5759f4b3f3fdaa0c76fbf)), closes [#717](https://github.com/googleapis/genai-toolbox/issues/717)
|
||||
* Set default value to field's type during unmarshalling ([#774](https://github.com/googleapis/genai-toolbox/issues/774)) ([fafed24](https://github.com/googleapis/genai-toolbox/commit/fafed2485839cf1acc1350e8a24103d2e6356ee0)), closes [#771](https://github.com/googleapis/genai-toolbox/issues/771)
|
||||
* **server/mcp:** Do not listen from port for stdio ([#719](https://github.com/googleapis/genai-toolbox/issues/719)) ([d51dbc7](https://github.com/googleapis/genai-toolbox/commit/d51dbc759ba493021d3ec6f5417fc04c21f7044f)), closes [#711](https://github.com/googleapis/genai-toolbox/issues/711)
|
||||
* **tools/mysqlexecutesql:** Handle nil panic and connection leak in Invoke ([#757](https://github.com/googleapis/genai-toolbox/issues/757)) ([7badba4](https://github.com/googleapis/genai-toolbox/commit/7badba42eefb34252be77b852a57d6bd78dd267d))
|
||||
* **tools/mysqlsql:** Handle nil panic and connection leak in invoke ([#758](https://github.com/googleapis/genai-toolbox/issues/758)) ([cbb4a33](https://github.com/googleapis/genai-toolbox/commit/cbb4a333517313744800d148840312e56340f3fd))
|
||||
|
||||
## [0.7.0](https://github.com/googleapis/genai-toolbox/compare/v0.6.0...v0.7.0) (2025-06-10)
|
||||
|
||||
|
||||
|
||||
@@ -14,21 +14,21 @@ race, religion, or sexual identity and orientation.
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
@@ -75,7 +75,7 @@ receive and address reported violations of the code of conduct. They will then
|
||||
work with a committee consisting of representatives from the Open Source
|
||||
Programs Office and the Google Open Source Strategy team. If for any reason you
|
||||
are uncomfortable reaching out to the Project Steward, please email
|
||||
<opensource@google.com>.
|
||||
opensource@google.com.
|
||||
|
||||
We will investigate every complaint, but you may not receive a direct response.
|
||||
We will use our discretion in determining when and how to follow up on reported
|
||||
@@ -90,4 +90,4 @@ harassment or threats to anyone's safety, we may take action without notice.
|
||||
|
||||
This Code of Conduct is adapted from the Contributor Covenant, version 1.4,
|
||||
available at
|
||||
<https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
|
||||
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
207
CONTRIBUTING.md
207
CONTRIBUTING.md
@@ -25,212 +25,9 @@ This project follows
|
||||
|
||||
## Contribution process
|
||||
|
||||
> [!NOTE]
|
||||
> New contributions should always include both unit and integration tests.
|
||||
### Code reviews
|
||||
|
||||
All submissions, including submissions by project members, require review. We
|
||||
use GitHub pull requests for this purpose. Consult
|
||||
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||
information on using pull requests.
|
||||
|
||||
### Code reviews
|
||||
|
||||
* Within 2-5 days, a reviewer will review your PR. They may approve it, or request
|
||||
changes.
|
||||
* When requesting changes, reviewers should self-assign the PR to ensure
|
||||
they are aware of any updates.
|
||||
* If additional changes are needed, push additional commits to your PR branch -
|
||||
this helps the reviewer know which parts of the PR have changed.
|
||||
* Commits will be
|
||||
squashed when merged.
|
||||
* Please follow up with changes promptly.
|
||||
* If a PR is awaiting changes by the
|
||||
author for more than 10 days, maintainers may mark that PR as Draft. PRs that
|
||||
are inactive for more than 30 days may be closed.
|
||||
|
||||
## Adding a New Database Source or Tool
|
||||
|
||||
Please create an
|
||||
[issue](https://github.com/googleapis/genai-toolbox/issues) before
|
||||
implementation to ensure we can accept the contribution and no duplicated work.
|
||||
This issue should include an overview of the API design. If you have any
|
||||
questions, reach out on our [Discord](https://discord.gg/Dmm69peqjh) to chat
|
||||
directly with the team.
|
||||
|
||||
> [!NOTE]
|
||||
> New tools can be added for [pre-existing data
|
||||
> sources](https://github.com/googleapis/genai-toolbox/tree/main/internal/sources).
|
||||
> However, any new database source should also include at least one new tool
|
||||
> type.
|
||||
|
||||
### Adding a New Database Source
|
||||
|
||||
We recommend looking at an [example source
|
||||
implementation](https://github.com/googleapis/genai-toolbox/blob/main/internal/sources/postgres/postgres.go).
|
||||
|
||||
* **Create a new directory** under `internal/sources` for your database type
|
||||
(e.g., `internal/sources/newdb`).
|
||||
* **Define a configuration struct** for your data source in a file named
|
||||
`newdb.go`. Create a `Config` struct to include all the necessary parameters
|
||||
for connecting to the database (e.g., host, port, username, password, database
|
||||
name) and a `Source` struct to store necessary parameters for tools (e.g.,
|
||||
Name, Kind, connection object, additional config).
|
||||
* **Implement the
|
||||
[`SourceConfig`](https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/internal/sources/sources.go#L57)
|
||||
interface**. This interface requires two methods:
|
||||
* `SourceConfigKind() string`: Returns a unique string identifier for your
|
||||
data source (e.g., `"newdb"`).
|
||||
* `Initialize(ctx context.Context, tracer trace.Tracer) (Source, error)`:
|
||||
Creates a new instance of your data source and establishes a connection to
|
||||
the database.
|
||||
* **Implement the
|
||||
[`Source`](https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/internal/sources/sources.go#L63)
|
||||
interface**. This interface requires one method:
|
||||
* `SourceKind() string`: Returns the same string identifier as `SourceConfigKind()`.
|
||||
* **Implement `init()`** to register the new Source.
|
||||
* **Implement Unit Tests** in a file named `newdb_test.go`.
|
||||
|
||||
### Adding a New Tool
|
||||
|
||||
> [!NOTE]
|
||||
> Please follow the tool naming convention detailed [here](./DEVELOPER.md#tool-naming-conventions).
|
||||
|
||||
We recommend looking at an [example tool
|
||||
implementation](https://github.com/googleapis/genai-toolbox/tree/main/internal/tools/postgres/postgressql).
|
||||
|
||||
* **Create a new directory** under `internal/tools` for your tool type (e.g.,
|
||||
`internal/tools/newdb` or `internal/tools/newdb<tool_name>`).
|
||||
* **Define a configuration struct** for your tool in a file named `newdbtool.go`.
|
||||
Create a `Config` struct and a `Tool` struct to store necessary parameters for
|
||||
tools.
|
||||
* **Implement the
|
||||
[`ToolConfig`](https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/internal/tools/tools.go#L61)
|
||||
interface**. This interface requires one method:
|
||||
* `ToolConfigKind() string`: Returns a unique string identifier for your tool
|
||||
(e.g., `"newdb"`).
|
||||
* `Initialize(sources map[string]Source) (Tool, error)`: Creates a new
|
||||
instance of your tool and validates that it can connect to the specified
|
||||
data source.
|
||||
* **Implement the `Tool` interface**. This interface requires the following
|
||||
methods:
|
||||
* `Invoke(ctx context.Context, params map[string]any) ([]any, error)`:
|
||||
Executes the operation on the database using the provided parameters.
|
||||
* `ParseParams(data map[string]any, claims map[string]map[string]any)
|
||||
(ParamValues, error)`: Parses and validates the input parameters.
|
||||
* `Manifest() Manifest`: Returns a manifest describing the tool's capabilities
|
||||
and parameters.
|
||||
* `McpManifest() McpManifest`: Returns an MCP manifest describing the tool for
|
||||
use with the Model Context Protocol.
|
||||
* `Authorized(services []string) bool`: Checks if the tool is authorized to
|
||||
run based on the provided authentication services.
|
||||
* **Implement `init()`** to register the new Tool.
|
||||
* **Implement Unit Tests** in a file named `newdb_test.go`.
|
||||
|
||||
### Adding Integration Tests
|
||||
|
||||
* **Add a test file** under a new directory `tests/newdb`.
|
||||
* **Add pre-defined integration test suites** in the
|
||||
`/tests/newdb/newdb_test.go` that are **required** to be run as long as your
|
||||
code contains related features. Please check each test suites for the config
|
||||
defaults, if your source require test suites config updates, please refer to
|
||||
[config option](./tests/option.go):
|
||||
|
||||
1. [RunToolGetTest][tool-get]: tests for the `GET` endpoint that returns the
|
||||
tool's manifest.
|
||||
|
||||
2. [RunToolInvokeTest][tool-call]: tests for tool calling through the native
|
||||
Toolbox endpoints.
|
||||
|
||||
3. [RunMCPToolCallMethod][mcp-call]: tests tool calling through the MCP
|
||||
endpoints.
|
||||
|
||||
4. (Optional) [RunExecuteSqlToolInvokeTest][execute-sql]: tests an
|
||||
`execute-sql` tool for any source. Only run this test if you are adding an
|
||||
`execute-sql` tool.
|
||||
|
||||
5. (Optional) [RunToolInvokeWithTemplateParameters][temp-param]: tests for [template
|
||||
parameters][temp-param-doc]. Only run this test if template
|
||||
parameters apply to your tool.
|
||||
|
||||
* **Add the new database to the integration test workflow** in
|
||||
[integration.cloudbuild.yaml](.ci/integration.cloudbuild.yaml).
|
||||
|
||||
[tool-get]:
|
||||
https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L31
|
||||
[tool-call]:
|
||||
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L79>
|
||||
[mcp-call]:
|
||||
https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L554
|
||||
[execute-sql]:
|
||||
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L431>
|
||||
[temp-param]:
|
||||
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L297>
|
||||
[temp-param-doc]:
|
||||
https://googleapis.github.io/genai-toolbox/resources/tools/#template-parameters
|
||||
|
||||
### Adding Documentation
|
||||
|
||||
* **Update the documentation** to include information about your new data source
|
||||
and tool. This includes:
|
||||
* Adding a new page to the `docs/en/resources/sources` directory for your data
|
||||
source.
|
||||
* Adding a new page to the `docs/en/resources/tools` directory for your tool.
|
||||
|
||||
* **(Optional) Add samples** to the `docs/en/samples/<newdb>` directory.
|
||||
|
||||
### (Optional) Adding Prebuilt Tools
|
||||
|
||||
You can provide developers with a set of "build-time" tools to aid common
|
||||
software development user journeys like viewing and creating tables/collections
|
||||
and data.
|
||||
|
||||
* **Create a set of prebuilt tools** by defining a new `tools.yaml` and adding
|
||||
it to `internal/tools`. Make sure the file name matches the source (i.e. for
|
||||
source "alloydb-postgres" create a file named "alloydb-postgres.yaml").
|
||||
* **Update `cmd/root.go`** to add new source to the `prebuilt` flag.
|
||||
* **Add tests** in
|
||||
[internal/prebuiltconfigs/prebuiltconfigs_test.go](internal/prebuiltconfigs/prebuiltconfigs_test.go)
|
||||
and [cmd/root_test.go](cmd/root_test.go).
|
||||
|
||||
## Submitting a Pull Request
|
||||
|
||||
Submit a pull request to the repository with your changes. Be sure to include a
|
||||
detailed description of your changes and any requests for long term testing
|
||||
resources.
|
||||
|
||||
* **Title:** All pull request title should follow the formatting of
|
||||
[Conventional
|
||||
Commit](https://www.conventionalcommits.org/) guidelines: `<type>[optional
|
||||
scope]: description`. For example, if you are adding a new field in postgres
|
||||
source, the title should be `feat(source/postgres): add support for
|
||||
"new-field" field in postgres source`.
|
||||
|
||||
Here are some commonly used `type` in this GitHub repo.
|
||||
|
||||
| **type** | **description** |
|
||||
|-----------------|-------------------------------------------------------------------------------------------------------|
|
||||
| Breaking Change | Anything with this type of a `!` after the type/scope introduces a breaking change. |
|
||||
| feat | Adding a new feature to the codebase. |
|
||||
| fix | Fixing a bug or typo in the codebase. This does not include fixing docs. |
|
||||
| test | Changes made to test files. |
|
||||
| ci | Changes made to the cicd configuration files or scripts. |
|
||||
| docs | Documentation-related PRs, including fixes on docs. |
|
||||
| chore | Other small tasks or updates that don't fall into any of the above types. |
|
||||
| refactor | Change src code but unlike feat, there are no tests broke and no line lost coverage. |
|
||||
| revert | Revert changes made in another commit. |
|
||||
| style | Update src code, with only formatting and whitespace updates (e.g. code formatter or linter changes). |
|
||||
|
||||
Pull requests should always add scope whenever possible. The scope is
|
||||
formatted as `<scope-type>/<scope-kind>` (e.g., `sources/postgres`, or
|
||||
`tools/mssql-sql`).
|
||||
|
||||
Ideally, **each PR covers only one scope**, if this is
|
||||
inevitable, multiple scopes can be seaparated with a comma (e.g.
|
||||
`sources/postgres,sources/alloydbpg`). If the PR covers multiple `scope-type`
|
||||
(such as adding a new database), you can disregard the `scope-type`, e.g.
|
||||
`feat(new-db): adding support for new-db source and tool`.
|
||||
|
||||
* **PR Description:** PR description should **always** be included. It should
|
||||
include a concise description of the changes, it's impact, along with a
|
||||
summary of the solution. If the PR is related to a specific issue, the issue
|
||||
number should be mentioned in the PR description (e.g. `Fixes #1`).
|
||||
information on using pull requests.
|
||||
459
DEVELOPER.md
459
DEVELOPER.md
@@ -1,16 +1,12 @@
|
||||
# DEVELOPER.md
|
||||
|
||||
This document provides instructions for setting up your development environment
|
||||
and contributing to the Toolbox project.
|
||||
## Before you begin
|
||||
|
||||
## Prerequisites
|
||||
1. Make sure you've setup your databases.
|
||||
|
||||
Before you begin, ensure you have the following:
|
||||
1. Install the latest version of [Go](https://go.dev/doc/install).
|
||||
|
||||
1. **Databases:** Set up the necessary databases for your development
|
||||
environment.
|
||||
1. **Go:** Install the latest version of [Go](https://go.dev/doc/install).
|
||||
1. **Dependencies:** Download and manage project dependencies:
|
||||
1. Locate and download dependencies:
|
||||
|
||||
```bash
|
||||
go get
|
||||
@@ -19,307 +15,196 @@ Before you begin, ensure you have the following:
|
||||
|
||||
## Developing Toolbox
|
||||
|
||||
### Running from Local Source
|
||||
### Run Toolbox from local source
|
||||
|
||||
1. **Configuration:** Create a `tools.yaml` file to configure your sources and
|
||||
tools. See the [Configuration section in the
|
||||
README](./README.md#Configuration) for details.
|
||||
1. **CLI Flags:** List available command-line flags for the Toolbox server:
|
||||
1. Create a `tools.yaml` file with your [sources and tools configurations](./README.md#Configuration).
|
||||
|
||||
1. You can specify flags for the Toolbox server. Execute the following to list the possible CLI flags:
|
||||
|
||||
```bash
|
||||
go run . --help
|
||||
```
|
||||
|
||||
1. **Running the Server:** Start the Toolbox server with optional flags. The
|
||||
server listens on port 5000 by default.
|
||||
1. To run the server, execute the following (with any flags, if applicable):
|
||||
|
||||
```bash
|
||||
go run .
|
||||
```
|
||||
|
||||
1. **Testing the Endpoint:** Verify the server is running by sending a request
|
||||
to the endpoint:
|
||||
The server will listen on port 5000 (by default).
|
||||
|
||||
1. Test endpoint using the following:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:5000
|
||||
```
|
||||
|
||||
### Tool Naming Conventions
|
||||
### Testing
|
||||
|
||||
This section details the purpose and conventions for MCP Toolbox's tools naming
|
||||
properties, **tool name** and **tool kind**.
|
||||
#### Writing Tests
|
||||
|
||||
```
|
||||
cancel_hotel: <- tool name
|
||||
kind: postgres-sql <- tool kind
|
||||
source: my_pg_source
|
||||
```
|
||||
New contributions should be added with both unit tests and integration tests.
|
||||
|
||||
#### Tool Name
|
||||
- Unit tests are in the same package as the source code.
|
||||
|
||||
Tool name is the identifier used by a Large Language Model (LLM) to invoke a
|
||||
specific tool.
|
||||
- Integration tests are in the `/tests` directory, under its dedicated package
|
||||
named after its source. We have several pre-defined integration test suites
|
||||
in the `/tests/tool.go` that are **required** to be run as long as your code contains related
|
||||
features:
|
||||
|
||||
* Custom tools: The user can define any name they want. The below guidelines
|
||||
do not apply.
|
||||
* Pre-built tools: The tool name is predefined and cannot be changed. It
|
||||
should follow the guidelines.
|
||||
1. [RunToolGetTest][tool-get]: tests for the `GET` endpoint that returns the
|
||||
tool's manifest.
|
||||
|
||||
2. [RunToolInvokeTest][tool-call]: tests for tool calling through the native
|
||||
Toolbox endpoints.
|
||||
|
||||
The following guidelines apply to tool names:
|
||||
3. [RunMCPToolCallMethod][mcp-call]: tests tool calling through the MCP
|
||||
endpoints.
|
||||
|
||||
4. (Optional) [RunExecuteSqlToolInvokeTest][execute-sql]: tests an
|
||||
`execute-sql` tool for any source. Only run this test if you are adding an
|
||||
`execute-sql` tool.
|
||||
|
||||
* Should use underscores over hyphens (e.g., `list_collections` instead of
|
||||
`list-collections`).
|
||||
* Should not have the product name in the name (e.g., `list_collections` instead
|
||||
of `firestore_list_collections`).
|
||||
* Superficial changes are NOT considered as breaking (e.g., changing tool name).
|
||||
* Non-superficial changes MAY be considered breaking (e.g. adding new parameters
|
||||
to a function) until they can be validated through extensive testing to ensure
|
||||
they do not negatively impact agent's performances.
|
||||
5. (Optional) [RunToolInvokeWithTemplateParameters][temp-param]: tests for [template
|
||||
parameters][temp-param-doc]. Only run this test if template parameters apply to your tool.
|
||||
|
||||
[tool-get]:
|
||||
https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L31
|
||||
[tool-call]:
|
||||
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L79>
|
||||
[mcp-call]:
|
||||
https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L554
|
||||
[execute-sql]:
|
||||
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L431>
|
||||
[temp-param]:
|
||||
<https://github.com/googleapis/genai-toolbox/blob/fd300dc606d88bf9f7bba689e2cee4e3565537dd/tests/tool.go#L297>
|
||||
[temp-param-doc]:
|
||||
https://googleapis.github.io/genai-toolbox/resources/tools/#template-parameters
|
||||
|
||||
#### Tool Kind
|
||||
#### Running Tests
|
||||
|
||||
Tool kind serves as a category or type that a user can assign to a tool.
|
||||
- Run the lint check:
|
||||
|
||||
The following guidelines apply to tool kinds:
|
||||
|
||||
* Should user hyphens over underscores (e.g. `firestore-list-collections` or
|
||||
`firestore_list_colelctions`).
|
||||
* Should use product name in name (e.g. `firestore-list-collections` over
|
||||
`list-collections`).
|
||||
* Changes to tool kind are breaking changes and should be avoided.
|
||||
|
||||
## Testing
|
||||
|
||||
### Infrastructure
|
||||
|
||||
Toolbox uses both GitHub Actions and Cloud Build to run test workflows. Cloud
|
||||
Build is used when Google credentials are required. Cloud Build uses test
|
||||
project "toolbox-testing-438616".
|
||||
|
||||
### Linting
|
||||
|
||||
Run the lint check to ensure code quality:
|
||||
|
||||
```bash
|
||||
golangci-lint run --fix
|
||||
```
|
||||
|
||||
### Unit Tests
|
||||
|
||||
Execute unit tests locally:
|
||||
|
||||
```bash
|
||||
go test -race -v ./...
|
||||
```
|
||||
|
||||
### Integration Tests
|
||||
|
||||
#### Running Locally
|
||||
|
||||
1. **Environment Variables:** Set the required environment variables. Refer to
|
||||
the [Cloud Build testing configuration](./.ci/integration.cloudbuild.yaml)
|
||||
for a complete list of variables for each source.
|
||||
* `SERVICE_ACCOUNT_EMAIL`: Use your own GCP email.
|
||||
* `CLIENT_ID`: Use the Google Cloud SDK application Client ID. Contact
|
||||
Toolbox maintainers if you don't have it.
|
||||
1. **Running Tests:** Run the integration test for your target source. Specify
|
||||
the required Go build tags at the top of each integration test file.
|
||||
|
||||
```shell
|
||||
go test -race -v ./tests/<YOUR_TEST_DIR>
|
||||
```bash
|
||||
golangci-lint run --fix
|
||||
```
|
||||
|
||||
For example, to run the AlloyDB integration test:
|
||||
- Run unit tests locally:
|
||||
|
||||
```shell
|
||||
go test -race -v ./tests/alloydbpg
|
||||
```bash
|
||||
go test -race -v ./...
|
||||
```
|
||||
|
||||
1. **Timeout:** The integration test should have a timeout on the server.
|
||||
Look for code like this:
|
||||
- Run integration tests locally:
|
||||
1. Set required environment variables. For a complete lists of required
|
||||
vairables for each source, check out the [Cloud Build testing
|
||||
configuration](./.ci/integration.cloudbuild.yaml).
|
||||
- Use your own GCP email as the `SERVICE_ACCOUNT_EMAIL`.
|
||||
- Use the Google Cloud SDK application Client ID as the `CLIENT_ID`. Ask the
|
||||
Toolbox maintainers if you don't know it already.
|
||||
|
||||
```go
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancel()
|
||||
2. Run the integration test for your target source with the required Go
|
||||
build tags specified at the top of each integration test file:
|
||||
|
||||
cmd, cleanup, err := tests.StartCmd(ctx, toolsFile, args...)
|
||||
if err != nil {
|
||||
t.Fatalf("command initialization returned an error: %s", err)
|
||||
}
|
||||
defer cleanup()
|
||||
```
|
||||
```shell
|
||||
go test -race -v ./tests/<YOUR_TEST_DIR>
|
||||
```
|
||||
|
||||
Be sure to set the timeout to a reasonable value for your tests.
|
||||
For example, to run the AlloyDB integration test, run:
|
||||
|
||||
#### Running on Pull Requests
|
||||
```shell
|
||||
go test -race -v ./tests/alloydbpg
|
||||
```
|
||||
|
||||
* **Internal Contributors:** Testing workflows should trigger automatically.
|
||||
* **External Contributors:** Request Toolbox maintainers to trigger the testing
|
||||
workflows on your PR.
|
||||
* Maintainers can comment `/gcbrun` to execute the integration tests.
|
||||
* Maintainers can add the label `tests:run` to execute the unit tests.
|
||||
- Run integration tests on your PR:
|
||||
|
||||
#### Test Resources
|
||||
|
||||
The following databases have been added as test resources. To add a new database
|
||||
to test against, please contact the Toolbox maintainer team via an issue or PR.
|
||||
Refer to the [Cloud Build testing
|
||||
configuration](./.ci/integration.cloudbuild.yaml) for a complete list of
|
||||
variables for each source.
|
||||
|
||||
* AlloyDB - setup in the test project
|
||||
* AI Natural Language ([setup
|
||||
instructions](https://cloud.google.com/alloydb/docs/ai/use-natural-language-generate-sql-queries))
|
||||
has been configured for `alloydb-ai-nl` tool tests
|
||||
* The Cloud Build service account is a user
|
||||
* Bigtable - setup in the test project
|
||||
* The Cloud Build service account is a user
|
||||
* BigQuery - setup in the test project
|
||||
* The Cloud Build service account is a user
|
||||
* Cloud SQL Postgres - setup in the test project
|
||||
* The Cloud Build service account is a user
|
||||
* Cloud SQL MySQL - setup in the test project
|
||||
* The Cloud Build service account is a user
|
||||
* Cloud SQL SQL Server - setup in the test project
|
||||
* The Cloud Build service account is a user
|
||||
* Couchbase - setup in the test project via the Marketplace
|
||||
* DGraph - using the public dgraph interface <https://play.dgraph.io> for
|
||||
testing
|
||||
* Looker
|
||||
* The Cloud Build service account is a user for conversational analytics
|
||||
* The Looker instance runs under google.com:looker-sandbox.
|
||||
* Memorystore Redis - setup in the test project using a Memorystore for Redis
|
||||
standalone instance
|
||||
* Memorystore Redis Cluster, Memorystore Valkey standalone, and Memorystore
|
||||
Valkey Cluster instances all require PSC connections, which requires extra
|
||||
security setup to connect from Cloud Build. Memorystore Redis standalone is
|
||||
the only one allowing PSA connection.
|
||||
* The Cloud Build service account is a user
|
||||
* Memorystore Valkey - setup in the test project using a Memorystore for Redis
|
||||
standalone instance
|
||||
* The Cloud Build service account is a user
|
||||
* MySQL - setup in the test project using a Cloud SQL instance
|
||||
* Neo4j - setup in the test project on a GCE VM
|
||||
* Postgres - setup in the test project using an AlloyDB instance
|
||||
* Spanner - setup in the test project
|
||||
* The Cloud Build service account is a user
|
||||
* SQL Server - setup in the test project using a Cloud SQL instance
|
||||
* SQLite - setup in the integration test, where we create a temporary database
|
||||
file
|
||||
|
||||
### Other GitHub Checks
|
||||
|
||||
* License header check (`.github/header-checker-lint.yml`) - Ensures files have
|
||||
the appropriate license
|
||||
* CLA/google - Ensures the developer has signed the CLA:
|
||||
<https://cla.developers.google.com/>
|
||||
* conventionalcommits.org - Ensures the commit messages are in the correct
|
||||
format. This repository uses tool [Release
|
||||
Please](https://github.com/googleapis/release-please) to create GitHub
|
||||
releases. It does so by parsing your git history, looking for [Conventional
|
||||
Commit messages](https://www.conventionalcommits.org/), and creating release
|
||||
PRs. Learn more by reading [How should I write my
|
||||
commits?](https://github.com/googleapis/release-please?tab=readme-ov-file#how-should-i-write-my-commits)
|
||||
For internal contributors, the testing workflows should trigger
|
||||
automatically. For external contributors, ask the Toolbox
|
||||
maintainers to trigger the testing workflows on your PR.
|
||||
|
||||
## Developing Documentation
|
||||
|
||||
### Running a Local Hugo Server
|
||||
Follow these steps to run a Hugo server for local preview:
|
||||
|
||||
Follow these steps to preview documentation changes locally using a Hugo server:
|
||||
|
||||
1. **Install Hugo:** Ensure you have
|
||||
[Hugo](https://gohugo.io/installation/macos/) extended edition version
|
||||
0.146.0 or later installed.
|
||||
1. **Navigate to the Hugo Directory:**
|
||||
1. [Install Hugo](https://gohugo.io/installation/macos/) version 0.146.0+.
|
||||
1. Move into the `.hugo` directory
|
||||
|
||||
```bash
|
||||
cd .hugo
|
||||
```
|
||||
|
||||
1. **Install Dependencies:**
|
||||
1. Install dependencies
|
||||
|
||||
```bash
|
||||
npm ci
|
||||
```
|
||||
|
||||
1. **Start the Server:**
|
||||
1. Run the server
|
||||
|
||||
```bash
|
||||
hugo server
|
||||
```
|
||||
|
||||
### Previewing Documentation on Pull Requests
|
||||
### PR documentation preview
|
||||
|
||||
### Document Versioning Setup
|
||||
- For contributors:
|
||||
|
||||
There are 3 GHA workflows we use to achieve document versioning:
|
||||
- Ask a repo owner to run the preview deployment workflow on your PR. The preview link
|
||||
will be commented under your PR automatically.
|
||||
|
||||
1. **Deploy In-development docs:**
|
||||
This workflow is run on every commit merged into the main branch. It deploys the built site to the `/dev/` subdirectory for the in-development documentation.
|
||||
- For maintainers:
|
||||
|
||||
1. **Deploy Versioned Docs:**
|
||||
When a new GitHub Release is published, it performs two deployments based on the new release tag.
|
||||
One to the new version subdirectory and one to the root directory of the versioned-gh-pages branch.
|
||||
- Inspect the proposed changes in the PR and ensure that it does not contain
|
||||
malicious code changes. You should be especially alert to any proposed changes in the
|
||||
`.github/workflows/` directory that affect workflow files.
|
||||
- After you make sure the changes are safe, apply the `docs: deploy-preview`
|
||||
label to the PR to deploy documentation preview.
|
||||
|
||||
**Note:** Before the release PR from release-please is merged, add the newest version into the hugo.toml file.
|
||||
## Compile the app locally
|
||||
|
||||
1. **Deploy Previous Version Docs:**
|
||||
This is a manual workflow, started from the GitHub Actions UI.
|
||||
To rebuild and redeploy documentation for an already released version that were released before this new system was in place. This workflow can be started on the UI by providing the git version tag which you want to create the documentation for.
|
||||
The specific versioned subdirectory and the root docs are updated on the versioned-gh-pages branch.
|
||||
### Compile Toolbox binary
|
||||
|
||||
#### Contributors
|
||||
|
||||
Request a repo owner to run the preview deployment workflow on your PR. A
|
||||
preview link will be automatically added as a comment to your PR.
|
||||
|
||||
#### Maintainers
|
||||
|
||||
1. **Inspect Changes:** Review the proposed changes in the PR to ensure they are
|
||||
safe and do not contain malicious code. Pay close attention to changes in the
|
||||
`.github/workflows/` directory.
|
||||
1. **Deploy Preview:** Apply the `docs: deploy-preview` label to the PR to
|
||||
deploy a documentation preview.
|
||||
|
||||
## Building Toolbox
|
||||
|
||||
### Building the Binary
|
||||
|
||||
1. **Build Command:** Compile the Toolbox binary:
|
||||
1. Run build to compile binary:
|
||||
|
||||
```bash
|
||||
go build -o toolbox
|
||||
```
|
||||
|
||||
1. **Running the Binary:** Execute the compiled binary with optional flags. The
|
||||
server listens on port 5000 by default:
|
||||
1. You can specify flags for the Toolbox server. Execute the following to list the possible CLI flags:
|
||||
|
||||
```bash
|
||||
./toolbox --help
|
||||
```
|
||||
|
||||
1. To run the binary, execute the following (with any flags, if applicable):
|
||||
|
||||
```bash
|
||||
./toolbox
|
||||
```
|
||||
|
||||
1. **Testing the Endpoint:** Verify the server is running by sending a request
|
||||
to the endpoint:
|
||||
The server will listen on port 5000 (by default).
|
||||
|
||||
1. Test endpoint using the following:
|
||||
|
||||
```bash
|
||||
curl http://127.0.0.1:5000
|
||||
```
|
||||
|
||||
### Building Container Images
|
||||
### Compile Toolbox container images
|
||||
|
||||
1. **Build Command:** Build the Toolbox container image:
|
||||
1. Run build to compile container image:
|
||||
|
||||
```bash
|
||||
docker build -t toolbox:dev .
|
||||
```
|
||||
|
||||
1. **View Image:** List available Docker images to confirm the build:
|
||||
1. Execute the following to view image:
|
||||
|
||||
```bash
|
||||
docker images
|
||||
```
|
||||
|
||||
1. **Run Container:** Run the Toolbox container image using Docker:
|
||||
1. Run container image with Docker:
|
||||
|
||||
```bash
|
||||
docker run -d toolbox:dev
|
||||
@@ -327,124 +212,56 @@ preview link will be automatically added as a comment to your PR.
|
||||
|
||||
## Developing Toolbox SDKs
|
||||
|
||||
Refer to the [SDK developer
|
||||
guide](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/DEVELOPER.md)
|
||||
for instructions on developing Toolbox SDKs.
|
||||
Please refer to the [SDK developer guide](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/DEVELOPER.md)
|
||||
|
||||
## Maintainer Information
|
||||
|
||||
### Team
|
||||
|
||||
Team `@googleapis/senseai-eco` has been set as
|
||||
[CODEOWNERS](.github/CODEOWNERS). The GitHub TeamSync tool is used to create
|
||||
this team from MDB Group, `senseai-eco`.
|
||||
|
||||
Team `@googleapis/toolbox-contributors` has write access to this repo. They
|
||||
can create branches and approve test runs. But they do not have the ability
|
||||
to approve PRs for main. TeamSync is used to create this team from the MDB
|
||||
Group `toolbox-contributors`. Googlers who are developing for MCP-Toolbox
|
||||
but aren't part of the core team should join this group.
|
||||
## (Optional) Maintainer Information
|
||||
|
||||
### Releasing
|
||||
|
||||
Toolbox has two types of releases: versioned and continuous. It uses Google
|
||||
Cloud project, `database-toolbox`.
|
||||
There are two types of release for Toolbox, including a versioned release and continuous release.
|
||||
|
||||
* **Versioned Release:** Official, supported distributions tagged as `latest`.
|
||||
The release process is defined in
|
||||
[versioned.release.cloudbuild.yaml](.ci/versioned.release.cloudbuild.yaml).
|
||||
* **Continuous Release:** Used for early testing of features between official
|
||||
releases and for end-to-end testing. The release process is defined in
|
||||
[continuous.release.cloudbuild.yaml](.ci/continuous.release.cloudbuild.yaml).
|
||||
* **GitHub Release:** `.github/release-please.yml` automatically creates GitHub
|
||||
Releases and release PRs.
|
||||
- Versioned release: Official supported distributions with the `latest` tag. The release process for versioned release is in [versioned.release.cloudbuild.yaml](https://github.com/googleapis/genai-toolbox/blob/main/versioned.release.cloudbuild.yaml).
|
||||
- Continuous release: Used for early testing features between official supported releases and end-to-end testings.
|
||||
|
||||
### How-to Release a new Version
|
||||
#### Supported OS and Architecture binaries
|
||||
|
||||
1. [Optional] If you want to override the version number, send a
|
||||
[PR](https://github.com/googleapis/genai-toolbox/pull/31) to trigger
|
||||
[release-please](https://github.com/googleapis/release-please?tab=readme-ov-file#how-do-i-change-the-version-number).
|
||||
You can generate a commit with the following line: `git commit -m "chore:
|
||||
release 0.1.0" -m "Release-As: 0.1.0" --allow-empty`
|
||||
1. [Optional] If you want to edit the changelog, send commits to the release PR
|
||||
1. Approve and merge the PR with the title “[chore(main): release
|
||||
x.x.x](https://github.com/googleapis/genai-toolbox/pull/16)”
|
||||
1. The
|
||||
[trigger](https://pantheon.corp.google.com/cloud-build/triggers;region=us-central1/edit/27bd0d21-264a-4446-b2d7-0df4e9915fb3?e=13802955&inv=1&invt=AbhU8A&mods=logs_tg_staging&project=database-toolbox)
|
||||
should automatically run when a new tag is pushed. You can view [triggered
|
||||
builds here to check the
|
||||
status](https://pantheon.corp.google.com/cloud-build/builds;region=us-central1?query=trigger_id%3D%2227bd0d21-264a-4446-b2d7-0df4e9915fb3%22&e=13802955&inv=1&invt=AbhU8A&mods=logs_tg_staging&project=database-toolbox)
|
||||
1. Update the Github release notes to include the following table:
|
||||
1. Run the following command (from the root directory):
|
||||
The following OS and computer architecture is supported within the binary releases.
|
||||
|
||||
```
|
||||
export VERSION="v0.0.0"
|
||||
.ci/generate_release_table.sh
|
||||
```
|
||||
- linux/amd64
|
||||
- darwin/arm64
|
||||
- darwin/amd64
|
||||
- windows/amd64
|
||||
|
||||
1. Copy the table output
|
||||
1. In the GitHub UI, navigate to Releases and click the `edit` button.
|
||||
1. Paste the table at the bottom of release note and click `Update release`.
|
||||
1. Post release in internal chat and on Discord.
|
||||
#### Supported container images
|
||||
|
||||
#### Supported Binaries
|
||||
The following base container images is supported within the container image releases.
|
||||
|
||||
The following operating systems and architectures are supported for binary
|
||||
releases:
|
||||
- distroless
|
||||
|
||||
* linux/amd64
|
||||
* darwin/arm64
|
||||
* darwin/amd64
|
||||
* windows/amd64
|
||||
### Automated tests
|
||||
|
||||
#### Supported Container Images
|
||||
|
||||
The following base container images are supported for container image releases:
|
||||
|
||||
* distroless
|
||||
|
||||
### Automated Tests
|
||||
|
||||
Integration and unit tests are automatically triggered via Cloud Build on each
|
||||
pull request. Integration tests run on merge and nightly.
|
||||
|
||||
#### Failure notifications
|
||||
|
||||
On-merge and nightly tests that fail have notification setup via Cloud Build
|
||||
Failure Reporter [GitHub Actions
|
||||
Workflow](.github/workflows/schedule_reporter.yml).
|
||||
Integration and unit tests are automatically triggered via CloudBuild during each PR creation.
|
||||
|
||||
#### Trigger Setup
|
||||
|
||||
Configure a Cloud Build trigger using the UI or `gcloud` with the following
|
||||
settings:
|
||||
Create a Cloud Build trigger via the UI or `gcloud` with the following specs:
|
||||
|
||||
* **Event:** Pull request
|
||||
* **Region:** global (for default worker pools)
|
||||
* **Source:**
|
||||
* Generation: 1st gen
|
||||
* Repo: googleapis/genai-toolbox (GitHub App)
|
||||
* Base branch: `^main$`
|
||||
* **Comment control:** Required except for owners and collaborators
|
||||
* **Filters:** Add directory filter
|
||||
* **Config:** Cloud Build configuration file
|
||||
* Location: Repository (add path to file)
|
||||
* **Service account:** Set for demo service to enable ID token creation for
|
||||
authenticated services
|
||||
- Event: Pull request
|
||||
- Region:
|
||||
- global - for default worker pools
|
||||
- Source:
|
||||
- Generation: 1st gen
|
||||
- Repo: googleapis/genai-toolbox (GitHub App)
|
||||
- Base branch: `^main$`
|
||||
- Comment control: Required except for owners and collaborators
|
||||
- Filters: add directory filter
|
||||
- Config: Cloud Build configuration file
|
||||
- Location: Repository (add path to file)
|
||||
- Service account: set for demo service to enable ID token creation to use to authenticated services
|
||||
|
||||
### Triggering Tests
|
||||
### Trigger
|
||||
|
||||
Trigger pull request tests for external contributors by:
|
||||
Trigger the PR tests on PRs from external contributors:
|
||||
|
||||
* **Cloud Build tests:** Comment `/gcbrun`
|
||||
* **Unit tests:** Add the `tests:run` label
|
||||
|
||||
## Repo Setup & Automation
|
||||
|
||||
* .github/blunderbuss.yml - Auto-assign issues and PRs from GitHub teams
|
||||
* .github/renovate.json5 - Tooling for dependency updates. Dependabot is built
|
||||
into the GitHub repo for GitHub security warnings
|
||||
* go/github-issue-mirror - GitHub issues are automatically mirrored into buganizer
|
||||
* (Suspended) .github/sync-repo-settings.yaml - configure repo settings
|
||||
* .github/release-please.yml - Creates GitHub releases
|
||||
* .github/ISSUE_TEMPLATE - templates for GitHub issues
|
||||
- Cloud Build tests: comment `/gcbrun`
|
||||
- Unit tests: add `tests:run` label
|
||||
|
||||
@@ -25,7 +25,7 @@ ARG COMMIT_SHA=""
|
||||
|
||||
RUN go get ./...
|
||||
RUN CGO_ENABLED=0 GOOS=${TARGETOS} GOARCH=${TARGETARCH} \
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=${BUILD_TYPE} -X github.com/googleapis/genai-toolbox/cmd.commitSha=${COMMIT_SHA}"
|
||||
go build -ldflags "-X github.com/googleapis/genai-toolbox/cmd.buildType=container.${BUILD_TYPE} -X github.com/googleapis/genai-toolbox/cmd.commitSha=${COMMIT_SHA}"
|
||||
|
||||
# Final Stage
|
||||
FROM gcr.io/distroless/static:nonroot
|
||||
|
||||
@@ -1,189 +0,0 @@
|
||||
This document helps you find and install the right Gemini CLI extension to interact with your databases.
|
||||
|
||||
## How to Install an Extension
|
||||
|
||||
To install any of the extensions listed below, use the `gemini extensions install` command followed by the extension's GitHub repository URL.
|
||||
|
||||
For complete instructions on finding, installing, and managing extensions, please see the [official Gemini CLI extensions documentation](https://github.com/google-gemini/gemini-cli/blob/main/docs/extensions/index.md).
|
||||
|
||||
**Example Installation Command:**
|
||||
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/EXTENSION_NAME
|
||||
```
|
||||
|
||||
Make sure the user knows:
|
||||
* These commands are not supported from within the CLI
|
||||
* These commands will only be reflected in active CLI sessions on restart
|
||||
* Extensions require Application Default Credentials in your environment. See [Set up ADC for a local development environment](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment) to learn how you can provide either your user credentials or service account credentials to ADC in a local development environment.
|
||||
* Most extensions require you to set environment variables to connect to a database. If there is a link provided for the configuration, fetch the web page and return the configuration.
|
||||
|
||||
-----
|
||||
|
||||
## Find Your Database Extension
|
||||
|
||||
Find your database or service in the list below to get the correct installation command.
|
||||
|
||||
**Note on Observability:** Extensions with `-observability` in their name are designed to help you understand the health and performance of your database instances, often by analyzing metrics and logs.
|
||||
|
||||
### Google Cloud Managed Databases
|
||||
|
||||
#### BigQuery
|
||||
|
||||
* For data analytics and querying:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/bigquery-data-analytics
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/bigquery-data-analytics/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
* For conversational analytics (using natural language):
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/bigquery-conversational-analytics
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/bigquery-conversational-analytics/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
#### Cloud SQL for MySQL
|
||||
|
||||
* Main Extension:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/cloud-sql-mysql
|
||||
```
|
||||
Configuration: https://github.com/gemini-cli-extensions/cloud-sql-mysql/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
* Observability:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/cloud-sql-mysql-observability
|
||||
```
|
||||
|
||||
If you are looking for self-hosted MySQL, consider the `mysql` extension.
|
||||
|
||||
#### Cloud SQL for PostgreSQL
|
||||
|
||||
* Main Extension:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/cloud-sql-postgresql
|
||||
```
|
||||
Configuration: https://github.com/gemini-cli-extensions/cloud-sql-postgresql/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
* Observability:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/cloud-sql-postgresql-observability
|
||||
```
|
||||
|
||||
If you are looking for other PostgreSQL options, consider the `postgres` extension for self-hosted instances, or the `alloydb` extension for AlloyDB for PostgreSQL.
|
||||
|
||||
#### Cloud SQL for SQL Server
|
||||
|
||||
* Main Extension:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/cloud-sql-sqlserver
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/cloud-sql-sqlserver/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
* Observability:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/cloud-sql-sqlserver-observability
|
||||
```
|
||||
|
||||
If you are looking for self-hosted SQL Server, consider the `sql-server` extension.
|
||||
|
||||
#### AlloyDB for PostgreSQL
|
||||
|
||||
* Main Extension:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/alloydb
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/alloydb/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
* Observability:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/alloydb-observability
|
||||
```
|
||||
|
||||
If you are looking for other PostgreSQL options, consider the `postgres` extension for self-hosted instances, or the `cloud-sql-postgresql` extension for Cloud SQL for PostgreSQL.
|
||||
|
||||
#### Spanner
|
||||
|
||||
* For querying Spanner databases:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/spanner
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/spanner/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
#### Firestore
|
||||
|
||||
* For querying Firestore in Native Mode:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/firestore-native
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/firestore-native/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
### Other Google Cloud Data Services
|
||||
|
||||
#### Dataplex
|
||||
|
||||
* For interacting with Dataplex data lakes and assets:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/dataplex
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/dataplex/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
#### Looker
|
||||
|
||||
* For querying Looker instances:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/looker
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/looker/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
### Other Database Engines
|
||||
|
||||
These extensions are for connecting to database instances not managed by Cloud SQL (e.g., self-hosted on-prem, on a VM, or in another cloud).
|
||||
|
||||
* MySQL:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/mysql
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/mysql/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
If you are looking for Google Cloud managed MySQL, consider the `cloud-sql-mysql` extension.
|
||||
|
||||
* PostgreSQL:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/postgres
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/postgres/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
If you are looking for Google Cloud managed PostgreSQL, consider the `cloud-sql-postgresql` or `alloydb` extensions.
|
||||
|
||||
* SQL Server:
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/sql-server
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/sql-server/tree/main?tab=readme-ov-file#configuration
|
||||
|
||||
If you are looking for Google Cloud managed SQL Server, consider the `cloud-sql-sqlserver` extension.
|
||||
|
||||
### Custom Tools
|
||||
|
||||
#### MCP Toolbox
|
||||
|
||||
* For connecting to MCP Toolbox servers:
|
||||
|
||||
This extension can be used with any Google Cloud database to build custom tools. For more information, see the [MCP Toolbox documentation](https://googleapis.github.io/genai-toolbox/getting-started/introduction/).
|
||||
```bash
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/mcp-toolbox
|
||||
```
|
||||
|
||||
Configuration: https://github.com/gemini-cli-extensions/mcp-toolbox/tree/main?tab=readme-ov-file#configuration
|
||||
695
README.md
695
README.md
@@ -2,9 +2,7 @@
|
||||
|
||||
# MCP Toolbox for Databases
|
||||
|
||||
[](https://googleapis.github.io/genai-toolbox/)
|
||||
[](https://discord.gg/Dmm69peqjh)
|
||||
[](https://medium.com/@mcp_toolbox)
|
||||
[](https://discord.gg/Dmm69peqjh)
|
||||
[](https://goreportcard.com/report/github.com/googleapis/genai-toolbox)
|
||||
|
||||
> [!NOTE]
|
||||
@@ -18,6 +16,7 @@ such as connection pooling, authentication, and more.
|
||||
This README provides a brief overview. For comprehensive details, see the [full
|
||||
documentation](https://googleapis.github.io/genai-toolbox/).
|
||||
|
||||
|
||||
> [!NOTE]
|
||||
> This solution was originally named “Gen AI Toolbox for Databases” as
|
||||
> its initial development predated MCP, but was renamed to align with recently
|
||||
@@ -31,27 +30,23 @@ documentation](https://googleapis.github.io/genai-toolbox/).
|
||||
- [Why Toolbox?](#why-toolbox)
|
||||
- [General Architecture](#general-architecture)
|
||||
- [Getting Started](#getting-started)
|
||||
- [Installing the server](#installing-the-server)
|
||||
- [Running the server](#running-the-server)
|
||||
- [Integrating your application](#integrating-your-application)
|
||||
- [Using Toolbox with Gemini CLI Extensions](#using-toolbox-with-gemini-cli-extensions)
|
||||
- [Installing the server](#installing-the-server)
|
||||
- [Running the server](#running-the-server)
|
||||
- [Integrating your application](#integrating-your-application)
|
||||
- [Configuration](#configuration)
|
||||
- [Sources](#sources)
|
||||
- [Tools](#tools)
|
||||
- [Toolsets](#toolsets)
|
||||
- [Sources](#sources)
|
||||
- [Tools](#tools)
|
||||
- [Toolsets](#toolsets)
|
||||
- [Versioning](#versioning)
|
||||
- [Pre-1.0.0 Versioning](#pre-100-versioning)
|
||||
- [Post-1.0.0 Versioning](#post-100-versioning)
|
||||
- [Contributing](#contributing)
|
||||
- [Community](#community)
|
||||
|
||||
<!-- /TOC -->
|
||||
|
||||
## Why Toolbox?
|
||||
|
||||
## Why Toolbox?
|
||||
|
||||
Toolbox helps you build Gen AI tools that let your agents access data in your
|
||||
database. Toolbox provides:
|
||||
|
||||
- **Simplified development**: Integrate tools to your agent in less than 10
|
||||
lines of code, reuse tools between multiple agents or frameworks, and deploy
|
||||
new versions of tools more easily.
|
||||
@@ -61,29 +56,17 @@ database. Toolbox provides:
|
||||
- **End-to-end observability**: Out of the box metrics and tracing with built-in
|
||||
support for OpenTelemetry.
|
||||
|
||||
|
||||
**⚡ Supercharge Your Workflow with an AI Database Assistant ⚡**
|
||||
|
||||
Stop context-switching and let your AI assistant become a true co-developer. By
|
||||
[connecting your IDE to your databases with MCP Toolbox][connect-ide], you can
|
||||
delegate complex and time-consuming database tasks, allowing you to build faster
|
||||
and focus on what matters. This isn't just about code completion; it's about
|
||||
giving your AI the context it needs to handle the entire development lifecycle.
|
||||
Stop context-switching and let your AI assistant become a true co-developer. By [connecting your IDE to your databases with MCP Toolbox][connect-ide], you can delegate complex and time-consuming database tasks, allowing you to build faster and focus on what matters. This isn't just about code completion; it's about giving your AI the context it needs to handle the entire development lifecycle.
|
||||
|
||||
Here’s how it will save you time:
|
||||
|
||||
- **Query in Plain English**: Interact with your data using natural language
|
||||
right from your IDE. Ask complex questions like, *"How many orders were
|
||||
delivered in 2024, and what items were in them?"* without writing any SQL.
|
||||
- **Automate Database Management**: Simply describe your data needs, and let the
|
||||
AI assistant manage your database for you. It can handle generating queries,
|
||||
creating tables, adding indexes, and more.
|
||||
- **Generate Context-Aware Code**: Empower your AI assistant to generate
|
||||
application code and tests with a deep understanding of your real-time
|
||||
database schema. This accelerates the development cycle by ensuring the
|
||||
generated code is directly usable.
|
||||
- **Slash Development Overhead**: Radically reduce the time spent on manual
|
||||
setup and boilerplate. MCP Toolbox helps streamline lengthy database
|
||||
configurations, repetitive code, and error-prone schema migrations.
|
||||
* **Query in Plain English**: Interact with your data using natural language right from your IDE. Ask complex questions like, *"How many orders were delivered in 2024, and what items were in them?"* without writing any SQL.
|
||||
* **Automate Database Management**: Simply describe your data needs, and let the AI assistant manage your database for you. It can handle generating queries, creating tables, adding indexes, and more.
|
||||
* **Generate Context-Aware Code**: Empower your AI assistant to generate application code and tests with a deep understanding of your real-time database schema. This accelerates the development cycle by ensuring the generated code is directly usable.
|
||||
* **Slash Development Overhead**: Radically reduce the time spent on manual setup and boilerplate. MCP Toolbox helps streamline lengthy database configurations, repetitive code, and error-prone schema migrations.
|
||||
|
||||
Learn [how to connect your AI tools (IDEs) to Toolbox using MCP][connect-ide].
|
||||
|
||||
@@ -103,7 +86,6 @@ redeploying your application.
|
||||
## Getting Started
|
||||
|
||||
### Installing the server
|
||||
|
||||
For the latest version, check the [releases page][releases] and use the
|
||||
following instructions for your OS and CPU architecture.
|
||||
|
||||
@@ -115,57 +97,13 @@ following instructions for your OS and CPU architecture.
|
||||
To install Toolbox as a binary:
|
||||
|
||||
<!-- {x-release-please-start-version} -->
|
||||
> <details>
|
||||
> <summary>Linux (AMD64)</summary>
|
||||
>
|
||||
> To install Toolbox as a binary on Linux (AMD64):
|
||||
>
|
||||
> ```sh
|
||||
> # see releases page for other versions
|
||||
> export VERSION=0.18.0
|
||||
> curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
|
||||
> chmod +x toolbox
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>macOS (Apple Silicon)</summary>
|
||||
>
|
||||
> To install Toolbox as a binary on macOS (Apple Silicon):
|
||||
>
|
||||
> ```sh
|
||||
> # see releases page for other versions
|
||||
> export VERSION=0.18.0
|
||||
> curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/darwin/arm64/toolbox
|
||||
> chmod +x toolbox
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>macOS (Intel)</summary>
|
||||
>
|
||||
> To install Toolbox as a binary on macOS (Intel):
|
||||
>
|
||||
> ```sh
|
||||
> # see releases page for other versions
|
||||
> export VERSION=0.18.0
|
||||
> curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/darwin/amd64/toolbox
|
||||
> chmod +x toolbox
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
> <details>
|
||||
> <summary>Windows (AMD64)</summary>
|
||||
>
|
||||
> To install Toolbox as a binary on Windows (AMD64):
|
||||
>
|
||||
> ```powershell
|
||||
> # see releases page for other versions
|
||||
> $VERSION = "0.18.0"
|
||||
> Invoke-WebRequest -Uri "https://storage.googleapis.com/genai-toolbox/v$VERSION/windows/amd64/toolbox.exe" -OutFile "toolbox.exe"
|
||||
> ```
|
||||
>
|
||||
> </details>
|
||||
```sh
|
||||
# see releases page for other versions
|
||||
export VERSION=0.7.0
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
|
||||
chmod +x toolbox
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
@@ -174,23 +112,12 @@ You can also install Toolbox as a container:
|
||||
|
||||
```sh
|
||||
# see releases page for other versions
|
||||
export VERSION=0.18.0
|
||||
export VERSION=0.7.0
|
||||
docker pull us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$VERSION
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Homebrew</summary>
|
||||
|
||||
To install Toolbox using Homebrew on macOS or Linux:
|
||||
|
||||
```sh
|
||||
brew install mcp-toolbox
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Compile from source</summary>
|
||||
|
||||
@@ -198,106 +125,21 @@ To install from source, ensure you have the latest version of
|
||||
[Go installed](https://go.dev/doc/install), and then run the following command:
|
||||
|
||||
```sh
|
||||
go install github.com/googleapis/genai-toolbox@v0.18.0
|
||||
go install github.com/googleapis/genai-toolbox@v0.7.0
|
||||
```
|
||||
<!-- {x-release-please-end} -->
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>Gemini CLI Extensions</summary>
|
||||
|
||||
To install Gemini CLI Extensions for MCP Toolbox, run the following command:
|
||||
|
||||
```sh
|
||||
gemini extensions install https://github.com/gemini-cli-extensions/mcp-toolbox
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
### Running the server
|
||||
|
||||
[Configure](#configuration) a `tools.yaml` to define your tools, and then
|
||||
execute `toolbox` to start the server:
|
||||
|
||||
<details open>
|
||||
<summary>Binary</summary>
|
||||
|
||||
To run Toolbox from binary:
|
||||
|
||||
```sh
|
||||
./toolbox --tools-file "tools.yaml"
|
||||
```
|
||||
|
||||
> ⓘ Note
|
||||
> Toolbox enables dynamic reloading by default. To disable, use the
|
||||
> `--disable-reload` flag.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Container image</summary>
|
||||
|
||||
To run the server after pulling the [container image](#installing-the-server):
|
||||
|
||||
```sh
|
||||
export VERSION=0.11.0 # Use the version you pulled
|
||||
docker run -p 5000:5000 \
|
||||
-v $(pwd)/tools.yaml:/app/tools.yaml \
|
||||
us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$VERSION \
|
||||
--tools-file "/app/tools.yaml"
|
||||
```
|
||||
|
||||
> ⓘ Note
|
||||
> The `-v` flag mounts your local `tools.yaml` into the container, and `-p` maps
|
||||
> the container's port `5000` to your host's port `5000`.
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Source</summary>
|
||||
|
||||
To run the server directly from source, navigate to the project root directory
|
||||
and run:
|
||||
|
||||
```sh
|
||||
go run .
|
||||
```
|
||||
|
||||
> ⓘ Note
|
||||
> This command runs the project from source, and is more suitable for development
|
||||
> and testing. It does **not** compile a binary into your `$GOPATH`. If you want
|
||||
> to compile a binary instead, refer the [Developer
|
||||
> Documentation](./DEVELOPER.md#building-the-binary).
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Homebrew</summary>
|
||||
|
||||
If you installed Toolbox using [Homebrew](https://brew.sh/), the `toolbox`
|
||||
binary is available in your system path. You can start the server with the same
|
||||
command:
|
||||
|
||||
```sh
|
||||
toolbox --tools-file "tools.yaml"
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Gemini CLI</summary>
|
||||
|
||||
Interact with your custom tools using natural language. Check
|
||||
[gemini-cli-extensions/mcp-toolbox](https://github.com/gemini-cli-extensions/mcp-toolbox)
|
||||
for more information.
|
||||
|
||||
</details>
|
||||
|
||||
You can use `toolbox help` for a full list of flags! To stop the server, send a
|
||||
terminate signal (`ctrl+c` on most platforms).
|
||||
|
||||
@@ -311,21 +153,13 @@ Once your server is up and running, you can load the tools into your
|
||||
application. See below the list of Client SDKs for using various frameworks:
|
||||
|
||||
<details open>
|
||||
<summary>Python (<a href="https://github.com/googleapis/mcp-toolbox-sdk-python">Github</a>)</summary>
|
||||
<br>
|
||||
<blockquote>
|
||||
|
||||
<details open>
|
||||
<summary>Core</summary>
|
||||
<summary>Core</summary>
|
||||
|
||||
1. Install [Toolbox Core SDK][toolbox-core]:
|
||||
|
||||
```bash
|
||||
pip install toolbox-core
|
||||
```
|
||||
|
||||
1. Load tools:
|
||||
|
||||
```python
|
||||
from toolbox_core import ToolboxClient
|
||||
|
||||
@@ -342,18 +176,15 @@ For more detailed instructions on using the Toolbox Core SDK, see the
|
||||
[toolbox-core]: https://pypi.org/project/toolbox-core/
|
||||
[toolbox-core-readme]: https://github.com/googleapis/mcp-toolbox-sdk-python/tree/main/packages/toolbox-core/README.md
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>LangChain / LangGraph</summary>
|
||||
</details>
|
||||
<details>
|
||||
<summary>LangChain / LangGraph</summary>
|
||||
|
||||
1. Install [Toolbox LangChain SDK][toolbox-langchain]:
|
||||
|
||||
```bash
|
||||
pip install toolbox-langchain
|
||||
```
|
||||
|
||||
1. Load tools:
|
||||
|
||||
```python
|
||||
from toolbox_langchain import ToolboxClient
|
||||
|
||||
@@ -364,24 +195,22 @@ For more detailed instructions on using the Toolbox Core SDK, see the
|
||||
tools = client.load_toolset()
|
||||
```
|
||||
|
||||
For more detailed instructions on using the Toolbox LangChain SDK, see the
|
||||
[project's README][toolbox-langchain-readme].
|
||||
For more detailed instructions on using the Toolbox LangChain SDK, see the
|
||||
[project's README][toolbox-langchain-readme].
|
||||
|
||||
[toolbox-langchain]: https://pypi.org/project/toolbox-langchain/
|
||||
[toolbox-langchain-readme]: https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-langchain/README.md
|
||||
[toolbox-langchain]: https://pypi.org/project/toolbox-langchain/
|
||||
[toolbox-langchain-readme]: https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-langchain/README.md
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>LlamaIndex</summary>
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>LlamaIndex</summary>
|
||||
|
||||
1. Install [Toolbox Llamaindex SDK][toolbox-llamaindex]:
|
||||
|
||||
```bash
|
||||
pip install toolbox-llamaindex
|
||||
```
|
||||
|
||||
1. Load tools:
|
||||
|
||||
```python
|
||||
from toolbox_llamaindex import ToolboxClient
|
||||
|
||||
@@ -392,423 +221,13 @@ For more detailed instructions on using the Toolbox Core SDK, see the
|
||||
tools = client.load_toolset()
|
||||
```
|
||||
|
||||
For more detailed instructions on using the Toolbox Llamaindex SDK, see the
|
||||
[project's README][toolbox-llamaindex-readme].
|
||||
For more detailed instructions on using the Toolbox Llamaindex SDK, see the
|
||||
[project's README][toolbox-llamaindex-readme].
|
||||
|
||||
[toolbox-llamaindex]: https://pypi.org/project/toolbox-llamaindex/
|
||||
[toolbox-llamaindex-readme]: https://github.com/googleapis/genai-toolbox-llamaindex-python/blob/main/README.md
|
||||
[toolbox-llamaindex]: https://pypi.org/project/toolbox-llamaindex/
|
||||
[toolbox-llamaindex-readme]: https://github.com/googleapis/genai-toolbox-llamaindex-python/blob/main/README.md
|
||||
|
||||
</details>
|
||||
</details>
|
||||
</blockquote>
|
||||
<details>
|
||||
<summary>Javascript/Typescript (<a href="https://github.com/googleapis/mcp-toolbox-sdk-js">Github</a>)</summary>
|
||||
<br>
|
||||
<blockquote>
|
||||
|
||||
<details open>
|
||||
<summary>Core</summary>
|
||||
|
||||
1. Install [Toolbox Core SDK][toolbox-core-js]:
|
||||
|
||||
```bash
|
||||
npm install @toolbox-sdk/core
|
||||
```
|
||||
|
||||
1. Load tools:
|
||||
|
||||
```javascript
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const tools = await client.loadToolset('toolsetName');
|
||||
```
|
||||
|
||||
For more detailed instructions on using the Toolbox Core SDK, see the
|
||||
[project's README][toolbox-core-js-readme].
|
||||
|
||||
[toolbox-core-js]: https://www.npmjs.com/package/@toolbox-sdk/core
|
||||
[toolbox-core-js-readme]: https://github.com/googleapis/mcp-toolbox-sdk-js/blob/main/packages/toolbox-core/README.md
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>LangChain / LangGraph</summary>
|
||||
|
||||
1. Install [Toolbox Core SDK][toolbox-core-js]:
|
||||
|
||||
```bash
|
||||
npm install @toolbox-sdk/core
|
||||
```
|
||||
|
||||
2. Load tools:
|
||||
|
||||
```javascript
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const toolboxTools = await client.loadToolset('toolsetName');
|
||||
|
||||
// Define the basics of the tool: name, description, schema and core logic
|
||||
const getTool = (toolboxTool) => tool(currTool, {
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
schema: toolboxTool.getParamSchema()
|
||||
});
|
||||
|
||||
// Use these tools in your Langchain/Langraph applications
|
||||
const tools = toolboxTools.map(getTool);
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Genkit</summary>
|
||||
|
||||
1. Install [Toolbox Core SDK][toolbox-core-js]:
|
||||
|
||||
```bash
|
||||
npm install @toolbox-sdk/core
|
||||
```
|
||||
|
||||
2. Load tools:
|
||||
|
||||
```javascript
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
import { genkit } from 'genkit';
|
||||
|
||||
// Initialise genkit
|
||||
const ai = genkit({
|
||||
plugins: [
|
||||
googleAI({
|
||||
apiKey: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
||||
})
|
||||
],
|
||||
model: googleAI.model('gemini-2.0-flash'),
|
||||
});
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const toolboxTools = await client.loadToolset('toolsetName');
|
||||
|
||||
// Define the basics of the tool: name, description, schema and core logic
|
||||
const getTool = (toolboxTool) => ai.defineTool({
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
schema: toolboxTool.getParamSchema()
|
||||
}, toolboxTool)
|
||||
|
||||
// Use these tools in your Genkit applications
|
||||
const tools = toolboxTools.map(getTool);
|
||||
```
|
||||
|
||||
</details>
|
||||
</details>
|
||||
</blockquote>
|
||||
<details>
|
||||
<summary>Go (<a href="https://github.com/googleapis/mcp-toolbox-sdk-go">Github</a>)</summary>
|
||||
<br>
|
||||
<blockquote>
|
||||
|
||||
<details open>
|
||||
<summary>Core</summary>
|
||||
|
||||
1. Install [Toolbox Go SDK][toolbox-go]:
|
||||
|
||||
```bash
|
||||
go get github.com/googleapis/mcp-toolbox-sdk-go
|
||||
```
|
||||
|
||||
1. Load tools:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"context"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000";
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
|
||||
// Framework agnostic tools
|
||||
tools, err := client.LoadToolset("toolsetName", ctx)
|
||||
}
|
||||
```
|
||||
|
||||
For more detailed instructions on using the Toolbox Go SDK, see the
|
||||
[project's README][toolbox-core-go-readme].
|
||||
|
||||
[toolbox-go]: https://pkg.go.dev/github.com/googleapis/mcp-toolbox-sdk-go/core
|
||||
[toolbox-core-go-readme]: https://github.com/googleapis/mcp-toolbox-sdk-go/blob/main/core/README.md
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>LangChain Go</summary>
|
||||
|
||||
1. Install [Toolbox Go SDK][toolbox-go]:
|
||||
|
||||
```bash
|
||||
go get github.com/googleapis/mcp-toolbox-sdk-go
|
||||
```
|
||||
|
||||
2. Load tools:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := tool.InputSchema()
|
||||
|
||||
var paramsSchema map[string]any
|
||||
_ = json.Unmarshal(inputschema, ¶msSchema)
|
||||
|
||||
// Use this tool with LangChainGo
|
||||
langChainTool := llms.Tool{
|
||||
Type: "function",
|
||||
Function: &llms.FunctionDefinition{
|
||||
Name: tool.Name(),
|
||||
Description: tool.Description(),
|
||||
Parameters: paramsSchema,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Genkit</summary>
|
||||
|
||||
1. Install [Toolbox Go SDK][toolbox-go]:
|
||||
|
||||
```bash
|
||||
go get github.com/googleapis/mcp-toolbox-sdk-go
|
||||
```
|
||||
|
||||
2. Load tools:
|
||||
|
||||
```go
|
||||
package main
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/firebase/genkit/go/genkit"
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/tbgenkit"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// Update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
g := genkit.Init(ctx)
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
|
||||
// Convert the tool using the tbgenkit package
|
||||
// Use this tool with Genkit Go
|
||||
genkitTool, err := tbgenkit.ToGenkitTool(tool, g)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to convert tool: %v\n", err)
|
||||
}
|
||||
log.Printf("Successfully converted tool: %s", genkitTool.Name())
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>Go GenAI</summary>
|
||||
|
||||
1. Install [Toolbox Go SDK][toolbox-go]:
|
||||
|
||||
```bash
|
||||
go get github.com/googleapis/mcp-toolbox-sdk-go
|
||||
```
|
||||
|
||||
2. Load tools:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// Update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := tool.InputSchema()
|
||||
|
||||
var schema *genai.Schema
|
||||
_ = json.Unmarshal(inputschema, &schema)
|
||||
|
||||
funcDeclaration := &genai.FunctionDeclaration{
|
||||
Name: tool.Name(),
|
||||
Description: tool.Description(),
|
||||
Parameters: schema,
|
||||
}
|
||||
|
||||
// Use this tool with Go GenAI
|
||||
genAITool := &genai.Tool{
|
||||
FunctionDeclarations: []*genai.FunctionDeclaration{funcDeclaration},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
<details>
|
||||
<summary>OpenAI Go</summary>
|
||||
|
||||
1. Install [Toolbox Go SDK][toolbox-go]:
|
||||
|
||||
```bash
|
||||
go get github.com/googleapis/mcp-toolbox-sdk-go
|
||||
```
|
||||
|
||||
2. Load tools:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
openai "github.com/openai/openai-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// Update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := tool.InputSchema()
|
||||
|
||||
var paramsSchema openai.FunctionParameters
|
||||
_ = json.Unmarshal(inputschema, ¶msSchema)
|
||||
|
||||
// Use this tool with OpenAI Go
|
||||
openAITool := openai.ChatCompletionToolParam{
|
||||
Function: openai.FunctionDefinitionParam{
|
||||
Name: tool.Name(),
|
||||
Description: openai.String(tool.Description()),
|
||||
Parameters: paramsSchema,
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
</details>
|
||||
</details>
|
||||
</blockquote>
|
||||
</details>
|
||||
|
||||
### Using Toolbox with Gemini CLI Extensions
|
||||
|
||||
[Gemini CLI extensions][gemini-cli-extensions] provide tools to interact
|
||||
directly with your data sources from command line. Below is a list of Gemini CLI
|
||||
extensions that are built on top of **Toolbox**. They allow you to interact with
|
||||
your data sources through pre-defined or custom tools with natural language.
|
||||
Click into the link to see detailed instructions on their usage.
|
||||
|
||||
To use **custom** tools with Gemini CLI:
|
||||
|
||||
- [MCP Toolbox](https://github.com/gemini-cli-extensions/mcp-toolbox)
|
||||
|
||||
To use [prebuilt tools][prebuilt] with Gemini CLI:
|
||||
|
||||
- [AlloyDB for PostgreSQL](https://github.com/gemini-cli-extensions/alloydb)
|
||||
- [AlloyDB for PostgreSQL
|
||||
Observability](https://github.com/gemini-cli-extensions/alloydb-observability)
|
||||
- [BigQuery Data
|
||||
Analytics](https://github.com/gemini-cli-extensions/bigquery-data-analytics)
|
||||
- [BigQuery Conversational
|
||||
Analytics](https://github.com/gemini-cli-extensions/bigquery-conversational-analytics)
|
||||
- [Cloud SQL for
|
||||
MySQL](https://github.com/gemini-cli-extensions/cloud-sql-mysql)
|
||||
- [Cloud SQL for MySQL
|
||||
Observability](https://github.com/gemini-cli-extensions/cloud-sql-mysql-observability)
|
||||
- [Cloud SQL for
|
||||
PostgreSQL](https://github.com/gemini-cli-extensions/cloud-sql-postgresql)
|
||||
- [Cloud SQL for PostgreSQL
|
||||
Observability](https://github.com/gemini-cli-extensions/cloud-sql-postgresql-observability)
|
||||
- [Cloud SQL for SQL
|
||||
Server](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver)
|
||||
- [Cloud SQL for SQL Server
|
||||
Observability](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver-observability)
|
||||
- [Looker](https://github.com/gemini-cli-extensions/looker)
|
||||
- [Dataplex](https://github.com/gemini-cli-extensions/dataplex)
|
||||
- [MySQL](https://github.com/gemini-cli-extensions/mysql)
|
||||
- [PostgreSQL](https://github.com/gemini-cli-extensions/postgres)
|
||||
- [Spanner](https://github.com/gemini-cli-extensions/spanner)
|
||||
- [Firestore](https://github.com/gemini-cli-extensions/firestore-native)
|
||||
- [SQL Server](https://github.com/gemini-cli-extensions/sql-server)
|
||||
|
||||
[prebuilt]: https://googleapis.github.io/genai-toolbox/reference/prebuilt-tools/
|
||||
[gemini-cli-extensions]:
|
||||
https://github.com/google-gemini/gemini-cli/blob/main/docs/extensions/index.md
|
||||
|
||||
## Configuration
|
||||
|
||||
@@ -818,7 +237,6 @@ tools.yaml` flag.
|
||||
|
||||
You can find more detailed reference documentation to all resource types in the
|
||||
[Resources](https://googleapis.github.io/genai-toolbox/resources/).
|
||||
|
||||
### Sources
|
||||
|
||||
The `sources` section of your `tools.yaml` defines what data sources your
|
||||
@@ -860,6 +278,7 @@ tools:
|
||||
For more details on configuring different types of tools, see the
|
||||
[Tools](https://googleapis.github.io/genai-toolbox/resources/tools).
|
||||
|
||||
|
||||
### Toolsets
|
||||
|
||||
The `toolsets` section of your `tools.yaml` allows you to define groups of tools
|
||||
@@ -888,28 +307,12 @@ my_second_toolset = client.load_toolset("my_second_toolset")
|
||||
|
||||
## Versioning
|
||||
|
||||
This project uses [semantic versioning](https://semver.org/) (`MAJOR.MINOR.PATCH`).
|
||||
Since the project is in a pre-release stage (version `0.x.y`), we follow the
|
||||
standard conventions for initial development:
|
||||
This project uses [semantic versioning](https://semver.org/), including a
|
||||
`MAJOR.MINOR.PATCH` version number that increments with:
|
||||
|
||||
### Pre-1.0.0 Versioning
|
||||
|
||||
While the major version is `0`, the public API should be considered unstable.
|
||||
The version will be incremented as follows:
|
||||
|
||||
- **`0.MINOR.PATCH`**: The **MINOR** version is incremented when we add
|
||||
new functionality or make breaking, incompatible API changes.
|
||||
- **`0.MINOR.PATCH`**: The **PATCH** version is incremented for
|
||||
backward-compatible bug fixes.
|
||||
|
||||
### Post-1.0.0 Versioning
|
||||
|
||||
Once the project reaches a stable `1.0.0` release, the versioning will follow
|
||||
the more common convention:
|
||||
|
||||
- **`MAJOR.MINOR.PATCH`**: Incremented for incompatible API changes.
|
||||
- **`MAJOR.MINOR.PATCH`**: Incremented for new, backward-compatible functionality.
|
||||
- **`MAJOR.MINOR.PATCH`**: Incremented for backward-compatible bug fixes.
|
||||
- MAJOR version when we make incompatible API changes
|
||||
- MINOR version when we add functionality in a backward compatible manner
|
||||
- PATCH version when we make backward compatible bug fixes
|
||||
|
||||
The public API that this applies to is the CLI associated with Toolbox, the
|
||||
interactions with official SDKs, and the definitions in the `tools.yaml` file.
|
||||
@@ -922,7 +325,3 @@ to get started.
|
||||
Please note that this project is released with a Contributor Code of Conduct.
|
||||
By participating in this project you agree to abide by its terms. See
|
||||
[Contributor Code of Conduct](CODE_OF_CONDUCT.md) for more information.
|
||||
|
||||
## Community
|
||||
|
||||
Join our [discord community](https://discord.gg/GQrFB3Ec3W) to connect with our developers!
|
||||
|
||||
641
cmd/root.go
641
cmd/root.go
@@ -19,198 +19,65 @@ import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"maps"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"slices"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/fsnotify/fsnotify"
|
||||
yaml "github.com/goccy/go-yaml"
|
||||
"github.com/googleapis/genai-toolbox/internal/auth"
|
||||
"github.com/googleapis/genai-toolbox/internal/log"
|
||||
"github.com/googleapis/genai-toolbox/internal/prebuiltconfigs"
|
||||
"github.com/googleapis/genai-toolbox/internal/server"
|
||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||
"github.com/googleapis/genai-toolbox/internal/telemetry"
|
||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||
"github.com/googleapis/genai-toolbox/internal/util"
|
||||
|
||||
// Import tool packages for side effect of registration
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbcreatecluster"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbcreateinstance"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbcreateuser"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetcluster"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetinstance"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetuser"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistclusters"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistinstances"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistusers"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbwaitforoperation"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/alloydbainl"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigqueryanalyzecontribution"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigqueryconversationalanalytics"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigqueryexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigqueryforecast"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerygetdatasetinfo"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerygettableinfo"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerylistdatasetids"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerylisttableids"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerysearchcatalog"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerysql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquery"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigqueryexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquerygetdatasetinfo"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquerygettableinfo"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquerylistdatasetids"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigquerylisttableids"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/bigtable"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cassandra/cassandracql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/clickhouse/clickhouseexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/clickhouse/clickhouselistdatabases"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/clickhouse/clickhouselisttables"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/clickhouse/clickhousesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudmonitoring"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqlcreatedatabase"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqlcreateusers"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqlgetinstances"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqllistdatabases"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqllistinstances"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsql/cloudsqlwaitforoperation"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsqlmssql/cloudsqlmssqlcreateinstance"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsqlmysql/cloudsqlmysqlcreateinstance"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/cloudsqlpg/cloudsqlpgcreateinstances"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/couchbase"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/dataform/dataformcompilelocal"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/dataplex/dataplexlookupentry"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/dataplex/dataplexsearchaspecttypes"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/dataplex/dataplexsearchentries"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/dgraph"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firebird/firebirdexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firebird/firebirdsql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestoreadddocuments"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestoredeletedocuments"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestoregetdocuments"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestoregetrules"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestorelistcollections"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestorequery"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestorequerycollection"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestoreupdatedocument"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/firestore/firestorevalidaterules"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/http"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookeradddashboardelement"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookercreateprojectfile"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerconversationalanalytics"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerdeleteprojectfile"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerdevmode"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetconnectiondatabases"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetconnections"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetconnectionschemas"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetconnectiontables"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetconnectiontablecolumns"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetdashboards"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetdimensions"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetexplores"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetfilters"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetlooks"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetmeasures"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetmodels"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetparameters"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetprojectfile"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetprojectfiles"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookergetprojects"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerhealthanalyze"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerhealthpulse"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerhealthvacuum"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookermakedashboard"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookermakelook"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerquery"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerquerysql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerqueryurl"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerrunlook"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/looker/lookerupdateprojectfile"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbaggregate"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbdeletemany"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbdeleteone"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbfind"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbfindone"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbinsertmany"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbinsertone"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbupdatemany"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mongodb/mongodbupdateone"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mssql/mssqlexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mssql/mssqllisttables"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mssql/mssqlsql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqlexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllistactivequeries"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllisttablefragmentation"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllisttables"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqllisttablesmissinguniqueindexes"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysql/mysqlsql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/neo4j/neo4jcypher"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/neo4j/neo4jexecutecypher"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/neo4j/neo4jschema"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/oceanbase/oceanbaseexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/oceanbase/oceanbasesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/oracle/oracleexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/oracle/oraclesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgresexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistactivequeries"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistavailableextensions"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistinstalledextensions"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslisttables"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistviews"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgressql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mssqlexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mssqlsql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysqlexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/mysqlsql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/neo4j"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgresexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/postgressql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/redis"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/serverlessspark/serverlesssparkgetbatch"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/serverlessspark/serverlesssparklistbatches"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/spanner/spannerexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/spanner/spannerlisttables"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/spanner/spannersql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/sqlite/sqliteexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/sqlite/sqlitesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/tidb/tidbexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/tidb/tidbsql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/trino/trinoexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/trino/trinosql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/utility/wait"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/spanner"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/spannerexecutesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/sqlitesql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/valkey"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/tools/yugabytedbsql"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/alloydbadmin"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/alloydbpg"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/bigtable"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/cassandra"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/clickhouse"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudmonitoring"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqladmin"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmssql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlmysql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlpg"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/couchbase"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/dataplex"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/dgraph"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/firebird"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/firestore"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/http"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/looker"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/mongodb"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/mssql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/mysql"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/neo4j"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/oceanbase"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/oracle"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/postgres"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/redis"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/serverlessspark"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/spanner"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/sqlite"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/tidb"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/trino"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/valkey"
|
||||
_ "github.com/googleapis/genai-toolbox/internal/sources/yugabytedb"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -255,8 +122,6 @@ type Command struct {
|
||||
cfg server.ServerConfig
|
||||
logger log.Logger
|
||||
tools_file string
|
||||
tools_files []string
|
||||
tools_folder string
|
||||
prebuiltConfig string
|
||||
inStream io.Reader
|
||||
outStream io.Writer
|
||||
@@ -285,9 +150,6 @@ func NewCommand(opts ...Option) *Command {
|
||||
o(cmd)
|
||||
}
|
||||
|
||||
// Do not print Usage on runtime error
|
||||
cmd.SilenceUsage = true
|
||||
|
||||
// Set server version
|
||||
cmd.cfg.Version = versionString
|
||||
|
||||
@@ -303,24 +165,14 @@ func NewCommand(opts ...Option) *Command {
|
||||
flags.StringVar(&cmd.tools_file, "tools_file", "", "File path specifying the tool configuration. Cannot be used with --prebuilt.")
|
||||
// deprecate tools_file
|
||||
_ = flags.MarkDeprecated("tools_file", "please use --tools-file instead")
|
||||
flags.StringVar(&cmd.tools_file, "tools-file", "", "File path specifying the tool configuration. Cannot be used with --prebuilt, --tools-files, or --tools-folder.")
|
||||
flags.StringSliceVar(&cmd.tools_files, "tools-files", []string{}, "Multiple file paths specifying tool configurations. Files will be merged. Cannot be used with --prebuilt, --tools-file, or --tools-folder.")
|
||||
flags.StringVar(&cmd.tools_folder, "tools-folder", "", "Directory path containing YAML tool configuration files. All .yaml and .yml files in the directory will be loaded and merged. Cannot be used with --prebuilt, --tools-file, or --tools-files.")
|
||||
flags.StringVar(&cmd.tools_file, "tools-file", "", "File path specifying the tool configuration. Cannot be used with --prebuilt.")
|
||||
flags.Var(&cmd.cfg.LogLevel, "log-level", "Specify the minimum level logged. Allowed: 'DEBUG', 'INFO', 'WARN', 'ERROR'.")
|
||||
flags.Var(&cmd.cfg.LoggingFormat, "logging-format", "Specify logging format to use. Allowed: 'standard' or 'JSON'.")
|
||||
flags.BoolVar(&cmd.cfg.TelemetryGCP, "telemetry-gcp", false, "Enable exporting directly to Google Cloud Monitoring.")
|
||||
flags.StringVar(&cmd.cfg.TelemetryOTLP, "telemetry-otlp", "", "Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. 'http://127.0.0.1:4318')")
|
||||
flags.StringVar(&cmd.cfg.TelemetryServiceName, "telemetry-service-name", "toolbox", "Sets the value of the service.name resource attribute for telemetry data.")
|
||||
|
||||
// Fetch prebuilt tools sources to customize the help description
|
||||
prebuiltHelp := fmt.Sprintf(
|
||||
"Use a prebuilt tool configuration by source type. Cannot be used with --tools-file. Allowed: '%s'.",
|
||||
strings.Join(prebuiltconfigs.GetPrebuiltSources(), "', '"),
|
||||
)
|
||||
flags.StringVar(&cmd.prebuiltConfig, "prebuilt", "", prebuiltHelp)
|
||||
flags.StringVar(&cmd.prebuiltConfig, "prebuilt", "", "Use a prebuilt tool configuration by source type. Cannot be used with --tools-file. Allowed: 'alloydb-postgres', 'bigquery', 'cloud-sql-mysql', 'cloud-sql-postgres', 'cloud-sql-mssql', 'postgres', 'spanner', 'spanner-postgres'.")
|
||||
flags.BoolVar(&cmd.cfg.Stdio, "stdio", false, "Listens via MCP STDIO instead of acting as a remote HTTP server.")
|
||||
flags.BoolVar(&cmd.cfg.DisableReload, "disable-reload", false, "Disables dynamic reloading of tools file.")
|
||||
flags.BoolVar(&cmd.cfg.UI, "ui", false, "Launches the Toolbox UI web server.")
|
||||
|
||||
// wrap RunE command so that we have access to original Command object
|
||||
cmd.RunE = func(*cobra.Command, []string) error { return run(cmd) }
|
||||
@@ -337,376 +189,57 @@ type ToolsFile struct {
|
||||
}
|
||||
|
||||
// parseEnv replaces environment variables ${ENV_NAME} with their values.
|
||||
// also support ${ENV_NAME:default_value}.
|
||||
func parseEnv(input string) (string, error) {
|
||||
re := regexp.MustCompile(`\$\{(\w+)(:(\w*))?\}`)
|
||||
func parseEnv(input string) string {
|
||||
re := regexp.MustCompile(`\$\{(\w+)\}`)
|
||||
|
||||
var err error
|
||||
output := re.ReplaceAllStringFunc(input, func(match string) string {
|
||||
return re.ReplaceAllStringFunc(input, func(match string) string {
|
||||
parts := re.FindStringSubmatch(match)
|
||||
if len(parts) < 2 {
|
||||
// technically shouldn't happen
|
||||
return match
|
||||
}
|
||||
|
||||
// extract the variable name
|
||||
variableName := parts[1]
|
||||
if value, found := os.LookupEnv(variableName); found {
|
||||
return value
|
||||
}
|
||||
if parts[2] != "" {
|
||||
return parts[3]
|
||||
}
|
||||
err = fmt.Errorf("environment variable not found: %q", variableName)
|
||||
return ""
|
||||
return match
|
||||
})
|
||||
return output, err
|
||||
}
|
||||
|
||||
// parseToolsFile parses the provided yaml into appropriate configs.
|
||||
func parseToolsFile(ctx context.Context, raw []byte) (ToolsFile, error) {
|
||||
var toolsFile ToolsFile
|
||||
// Replace environment variables if found
|
||||
output, err := parseEnv(string(raw))
|
||||
if err != nil {
|
||||
return toolsFile, fmt.Errorf("error parsing environment variables: %s", err)
|
||||
}
|
||||
raw = []byte(output)
|
||||
|
||||
raw = []byte(parseEnv(string(raw)))
|
||||
// Parse contents
|
||||
err = yaml.UnmarshalContext(ctx, raw, &toolsFile, yaml.Strict())
|
||||
err := yaml.UnmarshalContext(ctx, raw, &toolsFile, yaml.Strict())
|
||||
if err != nil {
|
||||
return toolsFile, err
|
||||
}
|
||||
return toolsFile, nil
|
||||
}
|
||||
|
||||
// mergeToolsFiles merges multiple ToolsFile structs into one.
|
||||
// Detects and raises errors for resource conflicts in sources, authServices, tools, and toolsets.
|
||||
// All resource names (sources, authServices, tools, toolsets) must be unique across all files.
|
||||
func mergeToolsFiles(files ...ToolsFile) (ToolsFile, error) {
|
||||
merged := ToolsFile{
|
||||
Sources: make(server.SourceConfigs),
|
||||
AuthServices: make(server.AuthServiceConfigs),
|
||||
Tools: make(server.ToolConfigs),
|
||||
Toolsets: make(server.ToolsetConfigs),
|
||||
}
|
||||
|
||||
var conflicts []string
|
||||
|
||||
for fileIndex, file := range files {
|
||||
// Check for conflicts and merge sources
|
||||
for name, source := range file.Sources {
|
||||
if _, exists := merged.Sources[name]; exists {
|
||||
conflicts = append(conflicts, fmt.Sprintf("source '%s' (file #%d)", name, fileIndex+1))
|
||||
} else {
|
||||
merged.Sources[name] = source
|
||||
}
|
||||
}
|
||||
|
||||
// Check for conflicts and merge authSources (deprecated, but still support)
|
||||
for name, authSource := range file.AuthSources {
|
||||
if _, exists := merged.AuthSources[name]; exists {
|
||||
conflicts = append(conflicts, fmt.Sprintf("authSource '%s' (file #%d)", name, fileIndex+1))
|
||||
} else {
|
||||
merged.AuthSources[name] = authSource
|
||||
}
|
||||
}
|
||||
|
||||
// Check for conflicts and merge authServices
|
||||
for name, authService := range file.AuthServices {
|
||||
if _, exists := merged.AuthServices[name]; exists {
|
||||
conflicts = append(conflicts, fmt.Sprintf("authService '%s' (file #%d)", name, fileIndex+1))
|
||||
} else {
|
||||
merged.AuthServices[name] = authService
|
||||
}
|
||||
}
|
||||
|
||||
// Check for conflicts and merge tools
|
||||
for name, tool := range file.Tools {
|
||||
if _, exists := merged.Tools[name]; exists {
|
||||
conflicts = append(conflicts, fmt.Sprintf("tool '%s' (file #%d)", name, fileIndex+1))
|
||||
} else {
|
||||
merged.Tools[name] = tool
|
||||
}
|
||||
}
|
||||
|
||||
// Check for conflicts and merge toolsets
|
||||
for name, toolset := range file.Toolsets {
|
||||
if _, exists := merged.Toolsets[name]; exists {
|
||||
conflicts = append(conflicts, fmt.Sprintf("toolset '%s' (file #%d)", name, fileIndex+1))
|
||||
} else {
|
||||
merged.Toolsets[name] = toolset
|
||||
}
|
||||
// updateLogLevel checks if Toolbox have to update the existing log level set by users.
|
||||
// stdio doesn't support "debug" and "info" logs.
|
||||
func updateLogLevel(stdio bool, logLevel string) bool {
|
||||
if stdio {
|
||||
switch strings.ToUpper(logLevel) {
|
||||
case log.Debug, log.Info:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// If conflicts were detected, return an error
|
||||
if len(conflicts) > 0 {
|
||||
return ToolsFile{}, fmt.Errorf("resource conflicts detected:\n - %s\n\nPlease ensure each source, authService, tool, and toolset has a unique name across all files", strings.Join(conflicts, "\n - "))
|
||||
}
|
||||
|
||||
return merged, nil
|
||||
}
|
||||
|
||||
// loadAndMergeToolsFiles loads multiple YAML files and merges them
|
||||
func loadAndMergeToolsFiles(ctx context.Context, filePaths []string) (ToolsFile, error) {
|
||||
var toolsFiles []ToolsFile
|
||||
|
||||
for _, filePath := range filePaths {
|
||||
buf, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
return ToolsFile{}, fmt.Errorf("unable to read tool file at %q: %w", filePath, err)
|
||||
}
|
||||
|
||||
toolsFile, err := parseToolsFile(ctx, buf)
|
||||
if err != nil {
|
||||
return ToolsFile{}, fmt.Errorf("unable to parse tool file at %q: %w", filePath, err)
|
||||
}
|
||||
|
||||
toolsFiles = append(toolsFiles, toolsFile)
|
||||
}
|
||||
|
||||
mergedFile, err := mergeToolsFiles(toolsFiles...)
|
||||
if err != nil {
|
||||
return ToolsFile{}, fmt.Errorf("unable to merge tools files: %w", err)
|
||||
}
|
||||
|
||||
return mergedFile, nil
|
||||
}
|
||||
|
||||
// loadAndMergeToolsFolder loads all YAML files from a directory and merges them
|
||||
func loadAndMergeToolsFolder(ctx context.Context, folderPath string) (ToolsFile, error) {
|
||||
// Check if directory exists
|
||||
info, err := os.Stat(folderPath)
|
||||
if err != nil {
|
||||
return ToolsFile{}, fmt.Errorf("unable to access tools folder at %q: %w", folderPath, err)
|
||||
}
|
||||
if !info.IsDir() {
|
||||
return ToolsFile{}, fmt.Errorf("path %q is not a directory", folderPath)
|
||||
}
|
||||
|
||||
// Find all YAML files in the directory
|
||||
pattern := filepath.Join(folderPath, "*.yaml")
|
||||
yamlFiles, err := filepath.Glob(pattern)
|
||||
if err != nil {
|
||||
return ToolsFile{}, fmt.Errorf("error finding YAML files in %q: %w", folderPath, err)
|
||||
}
|
||||
|
||||
// Also find .yml files
|
||||
ymlPattern := filepath.Join(folderPath, "*.yml")
|
||||
ymlFiles, err := filepath.Glob(ymlPattern)
|
||||
if err != nil {
|
||||
return ToolsFile{}, fmt.Errorf("error finding YML files in %q: %w", folderPath, err)
|
||||
}
|
||||
|
||||
// Combine both file lists
|
||||
allFiles := append(yamlFiles, ymlFiles...)
|
||||
|
||||
if len(allFiles) == 0 {
|
||||
return ToolsFile{}, fmt.Errorf("no YAML files found in directory %q", folderPath)
|
||||
}
|
||||
|
||||
// Use existing loadAndMergeToolsFiles function
|
||||
return loadAndMergeToolsFiles(ctx, allFiles)
|
||||
}
|
||||
|
||||
func handleDynamicReload(ctx context.Context, toolsFile ToolsFile, s *server.Server) error {
|
||||
logger, err := util.LoggerFromContext(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
sourcesMap, authServicesMap, toolsMap, toolsetsMap, err := validateReloadEdits(ctx, toolsFile)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to validate reloaded edits: %w", err)
|
||||
logger.WarnContext(ctx, errMsg.Error())
|
||||
return err
|
||||
}
|
||||
|
||||
s.ResourceMgr.SetResources(sourcesMap, authServicesMap, toolsMap, toolsetsMap)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// validateReloadEdits checks that the reloaded tools file configs can initialized without failing
|
||||
func validateReloadEdits(
|
||||
ctx context.Context, toolsFile ToolsFile,
|
||||
) (map[string]sources.Source, map[string]auth.AuthService, map[string]tools.Tool, map[string]tools.Toolset, error,
|
||||
) {
|
||||
logger, err := util.LoggerFromContext(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
instrumentation, err := util.InstrumentationFromContext(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
logger.DebugContext(ctx, "Attempting to parse and validate reloaded tools file.")
|
||||
|
||||
ctx, span := instrumentation.Tracer.Start(ctx, "toolbox/server/reload")
|
||||
defer span.End()
|
||||
|
||||
reloadedConfig := server.ServerConfig{
|
||||
Version: versionString,
|
||||
SourceConfigs: toolsFile.Sources,
|
||||
AuthServiceConfigs: toolsFile.AuthServices,
|
||||
ToolConfigs: toolsFile.Tools,
|
||||
ToolsetConfigs: toolsFile.Toolsets,
|
||||
}
|
||||
|
||||
sourcesMap, authServicesMap, toolsMap, toolsetsMap, err := server.InitializeConfigs(ctx, reloadedConfig)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to initialize reloaded configs: %w", err)
|
||||
logger.WarnContext(ctx, errMsg.Error())
|
||||
return nil, nil, nil, nil, err
|
||||
}
|
||||
|
||||
return sourcesMap, authServicesMap, toolsMap, toolsetsMap, nil
|
||||
}
|
||||
|
||||
// watchChanges checks for changes in the provided yaml tools file(s) or folder.
|
||||
func watchChanges(ctx context.Context, watchDirs map[string]bool, watchedFiles map[string]bool, s *server.Server) {
|
||||
logger, err := util.LoggerFromContext(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
w, err := fsnotify.NewWatcher()
|
||||
if err != nil {
|
||||
logger.WarnContext(ctx, "error setting up new watcher %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
defer w.Close()
|
||||
|
||||
watchingFolder := false
|
||||
var folderToWatch string
|
||||
|
||||
// if watchedFiles is empty, indicates that user passed entire folder instead
|
||||
if len(watchedFiles) == 0 {
|
||||
watchingFolder = true
|
||||
|
||||
// validate that watchDirs only has single element
|
||||
if len(watchDirs) > 1 {
|
||||
logger.WarnContext(ctx, "error setting watcher, expected single tools folder if no file(s) are defined.")
|
||||
return
|
||||
}
|
||||
|
||||
for onlyKey := range watchDirs {
|
||||
folderToWatch = onlyKey
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
for dir := range watchDirs {
|
||||
err := w.Add(dir)
|
||||
if err != nil {
|
||||
logger.WarnContext(ctx, fmt.Sprintf("Error adding path %s to watcher: %s", dir, err))
|
||||
break
|
||||
}
|
||||
logger.DebugContext(ctx, fmt.Sprintf("Added directory %s to watcher.", dir))
|
||||
}
|
||||
|
||||
// debounce timer is used to prevent multiple writes triggering multiple reloads
|
||||
debounceDelay := 100 * time.Millisecond
|
||||
debounce := time.NewTimer(1 * time.Minute)
|
||||
debounce.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
logger.DebugContext(ctx, "file watcher context cancelled")
|
||||
return
|
||||
case err, ok := <-w.Errors:
|
||||
if !ok {
|
||||
logger.WarnContext(ctx, "file watcher was closed unexpectedly")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
logger.WarnContext(ctx, "file watcher error %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
case e, ok := <-w.Events:
|
||||
if !ok {
|
||||
logger.WarnContext(ctx, "file watcher already closed")
|
||||
return
|
||||
}
|
||||
|
||||
// only check for events which indicate user saved a new tools file
|
||||
// multiple operations checked due to various file update methods across editors
|
||||
if !e.Has(fsnotify.Write | fsnotify.Create | fsnotify.Rename) {
|
||||
continue
|
||||
}
|
||||
|
||||
cleanedFilename := filepath.Clean(e.Name)
|
||||
logger.DebugContext(ctx, fmt.Sprintf("%s event detected in %s", e.Op, cleanedFilename))
|
||||
|
||||
folderChanged := watchingFolder &&
|
||||
(strings.HasSuffix(cleanedFilename, ".yaml") || strings.HasSuffix(cleanedFilename, ".yml"))
|
||||
|
||||
if folderChanged || watchedFiles[cleanedFilename] {
|
||||
// indicates the write event is on a relevant file
|
||||
debounce.Reset(debounceDelay)
|
||||
}
|
||||
|
||||
case <-debounce.C:
|
||||
debounce.Stop()
|
||||
var reloadedToolsFile ToolsFile
|
||||
|
||||
if watchingFolder {
|
||||
logger.DebugContext(ctx, "Reloading tools folder.")
|
||||
reloadedToolsFile, err = loadAndMergeToolsFolder(ctx, folderToWatch)
|
||||
if err != nil {
|
||||
logger.WarnContext(ctx, "error loading tools folder %s", err)
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
logger.DebugContext(ctx, "Reloading tools file(s).")
|
||||
reloadedToolsFile, err = loadAndMergeToolsFiles(ctx, slices.Collect(maps.Keys(watchedFiles)))
|
||||
if err != nil {
|
||||
logger.WarnContext(ctx, "error loading tools files %s", err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
err = handleDynamicReload(ctx, reloadedToolsFile, s)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to parse reloaded tools file at %q: %w", reloadedToolsFile, err)
|
||||
logger.WarnContext(ctx, errMsg.Error())
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func resolveWatcherInputs(toolsFile string, toolsFiles []string, toolsFolder string) (map[string]bool, map[string]bool) {
|
||||
var relevantFiles []string
|
||||
|
||||
// map for efficiently checking if a file is relevant
|
||||
watchedFiles := make(map[string]bool)
|
||||
|
||||
// dirs that will be added to watcher (fsnotify prefers watching directory then filtering for file)
|
||||
watchDirs := make(map[string]bool)
|
||||
|
||||
if len(toolsFiles) > 0 {
|
||||
relevantFiles = toolsFiles
|
||||
} else if toolsFolder != "" {
|
||||
watchDirs[filepath.Clean(toolsFolder)] = true
|
||||
} else {
|
||||
relevantFiles = []string{toolsFile}
|
||||
}
|
||||
|
||||
// extract parent dir for relevant files and dedup
|
||||
for _, f := range relevantFiles {
|
||||
cleanFile := filepath.Clean(f)
|
||||
watchedFiles[cleanFile] = true
|
||||
watchDirs[filepath.Dir(cleanFile)] = true
|
||||
}
|
||||
|
||||
return watchDirs, watchedFiles
|
||||
return false
|
||||
}
|
||||
|
||||
func run(cmd *Command) error {
|
||||
if updateLogLevel(cmd.cfg.Stdio, cmd.cfg.LogLevel.String()) {
|
||||
cmd.cfg.LogLevel = server.StringLevel(log.Warn)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(cmd.Context())
|
||||
defer cancel()
|
||||
|
||||
@@ -730,22 +263,16 @@ func run(cmd *Command) error {
|
||||
cancel()
|
||||
}(ctx)
|
||||
|
||||
// If stdio, set logger's out stream (usually DEBUG and INFO logs) to errStream
|
||||
loggerOut := cmd.outStream
|
||||
if cmd.cfg.Stdio {
|
||||
loggerOut = cmd.errStream
|
||||
}
|
||||
|
||||
// Handle logger separately from config
|
||||
switch strings.ToLower(cmd.cfg.LoggingFormat.String()) {
|
||||
case "json":
|
||||
logger, err := log.NewStructuredLogger(loggerOut, cmd.errStream, cmd.cfg.LogLevel.String())
|
||||
logger, err := log.NewStructuredLogger(cmd.outStream, cmd.errStream, cmd.cfg.LogLevel.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize logger: %w", err)
|
||||
}
|
||||
cmd.logger = logger
|
||||
case "standard":
|
||||
logger, err := log.NewStdLogger(loggerOut, cmd.errStream, cmd.cfg.LogLevel.String())
|
||||
logger, err := log.NewStdLogger(cmd.outStream, cmd.errStream, cmd.cfg.LogLevel.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to initialize logger: %w", err)
|
||||
}
|
||||
@@ -771,17 +298,17 @@ func run(cmd *Command) error {
|
||||
}
|
||||
}()
|
||||
|
||||
var toolsFile ToolsFile
|
||||
var buf []byte
|
||||
|
||||
if cmd.prebuiltConfig != "" {
|
||||
// Make sure --prebuilt and --tools-file/--tools-files/--tools-folder flags are mutually exclusive
|
||||
if cmd.tools_file != "" || len(cmd.tools_files) > 0 || cmd.tools_folder != "" {
|
||||
errMsg := fmt.Errorf("--prebuilt and --tools-file/--tools-files/--tools-folder flags cannot be used simultaneously")
|
||||
// Make sure --prebuilt and --tools-file flags are mutually exclusive
|
||||
if cmd.tools_file != "" {
|
||||
errMsg := fmt.Errorf("--prebuilt and --tools-file flags cannot be used simultaneously")
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
// Use prebuilt tools
|
||||
buf, err := prebuiltconfigs.Get(cmd.prebuiltConfig)
|
||||
buf, err = prebuiltconfigs.Get(cmd.prebuiltConfig)
|
||||
if err != nil {
|
||||
cmd.logger.ErrorContext(ctx, err.Error())
|
||||
return err
|
||||
@@ -790,85 +317,35 @@ func run(cmd *Command) error {
|
||||
cmd.logger.InfoContext(ctx, logMsg)
|
||||
// Append prebuilt.source to Version string for the User Agent
|
||||
cmd.cfg.Version += "+prebuilt." + cmd.prebuiltConfig
|
||||
|
||||
toolsFile, err = parseToolsFile(ctx, buf)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to parse prebuilt tool configuration: %w", err)
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
} else if len(cmd.tools_files) > 0 {
|
||||
// Make sure --tools-file, --tools-files, and --tools-folder flags are mutually exclusive
|
||||
if cmd.tools_file != "" || cmd.tools_folder != "" {
|
||||
errMsg := fmt.Errorf("--tools-file, --tools-files, and --tools-folder flags cannot be used simultaneously")
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
|
||||
// Use multiple tools files
|
||||
cmd.logger.InfoContext(ctx, fmt.Sprintf("Loading and merging %d tool configuration files", len(cmd.tools_files)))
|
||||
var err error
|
||||
toolsFile, err = loadAndMergeToolsFiles(ctx, cmd.tools_files)
|
||||
if err != nil {
|
||||
cmd.logger.ErrorContext(ctx, err.Error())
|
||||
return err
|
||||
}
|
||||
} else if cmd.tools_folder != "" {
|
||||
// Make sure --tools-folder and other flags are mutually exclusive
|
||||
if cmd.tools_file != "" || len(cmd.tools_files) > 0 {
|
||||
errMsg := fmt.Errorf("--tools-file, --tools-files, and --tools-folder flags cannot be used simultaneously")
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
|
||||
// Use tools folder
|
||||
cmd.logger.InfoContext(ctx, fmt.Sprintf("Loading and merging all YAML files from directory: %s", cmd.tools_folder))
|
||||
var err error
|
||||
toolsFile, err = loadAndMergeToolsFolder(ctx, cmd.tools_folder)
|
||||
if err != nil {
|
||||
cmd.logger.ErrorContext(ctx, err.Error())
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
// Set default value of tools-file flag to tools.yaml
|
||||
if cmd.tools_file == "" {
|
||||
cmd.tools_file = "tools.yaml"
|
||||
}
|
||||
|
||||
// Read single tool file contents
|
||||
buf, err := os.ReadFile(cmd.tools_file)
|
||||
// Read tool file contents
|
||||
buf, err = os.ReadFile(cmd.tools_file)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to read tool file at %q: %w", cmd.tools_file, err)
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
|
||||
toolsFile, err = parseToolsFile(ctx, buf)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to parse tool file at %q: %w", cmd.tools_file, err)
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
}
|
||||
|
||||
toolsFile, err := parseToolsFile(ctx, buf)
|
||||
cmd.cfg.SourceConfigs, cmd.cfg.AuthServiceConfigs, cmd.cfg.ToolConfigs, cmd.cfg.ToolsetConfigs = toolsFile.Sources, toolsFile.AuthServices, toolsFile.Tools, toolsFile.Toolsets
|
||||
authSourceConfigs := toolsFile.AuthSources
|
||||
if authSourceConfigs != nil {
|
||||
cmd.logger.WarnContext(ctx, "`authSources` is deprecated, use `authServices` instead")
|
||||
cmd.cfg.AuthServiceConfigs = authSourceConfigs
|
||||
}
|
||||
|
||||
instrumentation, err := telemetry.CreateTelemetryInstrumentation(versionString)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("unable to create telemetry instrumentation: %w", err)
|
||||
errMsg := fmt.Errorf("unable to parse tool file at %q: %w", cmd.tools_file, err)
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
return errMsg
|
||||
}
|
||||
|
||||
ctx = util.WithInstrumentation(ctx, instrumentation)
|
||||
|
||||
// start server
|
||||
s, err := server.NewServer(ctx, cmd.cfg)
|
||||
s, err := server.NewServer(ctx, cmd.cfg, cmd.logger)
|
||||
if err != nil {
|
||||
errMsg := fmt.Errorf("toolbox failed to initialize: %w", err)
|
||||
cmd.logger.ErrorContext(ctx, errMsg.Error())
|
||||
@@ -893,9 +370,6 @@ func run(cmd *Command) error {
|
||||
return errMsg
|
||||
}
|
||||
cmd.logger.InfoContext(ctx, "Server ready to serve!")
|
||||
if cmd.cfg.UI {
|
||||
cmd.logger.InfoContext(ctx, fmt.Sprintf("Toolbox UI is up and running at: http://%s:%d/ui", cmd.cfg.Address, cmd.cfg.Port))
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(srvErr)
|
||||
@@ -906,13 +380,6 @@ func run(cmd *Command) error {
|
||||
}()
|
||||
}
|
||||
|
||||
watchDirs, watchedFiles := resolveWatcherInputs(cmd.tools_file, cmd.tools_files, cmd.tools_folder)
|
||||
|
||||
if !cmd.cfg.DisableReload {
|
||||
// start watching the file(s) or folder for changes to trigger dynamic reloading
|
||||
go watchChanges(ctx, watchDirs, watchedFiles, s)
|
||||
}
|
||||
|
||||
// wait for either the server to error out or the command's context to be canceled
|
||||
select {
|
||||
case err := <-srvErr:
|
||||
|
||||
756
cmd/root_test.go
756
cmd/root_test.go
@@ -16,33 +16,23 @@ package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
|
||||
"github.com/googleapis/genai-toolbox/internal/auth/google"
|
||||
"github.com/googleapis/genai-toolbox/internal/log"
|
||||
"github.com/googleapis/genai-toolbox/internal/prebuiltconfigs"
|
||||
"github.com/googleapis/genai-toolbox/internal/server"
|
||||
cloudsqlpgsrc "github.com/googleapis/genai-toolbox/internal/sources/cloudsqlpg"
|
||||
httpsrc "github.com/googleapis/genai-toolbox/internal/sources/http"
|
||||
"github.com/googleapis/genai-toolbox/internal/telemetry"
|
||||
"github.com/googleapis/genai-toolbox/internal/testutils"
|
||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||
"github.com/googleapis/genai-toolbox/internal/tools/http"
|
||||
"github.com/googleapis/genai-toolbox/internal/tools/postgres/postgressql"
|
||||
"github.com/googleapis/genai-toolbox/internal/util"
|
||||
"github.com/googleapis/genai-toolbox/internal/tools/postgressql"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -184,13 +174,6 @@ func TestServerConfigFlags(t *testing.T) {
|
||||
Stdio: true,
|
||||
}),
|
||||
},
|
||||
{
|
||||
desc: "disable reload",
|
||||
args: []string{"--disable-reload"},
|
||||
want: withDefaults(server.ServerConfig{
|
||||
DisableReload: true,
|
||||
}),
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
@@ -206,72 +189,6 @@ func TestServerConfigFlags(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseEnv(t *testing.T) {
|
||||
tcs := []struct {
|
||||
desc string
|
||||
env map[string]string
|
||||
in string
|
||||
want string
|
||||
err bool
|
||||
errString string
|
||||
}{
|
||||
{
|
||||
desc: "without default without env",
|
||||
in: "${FOO}",
|
||||
want: "",
|
||||
err: true,
|
||||
errString: `environment variable not found: "FOO"`,
|
||||
},
|
||||
{
|
||||
desc: "without default with env",
|
||||
env: map[string]string{
|
||||
"FOO": "bar",
|
||||
},
|
||||
in: "${FOO}",
|
||||
want: "bar",
|
||||
},
|
||||
{
|
||||
desc: "with empty default",
|
||||
in: "${FOO:}",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
desc: "with default",
|
||||
in: "${FOO:bar}",
|
||||
want: "bar",
|
||||
},
|
||||
{
|
||||
desc: "with default with env",
|
||||
env: map[string]string{
|
||||
"FOO": "hello",
|
||||
},
|
||||
in: "${FOO:bar}",
|
||||
want: "hello",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
if tc.env != nil {
|
||||
for k, v := range tc.env {
|
||||
t.Setenv(k, v)
|
||||
}
|
||||
}
|
||||
got, err := parseEnv(tc.in)
|
||||
if tc.err {
|
||||
if err == nil {
|
||||
t.Fatalf("expected error not found")
|
||||
}
|
||||
if tc.errString != err.Error() {
|
||||
t.Fatalf("incorrect error string: got %s, want %s", err, tc.errString)
|
||||
}
|
||||
}
|
||||
if tc.want != got {
|
||||
t.Fatalf("unexpected want: got %s, want %s", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToolFileFlag(t *testing.T) {
|
||||
tcs := []struct {
|
||||
desc string
|
||||
@@ -312,71 +229,6 @@ func TestToolFileFlag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestToolsFilesFlag(t *testing.T) {
|
||||
tcs := []struct {
|
||||
desc string
|
||||
args []string
|
||||
want []string
|
||||
}{
|
||||
{
|
||||
desc: "no value",
|
||||
args: []string{},
|
||||
want: []string{},
|
||||
},
|
||||
{
|
||||
desc: "single file",
|
||||
args: []string{"--tools-files", "foo.yaml"},
|
||||
want: []string{"foo.yaml"},
|
||||
},
|
||||
{
|
||||
desc: "multiple files",
|
||||
args: []string{"--tools-files", "foo.yaml,bar.yaml"},
|
||||
want: []string{"foo.yaml", "bar.yaml"},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
c, _, err := invokeCommand(tc.args)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error invoking command: %s", err)
|
||||
}
|
||||
if diff := cmp.Diff(c.tools_files, tc.want); diff != "" {
|
||||
t.Fatalf("got %v, want %v", c.tools_files, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToolsFolderFlag(t *testing.T) {
|
||||
tcs := []struct {
|
||||
desc string
|
||||
args []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
desc: "no value",
|
||||
args: []string{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
desc: "folder set",
|
||||
args: []string{"--tools-folder", "test-folder"},
|
||||
want: "test-folder",
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
c, _, err := invokeCommand(tc.args)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error invoking command: %s", err)
|
||||
}
|
||||
if c.tools_folder != tc.want {
|
||||
t.Fatalf("got %v, want %v", c.tools_folder, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrebuiltFlag(t *testing.T) {
|
||||
tcs := []struct {
|
||||
desc string
|
||||
@@ -886,14 +738,13 @@ func TestParseToolFileWithAuth(t *testing.T) {
|
||||
|
||||
func TestEnvVarReplacement(t *testing.T) {
|
||||
ctx, err := testutils.ContextWithNewLogger()
|
||||
t.Setenv("TestHeader", "ACTUAL_HEADER")
|
||||
t.Setenv("API_KEY", "ACTUAL_API_KEY")
|
||||
t.Setenv("clientId", "ACTUAL_CLIENT_ID")
|
||||
t.Setenv("clientId2", "ACTUAL_CLIENT_ID_2")
|
||||
t.Setenv("toolset_name", "ACTUAL_TOOLSET_NAME")
|
||||
t.Setenv("cat_string", "cat")
|
||||
t.Setenv("food_string", "food")
|
||||
t.Setenv("TestHeader", "ACTUAL_HEADER")
|
||||
os.Setenv("TestHeader", "ACTUAL_HEADER")
|
||||
os.Setenv("API_KEY", "ACTUAL_API_KEY")
|
||||
os.Setenv("clientId", "ACTUAL_CLIENT_ID")
|
||||
os.Setenv("clientId2", "ACTUAL_CLIENT_ID_2")
|
||||
os.Setenv("toolset_name", "ACTUAL_TOOLSET_NAME")
|
||||
os.Setenv("cat_string", "cat")
|
||||
os.Setenv("food_string", "food")
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
@@ -1049,299 +900,15 @@ func TestEnvVarReplacement(t *testing.T) {
|
||||
|
||||
}
|
||||
|
||||
// normalizeFilepaths is a helper function to allow same filepath formats for Mac and Windows.
|
||||
// this prevents needing multiple "want" cases for TestResolveWatcherInputs
|
||||
func normalizeFilepaths(m map[string]bool) map[string]bool {
|
||||
newMap := make(map[string]bool)
|
||||
for k, v := range m {
|
||||
newMap[filepath.ToSlash(k)] = v
|
||||
}
|
||||
return newMap
|
||||
}
|
||||
|
||||
func TestResolveWatcherInputs(t *testing.T) {
|
||||
tcs := []struct {
|
||||
description string
|
||||
toolsFile string
|
||||
toolsFiles []string
|
||||
toolsFolder string
|
||||
wantWatchDirs map[string]bool
|
||||
wantWatchedFiles map[string]bool
|
||||
}{
|
||||
{
|
||||
description: "single tools file",
|
||||
toolsFile: "tools_folder/example_tools.yaml",
|
||||
toolsFiles: []string{},
|
||||
toolsFolder: "",
|
||||
wantWatchDirs: map[string]bool{"tools_folder": true},
|
||||
wantWatchedFiles: map[string]bool{"tools_folder/example_tools.yaml": true},
|
||||
},
|
||||
{
|
||||
description: "default tools file (root dir)",
|
||||
toolsFile: "tools.yaml",
|
||||
toolsFiles: []string{},
|
||||
toolsFolder: "",
|
||||
wantWatchDirs: map[string]bool{".": true},
|
||||
wantWatchedFiles: map[string]bool{"tools.yaml": true},
|
||||
},
|
||||
{
|
||||
description: "multiple files in different folders",
|
||||
toolsFile: "",
|
||||
toolsFiles: []string{"tools_folder/example_tools.yaml", "tools_folder2/example_tools.yaml"},
|
||||
toolsFolder: "",
|
||||
wantWatchDirs: map[string]bool{"tools_folder": true, "tools_folder2": true},
|
||||
wantWatchedFiles: map[string]bool{
|
||||
"tools_folder/example_tools.yaml": true,
|
||||
"tools_folder2/example_tools.yaml": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "multiple files in same folder",
|
||||
toolsFile: "",
|
||||
toolsFiles: []string{"tools_folder/example_tools.yaml", "tools_folder/example_tools2.yaml"},
|
||||
toolsFolder: "",
|
||||
wantWatchDirs: map[string]bool{"tools_folder": true},
|
||||
wantWatchedFiles: map[string]bool{
|
||||
"tools_folder/example_tools.yaml": true,
|
||||
"tools_folder/example_tools2.yaml": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "multiple files in different levels",
|
||||
toolsFile: "",
|
||||
toolsFiles: []string{
|
||||
"tools_folder/example_tools.yaml",
|
||||
"tools_folder/special_tools/example_tools2.yaml"},
|
||||
toolsFolder: "",
|
||||
wantWatchDirs: map[string]bool{"tools_folder": true, "tools_folder/special_tools": true},
|
||||
wantWatchedFiles: map[string]bool{
|
||||
"tools_folder/example_tools.yaml": true,
|
||||
"tools_folder/special_tools/example_tools2.yaml": true,
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "tools folder",
|
||||
toolsFile: "",
|
||||
toolsFiles: []string{},
|
||||
toolsFolder: "tools_folder",
|
||||
wantWatchDirs: map[string]bool{"tools_folder": true},
|
||||
wantWatchedFiles: map[string]bool{},
|
||||
},
|
||||
}
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.description, func(t *testing.T) {
|
||||
gotWatchDirs, gotWatchedFiles := resolveWatcherInputs(tc.toolsFile, tc.toolsFiles, tc.toolsFolder)
|
||||
|
||||
normalizedGotWatchDirs := normalizeFilepaths(gotWatchDirs)
|
||||
normalizedGotWatchedFiles := normalizeFilepaths(gotWatchedFiles)
|
||||
|
||||
if diff := cmp.Diff(tc.wantWatchDirs, normalizedGotWatchDirs); diff != "" {
|
||||
t.Errorf("incorrect watchDirs: diff %v", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tc.wantWatchedFiles, normalizedGotWatchedFiles); diff != "" {
|
||||
t.Errorf("incorrect watchedFiles: diff %v", diff)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// helper function for testing file detection in dynamic reloading
|
||||
func tmpFileWithCleanup(content []byte) (string, func(), error) {
|
||||
f, err := os.CreateTemp("", "*")
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cleanup := func() { os.Remove(f.Name()) }
|
||||
|
||||
if _, err := f.Write(content); err != nil {
|
||||
cleanup()
|
||||
return "", nil, err
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
cleanup()
|
||||
return "", nil, err
|
||||
}
|
||||
return f.Name(), cleanup, err
|
||||
}
|
||||
|
||||
func TestSingleEdit(t *testing.T) {
|
||||
ctx, cancelCtx := context.WithTimeout(context.Background(), time.Minute)
|
||||
defer cancelCtx()
|
||||
|
||||
pr, pw := io.Pipe()
|
||||
defer pw.Close()
|
||||
defer pr.Close()
|
||||
|
||||
fileToWatch, cleanup, err := tmpFileWithCleanup([]byte("initial content"))
|
||||
if err != nil {
|
||||
t.Fatalf("error editing tools file %s", err)
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
logger, err := log.NewStdLogger(pw, pw, "DEBUG")
|
||||
if err != nil {
|
||||
t.Fatalf("failed to setup logger %s", err)
|
||||
}
|
||||
ctx = util.WithLogger(ctx, logger)
|
||||
|
||||
instrumentation, err := telemetry.CreateTelemetryInstrumentation(versionString)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to setup instrumentation %s", err)
|
||||
}
|
||||
ctx = util.WithInstrumentation(ctx, instrumentation)
|
||||
|
||||
mockServer := &server.Server{}
|
||||
|
||||
cleanFileToWatch := filepath.Clean(fileToWatch)
|
||||
watchDir := filepath.Dir(cleanFileToWatch)
|
||||
|
||||
watchedFiles := map[string]bool{cleanFileToWatch: true}
|
||||
watchDirs := map[string]bool{watchDir: true}
|
||||
|
||||
go watchChanges(ctx, watchDirs, watchedFiles, mockServer)
|
||||
|
||||
// escape backslash so regex doesn't fail on windows filepaths
|
||||
regexEscapedPathFile := strings.ReplaceAll(cleanFileToWatch, `\`, `\\\\*\\`)
|
||||
regexEscapedPathFile = path.Clean(regexEscapedPathFile)
|
||||
|
||||
regexEscapedPathDir := strings.ReplaceAll(watchDir, `\`, `\\\\*\\`)
|
||||
regexEscapedPathDir = path.Clean(regexEscapedPathDir)
|
||||
|
||||
begunWatchingDir := regexp.MustCompile(fmt.Sprintf(`DEBUG "Added directory %s to watcher."`, regexEscapedPathDir))
|
||||
_, err = testutils.WaitForString(ctx, begunWatchingDir, pr)
|
||||
if err != nil {
|
||||
t.Fatalf("timeout or error waiting for watcher to start: %s", err)
|
||||
}
|
||||
|
||||
err = os.WriteFile(fileToWatch, []byte("modification"), 0777)
|
||||
if err != nil {
|
||||
t.Fatalf("error writing to file: %v", err)
|
||||
}
|
||||
|
||||
// only check substring of DEBUG message due to some OS/editors firing different operations
|
||||
detectedFileChange := regexp.MustCompile(fmt.Sprintf(`event detected in %s"`, regexEscapedPathFile))
|
||||
_, err = testutils.WaitForString(ctx, detectedFileChange, pr)
|
||||
if err != nil {
|
||||
t.Fatalf("timeout or error waiting for file to detect write: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrebuiltTools(t *testing.T) {
|
||||
// Get prebuilt configs
|
||||
alloydb_admin_config, _ := prebuiltconfigs.Get("alloydb-postgres-admin")
|
||||
alloydb_config, _ := prebuiltconfigs.Get("alloydb-postgres")
|
||||
bigquery_config, _ := prebuiltconfigs.Get("bigquery")
|
||||
clickhouse_config, _ := prebuiltconfigs.Get("clickhouse")
|
||||
cloudsqlpg_config, _ := prebuiltconfigs.Get("cloud-sql-postgres")
|
||||
cloudsqlpg_admin_config, _ := prebuiltconfigs.Get("cloud-sql-postgres-admin")
|
||||
cloudsqlmysql_config, _ := prebuiltconfigs.Get("cloud-sql-mysql")
|
||||
cloudsqlmysql_admin_config, _ := prebuiltconfigs.Get("cloud-sql-mysql-admin")
|
||||
cloudsqlmssql_config, _ := prebuiltconfigs.Get("cloud-sql-mssql")
|
||||
cloudsqlmssql_admin_config, _ := prebuiltconfigs.Get("cloud-sql-mssql-admin")
|
||||
dataplex_config, _ := prebuiltconfigs.Get("dataplex")
|
||||
firestoreconfig, _ := prebuiltconfigs.Get("firestore")
|
||||
mysql_config, _ := prebuiltconfigs.Get("mysql")
|
||||
mssql_config, _ := prebuiltconfigs.Get("mssql")
|
||||
looker_config, _ := prebuiltconfigs.Get("looker")
|
||||
lookerca_config, _ := prebuiltconfigs.Get("looker-conversational-analytics")
|
||||
postgresconfig, _ := prebuiltconfigs.Get("postgres")
|
||||
spanner_config, _ := prebuiltconfigs.Get("spanner")
|
||||
spannerpg_config, _ := prebuiltconfigs.Get("spanner-postgres")
|
||||
sqlite_config, _ := prebuiltconfigs.Get("sqlite")
|
||||
neo4jconfig, _ := prebuiltconfigs.Get("neo4j")
|
||||
alloydbobsvconfig, _ := prebuiltconfigs.Get("alloydb-postgres-observability")
|
||||
cloudsqlpgobsvconfig, _ := prebuiltconfigs.Get("cloud-sql-postgres-observability")
|
||||
cloudsqlmysqlobsvconfig, _ := prebuiltconfigs.Get("cloud-sql-mysql-observability")
|
||||
cloudsqlmssqlobsvconfig, _ := prebuiltconfigs.Get("cloud-sql-mssql-observability")
|
||||
serverless_spark_config, _ := prebuiltconfigs.Get("serverless-spark")
|
||||
|
||||
// Set environment variables
|
||||
t.Setenv("API_KEY", "your_api_key")
|
||||
|
||||
t.Setenv("BIGQUERY_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("DATAPLEX_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("FIRESTORE_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("FIRESTORE_DATABASE", "your_firestore_db_name")
|
||||
|
||||
t.Setenv("SPANNER_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("SPANNER_INSTANCE", "your_spanner_instance")
|
||||
t.Setenv("SPANNER_DATABASE", "your_spanner_db")
|
||||
|
||||
t.Setenv("ALLOYDB_POSTGRES_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("ALLOYDB_POSTGRES_REGION", "your_gcp_region")
|
||||
t.Setenv("ALLOYDB_POSTGRES_CLUSTER", "your_alloydb_cluster")
|
||||
t.Setenv("ALLOYDB_POSTGRES_INSTANCE", "your_alloydb_instance")
|
||||
t.Setenv("ALLOYDB_POSTGRES_DATABASE", "your_alloydb_db")
|
||||
t.Setenv("ALLOYDB_POSTGRES_USER", "your_alloydb_user")
|
||||
t.Setenv("ALLOYDB_POSTGRES_PASSWORD", "your_alloydb_password")
|
||||
|
||||
t.Setenv("CLICKHOUSE_PROTOCOL", "your_clickhouse_protocol")
|
||||
t.Setenv("CLICKHOUSE_DATABASE", "your_clickhouse_database")
|
||||
t.Setenv("CLICKHOUSE_PASSWORD", "your_clickhouse_password")
|
||||
t.Setenv("CLICKHOUSE_USER", "your_clickhouse_user")
|
||||
t.Setenv("CLICKHOUSE_HOST", "your_clickhosue_host")
|
||||
t.Setenv("CLICKHOUSE_PORT", "8123")
|
||||
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_PROJECT", "your_pg_project")
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_INSTANCE", "your_pg_instance")
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_DATABASE", "your_pg_db")
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_REGION", "your_pg_region")
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_USER", "your_pg_user")
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_PASS", "your_pg_pass")
|
||||
|
||||
t.Setenv("CLOUD_SQL_MYSQL_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("CLOUD_SQL_MYSQL_REGION", "your_gcp_region")
|
||||
t.Setenv("CLOUD_SQL_MYSQL_INSTANCE", "your_instance")
|
||||
t.Setenv("CLOUD_SQL_MYSQL_DATABASE", "your_cloudsql_mysql_db")
|
||||
t.Setenv("CLOUD_SQL_MYSQL_USER", "your_cloudsql_mysql_user")
|
||||
t.Setenv("CLOUD_SQL_MYSQL_PASSWORD", "your_cloudsql_mysql_password")
|
||||
|
||||
t.Setenv("CLOUD_SQL_MSSQL_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("CLOUD_SQL_MSSQL_REGION", "your_gcp_region")
|
||||
t.Setenv("CLOUD_SQL_MSSQL_INSTANCE", "your_cloudsql_mssql_instance")
|
||||
t.Setenv("CLOUD_SQL_MSSQL_DATABASE", "your_cloudsql_mssql_db")
|
||||
t.Setenv("CLOUD_SQL_MSSQL_IP_ADDRESS", "127.0.0.1")
|
||||
t.Setenv("CLOUD_SQL_MSSQL_USER", "your_cloudsql_mssql_user")
|
||||
t.Setenv("CLOUD_SQL_MSSQL_PASSWORD", "your_cloudsql_mssql_password")
|
||||
t.Setenv("CLOUD_SQL_POSTGRES_PASSWORD", "your_cloudsql_pg_password")
|
||||
|
||||
t.Setenv("SERVERLESS_SPARK_PROJECT", "your_gcp_project_id")
|
||||
t.Setenv("SERVERLESS_SPARK_LOCATION", "your_gcp_location")
|
||||
|
||||
t.Setenv("POSTGRES_HOST", "localhost")
|
||||
t.Setenv("POSTGRES_PORT", "5432")
|
||||
t.Setenv("POSTGRES_DATABASE", "your_postgres_db")
|
||||
t.Setenv("POSTGRES_USER", "your_postgres_user")
|
||||
t.Setenv("POSTGRES_PASSWORD", "your_postgres_password")
|
||||
|
||||
t.Setenv("MYSQL_HOST", "localhost")
|
||||
t.Setenv("MYSQL_PORT", "3306")
|
||||
t.Setenv("MYSQL_DATABASE", "your_mysql_db")
|
||||
t.Setenv("MYSQL_USER", "your_mysql_user")
|
||||
t.Setenv("MYSQL_PASSWORD", "your_mysql_password")
|
||||
|
||||
t.Setenv("MSSQL_HOST", "localhost")
|
||||
t.Setenv("MSSQL_PORT", "1433")
|
||||
t.Setenv("MSSQL_DATABASE", "your_mssql_db")
|
||||
t.Setenv("MSSQL_USER", "your_mssql_user")
|
||||
t.Setenv("MSSQL_PASSWORD", "your_mssql_password")
|
||||
|
||||
t.Setenv("LOOKER_BASE_URL", "https://your_company.looker.com")
|
||||
t.Setenv("LOOKER_CLIENT_ID", "your_looker_client_id")
|
||||
t.Setenv("LOOKER_CLIENT_SECRET", "your_looker_client_secret")
|
||||
t.Setenv("LOOKER_VERIFY_SSL", "true")
|
||||
|
||||
t.Setenv("LOOKER_PROJECT", "your_project_id")
|
||||
t.Setenv("LOOKER_LOCATION", "us")
|
||||
|
||||
t.Setenv("SQLITE_DATABASE", "test.db")
|
||||
|
||||
t.Setenv("NEO4J_URI", "bolt://localhost:7687")
|
||||
t.Setenv("NEO4J_DATABASE", "neo4j")
|
||||
t.Setenv("NEO4J_USERNAME", "your_neo4j_user")
|
||||
t.Setenv("NEO4J_PASSWORD", "your_neo4j_password")
|
||||
|
||||
ctx, err := testutils.ContextWithNewLogger()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %s", err)
|
||||
@@ -1351,53 +918,13 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
in []byte
|
||||
wantToolset server.ToolsetConfigs
|
||||
}{
|
||||
{
|
||||
name: "alloydb postgres admin prebuilt tools",
|
||||
in: alloydb_admin_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"alloydb_postgres_admin_tools": tools.ToolsetConfig{
|
||||
Name: "alloydb_postgres_admin_tools",
|
||||
ToolNames: []string{"create_cluster", "wait_for_operation", "create_instance", "list_clusters", "list_instances", "list_users", "create_user", "get_cluster", "get_instance", "get_user"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cloudsql pg admin prebuilt tools",
|
||||
in: cloudsqlpg_admin_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_postgres_admin_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_postgres_admin_tools",
|
||||
ToolNames: []string{"create_instance", "get_instance", "list_instances", "create_database", "list_databases", "create_user", "wait_for_operation"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cloudsql mysql admin prebuilt tools",
|
||||
in: cloudsqlmysql_admin_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_mysql_admin_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_mysql_admin_tools",
|
||||
ToolNames: []string{"create_instance", "get_instance", "list_instances", "create_database", "list_databases", "create_user", "wait_for_operation"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cloudsql mssql admin prebuilt tools",
|
||||
in: cloudsqlmssql_admin_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_mssql_admin_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_mssql_admin_tools",
|
||||
ToolNames: []string{"create_instance", "get_instance", "list_instances", "create_database", "list_databases", "create_user", "wait_for_operation"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "alloydb prebuilt tools",
|
||||
in: alloydb_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"alloydb_postgres_database_tools": tools.ToolsetConfig{
|
||||
Name: "alloydb_postgres_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views"},
|
||||
"alloydb-postgres-database-tools": tools.ToolsetConfig{
|
||||
Name: "alloydb-postgres-database-tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1405,19 +932,9 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
name: "bigquery prebuilt tools",
|
||||
in: bigquery_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"bigquery_database_tools": tools.ToolsetConfig{
|
||||
Name: "bigquery_database_tools",
|
||||
ToolNames: []string{"analyze_contribution", "ask_data_insights", "execute_sql", "forecast", "get_dataset_info", "get_table_info", "list_dataset_ids", "list_table_ids", "search_catalog"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "clickhouse prebuilt tools",
|
||||
in: clickhouse_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"clickhouse_database_tools": tools.ToolsetConfig{
|
||||
Name: "clickhouse_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_databases", "list_tables"},
|
||||
"bigquery-database-tools": tools.ToolsetConfig{
|
||||
Name: "bigquery-database-tools",
|
||||
ToolNames: []string{"execute_sql", "get_dataset_info", "get_table_info", "list_dataset_ids", "list_table_ids"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1425,9 +942,9 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
name: "cloudsqlpg prebuilt tools",
|
||||
in: cloudsqlpg_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_postgres_database_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_postgres_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views"},
|
||||
"cloud-sql-postgres-database-tools": tools.ToolsetConfig{
|
||||
Name: "cloud-sql-postgres-database-tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1435,9 +952,9 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
name: "cloudsqlmysql prebuilt tools",
|
||||
in: cloudsqlmysql_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_mysql_database_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_mysql_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables", "get_query_plan", "list_active_queries", "list_tables_missing_unique_indexes", "list_table_fragmentation"},
|
||||
"cloud-sql-mysql-database-tools": tools.ToolsetConfig{
|
||||
Name: "cloud-sql-mysql-database-tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1445,89 +962,19 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
name: "cloudsqlmssql prebuilt tools",
|
||||
in: cloudsqlmssql_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_mssql_database_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_mssql_database_tools",
|
||||
"cloud-sql-mssql-database-tools": tools.ToolsetConfig{
|
||||
Name: "cloud-sql-mssql-database-tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "dataplex prebuilt tools",
|
||||
in: dataplex_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"dataplex_tools": tools.ToolsetConfig{
|
||||
Name: "dataplex_tools",
|
||||
ToolNames: []string{"search_entries", "lookup_entry", "search_aspect_types"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "serverless spark prebuilt tools",
|
||||
in: serverless_spark_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"serverless_spark_tools": tools.ToolsetConfig{
|
||||
Name: "serverless_spark_tools",
|
||||
ToolNames: []string{"list_batches", "get_batch"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "firestore prebuilt tools",
|
||||
in: firestoreconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"firestore_database_tools": tools.ToolsetConfig{
|
||||
Name: "firestore_database_tools",
|
||||
ToolNames: []string{"get_documents", "add_documents", "update_document", "list_collections", "delete_documents", "query_collection", "get_rules", "validate_rules"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mysql prebuilt tools",
|
||||
in: mysql_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"mysql_database_tools": tools.ToolsetConfig{
|
||||
Name: "mysql_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables", "get_query_plan", "list_active_queries", "list_tables_missing_unique_indexes", "list_table_fragmentation"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "mssql prebuilt tools",
|
||||
in: mssql_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"mssql_database_tools": tools.ToolsetConfig{
|
||||
Name: "mssql_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "looker prebuilt tools",
|
||||
in: looker_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"looker_tools": tools.ToolsetConfig{
|
||||
Name: "looker_tools",
|
||||
ToolNames: []string{"get_models", "get_explores", "get_dimensions", "get_measures", "get_filters", "get_parameters", "query", "query_sql", "query_url", "get_looks", "run_look", "make_look", "get_dashboards", "make_dashboard", "add_dashboard_element", "health_pulse", "health_analyze", "health_vacuum", "dev_mode", "get_projects", "get_project_files", "get_project_file", "create_project_file", "update_project_file", "delete_project_file", "get_connections", "get_connection_schemas", "get_connection_databases", "get_connection_tables", "get_connection_table_columns"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "looker-conversational-analytics prebuilt tools",
|
||||
in: lookerca_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"looker_conversational_analytics_tools": tools.ToolsetConfig{
|
||||
Name: "looker_conversational_analytics_tools",
|
||||
ToolNames: []string{"ask_data_insights", "get_models", "get_explores"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "postgres prebuilt tools",
|
||||
in: postgresconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"postgres_database_tools": tools.ToolsetConfig{
|
||||
Name: "postgres_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views"},
|
||||
"postgres-database-tools": tools.ToolsetConfig{
|
||||
Name: "postgres-database-tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -1545,72 +992,12 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
name: "spanner pg prebuilt tools",
|
||||
in: spannerpg_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"spanner_postgres_database_tools": tools.ToolsetConfig{
|
||||
Name: "spanner_postgres_database_tools",
|
||||
"spanner-postgres-database-tools": tools.ToolsetConfig{
|
||||
Name: "spanner-postgres-database-tools",
|
||||
ToolNames: []string{"execute_sql", "execute_sql_dql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sqlite prebuilt tools",
|
||||
in: sqlite_config,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"sqlite_database_tools": tools.ToolsetConfig{
|
||||
Name: "sqlite_database_tools",
|
||||
ToolNames: []string{"execute_sql", "list_tables"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "neo4j prebuilt tools",
|
||||
in: neo4jconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"neo4j_database_tools": tools.ToolsetConfig{
|
||||
Name: "neo4j_database_tools",
|
||||
ToolNames: []string{"execute_cypher", "get_schema"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "alloydb postgres observability prebuilt tools",
|
||||
in: alloydbobsvconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"alloydb_postgres_cloud_monitoring_tools": tools.ToolsetConfig{
|
||||
Name: "alloydb_postgres_cloud_monitoring_tools",
|
||||
ToolNames: []string{"get_system_metrics", "get_query_metrics"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cloudsql postgres observability prebuilt tools",
|
||||
in: cloudsqlpgobsvconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_postgres_cloud_monitoring_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_postgres_cloud_monitoring_tools",
|
||||
ToolNames: []string{"get_system_metrics", "get_query_metrics"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cloudsql mysql observability prebuilt tools",
|
||||
in: cloudsqlmysqlobsvconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_mysql_cloud_monitoring_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_mysql_cloud_monitoring_tools",
|
||||
ToolNames: []string{"get_system_metrics", "get_query_metrics"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "cloudsql mssql observability prebuilt tools",
|
||||
in: cloudsqlmssqlobsvconfig,
|
||||
wantToolset: server.ToolsetConfigs{
|
||||
"cloud_sql_mssql_cloud_monitoring_tools": tools.ToolsetConfig{
|
||||
Name: "cloud_sql_mssql_cloud_monitoring_tools",
|
||||
ToolNames: []string{"get_system_metrics"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tcs {
|
||||
@@ -1626,71 +1013,50 @@ func TestPrebuiltTools(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMutuallyExclusiveFlags(t *testing.T) {
|
||||
testCases := []struct {
|
||||
desc string
|
||||
args []string
|
||||
errString string
|
||||
func TestUpdateLogLevel(t *testing.T) {
|
||||
tcs := []struct {
|
||||
desc string
|
||||
stdio bool
|
||||
logLevel string
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
desc: "--prebuilt and --tools-file",
|
||||
args: []string{"--prebuilt", "alloydb", "--tools-file", "my.yaml"},
|
||||
errString: "--prebuilt and --tools-file/--tools-files/--tools-folder flags cannot be used simultaneously",
|
||||
desc: "no stdio",
|
||||
stdio: false,
|
||||
logLevel: "info",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "--tools-file and --tools-files",
|
||||
args: []string{"--tools-file", "my.yaml", "--tools-files", "a.yaml,b.yaml"},
|
||||
errString: "--tools-file, --tools-files, and --tools-folder flags cannot be used simultaneously",
|
||||
desc: "stdio with info log",
|
||||
stdio: true,
|
||||
logLevel: "info",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "--tools-folder and --tools-files",
|
||||
args: []string{"--tools-folder", "./", "--tools-files", "a.yaml,b.yaml"},
|
||||
errString: "--tools-file, --tools-files, and --tools-folder flags cannot be used simultaneously",
|
||||
desc: "stdio with debug log",
|
||||
stdio: true,
|
||||
logLevel: "debug",
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
desc: "stdio with warn log",
|
||||
stdio: true,
|
||||
logLevel: "warn",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
desc: "stdio with error log",
|
||||
stdio: true,
|
||||
logLevel: "error",
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
for _, tc := range tcs {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
cmd := NewCommand()
|
||||
cmd.SetArgs(tc.args)
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Fatalf("expected an error but got none")
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.errString) {
|
||||
t.Errorf("expected error message to contain %q, but got %q", tc.errString, err.Error())
|
||||
got := updateLogLevel(tc.stdio, tc.logLevel)
|
||||
if got != tc.want {
|
||||
t.Fatalf("incorrect indication to update log level: got %t, want %t", got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileLoadingErrors(t *testing.T) {
|
||||
t.Run("non-existent tools-file", func(t *testing.T) {
|
||||
cmd := NewCommand()
|
||||
// Use a file that is guaranteed not to exist
|
||||
nonExistentFile := filepath.Join(t.TempDir(), "non-existent-tools.yaml")
|
||||
cmd.SetArgs([]string{"--tools-file", nonExistentFile})
|
||||
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Fatal("expected an error for non-existent file but got none")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unable to read tool file") {
|
||||
t.Errorf("expected error about reading file, but got: %v", err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("non-existent tools-folder", func(t *testing.T) {
|
||||
cmd := NewCommand()
|
||||
nonExistentFolder := filepath.Join(t.TempDir(), "non-existent-folder")
|
||||
cmd.SetArgs([]string{"--tools-folder", nonExistentFolder})
|
||||
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Fatal("expected an error for non-existent folder but got none")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unable to access tools folder") {
|
||||
t.Errorf("expected error about accessing folder, but got: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
0.18.0
|
||||
0.7.0
|
||||
|
||||
@@ -4,12 +4,12 @@ type: docs
|
||||
notoc: false
|
||||
weight: 1
|
||||
description: >
|
||||
All of Toolbox's documentation.
|
||||
All of Toolbox's documentation.
|
||||
---
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<link rel="canonical" href="getting-started/introduction/"/>
|
||||
<meta http-equiv="refresh" content="0;url=getting-started/introduction/"/>
|
||||
<meta http-equiv="refresh" content="0;url=getting-started/introduction"/>
|
||||
</head>
|
||||
</html>
|
||||
|
||||
23
docs/en/about/blogs.md
Normal file
23
docs/en/about/blogs.md
Normal file
@@ -0,0 +1,23 @@
|
||||
---
|
||||
title: "Blogs"
|
||||
type: docs
|
||||
weight: 3
|
||||
description: Toolbox Tuesday blog posts.
|
||||
---
|
||||
|
||||
## Toolbox Tuesday Blogs
|
||||
|
||||
Every Tuesday, we post a blog on our [Medium page][medium]. These blogs will be covering
|
||||
topics, tutorials, or samples that are related to developing with Toolbox.
|
||||
Follow us and stay tuned!
|
||||
|
||||
## Previous Blogs
|
||||
|
||||
- [Powering your IDE’s build-time agents with MCP Toolbox for Databases][blog1]
|
||||
- [Using HTTP endpoints as tools with MCP Toolbox for Databases][blog2]
|
||||
|
||||
[medium]: https://medium.com/@mcp_toolbox
|
||||
[blog1]:
|
||||
https://medium.com/google-cloud/powering-your-ides-build-time-agents-with-mcp-toolbox-for-databases-123f0d837804
|
||||
[blog2]:
|
||||
https://medium.com/google-cloud/using-http-endpoints-as-tools-with-mcp-toolbox-for-databases-e93ab75b60cd
|
||||
22
docs/en/about/contact.md
Normal file
22
docs/en/about/contact.md
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
title: "Contact Us"
|
||||
type: docs
|
||||
weight: 10
|
||||
description: Contact the Toolbox team.
|
||||
---
|
||||
|
||||
Toolbox is an open source project and we welcome contributions and discussion from the
|
||||
developer community.
|
||||
|
||||
## How to Get in Touch
|
||||
|
||||
- If you want to make a contribution, [open an issue][issue] first so that we can agree
|
||||
on the general design.
|
||||
|
||||
- If you found a bug or have ideas for improvements, [open an issue][issue] and
|
||||
we will reply as soon as possible.
|
||||
|
||||
- For any topics, join our [discord server][discord], where we can discuss things in real-time for a faster response.
|
||||
|
||||
[issue]: https://github.com/googleapis/genai-toolbox/issues
|
||||
[discord]: https://discord.com/invite/Dmm69peqjh
|
||||
@@ -7,24 +7,24 @@ description: Frequently asked questions about Toolbox.
|
||||
|
||||
## How can I deploy or run Toolbox?
|
||||
|
||||
MCP Toolbox for Databases is open-source and can be run or deployed to a
|
||||
MCP Toolbox for Databases is open-source and can be ran or deployed to a
|
||||
multitude of environments. For convenience, we release [compiled binaries and
|
||||
docker images][release-notes] (but you can always compile yourself as well!).
|
||||
|
||||
For detailed instructions, check out these resources:
|
||||
docker images][release-notes] (but you can always compile yourself as well!).
|
||||
|
||||
For detailed instructions, check our these resources:
|
||||
- [Quickstart: How to Run Locally](../getting-started/local_quickstart.md)
|
||||
- [Deploy to Cloud Run](../how-to/deploy_toolbox.md)
|
||||
|
||||
[release-notes]: https://github.com/googleapis/genai-toolbox/releases/
|
||||
|
||||
|
||||
## Do I need a Google Cloud account/project to get started with Toolbox?
|
||||
|
||||
Nope! While some of the sources Toolbox connects to may require GCP credentials,
|
||||
Toolbox doesn't require them and can connect to a bunch of different resources
|
||||
that don't.
|
||||
that don't.
|
||||
|
||||
## Does Toolbox take contributions from external users?
|
||||
## Does Toolbox take contributions from external users?
|
||||
|
||||
Absolutely! Please check out our [DEVELOPER.md][] for instructions on how to get
|
||||
started developing _on_ Toolbox instead of with it, and the [CONTRIBUTING.md][]
|
||||
@@ -33,16 +33,17 @@ for instructions on completing the CLA and getting a PR accepted.
|
||||
[DEVELOPER.md]: https://github.com/googleapis/genai-toolbox/blob/main/DEVELOPER.md
|
||||
[CONTRIBUTING.MD]: https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md
|
||||
|
||||
## Can Toolbox support a feature to let me do _$FOO_?
|
||||
|
||||
## Can Toolbox support a feature to let me do _$FOO_?
|
||||
|
||||
Maybe? The best place to start is by [opening an issue][github-issue] for
|
||||
discussion (or seeing if there is already one open), so we can better understand
|
||||
your use case and the best way to solve it. Generally we aim to prioritize the
|
||||
most popular issues, so make sure to +1 ones you are the most interested in.
|
||||
most popular issues, so make sure to +1 ones you are the most interested in.
|
||||
|
||||
[github-issue]: https://github.com/googleapis/genai-toolbox/issues
|
||||
|
||||
## Can Toolbox be used for non-database tools?
|
||||
## Can Toolbox be used for non-database tools?
|
||||
|
||||
Currently, Toolbox is primarily focused on making it easier to create and
|
||||
develop tools focused on interacting with Databases. We believe that there are a
|
||||
@@ -54,21 +55,21 @@ GRPC tools might be helpful in assisting with migrating to Toolbox or in
|
||||
accomplishing more complicated workflows. We're looking into what that might
|
||||
best look like in Toolbox.
|
||||
|
||||
## Can I use _$BAR_ orchestration framework to use tools from Toolbox?
|
||||
## Can I use _$BAR_ orchestration framework to use tools from Toolbox?
|
||||
|
||||
Currently, Toolbox only supports a limited number of client SDKs at our initial
|
||||
launch. We are investigating support for more frameworks as well as more general
|
||||
approaches for users without a framework -- look forward to seeing an update
|
||||
soon.
|
||||
|
||||
## Why does Toolbox use a server-client architecture pattern?
|
||||
## Why does Toolbox use a server-client architecture pattern?
|
||||
|
||||
Toolbox's server-client architecture allows us to more easily support a wide
|
||||
variety of languages and frameworks with a centralized implementation. It also
|
||||
allows us to tackle problems like connection pooling, auth, or caching more
|
||||
completely than entirely client-side solutions.
|
||||
|
||||
## Why was Toolbox written in Go?
|
||||
## Why was Toolbox written in Go?
|
||||
|
||||
While a large part of the Gen AI Ecosystem is predominately Python, we opted to
|
||||
use Go. We chose Go because it's still easy and simple to use, but also easier
|
||||
@@ -79,9 +80,8 @@ to be able to use Toolbox on the serving path of mission critical applications.
|
||||
It's easier to build the needed robustness, performance and scalability in Go
|
||||
than in Python.
|
||||
|
||||
## Is Toolbox compatible with Model Context Protocol (MCP)?
|
||||
|
||||
Yes! Toolbox is compatible with [Anthropic's Model Context Protocol
|
||||
(MCP)](https://modelcontextprotocol.io/). Please checkout [Connect via
|
||||
MCP](../how-to/connect_via_mcp.md) on how to connect to Toolbox with an MCP
|
||||
client.
|
||||
## Is Toolbox compatible with Model Context Protocol (MCP)?
|
||||
|
||||
Yes! Toolbox is compatible with [Anthropic's Model Context Protocol (MCP)](https://modelcontextprotocol.io/). Please checkout [Connect via MCP](../how-to/connect_via_mcp.md) on how to
|
||||
connect to Toolbox with an MCP client.
|
||||
@@ -3,7 +3,7 @@ title: "Telemetry"
|
||||
type: docs
|
||||
weight: 2
|
||||
description: >
|
||||
An overview of telemetry and observability in Toolbox.
|
||||
An overview of telemetry and observability in Toolbox.
|
||||
---
|
||||
|
||||
## About
|
||||
@@ -17,6 +17,7 @@ through [OpenTelemetry](https://opentelemetry.io/). Additional flags can be
|
||||
passed to Toolbox to enable different logging behavior, or to export metrics
|
||||
through a specific [exporter](#exporter).
|
||||
|
||||
|
||||
## Logging
|
||||
|
||||
The following flags can be used to customize Toolbox logging:
|
||||
@@ -26,8 +27,7 @@ The following flags can be used to customize Toolbox logging:
|
||||
| `--log-level` | Preferred log level, allowed values: `debug`, `info`, `warn`, `error`. Default: `info`. |
|
||||
| `--logging-format` | Preferred logging format, allowed values: `standard`, `json`. Default: `standard`. |
|
||||
|
||||
**Example:**
|
||||
|
||||
__Example:__
|
||||
```bash
|
||||
./toolbox --tools-file "tools.yaml" --log-level warn --logging-format json
|
||||
```
|
||||
@@ -35,7 +35,6 @@ The following flags can be used to customize Toolbox logging:
|
||||
### Level
|
||||
|
||||
Toolbox supports the following log levels, including:
|
||||
|
||||
| **Log level** | **Description** |
|
||||
|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Debug | Debug logs typically contain information that is only useful during the debugging phase and may be of little value during production. |
|
||||
@@ -47,18 +46,17 @@ Toolbox will only output logs that are equal or more severe to the
|
||||
level that it is set. Below are the log levels that Toolbox supports in the
|
||||
order of severity.
|
||||
|
||||
|
||||
### Format
|
||||
|
||||
Toolbox supports both standard and structured logging format.
|
||||
|
||||
The standard logging outputs log as string:
|
||||
|
||||
```
|
||||
2024-11-12T15:08:11.451377-08:00 INFO "Initialized 0 sources.\n"
|
||||
```
|
||||
|
||||
The structured logging outputs log as JSON:
|
||||
|
||||
```
|
||||
{
|
||||
"timestamp":"2024-11-04T16:45:11.987299-08:00",
|
||||
@@ -68,9 +66,9 @@ The structured logging outputs log as JSON:
|
||||
}
|
||||
```
|
||||
|
||||
{{< notice tip >}}
|
||||
{{< notice tip >}}
|
||||
`logging.googleapis.com/sourceLocation` shows the source code
|
||||
location information associated with the log entry, if any.
|
||||
location information associated with the log entry, if any.
|
||||
{{< /notice >}}
|
||||
|
||||
## Telemetry
|
||||
@@ -127,6 +125,7 @@ unified [resource][resource]. The list of resource attributes included are:
|
||||
| `service.name` | Open telemetry service name. Defaulted to `toolbox`. User can set the service name via flag mentioned above to distinguish between different toolbox service. |
|
||||
| `service.version` | The version of Toolbox used. |
|
||||
|
||||
|
||||
[resource]: https://opentelemetry.io/docs/languages/go/resources/
|
||||
|
||||
### Exporter
|
||||
@@ -152,13 +151,12 @@ Exporter][gcp-trace-exporter].
|
||||
[gcp-trace-exporter]:
|
||||
https://github.com/GoogleCloudPlatform/opentelemetry-operations-go/tree/main/exporter/trace
|
||||
|
||||
{{< notice note >}}
|
||||
If you're using Google Cloud Monitoring, the following APIs will need to be
|
||||
{{< notice note >}}
|
||||
If you're using Google Cloud Monitoring, the following APIs will need to be
|
||||
enabled:
|
||||
|
||||
- [Cloud Logging API](https://cloud.google.com/logging/docs/api/enable-api)
|
||||
- [Cloud Monitoring API](https://cloud.google.com/monitoring/api/enable-api)
|
||||
- [Cloud Trace API](https://console.cloud.google.com/apis/enableflow?apiid=cloudtrace.googleapis.com)
|
||||
- [Cloud Trace API](https://cloud.google.com/apis/enableflow?apiid=cloudtrace.googleapis.com)
|
||||
{{< /notice >}}
|
||||
|
||||
#### OTLP Exporter
|
||||
@@ -177,7 +175,7 @@ It receives telemetry data, transforms it, and then exports data to backends
|
||||
that can store it permanently. Toolbox provide an option to export telemetry
|
||||
data to user's choice of backend(s) that are compatible with the Open Telemetry
|
||||
Protocol (OTLP). If you would like to use a collector, please refer to this
|
||||
[Export Telemetry using the Otel Collector](../../how-to/export_telemetry.md).
|
||||
[Export Telemetry using the Otel Collector](../how-to/export_telemetry.md).
|
||||
|
||||
### Flags
|
||||
|
||||
@@ -186,7 +184,7 @@ The following flags are used to determine Toolbox's telemetry configuration:
|
||||
| **flag** | **type** | **description** |
|
||||
|----------------------------|----------|----------------------------------------------------------------------------------------------------------------|
|
||||
| `--telemetry-gcp` | bool | Enable exporting directly to Google Cloud Monitoring. Default is `false`. |
|
||||
| `--telemetry-otlp` | string | Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. "<http://127.0.0.1:4318>"). |
|
||||
| `--telemetry-otlp` | string | Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. "http://127.0.0.1:4318"). |
|
||||
| `--telemetry-service-name` | string | Sets the value of the `service.name` resource attribute. Default is `toolbox`. |
|
||||
|
||||
In addition to the flags noted above, you can also make additional configuration
|
||||
@@ -196,16 +194,14 @@ environmental variables.
|
||||
[sdk-configuration]:
|
||||
https://opentelemetry.io/docs/languages/sdk-configuration/general/
|
||||
|
||||
**Examples:**
|
||||
__Examples:__
|
||||
|
||||
To enable Google Cloud Exporter:
|
||||
|
||||
```bash
|
||||
./toolbox --telemetry-gcp
|
||||
```
|
||||
|
||||
To enable OTLP Exporter, provide Collector endpoint:
|
||||
|
||||
```bash
|
||||
./toolbox --telemetry-otlp="http://127.0.0.1:4553"
|
||||
```
|
||||
|
||||
@@ -190,18 +190,6 @@
|
||||
"!sudo lsof -i :5432"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Optional: Enable Vertex AI API for Google Cloud\n",
|
||||
"\n",
|
||||
"If you're using a model hosted on **Vertex AI**, run the following command to enable the API:\n",
|
||||
"\n",
|
||||
"```bash\n",
|
||||
"!gcloud services enable aiplatform.googleapis.com\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -234,7 +222,7 @@
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"version = \"0.18.0\" # x-release-please-version\n",
|
||||
"version = \"0.7.0\" # x-release-please-version\n",
|
||||
"! curl -O https://storage.googleapis.com/genai-toolbox/v{version}/linux/amd64/toolbox\n",
|
||||
"\n",
|
||||
"# Make the binary executable\n",
|
||||
@@ -486,12 +474,165 @@
|
||||
"source": [
|
||||
"> You can either use LangGraph or LlamaIndex to develop a Toolbox based\n",
|
||||
"> application. Run one of the sections below\n",
|
||||
"> - [Connect using Google GenAI](#scrollTo=Fv2-uT4mvYtp)\n",
|
||||
"> - [Connect using Google GenAI](#scrollTo=Rwgv1LDdNKSn)\n",
|
||||
"> - [Connect using ADK](#scrollTo=QqRlWqvYNKSo)\n",
|
||||
"> - [Connect Using LangGraph](#scrollTo=pbapNMhhL33S)\n",
|
||||
"> - [Connect using LlamaIndex](#scrollTo=04iysrm_L_7v)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Rwgv1LDdNKSn"
|
||||
},
|
||||
"source": [
|
||||
"### Connect Using Google GenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "HY23RMk4NKSn"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Install the Toolbox Core package\n",
|
||||
"!pip install toolbox-core --quiet\n",
|
||||
"\n",
|
||||
"# Install the Google GenAI package\n",
|
||||
"!pip install google-genai --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "9F1u566sNKSn"
|
||||
},
|
||||
"source": [
|
||||
"Create a Google GenAI Application which can Search, Book and Cancel hotels."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "LAuBIOXvNKSn"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import asyncio\n",
|
||||
"\n",
|
||||
"from google import genai\n",
|
||||
"from google.genai.types import (\n",
|
||||
" Content,\n",
|
||||
" FunctionDeclaration,\n",
|
||||
" GenerateContentConfig,\n",
|
||||
" Part,\n",
|
||||
" Tool,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"from toolbox_core import ToolboxClient\n",
|
||||
"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
" You're a helpful hotel assistant. You handle hotel searching, booking and\n",
|
||||
" cancellations. When the user searches for a hotel, mention it's name, id,\n",
|
||||
" location and price tier. Always mention hotel id while performing any\n",
|
||||
" searches. This is very important for any operations. For any bookings or\n",
|
||||
" cancellations, please provide the appropriate confirmation. Be sure to\n",
|
||||
" update checkin or checkout dates if mentioned by the user.\n",
|
||||
" Don't ask for confirmations from the user.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"queries = [\n",
|
||||
" \"Find hotels in Basel with Basel in it's name.\",\n",
|
||||
" \"Please book the hotel Hilton Basel for me.\",\n",
|
||||
" \"This is too expensive. Please cancel it.\",\n",
|
||||
" \"Please book Hyatt Regency for me\",\n",
|
||||
" \"My check in dates for my booking would be from April 10, 2024 to April 19, 2024.\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"async def run_application():\n",
|
||||
" toolbox_client = ToolboxClient(\"http://127.0.0.1:5000\")\n",
|
||||
"\n",
|
||||
" # The toolbox_tools list contains Python callables (functions/methods) designed for LLM tool-use\n",
|
||||
" # integration. While this example uses Google's genai client, these callables can be adapted for\n",
|
||||
" # various function-calling or agent frameworks. For easier integration with supported frameworks\n",
|
||||
" # (https://github.com/googleapis/mcp-toolbox-python-sdk/tree/main/packages), use the\n",
|
||||
" # provided wrapper packages, which handle framework-specific boilerplate.\n",
|
||||
" toolbox_tools = await toolbox_client.load_toolset(\"my-toolset\")\n",
|
||||
" genai_client = genai.Client(\n",
|
||||
" vertexai=True, project=project_id, location=\"us-central1\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" genai_tools = [\n",
|
||||
" Tool(\n",
|
||||
" function_declarations=[\n",
|
||||
" FunctionDeclaration.from_callable_with_api_option(callable=tool)\n",
|
||||
" ]\n",
|
||||
" )\n",
|
||||
" for tool in toolbox_tools\n",
|
||||
" ]\n",
|
||||
" history = []\n",
|
||||
" for query in queries:\n",
|
||||
" user_prompt_content = Content(\n",
|
||||
" role=\"user\",\n",
|
||||
" parts=[Part.from_text(text=query)],\n",
|
||||
" )\n",
|
||||
" history.append(user_prompt_content)\n",
|
||||
"\n",
|
||||
" response = genai_client.models.generate_content(\n",
|
||||
" model=\"gemini-2.0-flash-001\",\n",
|
||||
" contents=history,\n",
|
||||
" config=GenerateContentConfig(\n",
|
||||
" system_instruction=prompt,\n",
|
||||
" tools=genai_tools,\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" history.append(response.candidates[0].content)\n",
|
||||
" function_response_parts = []\n",
|
||||
" for function_call in response.function_calls:\n",
|
||||
" fn_name = function_call.name\n",
|
||||
" # The tools are sorted alphabetically\n",
|
||||
" if fn_name == \"search-hotels-by-name\":\n",
|
||||
" function_result = await toolbox_tools[3](**function_call.args)\n",
|
||||
" elif fn_name == \"search-hotels-by-location\":\n",
|
||||
" function_result = await toolbox_tools[2](**function_call.args)\n",
|
||||
" elif fn_name == \"book-hotel\":\n",
|
||||
" function_result = await toolbox_tools[0](**function_call.args)\n",
|
||||
" elif fn_name == \"update-hotel\":\n",
|
||||
" function_result = await toolbox_tools[4](**function_call.args)\n",
|
||||
" elif fn_name == \"cancel-hotel\":\n",
|
||||
" function_result = await toolbox_tools[1](**function_call.args)\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\"Function name not present.\")\n",
|
||||
" function_response = {\"result\": function_result}\n",
|
||||
" function_response_part = Part.from_function_response(\n",
|
||||
" name=function_call.name,\n",
|
||||
" response=function_response,\n",
|
||||
" )\n",
|
||||
" function_response_parts.append(function_response_part)\n",
|
||||
"\n",
|
||||
" if function_response_parts:\n",
|
||||
" tool_response_content = Content(role=\"tool\", parts=function_response_parts)\n",
|
||||
" history.append(tool_response_content)\n",
|
||||
"\n",
|
||||
" response2 = genai_client.models.generate_content(\n",
|
||||
" model=\"gemini-2.0-flash-001\",\n",
|
||||
" contents=history,\n",
|
||||
" config=GenerateContentConfig(\n",
|
||||
" tools=genai_tools,\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" final_model_response_content = response2.candidates[0].content\n",
|
||||
" history.append(final_model_response_content)\n",
|
||||
" print(response2.text)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"asyncio.run(run_application())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
@@ -554,7 +695,7 @@
|
||||
"\n",
|
||||
"session_service = InMemorySessionService()\n",
|
||||
"artifacts_service = InMemoryArtifactService()\n",
|
||||
"session = await session_service.create_session(\n",
|
||||
"session = session_service.create_session(\n",
|
||||
" state={}, app_name='hotel_agent', user_id='123'\n",
|
||||
")\n",
|
||||
"runner = Runner(\n",
|
||||
@@ -790,159 +931,6 @@
|
||||
"await run_application()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "Fv2-uT4mvYtp"
|
||||
},
|
||||
"source": [
|
||||
"### Connect Using Google GenAI"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "mHSvk5_AvYtu"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Install the Toolbox Core package\n",
|
||||
"!pip install toolbox-core --quiet\n",
|
||||
"\n",
|
||||
"# Install the Google GenAI package\n",
|
||||
"!pip install google-genai --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
"id": "sO_7FGSYvYtu"
|
||||
},
|
||||
"source": [
|
||||
"Create a Google GenAI Application which can Search, Book and Cancel hotels."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"id": "-NVVBiLnvYtu"
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import asyncio\n",
|
||||
"\n",
|
||||
"from google import genai\n",
|
||||
"from google.genai.types import (\n",
|
||||
" Content,\n",
|
||||
" FunctionDeclaration,\n",
|
||||
" GenerateContentConfig,\n",
|
||||
" Part,\n",
|
||||
" Tool,\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"from toolbox_core import ToolboxClient\n",
|
||||
"\n",
|
||||
"prompt = \"\"\"\n",
|
||||
" You're a helpful hotel assistant. You handle hotel searching, booking and\n",
|
||||
" cancellations. When the user searches for a hotel, mention it's name, id,\n",
|
||||
" location and price tier. Always mention hotel id while performing any\n",
|
||||
" searches. This is very important for any operations. For any bookings or\n",
|
||||
" cancellations, please provide the appropriate confirmation. Be sure to\n",
|
||||
" update checkin or checkout dates if mentioned by the user.\n",
|
||||
" Don't ask for confirmations from the user.\n",
|
||||
"\"\"\"\n",
|
||||
"\n",
|
||||
"queries = [\n",
|
||||
" \"Find hotels in Basel with Basel in it's name.\",\n",
|
||||
" \"Please book the hotel Hilton Basel for me.\",\n",
|
||||
" \"This is too expensive. Please cancel it.\",\n",
|
||||
" \"Please book Hyatt Regency for me\",\n",
|
||||
" \"My check in dates for my booking would be from April 10, 2024 to April 19, 2024.\",\n",
|
||||
"]\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"async def run_application():\n",
|
||||
" toolbox_client = ToolboxClient(\"http://127.0.0.1:5000\")\n",
|
||||
"\n",
|
||||
" # The toolbox_tools list contains Python callables (functions/methods) designed for LLM tool-use\n",
|
||||
" # integration. While this example uses Google's genai client, these callables can be adapted for\n",
|
||||
" # various function-calling or agent frameworks. For easier integration with supported frameworks\n",
|
||||
" # (https://github.com/googleapis/mcp-toolbox-python-sdk/tree/main/packages), use the\n",
|
||||
" # provided wrapper packages, which handle framework-specific boilerplate.\n",
|
||||
" toolbox_tools = await toolbox_client.load_toolset(\"my-toolset\")\n",
|
||||
" genai_client = genai.Client(\n",
|
||||
" vertexai=True, project=project_id, location=\"us-central1\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
" genai_tools = [\n",
|
||||
" Tool(\n",
|
||||
" function_declarations=[\n",
|
||||
" FunctionDeclaration.from_callable_with_api_option(callable=tool)\n",
|
||||
" ]\n",
|
||||
" )\n",
|
||||
" for tool in toolbox_tools\n",
|
||||
" ]\n",
|
||||
" history = []\n",
|
||||
" for query in queries:\n",
|
||||
" user_prompt_content = Content(\n",
|
||||
" role=\"user\",\n",
|
||||
" parts=[Part.from_text(text=query)],\n",
|
||||
" )\n",
|
||||
" history.append(user_prompt_content)\n",
|
||||
"\n",
|
||||
" response = genai_client.models.generate_content(\n",
|
||||
" model=\"gemini-2.0-flash-001\",\n",
|
||||
" contents=history,\n",
|
||||
" config=GenerateContentConfig(\n",
|
||||
" system_instruction=prompt,\n",
|
||||
" tools=genai_tools,\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" history.append(response.candidates[0].content)\n",
|
||||
" function_response_parts = []\n",
|
||||
" for function_call in response.function_calls:\n",
|
||||
" fn_name = function_call.name\n",
|
||||
" # The tools are sorted alphabetically\n",
|
||||
" if fn_name == \"search-hotels-by-name\":\n",
|
||||
" function_result = await toolbox_tools[3](**function_call.args)\n",
|
||||
" elif fn_name == \"search-hotels-by-location\":\n",
|
||||
" function_result = await toolbox_tools[2](**function_call.args)\n",
|
||||
" elif fn_name == \"book-hotel\":\n",
|
||||
" function_result = await toolbox_tools[0](**function_call.args)\n",
|
||||
" elif fn_name == \"update-hotel\":\n",
|
||||
" function_result = await toolbox_tools[4](**function_call.args)\n",
|
||||
" elif fn_name == \"cancel-hotel\":\n",
|
||||
" function_result = await toolbox_tools[1](**function_call.args)\n",
|
||||
" else:\n",
|
||||
" raise ValueError(\"Function name not present.\")\n",
|
||||
" function_response = {\"result\": function_result}\n",
|
||||
" function_response_part = Part.from_function_response(\n",
|
||||
" name=function_call.name,\n",
|
||||
" response=function_response,\n",
|
||||
" )\n",
|
||||
" function_response_parts.append(function_response_part)\n",
|
||||
"\n",
|
||||
" if function_response_parts:\n",
|
||||
" tool_response_content = Content(role=\"tool\", parts=function_response_parts)\n",
|
||||
" history.append(tool_response_content)\n",
|
||||
"\n",
|
||||
" response2 = genai_client.models.generate_content(\n",
|
||||
" model=\"gemini-2.0-flash-001\",\n",
|
||||
" contents=history,\n",
|
||||
" config=GenerateContentConfig(\n",
|
||||
" tools=genai_tools,\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
" final_model_response_content = response2.candidates[0].content\n",
|
||||
" history.append(final_model_response_content)\n",
|
||||
" print(response2.text)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"asyncio.run(run_application())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
title: "Configuration"
|
||||
type: docs
|
||||
weight: 6
|
||||
weight: 4
|
||||
description: >
|
||||
How to configure Toolbox's tools.yaml file.
|
||||
---
|
||||
@@ -23,12 +23,6 @@ etc., you could use environment variables instead with the format `${ENV_NAME}`.
|
||||
password: ${PASSWORD}
|
||||
```
|
||||
|
||||
A default value can be specified like `${ENV_NAME:default}`.
|
||||
|
||||
```yaml
|
||||
port: ${DB_PORT:3306}
|
||||
```
|
||||
|
||||
### Sources
|
||||
|
||||
The `sources` section of your `tools.yaml` defines what data sources your
|
||||
@@ -51,7 +45,7 @@ For more details on configuring different types of sources, see the
|
||||
|
||||
### Tools
|
||||
|
||||
The `tools` section of your `tools.yaml` defines the actions your agent can
|
||||
The `tools` section of your `tools.yaml` define your the actions your agent can
|
||||
take: what kind of tool it is, which source(s) it affects, what parameters it
|
||||
uses, etc.
|
||||
|
||||
@@ -82,7 +76,7 @@ toolsets:
|
||||
my_first_toolset:
|
||||
- my_first_tool
|
||||
- my_second_tool
|
||||
my_second_toolset:
|
||||
my_second_toolset:
|
||||
- my_second_tool
|
||||
- my_third_tool
|
||||
```
|
||||
|
||||
@@ -10,17 +10,17 @@ MCP Toolbox for Databases is an open source MCP server for databases. It enables
|
||||
you to develop tools easier, faster, and more securely by handling the complexities
|
||||
such as connection pooling, authentication, and more.
|
||||
|
||||
|
||||
{{< notice note >}}
|
||||
This solution was originally named “Gen AI Toolbox for
|
||||
Databases” as its initial development predated MCP, but was renamed to align
|
||||
with recently added MCP compatibility.
|
||||
{{< /notice >}}
|
||||
|
||||
## Why Toolbox?
|
||||
## Why Toolbox?
|
||||
|
||||
Toolbox helps you build Gen AI tools that let your agents access data in your
|
||||
database. Toolbox provides:
|
||||
|
||||
- **Simplified development**: Integrate tools to your agent in less than 10
|
||||
lines of code, reuse tools between multiple agents or frameworks, and deploy
|
||||
new versions of tools more easily.
|
||||
@@ -30,29 +30,17 @@ database. Toolbox provides:
|
||||
- **End-to-end observability**: Out of the box metrics and tracing with built-in
|
||||
support for OpenTelemetry.
|
||||
|
||||
|
||||
**⚡ Supercharge Your Workflow with an AI Database Assistant ⚡**
|
||||
|
||||
Stop context-switching and let your AI assistant become a true co-developer. By
|
||||
[connecting your IDE to your databases with MCP Toolbox][connect-ide], you can
|
||||
delegate complex and time-consuming database tasks, allowing you to build faster
|
||||
and focus on what matters. This isn't just about code completion; it's about
|
||||
giving your AI the context it needs to handle the entire development lifecycle.
|
||||
Stop context-switching and let your AI assistant become a true co-developer. By [connecting your IDE to your databases with MCP Toolbox][connect-ide], you can delegate complex and time-consuming database tasks, allowing you to build faster and focus on what matters. This isn't just about code completion; it's about giving your AI the context it needs to handle the entire development lifecycle.
|
||||
|
||||
Here’s how it will save you time:
|
||||
|
||||
- **Query in Plain English**: Interact with your data using natural language
|
||||
right from your IDE. Ask complex questions like, *"How many orders were
|
||||
delivered in 2024, and what items were in them?"* without writing any SQL.
|
||||
- **Automate Database Management**: Simply describe your data needs, and let the
|
||||
AI assistant manage your database for you. It can handle generating queries,
|
||||
creating tables, adding indexes, and more.
|
||||
- **Generate Context-Aware Code**: Empower your AI assistant to generate
|
||||
application code and tests with a deep understanding of your real-time
|
||||
database schema. This accelerates the development cycle by ensuring the
|
||||
generated code is directly usable.
|
||||
- **Slash Development Overhead**: Radically reduce the time spent on manual
|
||||
setup and boilerplate. MCP Toolbox helps streamline lengthy database
|
||||
configurations, repetitive code, and error-prone schema migrations.
|
||||
* **Query in Plain English**: Interact with your data using natural language right from your IDE. Ask complex questions like, *"How many orders were delivered in 2024, and what items were in them?"* without writing any SQL.
|
||||
* **Automate Database Management**: Simply describe your data needs, and let the AI assistant manage your database for you. It can handle generating queries, creating tables, adding indexes, and more.
|
||||
* **Generate Context-Aware Code**: Empower your AI assistant to generate application code and tests with a deep understanding of your real-time database schema. This accelerates the development cycle by ensuring the generated code is directly usable.
|
||||
* **Slash Development Overhead**: Radically reduce the time spent on manual setup and boilerplate. MCP Toolbox helps streamline lengthy database configurations, repetitive code, and error-prone schema migrations.
|
||||
|
||||
Learn [how to connect your AI tools (IDEs) to Toolbox using MCP][connect-ide].
|
||||
|
||||
@@ -72,7 +60,6 @@ redeploying your application.
|
||||
## Getting Started
|
||||
|
||||
### Installing the server
|
||||
|
||||
For the latest version, check the [releases page][releases] and use the
|
||||
following instructions for your OS and CPU architecture.
|
||||
|
||||
@@ -81,61 +68,26 @@ following instructions for your OS and CPU architecture.
|
||||
<!-- {x-release-please-start-version} -->
|
||||
{{< tabpane text=true >}}
|
||||
{{% tab header="Binary" lang="en" %}}
|
||||
{{< tabpane text=true >}}
|
||||
{{% tab header="Linux (AMD64)" lang="en" %}}
|
||||
To install Toolbox as a binary on Linux (AMD64):
|
||||
|
||||
To install Toolbox as a binary:
|
||||
|
||||
```sh
|
||||
# see releases page for other versions
|
||||
export VERSION=0.18.0
|
||||
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
|
||||
export VERSION=0.7.0
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v$VERSION/linux/amd64/toolbox
|
||||
chmod +x toolbox
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab header="macOS (Apple Silicon)" lang="en" %}}
|
||||
To install Toolbox as a binary on macOS (Apple Silicon):
|
||||
```sh
|
||||
# see releases page for other versions
|
||||
export VERSION=0.18.0
|
||||
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/darwin/arm64/toolbox
|
||||
chmod +x toolbox
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab header="macOS (Intel)" lang="en" %}}
|
||||
To install Toolbox as a binary on macOS (Intel):
|
||||
```sh
|
||||
# see releases page for other versions
|
||||
export VERSION=0.18.0
|
||||
curl -L -o toolbox https://storage.googleapis.com/genai-toolbox/v$VERSION/darwin/amd64/toolbox
|
||||
chmod +x toolbox
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab header="Windows (AMD64)" lang="en" %}}
|
||||
To install Toolbox as a binary on Windows (AMD64):
|
||||
```powershell
|
||||
# see releases page for other versions
|
||||
$VERSION = "0.18.0"
|
||||
Invoke-WebRequest -Uri "https://storage.googleapis.com/genai-toolbox/v$VERSION/windows/amd64/toolbox.exe" -OutFile "toolbox.exe"
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Container image" lang="en" %}}
|
||||
You can also install Toolbox as a container:
|
||||
|
||||
```sh
|
||||
# see releases page for other versions
|
||||
export VERSION=0.18.0
|
||||
export VERSION=0.7.0
|
||||
docker pull us-central1-docker.pkg.dev/database-toolbox/toolbox/toolbox:$VERSION
|
||||
```
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Homebrew" lang="en" %}}
|
||||
To install Toolbox using Homebrew on macOS or Linux:
|
||||
|
||||
```sh
|
||||
brew install mcp-toolbox
|
||||
```
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Compile from source" lang="en" %}}
|
||||
|
||||
@@ -143,7 +95,7 @@ To install from source, ensure you have the latest version of
|
||||
[Go installed](https://go.dev/doc/install), and then run the following command:
|
||||
|
||||
```sh
|
||||
go install github.com/googleapis/genai-toolbox@v0.18.0
|
||||
go install github.com/googleapis/genai-toolbox@v0.7.0
|
||||
```
|
||||
|
||||
{{% /tab %}}
|
||||
@@ -159,43 +111,17 @@ execute `toolbox` to start the server:
|
||||
./toolbox --tools-file "tools.yaml"
|
||||
```
|
||||
|
||||
{{< notice note >}}
|
||||
Toolbox enables dynamic reloading by default. To disable, use the
|
||||
`--disable-reload` flag.
|
||||
{{< /notice >}}
|
||||
|
||||
#### Launching Toolbox UI
|
||||
|
||||
To launch Toolbox's interactive UI, use the `--ui` flag. This allows you to test
|
||||
tools and toolsets with features such as authorized parameters. To learn more,
|
||||
visit [Toolbox UI](../../how-to/toolbox-ui/index.md).
|
||||
|
||||
```sh
|
||||
./toolbox --ui
|
||||
```
|
||||
|
||||
#### Homebrew Users
|
||||
|
||||
If you installed Toolbox using Homebrew, the `toolbox` binary is available in
|
||||
your system path. You can start the server with the same command:
|
||||
|
||||
```sh
|
||||
toolbox --tools-file "tools.yaml"
|
||||
```
|
||||
|
||||
You can use `toolbox help` for a full list of flags! To stop the server, send a
|
||||
terminate signal (`ctrl+c` on most platforms).
|
||||
|
||||
For more detailed documentation on deploying to different environments, check
|
||||
out the resources in the [How-to section](../../how-to/)
|
||||
out the resources in the [How-to section](../../how-to/_index.md)
|
||||
|
||||
### Integrating your application
|
||||
|
||||
Once your server is up and running, you can load the tools into your
|
||||
application. See below the list of Client SDKs for using various frameworks:
|
||||
|
||||
#### Python
|
||||
|
||||
{{< tabpane text=true persist=header >}}
|
||||
{{% tab header="Core" lang="en" %}}
|
||||
|
||||
@@ -207,7 +133,6 @@ tools:
|
||||
from toolbox_core import ToolboxClient
|
||||
|
||||
# update the url to point to your server
|
||||
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
|
||||
# these tools can be passed to your application!
|
||||
@@ -215,8 +140,7 @@ async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
{{< /highlight >}}
|
||||
|
||||
For more detailed instructions on using the Toolbox Core SDK, see the
|
||||
[project's
|
||||
README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-core/README.md).
|
||||
[project's README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-core/README.md).
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="LangChain" lang="en" %}}
|
||||
@@ -229,7 +153,6 @@ tools:
|
||||
from toolbox_langchain import ToolboxClient
|
||||
|
||||
# update the url to point to your server
|
||||
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
|
||||
# these tools can be passed to your application!
|
||||
@@ -237,8 +160,7 @@ async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
{{< /highlight >}}
|
||||
|
||||
For more detailed instructions on using the Toolbox LangChain SDK, see the
|
||||
[project's
|
||||
README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-langchain/README.md).
|
||||
[project's README](https://github.com/googleapis/mcp-toolbox-sdk-python/blob/main/packages/toolbox-langchain/README.md).
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Llamaindex" lang="en" %}}
|
||||
@@ -251,382 +173,14 @@ tools:
|
||||
from toolbox_llamaindex import ToolboxClient
|
||||
|
||||
# update the url to point to your server
|
||||
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
|
||||
# these tools can be passed to your application
|
||||
|
||||
# these tools can be passed to your application!
|
||||
tools = client.load_toolset()
|
||||
{{< /highlight >}}
|
||||
|
||||
For more detailed instructions on using the Toolbox Llamaindex SDK, see the
|
||||
[project's
|
||||
README](https://github.com/googleapis/genai-toolbox-llamaindex-python/blob/main/README.md).
|
||||
[project's README](https://github.com/googleapis/genai-toolbox-llamaindex-python/blob/main/README.md).
|
||||
|
||||
{{% /tab %}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
#### Javascript/Typescript
|
||||
|
||||
Once you've installed the [Toolbox Core
|
||||
SDK](https://www.npmjs.com/package/@toolbox-sdk/core), you can load
|
||||
tools:
|
||||
|
||||
{{< tabpane text=true persist=header >}}
|
||||
{{% tab header="Core" lang="en" %}}
|
||||
|
||||
{{< highlight javascript >}}
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const toolboxTools = await client.loadToolset('toolsetName');
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="LangChain/Langraph" lang="en" %}}
|
||||
|
||||
{{< highlight javascript >}}
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const toolboxTools = await client.loadToolset('toolsetName');
|
||||
|
||||
// Define the basics of the tool: name, description, schema and core logic
|
||||
const getTool = (toolboxTool) => tool(currTool, {
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
schema: toolboxTool.getParamSchema()
|
||||
});
|
||||
|
||||
// Use these tools in your Langchain/Langraph applications
|
||||
const tools = toolboxTools.map(getTool);
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Genkit" lang="en" %}}
|
||||
|
||||
{{< highlight javascript >}}
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
import { genkit } from 'genkit';
|
||||
|
||||
// Initialise genkit
|
||||
const ai = genkit({
|
||||
plugins: [
|
||||
googleAI({
|
||||
apiKey: process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY
|
||||
})
|
||||
],
|
||||
model: googleAI.model('gemini-2.0-flash'),
|
||||
});
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const toolboxTools = await client.loadToolset('toolsetName');
|
||||
|
||||
// Define the basics of the tool: name, description, schema and core logic
|
||||
const getTool = (toolboxTool) => ai.defineTool({
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
schema: toolboxTool.getParamSchema()
|
||||
}, toolboxTool)
|
||||
|
||||
// Use these tools in your Genkit applications
|
||||
const tools = toolboxTools.map(getTool);
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="LlamaIndex" lang="en" %}}
|
||||
|
||||
{{< highlight javascript >}}
|
||||
import { ToolboxClient } from '@toolbox-sdk/core';
|
||||
import { tool } from "llamaindex";
|
||||
|
||||
// update the url to point to your server
|
||||
const URL = 'http://127.0.0.1:5000';
|
||||
let client = new ToolboxClient(URL);
|
||||
|
||||
// these tools can be passed to your application!
|
||||
const toolboxTools = await client.loadToolset('toolsetName');
|
||||
|
||||
// Define the basics of the tool: name, description, schema and core logic
|
||||
const getTool = (toolboxTool) => tool({
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
parameters: toolboxTool.getParamSchema(),
|
||||
execute: toolboxTool
|
||||
});;
|
||||
|
||||
// Use these tools in your LlamaIndex applications
|
||||
const tools = toolboxTools.map(getTool);
|
||||
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
For more detailed instructions on using the Toolbox Core SDK, see the
|
||||
[project's
|
||||
README](https://github.com/googleapis/mcp-toolbox-sdk-js/blob/main/packages/toolbox-core/README.md).
|
||||
|
||||
#### Go
|
||||
|
||||
Once you've installed the [Toolbox Go
|
||||
SDK](https://pkg.go.dev/github.com/googleapis/mcp-toolbox-sdk-go/core), you can load
|
||||
tools:
|
||||
|
||||
{{< tabpane text=true persist=header >}}
|
||||
{{% tab header="Core" lang="en" %}}
|
||||
|
||||
{{< highlight go >}}
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Framework agnostic tools
|
||||
tools, err := client.LoadToolset("toolsetName", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v", err)
|
||||
}
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="LangChain Go" lang="en" %}}
|
||||
|
||||
{{< highlight go >}}
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v", err)
|
||||
}
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := tool.InputSchema()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to fetch inputSchema: %v", err)
|
||||
}
|
||||
|
||||
var paramsSchema map[string]any
|
||||
_ = json.Unmarshal(inputschema, ¶msSchema)
|
||||
|
||||
// Use this tool with LangChainGo
|
||||
langChainTool := llms.Tool{
|
||||
Type: "function",
|
||||
Function: &llms.FunctionDefinition{
|
||||
Name: tool.Name(),
|
||||
Description: tool.Description(),
|
||||
Parameters: paramsSchema,
|
||||
},
|
||||
}
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Genkit Go" lang="en" %}}
|
||||
|
||||
{{< highlight go >}}
|
||||
package main
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/firebase/genkit/go/ai"
|
||||
"github.com/firebase/genkit/go/genkit"
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/tbgenkit"
|
||||
"github.com/invopop/jsonschema"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// Update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
g, err := genkit.Init(ctx)
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v", err)
|
||||
}
|
||||
|
||||
// Convert the tool using the tbgenkit package
|
||||
// Use this tool with Genkit Go
|
||||
genkitTool, err := tbgenkit.ToGenkitTool(tool, g)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to convert tool: %v\n", err)
|
||||
}
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{% tab header="Go GenAI" lang="en" %}}
|
||||
|
||||
{{< highlight go >}}
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// Update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v", err)
|
||||
}
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := tool.InputSchema()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to fetch inputSchema: %v", err)
|
||||
}
|
||||
|
||||
var schema *genai.Schema
|
||||
_ = json.Unmarshal(inputschema, &schema)
|
||||
|
||||
funcDeclaration := &genai.FunctionDeclaration{
|
||||
Name: tool.Name(),
|
||||
Description: tool.Description(),
|
||||
Parameters: schema,
|
||||
}
|
||||
|
||||
// Use this tool with Go GenAI
|
||||
genAITool := &genai.Tool{
|
||||
FunctionDeclarations: []*genai.FunctionDeclaration{funcDeclaration},
|
||||
}
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
|
||||
{{% tab header="OpenAI Go" lang="en" %}}
|
||||
|
||||
{{< highlight go >}}
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"log"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
openai "github.com/openai/openai-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Make sure to add the error checks
|
||||
// Update the url to point to your server
|
||||
URL := "http://127.0.0.1:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
client, err := core.NewToolboxClient(URL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Framework agnostic tool
|
||||
tool, err := client.LoadTool("toolName", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v", err)
|
||||
}
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := tool.InputSchema()
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to fetch inputSchema: %v", err)
|
||||
}
|
||||
|
||||
var paramsSchema openai.FunctionParameters
|
||||
_ = json.Unmarshal(inputschema, ¶msSchema)
|
||||
|
||||
// Use this tool with OpenAI Go
|
||||
openAITool := openai.ChatCompletionToolParam{
|
||||
Function: openai.FunctionDefinitionParam{
|
||||
Name: tool.Name(),
|
||||
Description: openai.String(tool.Description()),
|
||||
Parameters: paramsSchema,
|
||||
},
|
||||
}
|
||||
}
|
||||
{{< /highlight >}}
|
||||
|
||||
{{% /tab %}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
For more detailed instructions on using the Toolbox Go SDK, see the
|
||||
[project's
|
||||
README](https://github.com/googleapis/mcp-toolbox-sdk-go/blob/main/core/README.md).
|
||||
|
||||
For end-to-end samples on using the Toolbox Go SDK with orchestration
|
||||
frameworks, see the [project's
|
||||
samples](https://github.com/googleapis/mcp-toolbox-sdk-go/tree/main/core/samples)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 154 KiB |
@@ -1,10 +1,11 @@
|
||||
---
|
||||
title: "Python Quickstart (Local)"
|
||||
title: "Quickstart (Local)"
|
||||
type: docs
|
||||
weight: 2
|
||||
description: >
|
||||
How to get started running Toolbox locally with [Python](https://github.com/googleapis/mcp-toolbox-sdk-python), PostgreSQL, and [Agent Development Kit](https://google.github.io/adk-docs/),
|
||||
[LangGraph](https://www.langchain.com/langgraph), [LlamaIndex](https://www.llamaindex.ai/) or [GoogleGenAI](https://pypi.org/project/google-genai/).
|
||||
How to get started running Toolbox locally with Python, PostgreSQL, and
|
||||
[GoogleGenAI](https://pypi.org/project/google-genai/),
|
||||
[LangGraph](https://www.langchain.com/langgraph), [LlamaIndex](https://www.llamaindex.ai/) or [Agent Development Kit](https://google.github.io/adk-docs/).
|
||||
---
|
||||
|
||||
[](https://colab.research.google.com/github/googleapis/genai-toolbox/blob/main/docs/en/getting-started/colab_quickstart.ipynb)
|
||||
@@ -14,39 +15,248 @@ description: >
|
||||
This guide assumes you have already done the following:
|
||||
|
||||
1. Installed [Python 3.9+][install-python] (including [pip][install-pip] and
|
||||
your preferred virtual environment tool for managing dependencies e.g.
|
||||
[venv][install-venv]).
|
||||
1. Installed [PostgreSQL 16+ and the `psql` client][install-postgres].
|
||||
your preferred virtual environment tool for managing dependencies e.g. [venv][install-venv])
|
||||
1. Installed [PostgreSQL 16+ and the `psql` client][install-postgres]
|
||||
|
||||
[install-python]: https://wiki.python.org/moin/BeginnersGuide/Download
|
||||
[install-pip]: https://pip.pypa.io/en/stable/installation/
|
||||
[install-venv]:
|
||||
https://packaging.python.org/en/latest/tutorials/installing-packages/#creating-virtual-environments
|
||||
[install-venv]: https://packaging.python.org/en/latest/tutorials/installing-packages/#creating-virtual-environments
|
||||
[install-postgres]: https://www.postgresql.org/download/
|
||||
|
||||
### Cloud Setup (Optional)
|
||||
{{< regionInclude "quickstart/shared/cloud_setup.md" "cloud_setup" >}}
|
||||
|
||||
## Step 1: Set up your database
|
||||
{{< regionInclude "quickstart/shared/database_setup.md" "database_setup" >}}
|
||||
|
||||
In this section, we will create a database, insert some data that needs to be
|
||||
accessed by our agent, and create a database user for Toolbox to connect with.
|
||||
|
||||
1. Connect to postgres using the `psql` command:
|
||||
|
||||
```bash
|
||||
psql -h 127.0.0.1 -U postgres
|
||||
```
|
||||
|
||||
Here, `postgres` denotes the default postgres superuser.
|
||||
|
||||
{{< notice info >}}
|
||||
#### **Having trouble connecting?**
|
||||
|
||||
* **Password Prompt:** If you are prompted for a password for the `postgres` user and do not know it (or a blank password doesn't work), your PostgreSQL installation might require a password or a different authentication method.
|
||||
* **`FATAL: role "postgres" does not exist`:** This error means the default `postgres` superuser role isn't available under that name on your system.
|
||||
* **`Connection refused`:** Ensure your PostgreSQL server is actually running. You can typically check with `sudo systemctl status postgresql` and start it with `sudo systemctl start postgresql` on Linux systems.
|
||||
|
||||
<br/>
|
||||
|
||||
#### **Common Solution**
|
||||
|
||||
For password issues or if the `postgres` role seems inaccessible directly, try switching to the `postgres` operating system user first. This user often has permission to connect without a password for local connections (this is called peer authentication).
|
||||
```bash
|
||||
sudo -i -u postgres
|
||||
psql -h 127.0.0.1
|
||||
```
|
||||
Once you are in the `psql` shell using this method, you can proceed with the database creation steps below. Afterwards, type `\q` to exit `psql`, and then `exit` to return to your normal user shell.
|
||||
|
||||
If desired, once connected to `psql` as the `postgres` OS user, you can set a password for the `postgres` *database* user using: `ALTER USER postgres WITH PASSWORD 'your_chosen_password';`. This would allow direct connection with `-U postgres` and a password next time.
|
||||
{{< /notice >}}
|
||||
|
||||
1. Create a new database and a new user:
|
||||
|
||||
{{< notice tip >}}
|
||||
For a real application, it's best to follow the principle of least permission
|
||||
and only grant the privileges your application needs.
|
||||
{{< /notice >}}
|
||||
|
||||
```sql
|
||||
CREATE USER toolbox_user WITH PASSWORD 'my-password';
|
||||
|
||||
CREATE DATABASE toolbox_db;
|
||||
GRANT ALL PRIVILEGES ON DATABASE toolbox_db TO toolbox_user;
|
||||
|
||||
ALTER DATABASE toolbox_db OWNER TO toolbox_user;
|
||||
```
|
||||
|
||||
1. End the database session:
|
||||
|
||||
```bash
|
||||
\q
|
||||
```
|
||||
(If you used `sudo -i -u postgres` and then `psql`, remember you might also need to type `exit` after `\q` to leave the `postgres` user's shell session.)
|
||||
|
||||
1. Connect to your database with your new user:
|
||||
|
||||
```bash
|
||||
psql -h 127.0.0.1 -U toolbox_user -d toolbox_db
|
||||
```
|
||||
|
||||
1. Create a table using the following command:
|
||||
|
||||
```sql
|
||||
CREATE TABLE hotels(
|
||||
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
|
||||
);
|
||||
```
|
||||
|
||||
1. Insert data into the table.
|
||||
|
||||
```sql
|
||||
INSERT INTO hotels(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');
|
||||
```
|
||||
|
||||
1. End the database session:
|
||||
|
||||
```bash
|
||||
\q
|
||||
```
|
||||
|
||||
## Step 2: Install and configure Toolbox
|
||||
{{< regionInclude "quickstart/shared/configure_toolbox.md" "configure_toolbox" >}}
|
||||
|
||||
In this section, we will download Toolbox, configure our tools in a
|
||||
`tools.yaml`, and then run the Toolbox server.
|
||||
|
||||
1. Download the latest version of Toolbox as a binary:
|
||||
|
||||
{{< notice tip >}}
|
||||
Select the
|
||||
[correct binary](https://github.com/googleapis/genai-toolbox/releases)
|
||||
corresponding to your OS and CPU architecture.
|
||||
{{< /notice >}}
|
||||
<!-- {x-release-please-start-version} -->
|
||||
```bash
|
||||
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/$OS/toolbox
|
||||
```
|
||||
<!-- {x-release-please-end} -->
|
||||
|
||||
1. Make the binary executable:
|
||||
|
||||
```bash
|
||||
chmod +x toolbox
|
||||
```
|
||||
|
||||
1. Write the following into a `tools.yaml` file. Be sure to update any fields
|
||||
such as `user`, `password`, or `database` that you may have customized in the
|
||||
previous step.
|
||||
|
||||
{{< notice tip >}}
|
||||
In practice, use environment variable replacement with the format ${ENV_NAME}
|
||||
instead of hardcoding your secrets into the configuration file.
|
||||
{{< /notice >}}
|
||||
|
||||
```yaml
|
||||
sources:
|
||||
my-pg-source:
|
||||
kind: postgres
|
||||
host: 127.0.0.1
|
||||
port: 5432
|
||||
database: toolbox_db
|
||||
user: ${USER_NAME}
|
||||
password: ${PASSWORD}
|
||||
tools:
|
||||
search-hotels-by-name:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: Search for hotels based on name.
|
||||
parameters:
|
||||
- name: name
|
||||
type: string
|
||||
description: The name of the hotel.
|
||||
statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%';
|
||||
search-hotels-by-location:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: Search for hotels based on location.
|
||||
parameters:
|
||||
- name: location
|
||||
type: string
|
||||
description: The location of the hotel.
|
||||
statement: SELECT * FROM hotels WHERE location ILIKE '%' || $1 || '%';
|
||||
book-hotel:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: >-
|
||||
Book a hotel by its ID. If the hotel is successfully booked, returns a NULL, raises an error if not.
|
||||
parameters:
|
||||
- name: hotel_id
|
||||
type: string
|
||||
description: The ID of the hotel to book.
|
||||
statement: UPDATE hotels SET booked = B'1' WHERE id = $1;
|
||||
update-hotel:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: >-
|
||||
Update a hotel's check-in and check-out dates by its ID. Returns a message
|
||||
indicating whether the hotel was successfully updated or not.
|
||||
parameters:
|
||||
- name: hotel_id
|
||||
type: string
|
||||
description: The ID of the hotel to update.
|
||||
- name: checkin_date
|
||||
type: string
|
||||
description: The new check-in date of the hotel.
|
||||
- name: checkout_date
|
||||
type: string
|
||||
description: The new check-out date of the hotel.
|
||||
statement: >-
|
||||
UPDATE hotels SET checkin_date = CAST($2 as date), checkout_date = CAST($3
|
||||
as date) WHERE id = $1;
|
||||
cancel-hotel:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: Cancel a hotel by its ID.
|
||||
parameters:
|
||||
- name: hotel_id
|
||||
type: string
|
||||
description: The ID of the hotel to cancel.
|
||||
statement: UPDATE hotels SET booked = B'0' WHERE id = $1;
|
||||
toolsets:
|
||||
my-toolset:
|
||||
- search-hotels-by-name
|
||||
- search-hotels-by-location
|
||||
- book-hotel
|
||||
- update-hotel
|
||||
- cancel-hotel
|
||||
```
|
||||
|
||||
For more info on tools, check out the `Resources` section of the docs.
|
||||
|
||||
1. Run the Toolbox server, pointing to the `tools.yaml` file created earlier:
|
||||
|
||||
```bash
|
||||
./toolbox --tools-file "tools.yaml"
|
||||
```
|
||||
|
||||
## Step 3: Connect your agent to Toolbox
|
||||
|
||||
In this section, we will write and run an agent that will load the Tools
|
||||
from Toolbox.
|
||||
|
||||
{{< notice tip>}}
|
||||
If you prefer to experiment within a Google Colab environment, you can connect
|
||||
to a [local
|
||||
runtime](https://research.google.com/colaboratory/local-runtimes.html).
|
||||
{{< notice tip>}} If you prefer to experiment within a Google Colab environment,
|
||||
you can connect to a
|
||||
[local runtime](https://research.google.com/colaboratory/local-runtimes.html).
|
||||
{{< /notice >}}
|
||||
|
||||
1. In a new terminal, install the SDK package.
|
||||
|
||||
{{< tabpane persist=header >}}
|
||||
{{< tab header="Core" lang="bash" >}}
|
||||
|
||||
pip install toolbox-core
|
||||
{{< /tab >}}
|
||||
{{< tab header="ADK" lang="bash" >}}
|
||||
|
||||
pip install toolbox-core
|
||||
@@ -59,15 +269,15 @@ pip install toolbox-langchain
|
||||
|
||||
pip install toolbox-llamaindex
|
||||
{{< /tab >}}
|
||||
{{< tab header="Core" lang="bash" >}}
|
||||
|
||||
pip install toolbox-core
|
||||
{{< /tab >}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
1. Install other required dependencies:
|
||||
|
||||
{{< tabpane persist=header >}}
|
||||
{{< tab header="Core" lang="bash" >}}
|
||||
|
||||
pip install google-genai
|
||||
{{< /tab >}}
|
||||
{{< tab header="ADK" lang="bash" >}}
|
||||
|
||||
pip install google-adk
|
||||
@@ -91,56 +301,326 @@ pip install llama-index-llms-google-genai
|
||||
|
||||
# pip install llama-index-llms-anthropic
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab header="Core" lang="bash" >}}
|
||||
|
||||
pip install google-genai
|
||||
{{< /tab >}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
1. Create a new file named `hotel_agent.py` and copy the following
|
||||
code to create an agent:
|
||||
{{< tabpane persist=header >}}
|
||||
{{< tab header="Core" lang="python" >}}
|
||||
import asyncio
|
||||
|
||||
from google import genai
|
||||
from google.genai.types import (
|
||||
Content,
|
||||
FunctionDeclaration,
|
||||
GenerateContentConfig,
|
||||
Part,
|
||||
Tool,
|
||||
)
|
||||
|
||||
from toolbox_core import ToolboxClient
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel id while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in it's name.",
|
||||
"Please book the hotel Hilton Basel for me.",
|
||||
"This is too expensive. Please cancel it.",
|
||||
"Please book Hyatt Regency for me",
|
||||
"My check in dates for my booking would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
async def run_application():
|
||||
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
|
||||
# integration. While this example uses Google's genai client, these callables can be adapted for
|
||||
# various function-calling or agent frameworks. For easier integration with supported frameworks
|
||||
# (https://github.com/googleapis/mcp-toolbox-python-sdk/tree/main/packages), use the
|
||||
# provided wrapper packages, which handle framework-specific boilerplate.
|
||||
toolbox_tools = await toolbox_client.load_toolset("my-toolset")
|
||||
genai_client = genai.Client(
|
||||
vertexai=True, project="project-id", location="us-central1"
|
||||
)
|
||||
|
||||
genai_tools = [
|
||||
Tool(
|
||||
function_declarations=[
|
||||
FunctionDeclaration.from_callable_with_api_option(callable=tool)
|
||||
]
|
||||
)
|
||||
for tool in toolbox_tools
|
||||
]
|
||||
history = []
|
||||
for query in queries:
|
||||
user_prompt_content = Content(
|
||||
role="user",
|
||||
parts=[Part.from_text(text=query)],
|
||||
)
|
||||
history.append(user_prompt_content)
|
||||
|
||||
response = genai_client.models.generate_content(
|
||||
model="gemini-2.0-flash-001",
|
||||
contents=history,
|
||||
config=GenerateContentConfig(
|
||||
system_instruction=prompt,
|
||||
tools=genai_tools,
|
||||
),
|
||||
)
|
||||
history.append(response.candidates[0].content)
|
||||
function_response_parts = []
|
||||
for function_call in response.function_calls:
|
||||
fn_name = function_call.name
|
||||
# The tools are sorted alphabetically
|
||||
if fn_name == "search-hotels-by-name":
|
||||
function_result = await toolbox_tools[3](**function_call.args)
|
||||
elif fn_name == "search-hotels-by-location":
|
||||
function_result = await toolbox_tools[2](**function_call.args)
|
||||
elif fn_name == "book-hotel":
|
||||
function_result = await toolbox_tools[0](**function_call.args)
|
||||
elif fn_name == "update-hotel":
|
||||
function_result = await toolbox_tools[4](**function_call.args)
|
||||
elif fn_name == "cancel-hotel":
|
||||
function_result = await toolbox_tools[1](**function_call.args)
|
||||
else:
|
||||
raise ValueError("Function name not present.")
|
||||
function_response = {"result": function_result}
|
||||
function_response_part = Part.from_function_response(
|
||||
name=function_call.name,
|
||||
response=function_response,
|
||||
)
|
||||
function_response_parts.append(function_response_part)
|
||||
|
||||
if function_response_parts:
|
||||
tool_response_content = Content(role="tool", parts=function_response_parts)
|
||||
history.append(tool_response_content)
|
||||
|
||||
response2 = genai_client.models.generate_content(
|
||||
model="gemini-2.0-flash-001",
|
||||
contents=history,
|
||||
config=GenerateContentConfig(
|
||||
tools=genai_tools,
|
||||
),
|
||||
)
|
||||
final_model_response_content = response2.candidates[0].content
|
||||
history.append(final_model_response_content)
|
||||
print(response2.text)
|
||||
|
||||
asyncio.run(run_application())
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab header="ADK" lang="python" >}}
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.runners import Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
|
||||
from google.genai import types
|
||||
from toolbox_core import ToolboxSyncClient
|
||||
|
||||
{{< include "quickstart/python/adk/quickstart.py" >}}
|
||||
import os
|
||||
|
||||
# TODO(developer): replace this with your Google API key
|
||||
|
||||
os.environ['GOOGLE_API_KEY'] = 'your-api-key'
|
||||
|
||||
with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox_client:
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
root_agent = Agent(
|
||||
model='gemini-2.0-flash-001',
|
||||
name='hotel_agent',
|
||||
description='A helpful AI assistant.',
|
||||
instruction=prompt,
|
||||
tools=toolbox_client.load_toolset("my-toolset"),
|
||||
)
|
||||
|
||||
session_service = InMemorySessionService()
|
||||
artifacts_service = InMemoryArtifactService()
|
||||
session = session_service.create_session(
|
||||
state={}, app_name='hotel_agent', user_id='123'
|
||||
)
|
||||
runner = Runner(
|
||||
app_name='hotel_agent',
|
||||
agent=root_agent,
|
||||
artifact_service=artifacts_service,
|
||||
session_service=session_service,
|
||||
)
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in it's name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
for query in queries:
|
||||
content = types.Content(role='user', parts=[types.Part(text=query)])
|
||||
events = runner.run(session_id=session.id,
|
||||
user_id='123', new_message=content)
|
||||
|
||||
responses = (
|
||||
part.text
|
||||
for event in events
|
||||
for part in event.content.parts
|
||||
if part.text is not None
|
||||
)
|
||||
|
||||
for text in responses:
|
||||
print(text)
|
||||
{{< /tab >}}
|
||||
{{< tab header="LangChain" lang="python" >}}
|
||||
import asyncio
|
||||
|
||||
{{< include "quickstart/python/langchain/quickstart.py" >}}
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
# TODO(developer): replace this with another import if needed
|
||||
|
||||
from langchain_google_vertexai import ChatVertexAI
|
||||
|
||||
# from langchain_google_genai import ChatGoogleGenerativeAI
|
||||
|
||||
# from langchain_anthropic import ChatAnthropic
|
||||
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
|
||||
from toolbox_langchain import ToolboxClient
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in it's name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
async def run_application():
|
||||
# TODO(developer): replace this with another model if needed
|
||||
model = ChatVertexAI(model_name="gemini-2.0-flash-001")
|
||||
# model = ChatGoogleGenerativeAI(model="gemini-2.0-flash-001")
|
||||
# model = ChatAnthropic(model="claude-3-5-sonnet-20240620")
|
||||
|
||||
# Load the tools from the Toolbox server
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
tools = await client.aload_toolset()
|
||||
|
||||
agent = create_react_agent(model, tools, checkpointer=MemorySaver())
|
||||
|
||||
config = {"configurable": {"thread_id": "thread-1"}}
|
||||
for query in queries:
|
||||
inputs = {"messages": [("user", prompt + query)]}
|
||||
response = agent.invoke(inputs, stream_mode="values", config=config)
|
||||
print(response["messages"][-1].content)
|
||||
|
||||
asyncio.run(run_application())
|
||||
{{< /tab >}}
|
||||
{{< tab header="LlamaIndex" lang="python" >}}
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
{{< include "quickstart/python/llamaindex/quickstart.py" >}}
|
||||
from llama_index.core.agent.workflow import AgentWorkflow
|
||||
|
||||
{{< /tab >}}
|
||||
{{< tab header="Core" lang="python" >}}
|
||||
from llama_index.core.workflow import Context
|
||||
|
||||
{{< include "quickstart/python/core/quickstart.py" >}}
|
||||
# TODO(developer): replace this with another import if needed
|
||||
|
||||
from llama_index.llms.google_genai import GoogleGenAI
|
||||
|
||||
# from llama_index.llms.anthropic import Anthropic
|
||||
|
||||
from toolbox_llamaindex import ToolboxClient
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in it's name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
async def run_application():
|
||||
# TODO(developer): replace this with another model if needed
|
||||
llm = GoogleGenAI(
|
||||
model="gemini-2.0-flash-001",
|
||||
vertexai_config={"project": "project-id", "location": "us-central1"},
|
||||
)
|
||||
# llm = GoogleGenAI(
|
||||
# api_key=os.getenv("GOOGLE_API_KEY"),
|
||||
# model="gemini-2.0-flash-001",
|
||||
# )
|
||||
# llm = Anthropic(
|
||||
# model="claude-3-7-sonnet-latest",
|
||||
# api_key=os.getenv("ANTHROPIC_API_KEY")
|
||||
# )
|
||||
|
||||
# Load the tools from the Toolbox server
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
tools = await client.aload_toolset()
|
||||
|
||||
agent = AgentWorkflow.from_tools_or_functions(
|
||||
tools,
|
||||
llm=llm,
|
||||
system_prompt=prompt,
|
||||
)
|
||||
ctx = Context(agent)
|
||||
for query in queries:
|
||||
response = await agent.run(user_msg=query, ctx=ctx)
|
||||
print(f"---- {query} ----")
|
||||
print(str(response))
|
||||
|
||||
asyncio.run(run_application())
|
||||
{{< /tab >}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
{{< tabpane text=true persist=header >}}
|
||||
{{% tab header="ADK" lang="en" %}}
|
||||
To learn more about Agent Development Kit, check out the [ADK
|
||||
documentation.](https://google.github.io/adk-docs/)
|
||||
{{% /tab %}}
|
||||
{{% tab header="Langchain" lang="en" %}}
|
||||
To learn more about Agents in LangChain, check out the [LangGraph Agent
|
||||
documentation.](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent)
|
||||
{{% /tab %}}
|
||||
{{% tab header="LlamaIndex" lang="en" %}}
|
||||
To learn more about Agents in LlamaIndex, check out the [LlamaIndex
|
||||
AgentWorkflow
|
||||
documentation.](https://docs.llamaindex.ai/en/stable/examples/agent/agent_workflow_basic/)
|
||||
{{% /tab %}}
|
||||
{{% tab header="Core" lang="en" %}}
|
||||
To learn more about tool calling with Google GenAI, check out the
|
||||
[Google GenAI
|
||||
Documentation](https://github.com/googleapis/python-genai?tab=readme-ov-file#manually-declare-and-invoke-a-function-for-function-calling).
|
||||
[Google GenAI Documentation](https://github.com/googleapis/python-genai?tab=readme-ov-file#manually-declare-and-invoke-a-function-for-function-calling).
|
||||
{{% /tab %}}
|
||||
{{% tab header="ADK" lang="en" %}}
|
||||
To learn more about Agent Development Kit, check out the [ADK documentation.](https://google.github.io/adk-docs/)
|
||||
{{% /tab %}}
|
||||
{{% tab header="Langchain" lang="en" %}}
|
||||
To learn more about Agents in LangChain, check out the [LangGraph Agent documentation.](https://langchain-ai.github.io/langgraph/reference/prebuilt/#langgraph.prebuilt.chat_agent_executor.create_react_agent)
|
||||
{{% /tab %}}
|
||||
{{% tab header="LlamaIndex" lang="en" %}}
|
||||
To learn more about Agents in LlamaIndex, check out the
|
||||
[LlamaIndex AgentWorkflow documentation.](https://docs.llamaindex.ai/en/stable/examples/agent/agent_workflow_basic/)
|
||||
{{% /tab %}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
@@ -149,8 +629,3 @@ Documentation](https://github.com/googleapis/python-genai?tab=readme-ov-file#man
|
||||
```sh
|
||||
python hotel_agent.py
|
||||
```
|
||||
|
||||
{{< notice info >}}
|
||||
For more information, visit the [Python SDK
|
||||
repo](https://github.com/googleapis/mcp-toolbox-sdk-python).
|
||||
{{</ notice >}}
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
---
|
||||
title: "Go Quickstart (Local)"
|
||||
type: docs
|
||||
weight: 4
|
||||
description: >
|
||||
How to get started running Toolbox locally with [Go](https://github.com/googleapis/mcp-toolbox-sdk-go), PostgreSQL, and orchestration frameworks such as [LangChain Go](https://tmc.github.io/langchaingo/docs/), [GenkitGo](https://genkit.dev/go/docs/get-started-go/), [Go GenAI](https://github.com/googleapis/go-genai) and [OpenAI Go](https://github.com/openai/openai-go).
|
||||
---
|
||||
|
||||
## Before you begin
|
||||
|
||||
This guide assumes you have already done the following:
|
||||
|
||||
1. Installed [Go (v1.24.2 or higher)].
|
||||
1. Installed [PostgreSQL 16+ and the `psql` client][install-postgres].
|
||||
|
||||
[Go (v1.24.2 or higher)]: https://go.dev/doc/install
|
||||
[install-postgres]: https://www.postgresql.org/download/
|
||||
|
||||
### Cloud Setup (Optional)
|
||||
|
||||
{{< regionInclude "quickstart/shared/cloud_setup.md" "cloud_setup" >}}
|
||||
|
||||
## Step 1: Set up your database
|
||||
|
||||
{{< regionInclude "quickstart/shared/database_setup.md" "database_setup" >}}
|
||||
|
||||
## Step 2: Install and configure Toolbox
|
||||
|
||||
{{< regionInclude "quickstart/shared/configure_toolbox.md" "configure_toolbox" >}}
|
||||
|
||||
## Step 3: Connect your agent to Toolbox
|
||||
|
||||
In this section, we will write and run an agent that will load the Tools
|
||||
from Toolbox.
|
||||
|
||||
1. Initialize a go module:
|
||||
|
||||
```bash
|
||||
go mod init main
|
||||
```
|
||||
|
||||
1. In a new terminal, install the
|
||||
[SDK](https://pkg.go.dev/github.com/googleapis/mcp-toolbox-sdk-go).
|
||||
|
||||
```bash
|
||||
go get github.com/googleapis/mcp-toolbox-sdk-go
|
||||
```
|
||||
|
||||
1. Create a new file named `hotelagent.go` and copy the following code to create
|
||||
an agent:
|
||||
|
||||
{{< tabpane persist=header >}}
|
||||
{{< tab header="LangChain Go" lang="go" >}}
|
||||
|
||||
{{< include "quickstart/go/langchain/quickstart.go" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="Genkit Go" lang="go" >}}
|
||||
|
||||
{{< include "quickstart/go/genkit/quickstart.go" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="Go GenAI" lang="go" >}}
|
||||
|
||||
{{< include "quickstart/go/genAI/quickstart.go" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="OpenAI Go" lang="go" >}}
|
||||
|
||||
{{< include "quickstart/go/openAI/quickstart.go" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
1. Ensure all dependencies are installed:
|
||||
|
||||
```sh
|
||||
go mod tidy
|
||||
```
|
||||
|
||||
1. Run your agent, and observe the results:
|
||||
|
||||
```sh
|
||||
go run hotelagent.go
|
||||
```
|
||||
|
||||
{{< notice info >}}
|
||||
For more information, visit the [Go SDK
|
||||
repo](https://github.com/googleapis/mcp-toolbox-sdk-go).
|
||||
{{</ notice >}}
|
||||
@@ -1,105 +0,0 @@
|
||||
---
|
||||
title: "JS Quickstart (Local)"
|
||||
type: docs
|
||||
weight: 3
|
||||
description: >
|
||||
How to get started running Toolbox locally with [JavaScript](https://github.com/googleapis/mcp-toolbox-sdk-js), PostgreSQL, and orchestration frameworks such as [LangChain](https://js.langchain.com/docs/introduction/), [GenkitJS](https://genkit.dev/docs/get-started/), [LlamaIndex](https://ts.llamaindex.ai/) and [GoogleGenAI](https://github.com/googleapis/js-genai).
|
||||
---
|
||||
|
||||
## Before you begin
|
||||
|
||||
This guide assumes you have already done the following:
|
||||
|
||||
1. Installed [Node.js (v18 or higher)].
|
||||
1. Installed [PostgreSQL 16+ and the `psql` client][install-postgres].
|
||||
|
||||
[Node.js (v18 or higher)]: https://nodejs.org/
|
||||
[install-postgres]: https://www.postgresql.org/download/
|
||||
|
||||
### Cloud Setup (Optional)
|
||||
|
||||
{{< regionInclude "quickstart/shared/cloud_setup.md" "cloud_setup" >}}
|
||||
|
||||
## Step 1: Set up your database
|
||||
|
||||
{{< regionInclude "quickstart/shared/database_setup.md" "database_setup" >}}
|
||||
|
||||
## Step 2: Install and configure Toolbox
|
||||
|
||||
{{< regionInclude "quickstart/shared/configure_toolbox.md" "configure_toolbox" >}}
|
||||
|
||||
## Step 3: Connect your agent to Toolbox
|
||||
|
||||
In this section, we will write and run an agent that will load the Tools
|
||||
from Toolbox.
|
||||
|
||||
1. (Optional) Initialize a Node.js project:
|
||||
|
||||
```bash
|
||||
npm init -y
|
||||
```
|
||||
|
||||
1. In a new terminal, install the
|
||||
[SDK](https://www.npmjs.com/package/@toolbox-sdk/core).
|
||||
|
||||
```bash
|
||||
npm install @toolbox-sdk/core
|
||||
```
|
||||
|
||||
1. Install other required dependencies
|
||||
|
||||
{{< tabpane persist=header >}}
|
||||
{{< tab header="LangChain" lang="bash" >}}
|
||||
npm install langchain @langchain/google-genai
|
||||
{{< /tab >}}
|
||||
{{< tab header="GenkitJS" lang="bash" >}}
|
||||
npm install genkit @genkit-ai/googleai
|
||||
{{< /tab >}}
|
||||
{{< tab header="LlamaIndex" lang="bash" >}}
|
||||
npm install llamaindex @llamaindex/google @llamaindex/workflow
|
||||
{{< /tab >}}
|
||||
{{< tab header="GoogleGenAI" lang="bash" >}}
|
||||
npm install @google/genai
|
||||
{{< /tab >}}
|
||||
{{< /tabpane >}}
|
||||
|
||||
1. Create a new file named `hotelAgent.js` and copy the following code to create
|
||||
an agent:
|
||||
|
||||
{{< tabpane persist=header >}}
|
||||
{{< tab header="LangChain" lang="js" >}}
|
||||
|
||||
{{< include "quickstart/js/langchain/quickstart.js" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="GenkitJS" lang="js" >}}
|
||||
|
||||
{{< include "quickstart/js/genkit/quickstart.js" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="LlamaIndex" lang="js" >}}
|
||||
|
||||
{{< include "quickstart/js/llamaindex/quickstart.js" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< tab header="GoogleGenAI" lang="js" >}}
|
||||
|
||||
{{< include "quickstart/js/genAI/quickstart.js" >}}
|
||||
|
||||
{{< /tab >}}
|
||||
|
||||
{{< /tabpane >}}
|
||||
|
||||
1. Run your agent, and observe the results:
|
||||
|
||||
```sh
|
||||
node hotelAgent.js
|
||||
```
|
||||
|
||||
{{< notice info >}}
|
||||
For more information, visit the [JS SDK
|
||||
repo](https://github.com/googleapis/mcp-toolbox-sdk-js).
|
||||
{{</ notice >}}
|
||||
@@ -1,9 +1,9 @@
|
||||
---
|
||||
title: "Quickstart (MCP)"
|
||||
type: docs
|
||||
weight: 5
|
||||
weight: 3
|
||||
description: >
|
||||
How to get started running Toolbox locally with MCP Inspector.
|
||||
How to get started running Toolbox locally with MCP Inspector.
|
||||
---
|
||||
|
||||
## Overview
|
||||
@@ -71,7 +71,7 @@ access by our agent, and create a database user for Toolbox to connect with.
|
||||
|
||||
```sql
|
||||
INSERT INTO hotels(id, name, location, price_tier, checkin_date, checkout_date, booked)
|
||||
VALUES
|
||||
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'),
|
||||
@@ -105,7 +105,7 @@ In this section, we will download Toolbox, configure our tools in a
|
||||
<!-- {x-release-please-start-version} -->
|
||||
```bash
|
||||
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/$OS/toolbox
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.7.0/$OS/toolbox
|
||||
```
|
||||
<!-- {x-release-please-end} -->
|
||||
|
||||
@@ -199,8 +199,7 @@ In this section, we will download Toolbox, configure our tools in a
|
||||
- cancel-hotel
|
||||
```
|
||||
|
||||
For more info on tools, check out the
|
||||
[Tools](../../resources/tools/) section.
|
||||
For more info on tools, check out the [Tools](../../resources/tools/_index.md) section.
|
||||
|
||||
1. Run the Toolbox server, pointing to the `tools.yaml` file created earlier:
|
||||
|
||||
@@ -218,27 +217,17 @@ In this section, we will download Toolbox, configure our tools in a
|
||||
|
||||
1. Type `y` when it asks to install the inspector package.
|
||||
|
||||
1. It should show the following when the MCP Inspector is up and running (please
|
||||
take note of `<YOUR_SESSION_TOKEN>`):
|
||||
1. It should show the following when the MCP Inspector is up and running:
|
||||
|
||||
```bash
|
||||
Starting MCP inspector...
|
||||
⚙️ Proxy server listening on localhost:6277
|
||||
🔑 Session token: <YOUR_SESSION_TOKEN>
|
||||
Use this token to authenticate requests or set DANGEROUSLY_OMIT_AUTH=true to disable auth
|
||||
|
||||
🚀 MCP Inspector is up and running at:
|
||||
http://localhost:6274/?MCP_PROXY_AUTH_TOKEN=<YOUR_SESSION_TOKEN>
|
||||
🔍 MCP Inspector is up and running at http://127.0.0.1:5173 🚀
|
||||
```
|
||||
|
||||
1. Open the above link in your browser.
|
||||
|
||||
1. For `Transport Type`, select `Streamable HTTP`.
|
||||
1. For `Transport Type`, select `SSE`.
|
||||
|
||||
1. For `URL`, type in `http://127.0.0.1:5000/mcp`.
|
||||
|
||||
1. For `Configuration` -> `Proxy Session Token`, make sure
|
||||
`<YOUR_SESSION_TOKEN>` is present.
|
||||
1. For `URL`, type in `http://127.0.0.1:5000/mcp/sse`.
|
||||
|
||||
1. Click Connect.
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 22 KiB |
@@ -1,37 +0,0 @@
|
||||
module genai-quickstart
|
||||
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0
|
||||
google.golang.org/genai v1.33.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/api v0.248.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
)
|
||||
@@ -1,118 +0,0 @@
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
|
||||
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
|
||||
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||
cloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=
|
||||
cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=
|
||||
cloud.google.com/go/storage v1.56.1 h1:n6gy+yLnHn0hTwBFzNn8zJ1kqWfR91wzdM8hjRF4wP0=
|
||||
cloud.google.com/go/storage v1.56.1/go.mod h1:C9xuCZgFl3buo2HZU/1FncgvvOgTAs/rnh4gF4lMg0s=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0 h1:m/en3Pp3iGc99SYejUS9iQ01QXsDKMVA+Z456P6mAxY=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0/go.mod h1:DYgNeEV9WHpesG9O2Esr0o+s7Nag0H3h3U2JstK1g6I=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
google.golang.org/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
|
||||
google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
|
||||
google.golang.org/genai v1.33.0 h1:DExzJZbSbxSRmwX2gCsZ+V9vb6rjdmsOAy47ASBgKvg=
|
||||
google.golang.org/genai v1.33.0/go.mod h1:7pAilaICJlQBonjKKJNhftDFv3SREhZcTe9F6nRcjbg=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,174 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"google.golang.org/genai"
|
||||
)
|
||||
|
||||
// ConvertToGenaiTool translates a ToolboxTool into the genai.FunctionDeclaration format.
|
||||
func ConvertToGenaiTool(toolboxTool *core.ToolboxTool) *genai.Tool {
|
||||
|
||||
inputschema, err := toolboxTool.InputSchema()
|
||||
if err != nil {
|
||||
return &genai.Tool{}
|
||||
}
|
||||
|
||||
var paramsSchema *genai.Schema
|
||||
_ = json.Unmarshal(inputschema, ¶msSchema)
|
||||
// First, create the function declaration.
|
||||
funcDeclaration := &genai.FunctionDeclaration{
|
||||
Name: toolboxTool.Name(),
|
||||
Description: toolboxTool.Description(),
|
||||
Parameters: paramsSchema,
|
||||
}
|
||||
|
||||
// Then, wrap the function declaration in a genai.Tool struct.
|
||||
return &genai.Tool{
|
||||
FunctionDeclarations: []*genai.FunctionDeclaration{funcDeclaration},
|
||||
}
|
||||
}
|
||||
|
||||
func printResponse(resp *genai.GenerateContentResponse) {
|
||||
for _, cand := range resp.Candidates {
|
||||
if cand.Content != nil {
|
||||
for _, part := range cand.Content.Parts {
|
||||
fmt.Println(part.Text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const systemPrompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, mention its name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`
|
||||
|
||||
var queries = []string{
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the hotel Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it.",
|
||||
"Please book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Setup
|
||||
ctx := context.Background()
|
||||
apiKey := os.Getenv("GOOGLE_API_KEY")
|
||||
toolboxURL := "http://localhost:5000"
|
||||
|
||||
// Initialize the Google GenAI client using the explicit ClientConfig.
|
||||
client, err := genai.NewClient(ctx, &genai.ClientConfig{
|
||||
APIKey: apiKey,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Google GenAI client: %v", err)
|
||||
}
|
||||
|
||||
// Initialize the MCP Toolbox client.
|
||||
toolboxClient, err := core.NewToolboxClient(toolboxURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Load the tool using the MCP Toolbox SDK.
|
||||
tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err)
|
||||
}
|
||||
|
||||
genAITools := make([]*genai.Tool, len(tools))
|
||||
toolsMap := make(map[string]*core.ToolboxTool, len(tools))
|
||||
|
||||
for i, tool := range tools {
|
||||
genAITools[i] = ConvertToGenaiTool(tool)
|
||||
toolsMap[tool.Name()] = tool
|
||||
}
|
||||
|
||||
// Set up the generative model with the available tool.
|
||||
modelName := "gemini-2.0-flash"
|
||||
|
||||
// Create the initial content prompt for the model.
|
||||
messageHistory := []*genai.Content{
|
||||
genai.NewContentFromText(systemPrompt, genai.RoleUser),
|
||||
}
|
||||
config := &genai.GenerateContentConfig{
|
||||
Tools: genAITools,
|
||||
ToolConfig: &genai.ToolConfig{
|
||||
FunctionCallingConfig: &genai.FunctionCallingConfig{
|
||||
Mode: genai.FunctionCallingConfigModeAny,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, query := range queries {
|
||||
|
||||
messageHistory = append(messageHistory, genai.NewContentFromText(query, genai.RoleUser))
|
||||
|
||||
genContentResp, err := client.Models.GenerateContent(ctx, modelName, messageHistory, config)
|
||||
if err != nil {
|
||||
log.Fatalf("LLM call failed for query '%s': %v", query, err)
|
||||
}
|
||||
|
||||
if len(genContentResp.Candidates) > 0 && genContentResp.Candidates[0].Content != nil {
|
||||
messageHistory = append(messageHistory, genContentResp.Candidates[0].Content)
|
||||
}
|
||||
|
||||
functionCalls := genContentResp.FunctionCalls()
|
||||
|
||||
toolResponseParts := []*genai.Part{}
|
||||
|
||||
for _, fc := range functionCalls {
|
||||
|
||||
toolToInvoke, found := toolsMap[fc.Name]
|
||||
if !found {
|
||||
log.Fatalf("Tool '%s' not found in loaded tools map. Check toolset configuration.", fc.Name)
|
||||
}
|
||||
|
||||
toolResult, invokeErr := toolToInvoke.Invoke(ctx, fc.Args)
|
||||
if invokeErr != nil {
|
||||
log.Fatalf("Failed to execute tool '%s': %v", fc.Name, invokeErr)
|
||||
}
|
||||
|
||||
// Enhanced Tool Result Handling (retained to prevent nil issues)
|
||||
toolResultString := ""
|
||||
if toolResult != nil {
|
||||
jsonBytes, marshalErr := json.Marshal(toolResult)
|
||||
if marshalErr == nil {
|
||||
toolResultString = string(jsonBytes)
|
||||
} else {
|
||||
toolResultString = fmt.Sprintf("%v", toolResult)
|
||||
}
|
||||
}
|
||||
|
||||
responseMap := map[string]any{"result": toolResultString}
|
||||
|
||||
toolResponseParts = append(toolResponseParts, genai.NewPartFromFunctionResponse(fc.Name, responseMap))
|
||||
}
|
||||
// Add all accumulated tool responses for this turn to the message history.
|
||||
toolResponseContent := genai.NewContentFromParts(toolResponseParts, "function")
|
||||
messageHistory = append(messageHistory, toolResponseContent)
|
||||
|
||||
finalResponse, err := client.Models.GenerateContent(ctx, modelName, messageHistory, &genai.GenerateContentConfig{})
|
||||
if err != nil {
|
||||
log.Fatalf("Error calling GenerateContent (with function result): %v", err)
|
||||
}
|
||||
|
||||
printResponse(finalResponse)
|
||||
// Add the final textual response from the LLM to the history
|
||||
if len(finalResponse.Candidates) > 0 && finalResponse.Candidates[0].Content != nil {
|
||||
messageHistory = append(messageHistory, finalResponse.Candidates[0].Content)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
module genkit-quickstart
|
||||
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/firebase/genkit/go v1.1.0
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.1-0.20251031124047-f1f6a9faa2a1
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/auth v0.17.0 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.9.0 // indirect
|
||||
github.com/bahlo/generic-list-go v0.2.0 // indirect
|
||||
github.com/buger/jsonparser v1.1.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/goccy/go-yaml v1.17.1 // indirect
|
||||
github.com/google/dotprompt/go v0.0.0-20251014011017-8d056e027254 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/invopop/jsonschema v0.13.0 // indirect
|
||||
github.com/mailru/easyjson v0.9.0 // indirect
|
||||
github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a // indirect
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.37.0 // indirect
|
||||
golang.org/x/crypto v0.43.0 // indirect
|
||||
golang.org/x/net v0.46.0 // indirect
|
||||
golang.org/x/oauth2 v0.32.0 // indirect
|
||||
golang.org/x/sys v0.37.0 // indirect
|
||||
golang.org/x/text v0.30.0 // indirect
|
||||
google.golang.org/api v0.254.0 // indirect
|
||||
google.golang.org/genai v1.30.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 // indirect
|
||||
google.golang.org/grpc v1.76.0 // indirect
|
||||
google.golang.org/protobuf v1.36.10 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
@@ -1,162 +0,0 @@
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go/auth v0.17.0 h1:74yCm7hCj2rUyyAocqnFzsAYXgJhrG26XCFimrc/Kz4=
|
||||
cloud.google.com/go/auth v0.17.0/go.mod h1:6wv/t5/6rOPAX4fJiRjKkJCvswLwdet7G8+UGXt7nCQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
|
||||
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||
cloud.google.com/go/secretmanager v1.16.0 h1:19QT7ZsLJ8FSP1k+4esQvuCD7npMJml6hYzilxVyT+k=
|
||||
cloud.google.com/go/secretmanager v1.16.0/go.mod h1://C/e4I8D26SDTz1f3TQcddhcmiC3rMEl0S1Cakvs3Q=
|
||||
cloud.google.com/go/storage v1.57.1 h1:gzao6odNJ7dR3XXYvAgPK+Iw4fVPPznEPPyNjbaVkq8=
|
||||
cloud.google.com/go/storage v1.57.1/go.mod h1:329cwlpzALLgJuu8beyJ/uvQznDHpa2U5lGjWednkzg=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 h1:UQUsRi8WTzhZntp5313l+CHIAT95ojUI2lpP/ExlZa4=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0/go.mod h1:Cz6ft6Dkn3Et6l2v2a9/RpN7epQ1GtDlO6lj8bEcOvw=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
|
||||
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/firebase/genkit/go v1.1.0 h1:SQqzQt19gEubvUUCFV98TARFAzD30zT3QhseF3oTKqo=
|
||||
github.com/firebase/genkit/go v1.1.0/go.mod h1:ru1cIuxG1s3HeUjhnadVveDJ1yhinj+j+uUh0f0pyxE=
|
||||
github.com/go-jose/go-jose/v4 v4.1.2 h1:TK/7NqRQZfgAh+Td8AlsrvtPoUyiHh0LqVvokh+1vHI=
|
||||
github.com/go-jose/go-jose/v4 v4.1.2/go.mod h1:22cg9HWM1pOlnRiY+9cQYJ9XHmya1bYW8OeDM6Ku6Oo=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/goccy/go-yaml v1.17.1 h1:LI34wktB2xEE3ONG/2Ar54+/HJVBriAGJ55PHls4YuY=
|
||||
github.com/goccy/go-yaml v1.17.1/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/dotprompt/go v0.0.0-20251014011017-8d056e027254 h1:okN800+zMJOGHLJCgry+OGzhhtH6YrjQh1rluHmOacE=
|
||||
github.com/google/dotprompt/go v0.0.0-20251014011017-8d056e027254/go.mod h1:k8cjJAQWc//ac/bMnzItyOFbfT01tgRTZGgxELCuxEQ=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.1-0.20251031124047-f1f6a9faa2a1 h1:2tNgqscblFtzD0VB1VKqV4vVMveISvepf53GsVkOaaQ=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.1-0.20251031124047-f1f6a9faa2a1/go.mod h1:ywzclXOfzsAb2Z3TJqNOi9dZej+VrF9QfuvFOOHjpX8=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/invopop/jsonschema v0.13.0 h1:KvpoAJWEjR3uD9Kbm2HWJmqsEaHt8lBUpd0qHcIi21E=
|
||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
|
||||
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
|
||||
github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a h1:v2cBA3xWKv2cIOVhnzX/gNgkNXqiHfUgJtA3r61Hf7A=
|
||||
github.com/mbleigh/raymond v0.0.0-20250414171441-6b3a58ab9e0a/go.mod h1:Y6ghKH+ZijXn5d9E7qGGZBmjitx7iitZdQiIW97EpTU=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/fJgbpc=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo=
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
|
||||
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ=
|
||||
go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I=
|
||||
go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE=
|
||||
go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0 h1:ItB0QUqnjesGRvNcmAcU0LyvkVyGJ2xftD29bWdDvKI=
|
||||
go.opentelemetry.io/otel/sdk v1.37.0/go.mod h1:VredYzxUvuo2q3WRcDnKDjbdvmO0sCzOvVAiY+yUkAg=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0 h1:90lI228XrB9jCMuSdA0673aubgRobVZFhbjxHHspCPc=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.37.0/go.mod h1:cNen4ZWfiD37l5NhS+Keb5RXVWZWpRE+9WyVCpbo5ps=
|
||||
go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4=
|
||||
go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/oauth2 v0.32.0 h1:jsCblLleRMDrxMN29H3z/k1KliIvpLgCkE6R8FXXNgY=
|
||||
golang.org/x/oauth2 v0.32.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
|
||||
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ=
|
||||
golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
||||
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||
google.golang.org/api v0.254.0 h1:jl3XrGj7lRjnlUvZAbAdhINTLbsg5dbjmR90+pTQvt4=
|
||||
google.golang.org/api v0.254.0/go.mod h1:5BkSURm3D9kAqjGvBNgf0EcbX6Rnrf6UArKkwBzAyqQ=
|
||||
google.golang.org/genai v1.30.0 h1:7021aneIvl24nEBLbtQFEWleHsMbjzpcQvkT4WcJ1dc=
|
||||
google.golang.org/genai v1.30.0/go.mod h1:7pAilaICJlQBonjKKJNhftDFv3SREhZcTe9F6nRcjbg=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8 h1:M1rk8KBnUsBDg1oPGHNCxG4vc1f49epmTO7xscSajMk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20251022142026-3a174f9686a8/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||
google.golang.org/grpc v1.76.0 h1:UnVkv1+uMLYXoIz6o7chp59WfQUYA2ex/BXQ9rHZu7A=
|
||||
google.golang.org/grpc v1.76.0/go.mod h1:Ju12QI8M6iQJtbcsV+awF5a4hfJMLi4X0JLo94ULZ6c=
|
||||
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
|
||||
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,129 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/tbgenkit"
|
||||
|
||||
"github.com/firebase/genkit/go/ai"
|
||||
"github.com/firebase/genkit/go/genkit"
|
||||
"github.com/firebase/genkit/go/plugins/googlegenai"
|
||||
)
|
||||
|
||||
const systemPrompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, mention its name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`
|
||||
|
||||
var queries = []string{
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the hotel Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
}
|
||||
|
||||
func main() {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create Toolbox Client
|
||||
toolboxClient, err := core.NewToolboxClient("http://127.0.0.1:5000")
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Load the tools using the MCP Toolbox SDK.
|
||||
tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err)
|
||||
}
|
||||
|
||||
// Initialize Genkit
|
||||
g := genkit.Init(ctx,
|
||||
genkit.WithPlugins(&googlegenai.GoogleAI{}),
|
||||
genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to init genkit: %v\n", err)
|
||||
}
|
||||
|
||||
// Create a conversation history
|
||||
conversationHistory := []*ai.Message{
|
||||
ai.NewSystemTextMessage(systemPrompt),
|
||||
}
|
||||
|
||||
// Convert your tool to a Genkit tool.
|
||||
genkitTools := make([]ai.Tool, len(tools))
|
||||
for i, tool := range tools {
|
||||
newTool, err := tbgenkit.ToGenkitTool(tool, g)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to convert tool: %v\n", err)
|
||||
}
|
||||
genkitTools[i] = newTool
|
||||
}
|
||||
|
||||
toolRefs := make([]ai.ToolRef, len(genkitTools))
|
||||
|
||||
for i, tool := range genkitTools {
|
||||
toolRefs[i] = tool
|
||||
}
|
||||
|
||||
for _, query := range queries {
|
||||
conversationHistory = append(conversationHistory, ai.NewUserTextMessage(query))
|
||||
response, err := genkit.Generate(ctx, g,
|
||||
ai.WithMessages(conversationHistory...),
|
||||
ai.WithTools(toolRefs...),
|
||||
ai.WithReturnToolRequests(true),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("%v\n", err)
|
||||
}
|
||||
conversationHistory = append(conversationHistory, response.Message)
|
||||
|
||||
parts := []*ai.Part{}
|
||||
|
||||
for _, req := range response.ToolRequests() {
|
||||
tool := genkit.LookupTool(g, req.Name)
|
||||
if tool == nil {
|
||||
log.Fatalf("tool %q not found", req.Name)
|
||||
}
|
||||
|
||||
output, err := tool.RunRaw(ctx, req.Input)
|
||||
if err != nil {
|
||||
log.Fatalf("tool %q execution failed: %v", tool.Name(), err)
|
||||
}
|
||||
|
||||
parts = append(parts,
|
||||
ai.NewToolResponsePart(&ai.ToolResponse{
|
||||
Name: req.Name,
|
||||
Ref: req.Ref,
|
||||
Output: output,
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
if len(parts) > 0 {
|
||||
resp, err := genkit.Generate(ctx, g,
|
||||
ai.WithMessages(append(response.History(), ai.NewMessage(ai.RoleTool, nil, parts...))...),
|
||||
ai.WithTools(toolRefs...),
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fmt.Println("\n", resp.Text())
|
||||
conversationHistory = append(conversationHistory, resp.Message)
|
||||
} else {
|
||||
fmt.Println("\n", response.Text())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
module langchan-quickstart
|
||||
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0
|
||||
github.com/tmc/langchaingo v0.1.14
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.121.6 // indirect
|
||||
cloud.google.com/go/ai v0.7.0 // indirect
|
||||
cloud.google.com/go/aiplatform v1.89.0 // indirect
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
cloud.google.com/go/iam v1.5.2 // indirect
|
||||
cloud.google.com/go/longrunning v0.6.7 // indirect
|
||||
cloud.google.com/go/vertexai v0.12.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.10.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/google/generative-ai-go v0.15.1 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/pkoukk/tiktoken-go v0.1.6 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.16.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
golang.org/x/time v0.12.0 // indirect
|
||||
google.golang.org/api v0.248.0 // indirect
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 // indirect
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
)
|
||||
@@ -1,136 +0,0 @@
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go/ai v0.7.0 h1:P6+b5p4gXlza5E+u7uvcgYlzZ7103ACg70YdZeC6oGE=
|
||||
cloud.google.com/go/ai v0.7.0/go.mod h1:7ozuEcraovh4ABsPbrec3o4LmFl9HigNI3D5haxYeQo=
|
||||
cloud.google.com/go/aiplatform v1.89.0 h1:niSJYc6ldWWVM9faXPo1Et1MVSQoLvVGriD7fwbJdtE=
|
||||
cloud.google.com/go/aiplatform v1.89.0/go.mod h1:TzZtegPkinfXTtXVvZZpxx7noINFMVDrLkE7cEWhYEk=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
|
||||
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/longrunning v0.6.7 h1:IGtfDWHhQCgCjwQjV9iiLnUta9LBCo8R9QmAFsS/PrE=
|
||||
cloud.google.com/go/longrunning v0.6.7/go.mod h1:EAFV3IZAKmM56TyiE6VAP3VoTzhZzySwI/YI1s/nRsY=
|
||||
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
|
||||
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||
cloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=
|
||||
cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=
|
||||
cloud.google.com/go/storage v1.56.1 h1:n6gy+yLnHn0hTwBFzNn8zJ1kqWfR91wzdM8hjRF4wP0=
|
||||
cloud.google.com/go/storage v1.56.1/go.mod h1:C9xuCZgFl3buo2HZU/1FncgvvOgTAs/rnh4gF4lMg0s=
|
||||
cloud.google.com/go/vertexai v0.12.0 h1:zTadEo/CtsoyRXNx3uGCncoWAP1H2HakGqwznt+iMo8=
|
||||
cloud.google.com/go/vertexai v0.12.0/go.mod h1:8u+d0TsvBfAAd2x5R6GMgbYhsLgo3J7lmP4bR8g2ig8=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0=
|
||||
github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/generative-ai-go v0.15.1 h1:n8aQUpvhPOlGVuM2DRkJ2jvx04zpp42B778AROJa+pQ=
|
||||
github.com/google/generative-ai-go v0.15.1/go.mod h1:AAucpWZjXsDKhQYWvCYuP6d0yB1kX998pJlOW1rAesw=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0 h1:m/en3Pp3iGc99SYejUS9iQ01QXsDKMVA+Z456P6mAxY=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0/go.mod h1:DYgNeEV9WHpesG9O2Esr0o+s7Nag0H3h3U2JstK1g6I=
|
||||
github.com/pkoukk/tiktoken-go v0.1.6 h1:JF0TlJzhTbrI30wCvFuiw6FzP2+/bR+FIxUdgEAcUsw=
|
||||
github.com/pkoukk/tiktoken-go v0.1.6/go.mod h1:9NiV+i9mJKGj1rYOT+njbv+ZwA/zJxYdewGl6qVatpg=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tmc/langchaingo v0.1.14 h1:o1qWBPigAIuFvrG6cjTFo0cZPFEZ47ZqpOYMjM15yZc=
|
||||
github.com/tmc/langchaingo v0.1.14/go.mod h1:aKKYXYoqhIDEv7WKdpnnCLRaqXic69cX9MnDUk72378=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
google.golang.org/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
|
||||
google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
@@ -1,149 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
"github.com/tmc/langchaingo/llms/googleai"
|
||||
)
|
||||
|
||||
// ConvertToLangchainTool converts a generic core.ToolboxTool into a LangChainGo llms.Tool.
|
||||
func ConvertToLangchainTool(toolboxTool *core.ToolboxTool) llms.Tool {
|
||||
|
||||
// Fetch the tool's input schema
|
||||
inputschema, err := toolboxTool.InputSchema()
|
||||
if err != nil {
|
||||
return llms.Tool{}
|
||||
}
|
||||
|
||||
var paramsSchema map[string]any
|
||||
_ = json.Unmarshal(inputschema, ¶msSchema)
|
||||
|
||||
// Convert into LangChain's llms.Tool
|
||||
return llms.Tool{
|
||||
Type: "function",
|
||||
Function: &llms.FunctionDefinition{
|
||||
Name: toolboxTool.Name(),
|
||||
Description: toolboxTool.Description(),
|
||||
Parameters: paramsSchema,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const systemPrompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, mention its name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`
|
||||
|
||||
var queries = []string{
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the hotel Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it.",
|
||||
"Please book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
}
|
||||
|
||||
func main() {
|
||||
genaiKey := os.Getenv("GOOGLE_API_KEY")
|
||||
toolboxURL := "http://localhost:5000"
|
||||
ctx := context.Background()
|
||||
|
||||
// Initialize the Google AI client (LLM).
|
||||
llm, err := googleai.New(ctx, googleai.WithAPIKey(genaiKey), googleai.WithDefaultModel("gemini-2.0-flash"))
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Google AI client: %v", err)
|
||||
}
|
||||
|
||||
// Initialize the MCP Toolbox client.
|
||||
toolboxClient, err := core.NewToolboxClient(toolboxURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Load the tool using the MCP Toolbox SDK.
|
||||
tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tools: %v\nMake sure your Toolbox server is running and the tool is configured.", err)
|
||||
}
|
||||
|
||||
toolsMap := make(map[string]*core.ToolboxTool, len(tools))
|
||||
|
||||
langchainTools := make([]llms.Tool, len(tools))
|
||||
// Convert the loaded ToolboxTools into the format LangChainGo requires.
|
||||
for i, tool := range tools {
|
||||
langchainTools[i] = ConvertToLangchainTool(tool)
|
||||
toolsMap[tool.Name()] = tool
|
||||
}
|
||||
|
||||
// Start the conversation history.
|
||||
messageHistory := []llms.MessageContent{
|
||||
llms.TextParts(llms.ChatMessageTypeSystem, systemPrompt),
|
||||
}
|
||||
|
||||
for _, query := range queries {
|
||||
messageHistory = append(messageHistory, llms.TextParts(llms.ChatMessageTypeHuman, query))
|
||||
|
||||
// Make the first call to the LLM, making it aware of the tool.
|
||||
resp, err := llm.GenerateContent(ctx, messageHistory, llms.WithTools(langchainTools))
|
||||
if err != nil {
|
||||
log.Fatalf("LLM call failed: %v", err)
|
||||
}
|
||||
respChoice := resp.Choices[0]
|
||||
|
||||
assistantResponse := llms.TextParts(llms.ChatMessageTypeAI, respChoice.Content)
|
||||
for _, tc := range respChoice.ToolCalls {
|
||||
assistantResponse.Parts = append(assistantResponse.Parts, tc)
|
||||
}
|
||||
messageHistory = append(messageHistory, assistantResponse)
|
||||
|
||||
// Process each tool call requested by the model.
|
||||
for _, tc := range respChoice.ToolCalls {
|
||||
toolName := tc.FunctionCall.Name
|
||||
tool := toolsMap[toolName]
|
||||
var args map[string]any
|
||||
if err := json.Unmarshal([]byte(tc.FunctionCall.Arguments), &args); err != nil {
|
||||
log.Fatalf("Failed to unmarshal arguments for tool '%s': %v", toolName, err)
|
||||
}
|
||||
toolResult, err := tool.Invoke(ctx, args)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to execute tool '%s': %v", toolName, err)
|
||||
}
|
||||
if toolResult == "" || toolResult == nil {
|
||||
toolResult = "Operation completed successfully with no specific return value."
|
||||
}
|
||||
|
||||
// Create the tool call response message and add it to the history.
|
||||
toolResponse := llms.MessageContent{
|
||||
Role: llms.ChatMessageTypeTool,
|
||||
Parts: []llms.ContentPart{
|
||||
llms.ToolCallResponse{
|
||||
Name: toolName,
|
||||
Content: fmt.Sprintf("%v", toolResult),
|
||||
},
|
||||
},
|
||||
}
|
||||
messageHistory = append(messageHistory, toolResponse)
|
||||
}
|
||||
finalResp, err := llm.GenerateContent(ctx, messageHistory)
|
||||
if err != nil {
|
||||
log.Fatalf("Final LLM call failed after tool execution: %v", err)
|
||||
}
|
||||
|
||||
// Add the final textual response from the LLM to the history
|
||||
messageHistory = append(messageHistory, llms.TextParts(llms.ChatMessageTypeAI, finalResp.Choices[0].Content))
|
||||
|
||||
fmt.Println(finalResp.Choices[0].Content)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
module openai-quickstart
|
||||
|
||||
go 1.24.6
|
||||
|
||||
require (
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0
|
||||
github.com/openai/openai-go/v3 v3.3.0
|
||||
)
|
||||
|
||||
|
||||
require (
|
||||
cloud.google.com/go/auth v0.16.5 // indirect
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect
|
||||
cloud.google.com/go/compute/metadata v0.8.0 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.4 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/google/s2a-go v0.1.9 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 // indirect
|
||||
github.com/tidwall/gjson v1.14.4 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
|
||||
go.opentelemetry.io/otel v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v1.36.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.36.0 // indirect
|
||||
golang.org/x/crypto v0.41.0 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sys v0.35.0 // indirect
|
||||
golang.org/x/text v0.28.0 // indirect
|
||||
google.golang.org/api v0.248.0 // indirect
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c // indirect
|
||||
google.golang.org/grpc v1.74.2 // indirect
|
||||
google.golang.org/protobuf v1.36.7 // indirect
|
||||
)
|
||||
@@ -1,126 +0,0 @@
|
||||
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
|
||||
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
|
||||
cloud.google.com/go v0.121.6 h1:waZiuajrI28iAf40cWgycWNgaXPO06dupuS+sgibK6c=
|
||||
cloud.google.com/go v0.121.6/go.mod h1:coChdst4Ea5vUpiALcYKXEpR1S9ZgXbhEzzMcMR66vI=
|
||||
cloud.google.com/go/auth v0.16.5 h1:mFWNQ2FEVWAliEQWpAdH80omXFokmrnbDhUS9cBywsI=
|
||||
cloud.google.com/go/auth v0.16.5/go.mod h1:utzRfHMP+Vv0mpOkTRQoWD2q3BatTOoWbA7gCc2dUhQ=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc=
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.8.0 h1:HxMRIbao8w17ZX6wBnjhcDkW6lTFpgcaobyVfZWqRLA=
|
||||
cloud.google.com/go/compute/metadata v0.8.0/go.mod h1:sYOGTp851OV9bOFJ9CH7elVvyzopvWQFNNghtDQ/Biw=
|
||||
cloud.google.com/go/iam v1.5.2 h1:qgFRAGEmd8z6dJ/qyEchAuL9jpswyODjA2lS+w234g8=
|
||||
cloud.google.com/go/iam v1.5.2/go.mod h1:SE1vg0N81zQqLzQEwxL2WI6yhetBdbNQuTvIKCSkUHE=
|
||||
cloud.google.com/go/monitoring v1.24.2 h1:5OTsoJ1dXYIiMiuL+sYscLc9BumrL3CarVLL7dd7lHM=
|
||||
cloud.google.com/go/monitoring v1.24.2/go.mod h1:x7yzPWcgDRnPEv3sI+jJGBkwl5qINf+6qY4eq0I9B4U=
|
||||
cloud.google.com/go/secretmanager v1.15.0 h1:RtkCMgTpaBMbzozcRUGfZe46jb9a3qh5EdEtVRUATF8=
|
||||
cloud.google.com/go/secretmanager v1.15.0/go.mod h1:1hQSAhKK7FldiYw//wbR/XPfPc08eQ81oBsnRUHEvUc=
|
||||
cloud.google.com/go/storage v1.56.1 h1:n6gy+yLnHn0hTwBFzNn8zJ1kqWfR91wzdM8hjRF4wP0=
|
||||
cloud.google.com/go/storage v1.56.1/go.mod h1:C9xuCZgFl3buo2HZU/1FncgvvOgTAs/rnh4gF4lMg0s=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0 h1:ErKg/3iS1AKcTkf3yixlZ54f9U1rljCkQyEXWUnIUxc=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.27.0/go.mod h1:yAZHSGnqScoU556rBOVkwLze6WP5N+U11RHuWaGVxwY=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0 h1:owcC2UnmsZycprQ5RfRgjydWhuoxg71LUfyiQdijZuM=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.53.0/go.mod h1:ZPpqegjbE99EPKsu3iUWV22A04wzGPcAY/ziSIQEEgs=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0 h1:Ron4zCA/yk6U7WOBXhTJcDpsUBG9npumK6xw2auFltQ=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.53.0/go.mod h1:cSgYe11MCNYunTnRXrKiR/tHc0eoKjICUuWpNZoVCOo=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
|
||||
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.13.4 h1:zEqyPVyku6IvWCFwux4x9RxkLOMUL+1vC9xUFv5l2/M=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4 h1:jb83lalDRZSpPWW2Z7Mck/8kXZ5CQAFYVjQcdVIr83A=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
|
||||
github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6 h1:GW/XbdyBFQ8Qe+YAmFU9uHLo7OnF5tL52HFAgMmyrf4=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.6/go.mod h1:MkHOF77EYAE7qfSuSS9PU6g4Nt4e11cnsDUowfwewLA=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0 h1:SyjDc1mGgZU5LncH8gimWo9lW1DtIfPibOG81vgd/bo=
|
||||
github.com/googleapis/gax-go/v2 v2.15.0/go.mod h1:zVVkkxAQHa1RQpg9z2AUCMnKhi0Qld9rcmyfL1OZhoc=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0 h1:m/en3Pp3iGc99SYejUS9iQ01QXsDKMVA+Z456P6mAxY=
|
||||
github.com/googleapis/mcp-toolbox-sdk-go v0.3.0/go.mod h1:DYgNeEV9WHpesG9O2Esr0o+s7Nag0H3h3U2JstK1g6I=
|
||||
github.com/openai/openai-go v1.12.0 h1:NBQCnXzqOTv5wsgNC36PrFEiskGfO5wccfCWDo9S1U0=
|
||||
github.com/openai/openai-go v1.12.0/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgmp0tecUJ0sJuv4pzYCqS9+RGSn52M3FUwPs+uo=
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0 h1:N2I01KCUkv1FAjZXJMwh95KK1ZIQLYbPfhaxw8WS0hE=
|
||||
github.com/spiffe/go-spiffe/v2 v2.5.0/go.mod h1:P+NxobPc6wXhVtINNtFjNWGBTreew1GBUCwT2wPmb7g=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM=
|
||||
github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
|
||||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
|
||||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
|
||||
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
|
||||
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0 h1:F7q2tNlCaHY9nMKHR6XH9/qkp8FktLnIcy6jJNyOCQw=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.36.0/go.mod h1:IbBN8uAIIx734PTonTPxAxnjc2pQTxWNkwfstZ+6H2k=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0 h1:q4XOmH/0opmeuJtPsbFNivyl7bCt7yRBbeEm2sC/XtQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.61.0/go.mod h1:snMWehoOh2wsEwnvvwtDyFCxVeDAODenXHtn5vzrKjo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
|
||||
go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
|
||||
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
|
||||
go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
|
||||
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
|
||||
go.opentelemetry.io/otel/sdk v1.36.0/go.mod h1:+lC+mTgD+MUWfjJubi2vvXWcVxyr9rmlshZni72pXeY=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0 h1:r0ntwwGosWGaa0CrSt8cuNuTcccMXERFwHX4dThiPis=
|
||||
go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
|
||||
go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
|
||||
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
|
||||
golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4=
|
||||
golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc=
|
||||
golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE=
|
||||
golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg=
|
||||
golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI=
|
||||
golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU=
|
||||
golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
|
||||
golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
||||
golang.org/x/sys v0.35.0 h1:vz1N37gP5bs89s7He8XuIYXpyY0+QlsKmzipCbUtyxI=
|
||||
golang.org/x/sys v0.35.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng=
|
||||
golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU=
|
||||
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
|
||||
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
|
||||
google.golang.org/api v0.248.0 h1:hUotakSkcwGdYUqzCRc5yGYsg4wXxpkKlW5ryVqvC1Y=
|
||||
google.golang.org/api v0.248.0/go.mod h1:yAFUAF56Li7IuIQbTFoLwXTCI6XCFKueOlS7S9e4F9k=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822 h1:rHWScKit0gvAPuOnu87KpaYtjK5zBMLcULh7gxkCXu4=
|
||||
google.golang.org/genproto v0.0.0-20250603155806-513f23925822/go.mod h1:HubltRL7rMh0LfnQPkMH4NPDFEWp0jw3vixw7jEM53s=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c h1:AtEkQdl5b6zsybXcbz00j1LwNodDuH6hVifIaNqk7NQ=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20250818200422-3122310a409c/go.mod h1:ea2MjsO70ssTfCjiwHgI0ZFqcw45Ksuk2ckf9G468GA=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c h1:qXWI/sQtv5UKboZ/zUk7h+mrf/lXORyI+n9DKDAusdg=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20250818200422-3122310a409c/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
|
||||
google.golang.org/grpc v1.74.2 h1:WoosgB65DlWVC9FqI82dGsZhWFNBSLjQ84bjROOpMu4=
|
||||
google.golang.org/grpc v1.74.2/go.mod h1:CtQ+BGjaAIXHs/5YS3i473GqwBBa1zGQNevxdeBEXrM=
|
||||
google.golang.org/protobuf v1.36.7 h1:IgrO7UwFQGJdRNXH/sQux4R1Dj1WAKcLElzeeRaXV2A=
|
||||
google.golang.org/protobuf v1.36.7/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -1,141 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/googleapis/mcp-toolbox-sdk-go/core"
|
||||
openai "github.com/openai/openai-go"
|
||||
)
|
||||
|
||||
// ConvertToOpenAITool converts a ToolboxTool into the go-openai library's Tool format.
|
||||
func ConvertToOpenAITool(toolboxTool *core.ToolboxTool) openai.ChatCompletionToolParam {
|
||||
// Get the input schema
|
||||
jsonSchemaBytes, err := toolboxTool.InputSchema()
|
||||
if err != nil {
|
||||
return openai.ChatCompletionToolParam{}
|
||||
}
|
||||
|
||||
// Unmarshal the JSON bytes into FunctionParameters
|
||||
var paramsSchema openai.FunctionParameters
|
||||
if err := json.Unmarshal(jsonSchemaBytes, ¶msSchema); err != nil {
|
||||
return openai.ChatCompletionToolParam{}
|
||||
}
|
||||
|
||||
// Create and return the final tool parameter struct.
|
||||
return openai.ChatCompletionToolParam{
|
||||
Function: openai.FunctionDefinitionParam{
|
||||
Name: toolboxTool.Name(),
|
||||
Description: openai.String(toolboxTool.Description()),
|
||||
Parameters: paramsSchema,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
const systemPrompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, mention its name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`
|
||||
|
||||
var queries = []string{
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the hotel Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Setup
|
||||
ctx := context.Background()
|
||||
toolboxURL := "http://localhost:5000"
|
||||
openAIClient := openai.NewClient()
|
||||
|
||||
// Initialize the MCP Toolbox client.
|
||||
toolboxClient, err := core.NewToolboxClient(toolboxURL)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to create Toolbox client: %v", err)
|
||||
}
|
||||
|
||||
// Load the tools using the MCP Toolbox SDK.
|
||||
tools, err := toolboxClient.LoadToolset("my-toolset", ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to load tool : %v\nMake sure your Toolbox server is running and the tool is configured.", err)
|
||||
}
|
||||
|
||||
openAITools := make([]openai.ChatCompletionToolParam, len(tools))
|
||||
toolsMap := make(map[string]*core.ToolboxTool, len(tools))
|
||||
|
||||
for i, tool := range tools {
|
||||
// Convert the Toolbox tool into the openAI FunctionDeclaration format.
|
||||
openAITools[i] = ConvertToOpenAITool(tool)
|
||||
// Add tool to a map for lookup later
|
||||
toolsMap[tool.Name()] = tool
|
||||
|
||||
}
|
||||
|
||||
params := openai.ChatCompletionNewParams{
|
||||
Messages: []openai.ChatCompletionMessageParamUnion{
|
||||
openai.SystemMessage(systemPrompt),
|
||||
},
|
||||
Tools: openAITools,
|
||||
Seed: openai.Int(0),
|
||||
Model: openai.ChatModelGPT4o,
|
||||
}
|
||||
|
||||
for _, query := range queries {
|
||||
|
||||
params.Messages = append(params.Messages, openai.UserMessage(query))
|
||||
|
||||
// Make initial chat completion request
|
||||
completion, err := openAIClient.Chat.Completions.New(ctx, params)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
toolCalls := completion.Choices[0].Message.ToolCalls
|
||||
|
||||
// Return early if there are no tool calls
|
||||
if len(toolCalls) == 0 {
|
||||
log.Println("No function call")
|
||||
}
|
||||
|
||||
// If there was a function call, continue the conversation
|
||||
params.Messages = append(params.Messages, completion.Choices[0].Message.ToParam())
|
||||
for _, toolCall := range toolCalls {
|
||||
|
||||
toolName := toolCall.Function.Name
|
||||
toolToInvoke := toolsMap[toolName]
|
||||
|
||||
var args map[string]any
|
||||
err := json.Unmarshal([]byte(toolCall.Function.Arguments), &args)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
result, err := toolToInvoke.Invoke(ctx, args)
|
||||
if err != nil {
|
||||
log.Fatal("Could not invoke tool", err)
|
||||
}
|
||||
|
||||
params.Messages = append(params.Messages, openai.ToolMessage(result.(string), toolCall.ID))
|
||||
}
|
||||
|
||||
completion, err = openAIClient.Chat.Completions.New(ctx, params)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
params.Messages = append(params.Messages, openai.AssistantMessage(query))
|
||||
|
||||
fmt.Println("\n", completion.Choices[0].Message.Content)
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
// 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.
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestQuickstartSample(t *testing.T) {
|
||||
framework := os.Getenv("ORCH_NAME")
|
||||
if framework == "" {
|
||||
t.Skip("Skipping test: ORCH_NAME environment variable is not set.")
|
||||
}
|
||||
|
||||
t.Logf("--- Testing: %s ---", framework)
|
||||
|
||||
if framework == "openAI" {
|
||||
if os.Getenv("OPENAI_API_KEY") == "" {
|
||||
t.Skip("Skipping test: OPENAI_API_KEY environment variable is not set for openAI framework.")
|
||||
}
|
||||
} else {
|
||||
if os.Getenv("GOOGLE_API_KEY") == "" {
|
||||
t.Skipf("Skipping test for %s: GOOGLE_API_KEY environment variable is not set.", framework)
|
||||
}
|
||||
}
|
||||
|
||||
sampleDir := filepath.Join(".", framework)
|
||||
if _, err := os.Stat(sampleDir); os.IsNotExist(err) {
|
||||
t.Fatalf("Test setup failed: directory for framework '%s' not found.", framework)
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "run", ".")
|
||||
cmd.Dir = sampleDir
|
||||
var stdout, stderr bytes.Buffer
|
||||
cmd.Stdout = &stdout
|
||||
cmd.Stderr = &stderr
|
||||
|
||||
err := cmd.Run()
|
||||
actualOutput := stdout.String()
|
||||
|
||||
if err != nil {
|
||||
t.Fatalf("Script execution failed with error: %v\n--- STDERR ---\n%s", err, stderr.String())
|
||||
}
|
||||
if len(actualOutput) == 0 {
|
||||
t.Fatal("Script ran successfully but produced no output.")
|
||||
}
|
||||
|
||||
goldenFile, err := os.ReadFile("../golden.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("Could not read golden.txt to check for keywords: %v", err)
|
||||
}
|
||||
|
||||
keywords := strings.Split(string(goldenFile), "\n")
|
||||
var missingKeywords []string
|
||||
outputLower := strings.ToLower(actualOutput)
|
||||
|
||||
for _, keyword := range keywords {
|
||||
kw := strings.TrimSpace(keyword)
|
||||
if kw != "" && !strings.Contains(outputLower, strings.ToLower(kw)) {
|
||||
missingKeywords = append(missingKeywords, kw)
|
||||
}
|
||||
}
|
||||
|
||||
if len(missingKeywords) > 0 {
|
||||
t.Fatalf("FAIL: The following keywords were missing from the output: [%s]", strings.Join(missingKeywords, ", "))
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
Hilton Basel
|
||||
Hyatt Regency
|
||||
book
|
||||
@@ -1,740 +0,0 @@
|
||||
{
|
||||
"name": "genai",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "genai",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@google/genai": "^1.17.0",
|
||||
"@toolbox-sdk/core": "^0.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai": {
|
||||
"version": "1.17.0",
|
||||
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.17.0.tgz",
|
||||
"integrity": "sha512-r/OZWN9D8WvYrte3bcKPoLODrZ+2TjfxHm5OOyVHUbdFYIp1C4yJaXX4+sCS8I/+CbN9PxLjU5zm1cgmS7qz+A==",
|
||||
"dependencies": {
|
||||
"google-auth-library": "^9.14.2",
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.11.4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@modelcontextprotocol/sdk": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai/node_modules/gaxios": {
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
|
||||
"integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
|
||||
"dependencies": {
|
||||
"extend": "^3.0.2",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"is-stream": "^2.0.0",
|
||||
"node-fetch": "^2.6.9",
|
||||
"uuid": "^9.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai/node_modules/gcp-metadata": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz",
|
||||
"integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==",
|
||||
"dependencies": {
|
||||
"gaxios": "^6.1.1",
|
||||
"google-logging-utils": "^0.0.2",
|
||||
"json-bigint": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai/node_modules/google-auth-library": {
|
||||
"version": "9.15.1",
|
||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz",
|
||||
"integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"ecdsa-sig-formatter": "^1.0.11",
|
||||
"gaxios": "^6.1.1",
|
||||
"gcp-metadata": "^6.1.0",
|
||||
"gtoken": "^7.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai/node_modules/google-logging-utils": {
|
||||
"version": "0.0.2",
|
||||
"resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz",
|
||||
"integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai/node_modules/gtoken": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
|
||||
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
|
||||
"dependencies": {
|
||||
"gaxios": "^6.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@google/genai/node_modules/node-fetch": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@toolbox-sdk/core": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@toolbox-sdk/core/-/core-0.1.2.tgz",
|
||||
"integrity": "sha512-AKfejUi0KK5W1L5AKwfbYDk9GNU92tRYIOIGvDI93XoZU3IWsPHsPHOoE3DFNpY3HvAUdaCZHj7V4GW0kq7dyg==",
|
||||
"dependencies": {
|
||||
"axios": "^1.9.0",
|
||||
"google-auth-library": "^10.0.0",
|
||||
"zod": "^3.24.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.12.2",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
|
||||
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
"form-data": "^4.0.4",
|
||||
"proxy-from-env": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/base64-js": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
|
||||
"integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
|
||||
"integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-equal-constant-time": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||
},
|
||||
"node_modules/call-bind-apply-helpers": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
|
||||
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"dependencies": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
||||
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/dunder-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"gopd": "^1.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/ecdsa-sig-formatter": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es-define-property": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
|
||||
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-errors": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
|
||||
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-object-atoms": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
|
||||
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/es-set-tostringtag": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
|
||||
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.6",
|
||||
"has-tostringtag": "^1.0.2",
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.11",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
|
||||
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/form-data": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
|
||||
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
|
||||
"dependencies": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"es-set-tostringtag": "^2.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"mime-types": "^2.1.12"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.1.tgz",
|
||||
"integrity": "sha512-Odju3uBUJyVCkW64nLD4wKLhbh93bh6vIg/ZIXkWiLPBrdgtc65+tls/qml+un3pr6JqYVFDZbbmLDQT68rTOQ==",
|
||||
"dependencies": {
|
||||
"extend": "^3.0.2",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"node-fetch": "^3.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/gcp-metadata": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-7.0.1.tgz",
|
||||
"integrity": "sha512-UcO3kefx6dCcZkgcTGgVOTFb7b1LlQ02hY1omMjjrrBzkajRMCFgYOjs7J71WqnuG1k2b+9ppGL7FsOfhZMQKQ==",
|
||||
"dependencies": {
|
||||
"gaxios": "^7.0.0",
|
||||
"google-logging-utils": "^1.0.0",
|
||||
"json-bigint": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/get-intrinsic": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
|
||||
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
|
||||
"dependencies": {
|
||||
"call-bind-apply-helpers": "^1.0.2",
|
||||
"es-define-property": "^1.0.1",
|
||||
"es-errors": "^1.3.0",
|
||||
"es-object-atoms": "^1.1.1",
|
||||
"function-bind": "^1.1.2",
|
||||
"get-proto": "^1.0.1",
|
||||
"gopd": "^1.2.0",
|
||||
"has-symbols": "^1.1.0",
|
||||
"hasown": "^2.0.2",
|
||||
"math-intrinsics": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/get-proto": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
|
||||
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
|
||||
"dependencies": {
|
||||
"dunder-proto": "^1.0.1",
|
||||
"es-object-atoms": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/google-auth-library": {
|
||||
"version": "10.3.0",
|
||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.3.0.tgz",
|
||||
"integrity": "sha512-ylSE3RlCRZfZB56PFJSfUCuiuPq83Fx8hqu1KPWGK8FVdSaxlp/qkeMMX/DT/18xkwXIHvXEXkZsljRwfrdEfQ==",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.0",
|
||||
"ecdsa-sig-formatter": "^1.0.11",
|
||||
"gaxios": "^7.0.0",
|
||||
"gcp-metadata": "^7.0.0",
|
||||
"google-logging-utils": "^1.0.0",
|
||||
"gtoken": "^8.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/google-logging-utils": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.1.tgz",
|
||||
"integrity": "sha512-rcX58I7nqpu4mbKztFeOAObbomBbHU2oIb/d3tJfF3dizGSApqtSwYJigGCooHdnMyQBIw8BrWyK96w3YXgr6A==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
|
||||
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gtoken": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-8.0.0.tgz",
|
||||
"integrity": "sha512-+CqsMbHPiSTdtSO14O51eMNlrp9N79gmeqmXeouJOhfucAedHw9noVe/n5uJk3tbKE6a+6ZCQg3RPhVhHByAIw==",
|
||||
"dependencies": {
|
||||
"gaxios": "^7.0.0",
|
||||
"jws": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/has-symbols": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
|
||||
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/has-tostringtag": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
|
||||
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
|
||||
"dependencies": {
|
||||
"has-symbols": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/json-bigint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||
"dependencies": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jwa": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz",
|
||||
"integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==",
|
||||
"dependencies": {
|
||||
"buffer-equal-constant-time": "^1.0.1",
|
||||
"ecdsa-sig-formatter": "1.0.11",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jws": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
|
||||
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
|
||||
"dependencies": {
|
||||
"jwa": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/math-intrinsics": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"deprecated": "Use your platform's native DOMException instead",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
]
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz",
|
||||
"integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.18.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"name": "genai",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "quickstart.js",
|
||||
"type" : "module",
|
||||
"scripts": {
|
||||
"test": "node --test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@google/genai": "^1.17.0",
|
||||
"@toolbox-sdk/core": "^0.1.2"
|
||||
}
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
import { GoogleGenAI } from "@google/genai";
|
||||
import { ToolboxClient } from "@toolbox-sdk/core";
|
||||
|
||||
|
||||
const TOOLBOX_URL = "http://127.0.0.1:5000"; // Update if needed
|
||||
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key
|
||||
|
||||
const prompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, you MUST use the available tools to find information. Mention its name, id,
|
||||
location and price tier. Always mention hotel id while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`;
|
||||
|
||||
const queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
];
|
||||
|
||||
function mapZodTypeToOpenAPIType(zodTypeName) {
|
||||
|
||||
const typeMap = {
|
||||
'ZodString': 'string',
|
||||
'ZodNumber': 'number',
|
||||
'ZodBoolean': 'boolean',
|
||||
'ZodArray': 'array',
|
||||
'ZodObject': 'object',
|
||||
};
|
||||
return typeMap[zodTypeName] || 'string';
|
||||
}
|
||||
|
||||
export async function main() {
|
||||
|
||||
const toolboxClient = new ToolboxClient(TOOLBOX_URL);
|
||||
const toolboxTools = await toolboxClient.loadToolset("my-toolset");
|
||||
|
||||
const geminiTools = [{
|
||||
functionDeclarations: toolboxTools.map(tool => {
|
||||
|
||||
const schema = tool.getParamSchema();
|
||||
const properties = {};
|
||||
const required = [];
|
||||
|
||||
|
||||
for (const [key, param] of Object.entries(schema.shape)) {
|
||||
properties[key] = {
|
||||
type: mapZodTypeToOpenAPIType(param.constructor.name),
|
||||
description: param.description || '',
|
||||
};
|
||||
required.push(key)
|
||||
}
|
||||
|
||||
return {
|
||||
name: tool.getName(),
|
||||
description: tool.getDescription(),
|
||||
parameters: { type: 'object', properties, required },
|
||||
};
|
||||
})
|
||||
}];
|
||||
|
||||
|
||||
const genAI = new GoogleGenAI({ apiKey: GOOGLE_API_KEY });
|
||||
|
||||
const chat = genAI.chats.create({
|
||||
model: "gemini-2.5-flash",
|
||||
config: {
|
||||
systemInstruction: prompt,
|
||||
tools: geminiTools,
|
||||
}
|
||||
});
|
||||
|
||||
for (const query of queries) {
|
||||
|
||||
let currentResult = await chat.sendMessage({ message: query });
|
||||
|
||||
let finalResponseGiven = false
|
||||
while (!finalResponseGiven) {
|
||||
|
||||
const response = currentResult;
|
||||
const functionCalls = response.functionCalls || [];
|
||||
|
||||
if (functionCalls.length === 0) {
|
||||
console.log(response.text)
|
||||
finalResponseGiven = true;
|
||||
} else {
|
||||
const toolResponses = [];
|
||||
for (const call of functionCalls) {
|
||||
const toolName = call.name
|
||||
const toolToExecute = toolboxTools.find(t => t.getName() === toolName);
|
||||
|
||||
if (toolToExecute) {
|
||||
try {
|
||||
const functionResult = await toolToExecute(call.args);
|
||||
toolResponses.push({
|
||||
functionResponse: { name: call.name, response: { result: functionResult } }
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Error executing tool '${toolName}':`, e);
|
||||
toolResponses.push({
|
||||
functionResponse: { name: call.name, response: { error: e.message } }
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
currentResult = await chat.sendMessage({ message: toolResponses });
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "genkit",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "quickstart.js",
|
||||
"type" : "module",
|
||||
"scripts": {
|
||||
"test": "node --test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@genkit-ai/googleai": "^1.18.0",
|
||||
"@toolbox-sdk/core": "^0.1.2",
|
||||
"genkit": "^1.18.0"
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import { ToolboxClient } from "@toolbox-sdk/core";
|
||||
import { genkit } from "genkit";
|
||||
import { googleAI } from '@genkit-ai/googleai';
|
||||
|
||||
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key
|
||||
|
||||
const systemPrompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, mention its name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`;
|
||||
|
||||
const queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
];
|
||||
|
||||
export async function main() {
|
||||
const toolboxClient = new ToolboxClient("http://127.0.0.1:5000");
|
||||
|
||||
const ai = genkit({
|
||||
plugins: [
|
||||
googleAI({
|
||||
apiKey: process.env.GEMINI_API_KEY || GOOGLE_API_KEY
|
||||
})
|
||||
],
|
||||
model: googleAI.model('gemini-2.0-flash'),
|
||||
});
|
||||
|
||||
const toolboxTools = await toolboxClient.loadToolset("my-toolset");
|
||||
const toolMap = Object.fromEntries(
|
||||
toolboxTools.map((tool) => {
|
||||
const definedTool = ai.defineTool(
|
||||
{
|
||||
name: tool.getName(),
|
||||
description: tool.getDescription(),
|
||||
inputSchema: tool.getParamSchema(),
|
||||
},
|
||||
tool
|
||||
);
|
||||
return [tool.getName(), definedTool];
|
||||
})
|
||||
);
|
||||
const tools = Object.values(toolMap);
|
||||
|
||||
let conversationHistory = [{ role: "system", content: [{ text: systemPrompt }] }];
|
||||
|
||||
for (const query of queries) {
|
||||
conversationHistory.push({ role: "user", content: [{ text: query }] });
|
||||
const response = await ai.generate({
|
||||
messages: conversationHistory,
|
||||
tools: tools,
|
||||
});
|
||||
conversationHistory.push(response.message);
|
||||
|
||||
const toolRequests = response.toolRequests;
|
||||
if (toolRequests?.length > 0) {
|
||||
// Execute tools concurrently and collect their responses.
|
||||
const toolResponses = await Promise.all(
|
||||
toolRequests.map(async (call) => {
|
||||
try {
|
||||
const toolOutput = await toolMap[call.name].invoke(call.input);
|
||||
return { role: "tool", content: [{ toolResponse: { name: call.name, output: toolOutput } }] };
|
||||
} catch (e) {
|
||||
console.error(`Error executing tool ${call.name}:`, e);
|
||||
return { role: "tool", content: [{ toolResponse: { name: call.name, output: { error: e.message } } }] };
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
conversationHistory.push(...toolResponses);
|
||||
|
||||
// Call the AI again with the tool results.
|
||||
response = await ai.generate({ messages: conversationHistory, tools });
|
||||
conversationHistory.push(response.message);
|
||||
}
|
||||
|
||||
console.log(response.text);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "langchain",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "quickstart.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "node --test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@langchain/google-genai": "^0.2.17",
|
||||
"@langchain/langgraph": "^0.4.9",
|
||||
"@toolbox-sdk/core": "^0.1.2",
|
||||
"langchain": "^0.3.33"
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
import { ChatGoogleGenerativeAI } from "@langchain/google-genai";
|
||||
import { ToolboxClient } from "@toolbox-sdk/core";
|
||||
import { tool } from "@langchain/core/tools";
|
||||
import { createReactAgent } from "@langchain/langgraph/prebuilt";
|
||||
import { MemorySaver } from "@langchain/langgraph";
|
||||
|
||||
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key
|
||||
|
||||
const prompt = `
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking, and
|
||||
cancellations. When the user searches for a hotel, mention its name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
`;
|
||||
|
||||
const queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
];
|
||||
|
||||
export async function main() {
|
||||
const model = new ChatGoogleGenerativeAI({
|
||||
model: "gemini-2.0-flash",
|
||||
});
|
||||
|
||||
const client = new ToolboxClient("http://127.0.0.1:5000");
|
||||
const toolboxTools = await client.loadToolset("my-toolset");
|
||||
|
||||
// Define the basics of the tool: name, description, schema and core logic
|
||||
const getTool = (toolboxTool) => tool(toolboxTool, {
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
schema: toolboxTool.getParamSchema()
|
||||
});
|
||||
const tools = toolboxTools.map(getTool);
|
||||
|
||||
const agent = createReactAgent({
|
||||
llm: model,
|
||||
tools: tools,
|
||||
checkpointer: new MemorySaver(),
|
||||
systemPrompt: prompt,
|
||||
});
|
||||
|
||||
const langGraphConfig = {
|
||||
configurable: {
|
||||
thread_id: "test-thread",
|
||||
},
|
||||
};
|
||||
|
||||
for (const query of queries) {
|
||||
const agentOutput = await agent.invoke(
|
||||
{
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: query,
|
||||
},
|
||||
],
|
||||
verbose: true,
|
||||
},
|
||||
langGraphConfig
|
||||
);
|
||||
const response = agentOutput.messages[agentOutput.messages.length - 1].content;
|
||||
console.log(response);
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"name": "llamaindex",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "quickstart.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"test": "node --test"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@llamaindex/google": "^0.3.20",
|
||||
"@llamaindex/workflow": "^1.1.22",
|
||||
"@toolbox-sdk/core": "^0.1.2",
|
||||
"llamaindex": "^0.12.0"
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
import { gemini, GEMINI_MODEL } from "@llamaindex/google";
|
||||
import { agent } from "@llamaindex/workflow";
|
||||
import { createMemory, staticBlock, tool } from "llamaindex";
|
||||
import { ToolboxClient } from "@toolbox-sdk/core";
|
||||
|
||||
const TOOLBOX_URL = "http://127.0.0.1:5000"; // Update if needed
|
||||
const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key
|
||||
|
||||
const prompt = `
|
||||
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and cancellations.
|
||||
When the user searches for a hotel, mention its name, id, location and price tier.
|
||||
Always mention hotel ids while performing any searches — this is very important for operations.
|
||||
For any bookings or cancellations, please provide the appropriate confirmation.
|
||||
Update check-in or check-out dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
|
||||
`;
|
||||
|
||||
const queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
];
|
||||
|
||||
export async function main() {
|
||||
// Connect to MCP Toolbox
|
||||
const client = new ToolboxClient(TOOLBOX_URL);
|
||||
const toolboxTools = await client.loadToolset("my-toolset");
|
||||
const tools = toolboxTools.map((toolboxTool) => {
|
||||
return tool({
|
||||
name: toolboxTool.getName(),
|
||||
description: toolboxTool.getDescription(),
|
||||
parameters: toolboxTool.getParamSchema(),
|
||||
execute: toolboxTool,
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize LLM
|
||||
const llm = gemini({
|
||||
model: GEMINI_MODEL.GEMINI_2_0_FLASH,
|
||||
apiKey: GOOGLE_API_KEY,
|
||||
});
|
||||
|
||||
const memory = createMemory({
|
||||
memoryBlocks: [
|
||||
staticBlock({
|
||||
content: prompt,
|
||||
}),
|
||||
],
|
||||
});
|
||||
|
||||
// Create the Agent
|
||||
const myAgent = agent({
|
||||
tools: tools,
|
||||
llm,
|
||||
memory,
|
||||
systemPrompt: prompt,
|
||||
});
|
||||
|
||||
for (const query of queries) {
|
||||
const result = await myAgent.run(query);
|
||||
const output = result.data.result;
|
||||
|
||||
console.log(`\nUser: ${query}`);
|
||||
if (typeof output === "string") {
|
||||
console.log(output.trim());
|
||||
} else if (typeof output === "object" && "text" in output) {
|
||||
console.log(output.text.trim());
|
||||
} else {
|
||||
console.log(JSON.stringify(output));
|
||||
}
|
||||
}
|
||||
//You may observe some extra logs during execution due to the run method provided by Llama.
|
||||
console.log("Agent run finished.");
|
||||
}
|
||||
|
||||
main();
|
||||
@@ -1,70 +0,0 @@
|
||||
// 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 { describe, test, before, after } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const ORCH_NAME = process.env.ORCH_NAME;
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const orchDir = path.join(__dirname, ORCH_NAME);
|
||||
const quickstartPath = path.join(orchDir, "quickstart.js");
|
||||
|
||||
const { main: runAgent } = await import(quickstartPath);
|
||||
|
||||
const GOLDEN_FILE_PATH = path.resolve(__dirname, "../golden.txt");
|
||||
|
||||
describe(`${ORCH_NAME} Quickstart Agent`, () => {
|
||||
let capturedOutput = [];
|
||||
let originalLog;
|
||||
|
||||
before(() => {
|
||||
originalLog = console.log;
|
||||
console.log = (msg) => {
|
||||
capturedOutput.push(msg);
|
||||
};
|
||||
});
|
||||
|
||||
after(() => {
|
||||
console.log = originalLog;
|
||||
});
|
||||
|
||||
test("outputContainsRequiredKeywords", async () => {
|
||||
capturedOutput = [];
|
||||
await runAgent();
|
||||
const actualOutput = capturedOutput.join("\n");
|
||||
|
||||
assert.ok(
|
||||
actualOutput.length > 0,
|
||||
"Assertion Failed: Script ran successfully but produced no output."
|
||||
);
|
||||
|
||||
const goldenFile = fs.readFileSync(GOLDEN_FILE_PATH, "utf8");
|
||||
const keywords = goldenFile.split("\n").filter((kw) => kw.trim() !== "");
|
||||
const missingKeywords = [];
|
||||
|
||||
for (const keyword of keywords) {
|
||||
if (!actualOutput.toLowerCase().includes(keyword.toLowerCase())) {
|
||||
missingKeywords.push(keyword);
|
||||
}
|
||||
}
|
||||
|
||||
assert.ok(
|
||||
missingKeywords.length === 0,
|
||||
`Assertion Failed: The following keywords were missing from the output: [${missingKeywords.join(", ")}]`
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +0,0 @@
|
||||
# This file makes the 'quickstart' directory a Python package.
|
||||
|
||||
# You can include any package-level initialization logic here if needed.
|
||||
# For now, this file is empty.
|
||||
@@ -1,71 +0,0 @@
|
||||
from google.adk.agents import Agent
|
||||
from google.adk.runners import Runner
|
||||
from google.adk.sessions import InMemorySessionService
|
||||
from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService
|
||||
from google.genai import types
|
||||
from toolbox_core import ToolboxSyncClient
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
# TODO(developer): replace this with your Google API key
|
||||
|
||||
api_key = os.environ.get("GOOGLE_API_KEY") or "your-api-key" # Set your API key here
|
||||
os.environ["GOOGLE_API_KEY"] = api_key
|
||||
|
||||
async def main():
|
||||
with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox_client:
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
root_agent = Agent(
|
||||
model='gemini-2.0-flash-001',
|
||||
name='hotel_agent',
|
||||
description='A helpful AI assistant.',
|
||||
instruction=prompt,
|
||||
tools=toolbox_client.load_toolset("my-toolset"),
|
||||
)
|
||||
|
||||
session_service = InMemorySessionService()
|
||||
artifacts_service = InMemoryArtifactService()
|
||||
session = await session_service.create_session(
|
||||
state={}, app_name='hotel_agent', user_id='123'
|
||||
)
|
||||
runner = Runner(
|
||||
app_name='hotel_agent',
|
||||
agent=root_agent,
|
||||
artifact_service=artifacts_service,
|
||||
session_service=session_service,
|
||||
)
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
for query in queries:
|
||||
content = types.Content(role='user', parts=[types.Part(text=query)])
|
||||
events = runner.run(session_id=session.id,
|
||||
user_id='123', new_message=content)
|
||||
|
||||
responses = (
|
||||
part.text
|
||||
for event in events
|
||||
for part in event.content.parts
|
||||
if part.text is not None
|
||||
)
|
||||
|
||||
for text in responses:
|
||||
print(text)
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,3 +0,0 @@
|
||||
google-adk==1.15.1
|
||||
toolbox-core==0.5.2
|
||||
pytest==8.4.2
|
||||
@@ -1,116 +0,0 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from google import genai
|
||||
from google.genai.types import (
|
||||
Content,
|
||||
FunctionDeclaration,
|
||||
GenerateContentConfig,
|
||||
Part,
|
||||
Tool,
|
||||
)
|
||||
|
||||
from toolbox_core import ToolboxClient
|
||||
|
||||
project = os.environ.get("GCP_PROJECT") or "project-id"
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel id while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Please book the hotel Hilton Basel for me.",
|
||||
"This is too expensive. Please cancel it.",
|
||||
"Please book Hyatt Regency for me",
|
||||
"My check in dates for my booking would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
async def main():
|
||||
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
|
||||
# integration. While this example uses Google's genai client, these callables can be adapted for
|
||||
# various function-calling or agent frameworks. For easier integration with supported frameworks
|
||||
# (https://github.com/googleapis/mcp-toolbox-python-sdk/tree/main/packages), use the
|
||||
# provided wrapper packages, which handle framework-specific boilerplate.
|
||||
toolbox_tools = await toolbox_client.load_toolset("my-toolset")
|
||||
genai_client = genai.Client(
|
||||
vertexai=True, project=project, location="us-central1"
|
||||
)
|
||||
|
||||
genai_tools = [
|
||||
Tool(
|
||||
function_declarations=[
|
||||
FunctionDeclaration.from_callable_with_api_option(callable=tool)
|
||||
]
|
||||
)
|
||||
for tool in toolbox_tools
|
||||
]
|
||||
history = []
|
||||
for query in queries:
|
||||
user_prompt_content = Content(
|
||||
role="user",
|
||||
parts=[Part.from_text(text=query)],
|
||||
)
|
||||
history.append(user_prompt_content)
|
||||
|
||||
response = genai_client.models.generate_content(
|
||||
model="gemini-2.0-flash-001",
|
||||
contents=history,
|
||||
config=GenerateContentConfig(
|
||||
system_instruction=prompt,
|
||||
tools=genai_tools,
|
||||
),
|
||||
)
|
||||
history.append(response.candidates[0].content)
|
||||
function_response_parts = []
|
||||
|
||||
if response.function_calls:
|
||||
for function_call in response.function_calls:
|
||||
fn_name = function_call.name
|
||||
# The tools are sorted alphabetically
|
||||
if fn_name == "search-hotels-by-name":
|
||||
function_result = await toolbox_tools[3](**function_call.args)
|
||||
elif fn_name == "search-hotels-by-location":
|
||||
function_result = await toolbox_tools[2](**function_call.args)
|
||||
elif fn_name == "book-hotel":
|
||||
function_result = await toolbox_tools[0](**function_call.args)
|
||||
elif fn_name == "update-hotel":
|
||||
function_result = await toolbox_tools[4](**function_call.args)
|
||||
elif fn_name == "cancel-hotel":
|
||||
function_result = await toolbox_tools[1](**function_call.args)
|
||||
else:
|
||||
raise ValueError(f"Function name {fn_name} not present.")
|
||||
|
||||
function_response = {"result": function_result}
|
||||
function_response_part = Part.from_function_response(
|
||||
name=function_call.name,
|
||||
response=function_response,
|
||||
)
|
||||
function_response_parts.append(function_response_part)
|
||||
|
||||
if function_response_parts:
|
||||
tool_response_content = Content(role="tool", parts=function_response_parts)
|
||||
history.append(tool_response_content)
|
||||
|
||||
response2 = genai_client.models.generate_content(
|
||||
model="gemini-2.0-flash-001",
|
||||
contents=history,
|
||||
config=GenerateContentConfig(
|
||||
tools=genai_tools,
|
||||
),
|
||||
)
|
||||
final_model_response_content = response2.candidates[0].content
|
||||
history.append(final_model_response_content)
|
||||
print(response2.text)
|
||||
else:
|
||||
print(response.text)
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,3 +0,0 @@
|
||||
google-genai==1.47.0
|
||||
toolbox-core==0.5.2
|
||||
pytest==8.4.2
|
||||
@@ -1,52 +0,0 @@
|
||||
import asyncio
|
||||
|
||||
from langgraph.prebuilt import create_react_agent
|
||||
|
||||
# TODO(developer): replace this with another import if needed
|
||||
|
||||
from langchain_google_vertexai import ChatVertexAI
|
||||
|
||||
# from langchain_google_genai import ChatGoogleGenerativeAI
|
||||
|
||||
# from langchain_anthropic import ChatAnthropic
|
||||
|
||||
from langgraph.checkpoint.memory import MemorySaver
|
||||
|
||||
from toolbox_langchain import ToolboxClient
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
async def main():
|
||||
# TODO(developer): replace this with another model if needed
|
||||
model = ChatVertexAI(model_name="gemini-2.0-flash-001")
|
||||
# model = ChatGoogleGenerativeAI(model="gemini-2.0-flash-001")
|
||||
# model = ChatAnthropic(model="claude-3-5-sonnet-20240620")
|
||||
|
||||
# Load the tools from the Toolbox server
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
tools = await client.aload_toolset()
|
||||
|
||||
agent = create_react_agent(model, tools, checkpointer=MemorySaver())
|
||||
|
||||
config = {"configurable": {"thread_id": "thread-1"}}
|
||||
for query in queries:
|
||||
inputs = {"messages": [("user", prompt + query)]}
|
||||
response = agent.invoke(inputs, stream_mode="values", config=config)
|
||||
print(response["messages"][-1].content)
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,5 +0,0 @@
|
||||
langchain==0.3.27
|
||||
langchain-google-vertexai==2.1.2
|
||||
langgraph==1.0.1
|
||||
toolbox-langchain==0.5.2
|
||||
pytest==8.4.2
|
||||
@@ -1,65 +0,0 @@
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from llama_index.core.agent.workflow import AgentWorkflow
|
||||
|
||||
from llama_index.core.workflow import Context
|
||||
|
||||
# TODO(developer): replace this with another import if needed
|
||||
|
||||
from llama_index.llms.google_genai import GoogleGenAI
|
||||
|
||||
# from llama_index.llms.anthropic import Anthropic
|
||||
|
||||
from toolbox_llamaindex import ToolboxClient
|
||||
|
||||
project = os.environ.get("GCP_PROJECT") or "project-id"
|
||||
|
||||
prompt = """
|
||||
You're a helpful hotel assistant. You handle hotel searching, booking and
|
||||
cancellations. When the user searches for a hotel, mention it's name, id,
|
||||
location and price tier. Always mention hotel ids while performing any
|
||||
searches. This is very important for any operations. For any bookings or
|
||||
cancellations, please provide the appropriate confirmation. Be sure to
|
||||
update checkin or checkout dates if mentioned by the user.
|
||||
Don't ask for confirmations from the user.
|
||||
"""
|
||||
|
||||
queries = [
|
||||
"Find hotels in Basel with Basel in its name.",
|
||||
"Can you book the Hilton Basel for me?",
|
||||
"Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.",
|
||||
"My check in dates would be from April 10, 2024 to April 19, 2024.",
|
||||
]
|
||||
|
||||
async def main():
|
||||
# TODO(developer): replace this with another model if needed
|
||||
llm = GoogleGenAI(
|
||||
model="gemini-2.0-flash-001",
|
||||
vertexai_config={"project": project, "location": "us-central1"},
|
||||
)
|
||||
# llm = GoogleGenAI(
|
||||
# api_key=os.getenv("GOOGLE_API_KEY"),
|
||||
# model="gemini-2.0-flash-001",
|
||||
# )
|
||||
# llm = Anthropic(
|
||||
# model="claude-3-7-sonnet-latest",
|
||||
# api_key=os.getenv("ANTHROPIC_API_KEY")
|
||||
# )
|
||||
|
||||
# Load the tools from the Toolbox server
|
||||
async with ToolboxClient("http://127.0.0.1:5000") as client:
|
||||
tools = await client.aload_toolset()
|
||||
|
||||
agent = AgentWorkflow.from_tools_or_functions(
|
||||
tools,
|
||||
llm=llm,
|
||||
system_prompt=prompt,
|
||||
)
|
||||
ctx = Context(agent)
|
||||
for query in queries:
|
||||
response = await agent.run(user_msg=query, ctx=ctx)
|
||||
print(f"---- {query} ----")
|
||||
print(str(response))
|
||||
|
||||
asyncio.run(main())
|
||||
@@ -1,4 +0,0 @@
|
||||
llama-index==0.14.6
|
||||
llama-index-llms-google-genai==0.7.1
|
||||
toolbox-llamaindex==0.5.2
|
||||
pytest==8.4.2
|
||||
@@ -1,58 +0,0 @@
|
||||
# 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 os
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
import asyncio
|
||||
import sys
|
||||
import importlib.util
|
||||
|
||||
ORCH_NAME = os.environ.get("ORCH_NAME")
|
||||
module_path = f"python.{ORCH_NAME}.quickstart"
|
||||
quickstart = importlib.import_module(module_path)
|
||||
|
||||
|
||||
@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 TestExecution:
|
||||
"""Test framework execution and output validation."""
|
||||
|
||||
@pytest.fixture(scope="function")
|
||||
def script_output(self, capsys):
|
||||
"""Run the quickstart function and return its output."""
|
||||
asyncio.run(quickstart.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}"
|
||||
@@ -1,17 +0,0 @@
|
||||
<!-- This file has been used in local_quickstart.md, local_quickstart_go.md & local_quickstart_js.md -->
|
||||
<!-- [START cloud_setup] -->
|
||||
If you plan to use **Google Cloud’s Vertex AI** with your agent (e.g., using
|
||||
`vertexai=True` or a Google GenAI model), follow these one-time setup steps for
|
||||
local development:
|
||||
|
||||
1. [Install the Google Cloud CLI](https://cloud.google.com/sdk/docs/install)
|
||||
1. [Set up Application Default Credentials
|
||||
(ADC)](https://cloud.google.com/docs/authentication/set-up-adc-local-dev-environment)
|
||||
1. Set your project and enable Vertex AI
|
||||
|
||||
```bash
|
||||
gcloud config set project YOUR_PROJECT_ID
|
||||
gcloud services enable aiplatform.googleapis.com
|
||||
```
|
||||
|
||||
<!-- [END cloud_setup] -->
|
||||
@@ -1,122 +0,0 @@
|
||||
<!-- This file has been used in local_quickstart.md, local_quickstart_go.md & local_quickstart_js.md -->
|
||||
<!-- [START configure_toolbox] -->
|
||||
In this section, we will download Toolbox, configure our tools in a
|
||||
`tools.yaml`, and then run the Toolbox server.
|
||||
|
||||
1. Download the latest version of Toolbox as a binary:
|
||||
|
||||
{{< notice tip >}}
|
||||
Select the
|
||||
[correct binary](https://github.com/googleapis/genai-toolbox/releases)
|
||||
corresponding to your OS and CPU architecture.
|
||||
{{< /notice >}}
|
||||
<!-- {x-release-please-start-version} -->
|
||||
```bash
|
||||
export OS="linux/amd64" # one of linux/amd64, darwin/arm64, darwin/amd64, or windows/amd64
|
||||
curl -O https://storage.googleapis.com/genai-toolbox/v0.18.0/$OS/toolbox
|
||||
```
|
||||
<!-- {x-release-please-end} -->
|
||||
|
||||
1. Make the binary executable:
|
||||
|
||||
```bash
|
||||
chmod +x toolbox
|
||||
```
|
||||
|
||||
1. Write the following into a `tools.yaml` file. Be sure to update any fields
|
||||
such as `user`, `password`, or `database` that you may have customized in the
|
||||
previous step.
|
||||
|
||||
{{< notice tip >}}
|
||||
In practice, use environment variable replacement with the format ${ENV_NAME}
|
||||
instead of hardcoding your secrets into the configuration file.
|
||||
{{< /notice >}}
|
||||
|
||||
```yaml
|
||||
sources:
|
||||
my-pg-source:
|
||||
kind: postgres
|
||||
host: 127.0.0.1
|
||||
port: 5432
|
||||
database: toolbox_db
|
||||
user: ${USER_NAME}
|
||||
password: ${PASSWORD}
|
||||
tools:
|
||||
search-hotels-by-name:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: Search for hotels based on name.
|
||||
parameters:
|
||||
- name: name
|
||||
type: string
|
||||
description: The name of the hotel.
|
||||
statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%';
|
||||
search-hotels-by-location:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: Search for hotels based on location.
|
||||
parameters:
|
||||
- name: location
|
||||
type: string
|
||||
description: The location of the hotel.
|
||||
statement: SELECT * FROM hotels WHERE location ILIKE '%' || $1 || '%';
|
||||
book-hotel:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: >-
|
||||
Book a hotel by its ID. If the hotel is successfully booked, returns a NULL, raises an error if not.
|
||||
parameters:
|
||||
- name: hotel_id
|
||||
type: string
|
||||
description: The ID of the hotel to book.
|
||||
statement: UPDATE hotels SET booked = B'1' WHERE id = $1;
|
||||
update-hotel:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: >-
|
||||
Update a hotel's check-in and check-out dates by its ID. Returns a message
|
||||
indicating whether the hotel was successfully updated or not.
|
||||
parameters:
|
||||
- name: hotel_id
|
||||
type: string
|
||||
description: The ID of the hotel to update.
|
||||
- name: checkin_date
|
||||
type: string
|
||||
description: The new check-in date of the hotel.
|
||||
- name: checkout_date
|
||||
type: string
|
||||
description: The new check-out date of the hotel.
|
||||
statement: >-
|
||||
UPDATE hotels SET checkin_date = CAST($2 as date), checkout_date = CAST($3
|
||||
as date) WHERE id = $1;
|
||||
cancel-hotel:
|
||||
kind: postgres-sql
|
||||
source: my-pg-source
|
||||
description: Cancel a hotel by its ID.
|
||||
parameters:
|
||||
- name: hotel_id
|
||||
type: string
|
||||
description: The ID of the hotel to cancel.
|
||||
statement: UPDATE hotels SET booked = B'0' WHERE id = $1;
|
||||
toolsets:
|
||||
my-toolset:
|
||||
- search-hotels-by-name
|
||||
- search-hotels-by-location
|
||||
- book-hotel
|
||||
- update-hotel
|
||||
- cancel-hotel
|
||||
```
|
||||
|
||||
For more info on tools, check out the `Resources` section of the docs.
|
||||
|
||||
1. Run the Toolbox server, pointing to the `tools.yaml` file created earlier:
|
||||
|
||||
```bash
|
||||
./toolbox --tools-file "tools.yaml"
|
||||
```
|
||||
|
||||
{{< notice note >}}
|
||||
Toolbox enables dynamic reloading by default. To disable, use the
|
||||
`--disable-reload` flag.
|
||||
{{< /notice >}}
|
||||
<!-- [END configure_toolbox] -->
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user