This is page 4 of 45. Use http://codebase.md/googleapis/genai-toolbox?lines=true&page={x} to view the full context. # Directory Structure ``` ├── .ci │ ├── continuous.release.cloudbuild.yaml │ ├── generate_release_table.sh │ ├── integration.cloudbuild.yaml │ ├── quickstart_test │ │ ├── go.integration.cloudbuild.yaml │ │ ├── js.integration.cloudbuild.yaml │ │ ├── py.integration.cloudbuild.yaml │ │ ├── run_go_tests.sh │ │ ├── run_js_tests.sh │ │ ├── run_py_tests.sh │ │ └── setup_hotels_sample.sql │ ├── test_with_coverage.sh │ └── versioned.release.cloudbuild.yaml ├── .github │ ├── auto-label.yaml │ ├── blunderbuss.yml │ ├── CODEOWNERS │ ├── header-checker-lint.yml │ ├── ISSUE_TEMPLATE │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── feature_request.yml │ │ └── question.yml │ ├── label-sync.yml │ ├── labels.yaml │ ├── PULL_REQUEST_TEMPLATE.md │ ├── release-please.yml │ ├── renovate.json5 │ ├── sync-repo-settings.yaml │ └── workflows │ ├── cloud_build_failure_reporter.yml │ ├── deploy_dev_docs.yaml │ ├── deploy_previous_version_docs.yaml │ ├── deploy_versioned_docs.yaml │ ├── docs_deploy.yaml │ ├── docs_preview_clean.yaml │ ├── docs_preview_deploy.yaml │ ├── lint.yaml │ ├── schedule_reporter.yml │ ├── sync-labels.yaml │ └── tests.yaml ├── .gitignore ├── .gitmodules ├── .golangci.yaml ├── .hugo │ ├── archetypes │ │ └── default.md │ ├── assets │ │ ├── icons │ │ │ └── logo.svg │ │ └── scss │ │ ├── _styles_project.scss │ │ └── _variables_project.scss │ ├── go.mod │ ├── go.sum │ ├── hugo.toml │ ├── layouts │ │ ├── _default │ │ │ └── home.releases.releases │ │ ├── index.llms-full.txt │ │ ├── index.llms.txt │ │ ├── partials │ │ │ ├── hooks │ │ │ │ └── head-end.html │ │ │ ├── navbar-version-selector.html │ │ │ ├── page-meta-links.html │ │ │ └── td │ │ │ └── render-heading.html │ │ ├── robot.txt │ │ └── shortcodes │ │ ├── include.html │ │ ├── ipynb.html │ │ └── regionInclude.html │ ├── package-lock.json │ ├── package.json │ └── static │ ├── favicons │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ └── favicon.ico │ └── js │ └── w3.js ├── CHANGELOG.md ├── cmd │ ├── options_test.go │ ├── options.go │ ├── root_test.go │ ├── root.go │ └── version.txt ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOPER.md ├── Dockerfile ├── docs │ └── en │ ├── _index.md │ ├── about │ │ ├── _index.md │ │ └── faq.md │ ├── concepts │ │ ├── _index.md │ │ └── telemetry │ │ ├── index.md │ │ ├── telemetry_flow.png │ │ └── telemetry_traces.png │ ├── getting-started │ │ ├── _index.md │ │ ├── colab_quickstart.ipynb │ │ ├── configure.md │ │ ├── introduction │ │ │ ├── _index.md │ │ │ └── architecture.png │ │ ├── local_quickstart_go.md │ │ ├── local_quickstart_js.md │ │ ├── local_quickstart.md │ │ ├── mcp_quickstart │ │ │ ├── _index.md │ │ │ ├── inspector_tools.png │ │ │ └── inspector.png │ │ └── quickstart │ │ ├── go │ │ │ ├── genAI │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ ├── genkit │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ ├── langchain │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ ├── openAI │ │ │ │ ├── go.mod │ │ │ │ ├── go.sum │ │ │ │ └── quickstart.go │ │ │ └── quickstart_test.go │ │ ├── golden.txt │ │ ├── js │ │ │ ├── genAI │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ ├── genkit │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ ├── langchain │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ ├── llamaindex │ │ │ │ ├── package-lock.json │ │ │ │ ├── package.json │ │ │ │ └── quickstart.js │ │ │ └── quickstart.test.js │ │ ├── python │ │ │ ├── __init__.py │ │ │ ├── adk │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ ├── core │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ ├── langchain │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ ├── llamaindex │ │ │ │ ├── quickstart.py │ │ │ │ └── requirements.txt │ │ │ └── quickstart_test.py │ │ └── shared │ │ ├── cloud_setup.md │ │ ├── configure_toolbox.md │ │ └── database_setup.md │ ├── how-to │ │ ├── _index.md │ │ ├── connect_via_geminicli.md │ │ ├── connect_via_mcp.md │ │ ├── connect-ide │ │ │ ├── _index.md │ │ │ ├── alloydb_pg_admin_mcp.md │ │ │ ├── alloydb_pg_mcp.md │ │ │ ├── bigquery_mcp.md │ │ │ ├── cloud_sql_mssql_admin_mcp.md │ │ │ ├── cloud_sql_mssql_mcp.md │ │ │ ├── cloud_sql_mysql_admin_mcp.md │ │ │ ├── cloud_sql_mysql_mcp.md │ │ │ ├── cloud_sql_pg_admin_mcp.md │ │ │ ├── cloud_sql_pg_mcp.md │ │ │ ├── firestore_mcp.md │ │ │ ├── looker_mcp.md │ │ │ ├── mssql_mcp.md │ │ │ ├── mysql_mcp.md │ │ │ ├── neo4j_mcp.md │ │ │ ├── postgres_mcp.md │ │ │ ├── spanner_mcp.md │ │ │ └── sqlite_mcp.md │ │ ├── deploy_docker.md │ │ ├── deploy_gke.md │ │ ├── deploy_toolbox.md │ │ ├── export_telemetry.md │ │ └── toolbox-ui │ │ ├── edit-headers.gif │ │ ├── edit-headers.png │ │ ├── index.md │ │ ├── optional-param-checked.png │ │ ├── optional-param-unchecked.png │ │ ├── run-tool.gif │ │ ├── tools.png │ │ └── toolsets.png │ ├── reference │ │ ├── _index.md │ │ ├── cli.md │ │ └── prebuilt-tools.md │ ├── resources │ │ ├── _index.md │ │ ├── authServices │ │ │ ├── _index.md │ │ │ └── google.md │ │ ├── sources │ │ │ ├── _index.md │ │ │ ├── alloydb-admin.md │ │ │ ├── alloydb-pg.md │ │ │ ├── bigquery.md │ │ │ ├── bigtable.md │ │ │ ├── cassandra.md │ │ │ ├── clickhouse.md │ │ │ ├── cloud-monitoring.md │ │ │ ├── cloud-sql-admin.md │ │ │ ├── cloud-sql-mssql.md │ │ │ ├── cloud-sql-mysql.md │ │ │ ├── cloud-sql-pg.md │ │ │ ├── couchbase.md │ │ │ ├── dataplex.md │ │ │ ├── dgraph.md │ │ │ ├── firebird.md │ │ │ ├── firestore.md │ │ │ ├── http.md │ │ │ ├── looker.md │ │ │ ├── mongodb.md │ │ │ ├── mssql.md │ │ │ ├── mysql.md │ │ │ ├── neo4j.md │ │ │ ├── oceanbase.md │ │ │ ├── oracle.md │ │ │ ├── postgres.md │ │ │ ├── redis.md │ │ │ ├── spanner.md │ │ │ ├── sqlite.md │ │ │ ├── tidb.md │ │ │ ├── trino.md │ │ │ ├── valkey.md │ │ │ └── yugabytedb.md │ │ └── tools │ │ ├── _index.md │ │ ├── alloydb │ │ │ ├── _index.md │ │ │ ├── alloydb-create-cluster.md │ │ │ ├── alloydb-create-instance.md │ │ │ ├── alloydb-create-user.md │ │ │ ├── alloydb-get-cluster.md │ │ │ ├── alloydb-get-instance.md │ │ │ ├── alloydb-get-user.md │ │ │ ├── alloydb-list-clusters.md │ │ │ ├── alloydb-list-instances.md │ │ │ ├── alloydb-list-users.md │ │ │ └── alloydb-wait-for-operation.md │ │ ├── alloydbainl │ │ │ ├── _index.md │ │ │ └── alloydb-ai-nl.md │ │ ├── bigquery │ │ │ ├── _index.md │ │ │ ├── bigquery-analyze-contribution.md │ │ │ ├── bigquery-conversational-analytics.md │ │ │ ├── bigquery-execute-sql.md │ │ │ ├── bigquery-forecast.md │ │ │ ├── bigquery-get-dataset-info.md │ │ │ ├── bigquery-get-table-info.md │ │ │ ├── bigquery-list-dataset-ids.md │ │ │ ├── bigquery-list-table-ids.md │ │ │ ├── bigquery-search-catalog.md │ │ │ └── bigquery-sql.md │ │ ├── bigtable │ │ │ ├── _index.md │ │ │ └── bigtable-sql.md │ │ ├── cassandra │ │ │ ├── _index.md │ │ │ └── cassandra-cql.md │ │ ├── clickhouse │ │ │ ├── _index.md │ │ │ ├── clickhouse-execute-sql.md │ │ │ ├── clickhouse-list-databases.md │ │ │ ├── clickhouse-list-tables.md │ │ │ └── clickhouse-sql.md │ │ ├── cloudmonitoring │ │ │ ├── _index.md │ │ │ └── cloud-monitoring-query-prometheus.md │ │ ├── cloudsql │ │ │ ├── _index.md │ │ │ ├── cloudsqlcreatedatabase.md │ │ │ ├── cloudsqlcreateusers.md │ │ │ ├── cloudsqlgetinstances.md │ │ │ ├── cloudsqllistdatabases.md │ │ │ ├── cloudsqllistinstances.md │ │ │ ├── cloudsqlmssqlcreateinstance.md │ │ │ ├── cloudsqlmysqlcreateinstance.md │ │ │ ├── cloudsqlpgcreateinstances.md │ │ │ └── cloudsqlwaitforoperation.md │ │ ├── couchbase │ │ │ ├── _index.md │ │ │ └── couchbase-sql.md │ │ ├── dataform │ │ │ ├── _index.md │ │ │ └── dataform-compile-local.md │ │ ├── dataplex │ │ │ ├── _index.md │ │ │ ├── dataplex-lookup-entry.md │ │ │ ├── dataplex-search-aspect-types.md │ │ │ └── dataplex-search-entries.md │ │ ├── dgraph │ │ │ ├── _index.md │ │ │ └── dgraph-dql.md │ │ ├── firebird │ │ │ ├── _index.md │ │ │ ├── firebird-execute-sql.md │ │ │ └── firebird-sql.md │ │ ├── firestore │ │ │ ├── _index.md │ │ │ ├── firestore-add-documents.md │ │ │ ├── firestore-delete-documents.md │ │ │ ├── firestore-get-documents.md │ │ │ ├── firestore-get-rules.md │ │ │ ├── firestore-list-collections.md │ │ │ ├── firestore-query-collection.md │ │ │ ├── firestore-query.md │ │ │ ├── firestore-update-document.md │ │ │ └── firestore-validate-rules.md │ │ ├── http │ │ │ ├── _index.md │ │ │ └── http.md │ │ ├── looker │ │ │ ├── _index.md │ │ │ ├── looker-add-dashboard-element.md │ │ │ ├── looker-conversational-analytics.md │ │ │ ├── looker-get-dashboards.md │ │ │ ├── looker-get-dimensions.md │ │ │ ├── looker-get-explores.md │ │ │ ├── looker-get-filters.md │ │ │ ├── looker-get-looks.md │ │ │ ├── looker-get-measures.md │ │ │ ├── looker-get-models.md │ │ │ ├── looker-get-parameters.md │ │ │ ├── looker-health-analyze.md │ │ │ ├── looker-health-pulse.md │ │ │ ├── looker-health-vacuum.md │ │ │ ├── looker-make-dashboard.md │ │ │ ├── looker-make-look.md │ │ │ ├── looker-query-sql.md │ │ │ ├── looker-query-url.md │ │ │ ├── looker-query.md │ │ │ └── looker-run-look.md │ │ ├── mongodb │ │ │ ├── _index.md │ │ │ ├── mongodb-aggregate.md │ │ │ ├── mongodb-delete-many.md │ │ │ ├── mongodb-delete-one.md │ │ │ ├── mongodb-find-one.md │ │ │ ├── mongodb-find.md │ │ │ ├── mongodb-insert-many.md │ │ │ ├── mongodb-insert-one.md │ │ │ ├── mongodb-update-many.md │ │ │ └── mongodb-update-one.md │ │ ├── mssql │ │ │ ├── _index.md │ │ │ ├── mssql-execute-sql.md │ │ │ ├── mssql-list-tables.md │ │ │ └── mssql-sql.md │ │ ├── mysql │ │ │ ├── _index.md │ │ │ ├── mysql-execute-sql.md │ │ │ ├── mysql-list-active-queries.md │ │ │ ├── mysql-list-table-fragmentation.md │ │ │ ├── mysql-list-tables-missing-unique-indexes.md │ │ │ ├── mysql-list-tables.md │ │ │ └── mysql-sql.md │ │ ├── neo4j │ │ │ ├── _index.md │ │ │ ├── neo4j-cypher.md │ │ │ ├── neo4j-execute-cypher.md │ │ │ └── neo4j-schema.md │ │ ├── oceanbase │ │ │ ├── _index.md │ │ │ ├── oceanbase-execute-sql.md │ │ │ └── oceanbase-sql.md │ │ ├── oracle │ │ │ ├── _index.md │ │ │ ├── oracle-execute-sql.md │ │ │ └── oracle-sql.md │ │ ├── postgres │ │ │ ├── _index.md │ │ │ ├── postgres-execute-sql.md │ │ │ ├── postgres-list-active-queries.md │ │ │ ├── postgres-list-available-extensions.md │ │ │ ├── postgres-list-installed-extensions.md │ │ │ ├── postgres-list-tables.md │ │ │ └── postgres-sql.md │ │ ├── redis │ │ │ ├── _index.md │ │ │ └── redis.md │ │ ├── spanner │ │ │ ├── _index.md │ │ │ ├── spanner-execute-sql.md │ │ │ ├── spanner-list-tables.md │ │ │ └── spanner-sql.md │ │ ├── sqlite │ │ │ ├── _index.md │ │ │ ├── sqlite-execute-sql.md │ │ │ └── sqlite-sql.md │ │ ├── tidb │ │ │ ├── _index.md │ │ │ ├── tidb-execute-sql.md │ │ │ └── tidb-sql.md │ │ ├── trino │ │ │ ├── _index.md │ │ │ ├── trino-execute-sql.md │ │ │ └── trino-sql.md │ │ ├── utility │ │ │ ├── _index.md │ │ │ └── wait.md │ │ ├── valkey │ │ │ ├── _index.md │ │ │ └── valkey.md │ │ └── yuagbytedb │ │ ├── _index.md │ │ └── yugabytedb-sql.md │ ├── samples │ │ ├── _index.md │ │ ├── alloydb │ │ │ ├── _index.md │ │ │ ├── ai-nl │ │ │ │ ├── alloydb_ai_nl.ipynb │ │ │ │ └── index.md │ │ │ └── mcp_quickstart.md │ │ ├── bigquery │ │ │ ├── _index.md │ │ │ ├── colab_quickstart_bigquery.ipynb │ │ │ ├── local_quickstart.md │ │ │ └── mcp_quickstart │ │ │ ├── _index.md │ │ │ ├── inspector_tools.png │ │ │ └── inspector.png │ │ └── looker │ │ ├── _index.md │ │ ├── looker_gemini_oauth │ │ │ ├── _index.md │ │ │ ├── authenticated.png │ │ │ ├── authorize.png │ │ │ └── registration.png │ │ ├── looker_gemini.md │ │ └── looker_mcp_inspector │ │ ├── _index.md │ │ ├── inspector_tools.png │ │ └── inspector.png │ └── sdks │ ├── _index.md │ ├── go-sdk.md │ ├── js-sdk.md │ └── python-sdk.md ├── go.mod ├── go.sum ├── internal │ ├── auth │ │ ├── auth.go │ │ └── google │ │ └── google.go │ ├── log │ │ ├── handler.go │ │ ├── log_test.go │ │ ├── log.go │ │ └── logger.go │ ├── prebuiltconfigs │ │ ├── prebuiltconfigs_test.go │ │ ├── prebuiltconfigs.go │ │ └── tools │ │ ├── alloydb-postgres-admin.yaml │ │ ├── alloydb-postgres-observability.yaml │ │ ├── alloydb-postgres.yaml │ │ ├── bigquery.yaml │ │ ├── clickhouse.yaml │ │ ├── cloud-sql-mssql-admin.yaml │ │ ├── cloud-sql-mssql-observability.yaml │ │ ├── cloud-sql-mssql.yaml │ │ ├── cloud-sql-mysql-admin.yaml │ │ ├── cloud-sql-mysql-observability.yaml │ │ ├── cloud-sql-mysql.yaml │ │ ├── cloud-sql-postgres-admin.yaml │ │ ├── cloud-sql-postgres-observability.yaml │ │ ├── cloud-sql-postgres.yaml │ │ ├── dataplex.yaml │ │ ├── firestore.yaml │ │ ├── looker-conversational-analytics.yaml │ │ ├── looker.yaml │ │ ├── mssql.yaml │ │ ├── mysql.yaml │ │ ├── neo4j.yaml │ │ ├── oceanbase.yaml │ │ ├── postgres.yaml │ │ ├── spanner-postgres.yaml │ │ ├── spanner.yaml │ │ └── sqlite.yaml │ ├── server │ │ ├── api_test.go │ │ ├── api.go │ │ ├── common_test.go │ │ ├── config.go │ │ ├── mcp │ │ │ ├── jsonrpc │ │ │ │ ├── jsonrpc_test.go │ │ │ │ └── jsonrpc.go │ │ │ ├── mcp.go │ │ │ ├── util │ │ │ │ └── lifecycle.go │ │ │ ├── v20241105 │ │ │ │ ├── method.go │ │ │ │ └── types.go │ │ │ ├── v20250326 │ │ │ │ ├── method.go │ │ │ │ └── types.go │ │ │ └── v20250618 │ │ │ ├── method.go │ │ │ └── types.go │ │ ├── mcp_test.go │ │ ├── mcp.go │ │ ├── server_test.go │ │ ├── server.go │ │ ├── static │ │ │ ├── assets │ │ │ │ └── mcptoolboxlogo.png │ │ │ ├── css │ │ │ │ └── style.css │ │ │ ├── index.html │ │ │ ├── js │ │ │ │ ├── auth.js │ │ │ │ ├── loadTools.js │ │ │ │ ├── mainContent.js │ │ │ │ ├── navbar.js │ │ │ │ ├── runTool.js │ │ │ │ ├── toolDisplay.js │ │ │ │ ├── tools.js │ │ │ │ └── toolsets.js │ │ │ ├── tools.html │ │ │ └── toolsets.html │ │ ├── web_test.go │ │ └── web.go │ ├── sources │ │ ├── alloydbadmin │ │ │ ├── alloydbadmin_test.go │ │ │ └── alloydbadmin.go │ │ ├── alloydbpg │ │ │ ├── alloydb_pg_test.go │ │ │ └── alloydb_pg.go │ │ ├── bigquery │ │ │ ├── bigquery_test.go │ │ │ └── bigquery.go │ │ ├── bigtable │ │ │ ├── bigtable_test.go │ │ │ └── bigtable.go │ │ ├── cassandra │ │ │ ├── cassandra_test.go │ │ │ └── cassandra.go │ │ ├── clickhouse │ │ │ ├── clickhouse_test.go │ │ │ └── clickhouse.go │ │ ├── cloudmonitoring │ │ │ ├── cloud_monitoring_test.go │ │ │ └── cloud_monitoring.go │ │ ├── cloudsqladmin │ │ │ ├── cloud_sql_admin_test.go │ │ │ └── cloud_sql_admin.go │ │ ├── cloudsqlmssql │ │ │ ├── cloud_sql_mssql_test.go │ │ │ └── cloud_sql_mssql.go │ │ ├── cloudsqlmysql │ │ │ ├── cloud_sql_mysql_test.go │ │ │ └── cloud_sql_mysql.go │ │ ├── cloudsqlpg │ │ │ ├── cloud_sql_pg_test.go │ │ │ └── cloud_sql_pg.go │ │ ├── couchbase │ │ │ ├── couchbase_test.go │ │ │ └── couchbase.go │ │ ├── dataplex │ │ │ ├── dataplex_test.go │ │ │ └── dataplex.go │ │ ├── dgraph │ │ │ ├── dgraph_test.go │ │ │ └── dgraph.go │ │ ├── dialect.go │ │ ├── firebird │ │ │ ├── firebird_test.go │ │ │ └── firebird.go │ │ ├── firestore │ │ │ ├── firestore_test.go │ │ │ └── firestore.go │ │ ├── http │ │ │ ├── http_test.go │ │ │ └── http.go │ │ ├── ip_type.go │ │ ├── looker │ │ │ ├── looker_test.go │ │ │ └── looker.go │ │ ├── mongodb │ │ │ ├── mongodb_test.go │ │ │ └── mongodb.go │ │ ├── mssql │ │ │ ├── mssql_test.go │ │ │ └── mssql.go │ │ ├── mysql │ │ │ ├── mysql_test.go │ │ │ └── mysql.go │ │ ├── neo4j │ │ │ ├── neo4j_test.go │ │ │ └── neo4j.go │ │ ├── oceanbase │ │ │ ├── oceanbase_test.go │ │ │ └── oceanbase.go │ │ ├── oracle │ │ │ └── oracle.go │ │ ├── postgres │ │ │ ├── postgres_test.go │ │ │ └── postgres.go │ │ ├── redis │ │ │ ├── redis_test.go │ │ │ └── redis.go │ │ ├── sources.go │ │ ├── spanner │ │ │ ├── spanner_test.go │ │ │ └── spanner.go │ │ ├── sqlite │ │ │ ├── sqlite_test.go │ │ │ └── sqlite.go │ │ ├── tidb │ │ │ ├── tidb_test.go │ │ │ └── tidb.go │ │ ├── trino │ │ │ ├── trino_test.go │ │ │ └── trino.go │ │ ├── util.go │ │ ├── valkey │ │ │ ├── valkey_test.go │ │ │ └── valkey.go │ │ └── yugabytedb │ │ ├── yugabytedb_test.go │ │ └── yugabytedb.go │ ├── telemetry │ │ ├── instrumentation.go │ │ └── telemetry.go │ ├── testutils │ │ └── testutils.go │ ├── tools │ │ ├── alloydb │ │ │ ├── alloydbcreatecluster │ │ │ │ ├── alloydbcreatecluster_test.go │ │ │ │ └── alloydbcreatecluster.go │ │ │ ├── alloydbcreateinstance │ │ │ │ ├── alloydbcreateinstance_test.go │ │ │ │ └── alloydbcreateinstance.go │ │ │ ├── alloydbcreateuser │ │ │ │ ├── alloydbcreateuser_test.go │ │ │ │ └── alloydbcreateuser.go │ │ │ ├── alloydbgetcluster │ │ │ │ ├── alloydbgetcluster_test.go │ │ │ │ └── alloydbgetcluster.go │ │ │ ├── alloydbgetinstance │ │ │ │ ├── alloydbgetinstance_test.go │ │ │ │ └── alloydbgetinstance.go │ │ │ ├── alloydbgetuser │ │ │ │ ├── alloydbgetuser_test.go │ │ │ │ └── alloydbgetuser.go │ │ │ ├── alloydblistclusters │ │ │ │ ├── alloydblistclusters_test.go │ │ │ │ └── alloydblistclusters.go │ │ │ ├── alloydblistinstances │ │ │ │ ├── alloydblistinstances_test.go │ │ │ │ └── alloydblistinstances.go │ │ │ ├── alloydblistusers │ │ │ │ ├── alloydblistusers_test.go │ │ │ │ └── alloydblistusers.go │ │ │ └── alloydbwaitforoperation │ │ │ ├── alloydbwaitforoperation_test.go │ │ │ └── alloydbwaitforoperation.go │ │ ├── alloydbainl │ │ │ ├── alloydbainl_test.go │ │ │ └── alloydbainl.go │ │ ├── bigquery │ │ │ ├── bigqueryanalyzecontribution │ │ │ │ ├── bigqueryanalyzecontribution_test.go │ │ │ │ └── bigqueryanalyzecontribution.go │ │ │ ├── bigquerycommon │ │ │ │ ├── table_name_parser_test.go │ │ │ │ ├── table_name_parser.go │ │ │ │ └── util.go │ │ │ ├── bigqueryconversationalanalytics │ │ │ │ ├── bigqueryconversationalanalytics_test.go │ │ │ │ └── bigqueryconversationalanalytics.go │ │ │ ├── bigqueryexecutesql │ │ │ │ ├── bigqueryexecutesql_test.go │ │ │ │ └── bigqueryexecutesql.go │ │ │ ├── bigqueryforecast │ │ │ │ ├── bigqueryforecast_test.go │ │ │ │ └── bigqueryforecast.go │ │ │ ├── bigquerygetdatasetinfo │ │ │ │ ├── bigquerygetdatasetinfo_test.go │ │ │ │ └── bigquerygetdatasetinfo.go │ │ │ ├── bigquerygettableinfo │ │ │ │ ├── bigquerygettableinfo_test.go │ │ │ │ └── bigquerygettableinfo.go │ │ │ ├── bigquerylistdatasetids │ │ │ │ ├── bigquerylistdatasetids_test.go │ │ │ │ └── bigquerylistdatasetids.go │ │ │ ├── bigquerylisttableids │ │ │ │ ├── bigquerylisttableids_test.go │ │ │ │ └── bigquerylisttableids.go │ │ │ ├── bigquerysearchcatalog │ │ │ │ ├── bigquerysearchcatalog_test.go │ │ │ │ └── bigquerysearchcatalog.go │ │ │ └── bigquerysql │ │ │ ├── bigquerysql_test.go │ │ │ └── bigquerysql.go │ │ ├── bigtable │ │ │ ├── bigtable_test.go │ │ │ └── bigtable.go │ │ ├── cassandra │ │ │ └── cassandracql │ │ │ ├── cassandracql_test.go │ │ │ └── cassandracql.go │ │ ├── clickhouse │ │ │ ├── clickhouseexecutesql │ │ │ │ ├── clickhouseexecutesql_test.go │ │ │ │ └── clickhouseexecutesql.go │ │ │ ├── clickhouselistdatabases │ │ │ │ ├── clickhouselistdatabases_test.go │ │ │ │ └── clickhouselistdatabases.go │ │ │ ├── clickhouselisttables │ │ │ │ ├── clickhouselisttables_test.go │ │ │ │ └── clickhouselisttables.go │ │ │ └── clickhousesql │ │ │ ├── clickhousesql_test.go │ │ │ └── clickhousesql.go │ │ ├── cloudmonitoring │ │ │ ├── cloudmonitoring_test.go │ │ │ └── cloudmonitoring.go │ │ ├── cloudsql │ │ │ ├── cloudsqlcreatedatabase │ │ │ │ ├── cloudsqlcreatedatabase_test.go │ │ │ │ └── cloudsqlcreatedatabase.go │ │ │ ├── cloudsqlcreateusers │ │ │ │ ├── cloudsqlcreateusers_test.go │ │ │ │ └── cloudsqlcreateusers.go │ │ │ ├── cloudsqlgetinstances │ │ │ │ ├── cloudsqlgetinstances_test.go │ │ │ │ └── cloudsqlgetinstances.go │ │ │ ├── cloudsqllistdatabases │ │ │ │ ├── cloudsqllistdatabases_test.go │ │ │ │ └── cloudsqllistdatabases.go │ │ │ ├── cloudsqllistinstances │ │ │ │ ├── cloudsqllistinstances_test.go │ │ │ │ └── cloudsqllistinstances.go │ │ │ └── cloudsqlwaitforoperation │ │ │ ├── cloudsqlwaitforoperation_test.go │ │ │ └── cloudsqlwaitforoperation.go │ │ ├── cloudsqlmssql │ │ │ └── cloudsqlmssqlcreateinstance │ │ │ ├── cloudsqlmssqlcreateinstance_test.go │ │ │ └── cloudsqlmssqlcreateinstance.go │ │ ├── cloudsqlmysql │ │ │ └── cloudsqlmysqlcreateinstance │ │ │ ├── cloudsqlmysqlcreateinstance_test.go │ │ │ └── cloudsqlmysqlcreateinstance.go │ │ ├── cloudsqlpg │ │ │ └── cloudsqlpgcreateinstances │ │ │ ├── cloudsqlpgcreateinstances_test.go │ │ │ └── cloudsqlpgcreateinstances.go │ │ ├── common_test.go │ │ ├── common.go │ │ ├── couchbase │ │ │ ├── couchbase_test.go │ │ │ └── couchbase.go │ │ ├── dataform │ │ │ └── dataformcompilelocal │ │ │ ├── dataformcompilelocal_test.go │ │ │ └── dataformcompilelocal.go │ │ ├── dataplex │ │ │ ├── dataplexlookupentry │ │ │ │ ├── dataplexlookupentry_test.go │ │ │ │ └── dataplexlookupentry.go │ │ │ ├── dataplexsearchaspecttypes │ │ │ │ ├── dataplexsearchaspecttypes_test.go │ │ │ │ └── dataplexsearchaspecttypes.go │ │ │ └── dataplexsearchentries │ │ │ ├── dataplexsearchentries_test.go │ │ │ └── dataplexsearchentries.go │ │ ├── dgraph │ │ │ ├── dgraph_test.go │ │ │ └── dgraph.go │ │ ├── firebird │ │ │ ├── firebirdexecutesql │ │ │ │ ├── firebirdexecutesql_test.go │ │ │ │ └── firebirdexecutesql.go │ │ │ └── firebirdsql │ │ │ ├── firebirdsql_test.go │ │ │ └── firebirdsql.go │ │ ├── firestore │ │ │ ├── firestoreadddocuments │ │ │ │ ├── firestoreadddocuments_test.go │ │ │ │ └── firestoreadddocuments.go │ │ │ ├── firestoredeletedocuments │ │ │ │ ├── firestoredeletedocuments_test.go │ │ │ │ └── firestoredeletedocuments.go │ │ │ ├── firestoregetdocuments │ │ │ │ ├── firestoregetdocuments_test.go │ │ │ │ └── firestoregetdocuments.go │ │ │ ├── firestoregetrules │ │ │ │ ├── firestoregetrules_test.go │ │ │ │ └── firestoregetrules.go │ │ │ ├── firestorelistcollections │ │ │ │ ├── firestorelistcollections_test.go │ │ │ │ └── firestorelistcollections.go │ │ │ ├── firestorequery │ │ │ │ ├── firestorequery_test.go │ │ │ │ └── firestorequery.go │ │ │ ├── firestorequerycollection │ │ │ │ ├── firestorequerycollection_test.go │ │ │ │ └── firestorequerycollection.go │ │ │ ├── firestoreupdatedocument │ │ │ │ ├── firestoreupdatedocument_test.go │ │ │ │ └── firestoreupdatedocument.go │ │ │ ├── firestorevalidaterules │ │ │ │ ├── firestorevalidaterules_test.go │ │ │ │ └── firestorevalidaterules.go │ │ │ └── util │ │ │ ├── converter_test.go │ │ │ ├── converter.go │ │ │ ├── validator_test.go │ │ │ └── validator.go │ │ ├── http │ │ │ ├── http_test.go │ │ │ └── http.go │ │ ├── http_method.go │ │ ├── looker │ │ │ ├── lookeradddashboardelement │ │ │ │ ├── lookeradddashboardelement_test.go │ │ │ │ └── lookeradddashboardelement.go │ │ │ ├── lookercommon │ │ │ │ ├── lookercommon_test.go │ │ │ │ └── lookercommon.go │ │ │ ├── lookerconversationalanalytics │ │ │ │ ├── lookerconversationalanalytics_test.go │ │ │ │ └── lookerconversationalanalytics.go │ │ │ ├── lookergetdashboards │ │ │ │ ├── lookergetdashboards_test.go │ │ │ │ └── lookergetdashboards.go │ │ │ ├── lookergetdimensions │ │ │ │ ├── lookergetdimensions_test.go │ │ │ │ └── lookergetdimensions.go │ │ │ ├── lookergetexplores │ │ │ │ ├── lookergetexplores_test.go │ │ │ │ └── lookergetexplores.go │ │ │ ├── lookergetfilters │ │ │ │ ├── lookergetfilters_test.go │ │ │ │ └── lookergetfilters.go │ │ │ ├── lookergetlooks │ │ │ │ ├── lookergetlooks_test.go │ │ │ │ └── lookergetlooks.go │ │ │ ├── lookergetmeasures │ │ │ │ ├── lookergetmeasures_test.go │ │ │ │ └── lookergetmeasures.go │ │ │ ├── lookergetmodels │ │ │ │ ├── lookergetmodels_test.go │ │ │ │ └── lookergetmodels.go │ │ │ ├── lookergetparameters │ │ │ │ ├── lookergetparameters_test.go │ │ │ │ └── lookergetparameters.go │ │ │ ├── lookerhealthanalyze │ │ │ │ ├── lookerhealthanalyze_test.go │ │ │ │ └── lookerhealthanalyze.go │ │ │ ├── lookerhealthpulse │ │ │ │ ├── lookerhealthpulse_test.go │ │ │ │ └── lookerhealthpulse.go │ │ │ ├── lookerhealthvacuum │ │ │ │ ├── lookerhealthvacuum_test.go │ │ │ │ └── lookerhealthvacuum.go │ │ │ ├── lookermakedashboard │ │ │ │ ├── lookermakedashboard_test.go │ │ │ │ └── lookermakedashboard.go │ │ │ ├── lookermakelook │ │ │ │ ├── lookermakelook_test.go │ │ │ │ └── lookermakelook.go │ │ │ ├── lookerquery │ │ │ │ ├── lookerquery_test.go │ │ │ │ └── lookerquery.go │ │ │ ├── lookerquerysql │ │ │ │ ├── lookerquerysql_test.go │ │ │ │ └── lookerquerysql.go │ │ │ ├── lookerqueryurl │ │ │ │ ├── lookerqueryurl_test.go │ │ │ │ └── lookerqueryurl.go │ │ │ └── lookerrunlook │ │ │ ├── lookerrunlook_test.go │ │ │ └── lookerrunlook.go │ │ ├── mongodb │ │ │ ├── mongodbaggregate │ │ │ │ ├── mongodbaggregate_test.go │ │ │ │ └── mongodbaggregate.go │ │ │ ├── mongodbdeletemany │ │ │ │ ├── mongodbdeletemany_test.go │ │ │ │ └── mongodbdeletemany.go │ │ │ ├── mongodbdeleteone │ │ │ │ ├── mongodbdeleteone_test.go │ │ │ │ └── mongodbdeleteone.go │ │ │ ├── mongodbfind │ │ │ │ ├── mongodbfind_test.go │ │ │ │ └── mongodbfind.go │ │ │ ├── mongodbfindone │ │ │ │ ├── mongodbfindone_test.go │ │ │ │ └── mongodbfindone.go │ │ │ ├── mongodbinsertmany │ │ │ │ ├── mongodbinsertmany_test.go │ │ │ │ └── mongodbinsertmany.go │ │ │ ├── mongodbinsertone │ │ │ │ ├── mongodbinsertone_test.go │ │ │ │ └── mongodbinsertone.go │ │ │ ├── mongodbupdatemany │ │ │ │ ├── mongodbupdatemany_test.go │ │ │ │ └── mongodbupdatemany.go │ │ │ └── mongodbupdateone │ │ │ ├── mongodbupdateone_test.go │ │ │ └── mongodbupdateone.go │ │ ├── mssql │ │ │ ├── mssqlexecutesql │ │ │ │ ├── mssqlexecutesql_test.go │ │ │ │ └── mssqlexecutesql.go │ │ │ ├── mssqllisttables │ │ │ │ ├── mssqllisttables_test.go │ │ │ │ └── mssqllisttables.go │ │ │ └── mssqlsql │ │ │ ├── mssqlsql_test.go │ │ │ └── mssqlsql.go │ │ ├── mysql │ │ │ ├── mysqlcommon │ │ │ │ └── mysqlcommon.go │ │ │ ├── mysqlexecutesql │ │ │ │ ├── mysqlexecutesql_test.go │ │ │ │ └── mysqlexecutesql.go │ │ │ ├── mysqllistactivequeries │ │ │ │ ├── mysqllistactivequeries_test.go │ │ │ │ └── mysqllistactivequeries.go │ │ │ ├── mysqllisttablefragmentation │ │ │ │ ├── mysqllisttablefragmentation_test.go │ │ │ │ └── mysqllisttablefragmentation.go │ │ │ ├── mysqllisttables │ │ │ │ ├── mysqllisttables_test.go │ │ │ │ └── mysqllisttables.go │ │ │ ├── mysqllisttablesmissinguniqueindexes │ │ │ │ ├── mysqllisttablesmissinguniqueindexes_test.go │ │ │ │ └── mysqllisttablesmissinguniqueindexes.go │ │ │ └── mysqlsql │ │ │ ├── mysqlsql_test.go │ │ │ └── mysqlsql.go │ │ ├── neo4j │ │ │ ├── neo4jcypher │ │ │ │ ├── neo4jcypher_test.go │ │ │ │ └── neo4jcypher.go │ │ │ ├── neo4jexecutecypher │ │ │ │ ├── classifier │ │ │ │ │ ├── classifier_test.go │ │ │ │ │ └── classifier.go │ │ │ │ ├── neo4jexecutecypher_test.go │ │ │ │ └── neo4jexecutecypher.go │ │ │ └── neo4jschema │ │ │ ├── cache │ │ │ │ ├── cache_test.go │ │ │ │ └── cache.go │ │ │ ├── helpers │ │ │ │ ├── helpers_test.go │ │ │ │ └── helpers.go │ │ │ ├── neo4jschema_test.go │ │ │ ├── neo4jschema.go │ │ │ └── types │ │ │ └── types.go │ │ ├── oceanbase │ │ │ ├── oceanbaseexecutesql │ │ │ │ ├── oceanbaseexecutesql_test.go │ │ │ │ └── oceanbaseexecutesql.go │ │ │ └── oceanbasesql │ │ │ ├── oceanbasesql_test.go │ │ │ └── oceanbasesql.go │ │ ├── oracle │ │ │ ├── oracleexecutesql │ │ │ │ └── oracleexecutesql.go │ │ │ └── oraclesql │ │ │ └── oraclesql.go │ │ ├── parameters_test.go │ │ ├── parameters.go │ │ ├── postgres │ │ │ ├── postgresexecutesql │ │ │ │ ├── postgresexecutesql_test.go │ │ │ │ └── postgresexecutesql.go │ │ │ ├── postgreslistactivequeries │ │ │ │ ├── postgreslistactivequeries_test.go │ │ │ │ └── postgreslistactivequeries.go │ │ │ ├── postgreslistavailableextensions │ │ │ │ ├── postgreslistavailableextensions_test.go │ │ │ │ └── postgreslistavailableextensions.go │ │ │ ├── postgreslistinstalledextensions │ │ │ │ ├── postgreslistinstalledextensions_test.go │ │ │ │ └── postgreslistinstalledextensions.go │ │ │ ├── postgreslisttables │ │ │ │ ├── postgreslisttables_test.go │ │ │ │ └── postgreslisttables.go │ │ │ └── postgressql │ │ │ ├── postgressql_test.go │ │ │ └── postgressql.go │ │ ├── redis │ │ │ ├── redis_test.go │ │ │ └── redis.go │ │ ├── spanner │ │ │ ├── spannerexecutesql │ │ │ │ ├── spannerexecutesql_test.go │ │ │ │ └── spannerexecutesql.go │ │ │ ├── spannerlisttables │ │ │ │ ├── spannerlisttables_test.go │ │ │ │ └── spannerlisttables.go │ │ │ └── spannersql │ │ │ ├── spanner_test.go │ │ │ └── spannersql.go │ │ ├── sqlite │ │ │ ├── sqliteexecutesql │ │ │ │ ├── sqliteexecutesql_test.go │ │ │ │ └── sqliteexecutesql.go │ │ │ └── sqlitesql │ │ │ ├── sqlitesql_test.go │ │ │ └── sqlitesql.go │ │ ├── tidb │ │ │ ├── tidbexecutesql │ │ │ │ ├── tidbexecutesql_test.go │ │ │ │ └── tidbexecutesql.go │ │ │ └── tidbsql │ │ │ ├── tidbsql_test.go │ │ │ └── tidbsql.go │ │ ├── tools_test.go │ │ ├── tools.go │ │ ├── toolsets.go │ │ ├── trino │ │ │ ├── trinoexecutesql │ │ │ │ ├── trinoexecutesql_test.go │ │ │ │ └── trinoexecutesql.go │ │ │ └── trinosql │ │ │ ├── trinosql_test.go │ │ │ └── trinosql.go │ │ ├── utility │ │ │ └── wait │ │ │ ├── wait_test.go │ │ │ └── wait.go │ │ ├── valkey │ │ │ ├── valkey_test.go │ │ │ └── valkey.go │ │ └── yugabytedbsql │ │ ├── yugabytedbsql_test.go │ │ └── yugabytedbsql.go │ └── util │ └── util.go ├── LICENSE ├── logo.png ├── main.go ├── README.md └── tests ├── alloydb │ ├── alloydb_integration_test.go │ └── alloydb_wait_for_operation_test.go ├── alloydbainl │ └── alloydb_ai_nl_integration_test.go ├── alloydbpg │ └── alloydb_pg_integration_test.go ├── auth.go ├── bigquery │ └── bigquery_integration_test.go ├── bigtable │ └── bigtable_integration_test.go ├── cassandra │ └── cassandra_integration_test.go ├── clickhouse │ └── clickhouse_integration_test.go ├── cloudmonitoring │ └── cloud_monitoring_integration_test.go ├── cloudsql │ ├── cloud_sql_create_database_test.go │ ├── cloud_sql_create_users_test.go │ ├── cloud_sql_get_instances_test.go │ ├── cloud_sql_list_databases_test.go │ ├── cloudsql_list_instances_test.go │ └── cloudsql_wait_for_operation_test.go ├── cloudsqlmssql │ ├── cloud_sql_mssql_create_instance_integration_test.go │ └── cloud_sql_mssql_integration_test.go ├── cloudsqlmysql │ ├── cloud_sql_mysql_create_instance_integration_test.go │ └── cloud_sql_mysql_integration_test.go ├── cloudsqlpg │ ├── cloud_sql_pg_create_instances_test.go │ └── cloud_sql_pg_integration_test.go ├── common.go ├── couchbase │ └── couchbase_integration_test.go ├── dataform │ └── dataform_integration_test.go ├── dataplex │ └── dataplex_integration_test.go ├── dgraph │ └── dgraph_integration_test.go ├── firebird │ └── firebird_integration_test.go ├── firestore │ └── firestore_integration_test.go ├── http │ └── http_integration_test.go ├── looker │ └── looker_integration_test.go ├── mongodb │ └── mongodb_integration_test.go ├── mssql │ └── mssql_integration_test.go ├── mysql │ └── mysql_integration_test.go ├── neo4j │ └── neo4j_integration_test.go ├── oceanbase │ └── oceanbase_integration_test.go ├── option.go ├── oracle │ └── oracle_integration_test.go ├── postgres │ └── postgres_integration_test.go ├── redis │ └── redis_test.go ├── server.go ├── source.go ├── spanner │ └── spanner_integration_test.go ├── sqlite │ └── sqlite_integration_test.go ├── tidb │ └── tidb_integration_test.go ├── tool.go ├── trino │ └── trino_integration_test.go ├── utility │ └── wait_integration_test.go ├── valkey │ └── valkey_test.go └── yugabytedb └── yugabytedb_integration_test.go ``` # Files -------------------------------------------------------------------------------- /internal/tools/redis/redis_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package redis_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools" 25 | "github.com/googleapis/genai-toolbox/internal/tools/redis" 26 | ) 27 | 28 | func TestParseFromYamlRedis(t *testing.T) { 29 | ctx, err := testutils.ContextWithNewLogger() 30 | if err != nil { 31 | t.Fatalf("unexpected error: %s", err) 32 | } 33 | tcs := []struct { 34 | desc string 35 | in string 36 | want server.ToolConfigs 37 | }{ 38 | { 39 | desc: "basic example", 40 | in: ` 41 | tools: 42 | redis_tool: 43 | kind: redis 44 | source: my-redis-instance 45 | description: some description 46 | commands: 47 | - [SET, greeting, "hello, {{.name}}"] 48 | - [GET, id] 49 | parameters: 50 | - name: name 51 | type: string 52 | description: user name 53 | `, 54 | want: server.ToolConfigs{ 55 | "redis_tool": redis.Config{ 56 | Name: "redis_tool", 57 | Kind: "redis", 58 | Source: "my-redis-instance", 59 | Description: "some description", 60 | AuthRequired: []string{}, 61 | Commands: [][]string{{"SET", "greeting", "hello, {{.name}}"}, {"GET", "id"}}, 62 | Parameters: []tools.Parameter{ 63 | tools.NewStringParameter("name", "user name"), 64 | }, 65 | }, 66 | }, 67 | }, 68 | } 69 | for _, tc := range tcs { 70 | t.Run(tc.desc, func(t *testing.T) { 71 | got := struct { 72 | Tools server.ToolConfigs `yaml:"tools"` 73 | }{} 74 | // Parse contents 75 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 76 | if err != nil { 77 | t.Fatalf("unable to unmarshal: %s", err) 78 | } 79 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 80 | t.Fatalf("incorrect parse: diff %v", diff) 81 | } 82 | }) 83 | } 84 | 85 | } 86 | ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- ```yaml 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # https://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: ✨ Feature Request 16 | description: Suggest an idea for new or improved behavior. 17 | title: "<brief summary of the proposed feature>" 18 | labels: ["type: feature request"] 19 | type: feature 20 | body: 21 | - type: markdown 22 | attributes: 23 | value: | 24 | Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your feature request. 25 | 26 | - id: preamble 27 | type: checkboxes 28 | attributes: 29 | label: Prerequisites 30 | description: | 31 | Please run through the following list and make sure you've tried the usual "quick fixes": 32 | options: 33 | - label: "Search the [current open issues](https://github.com/googleapis/genai-toolbox/issues)" 34 | required: true 35 | 36 | - type: textarea 37 | id: use-case 38 | attributes: 39 | label: What are you trying to do that currently feels hard or impossible? 40 | description: "A clear and concise description of what the end goal for the feature should be -- avoid generalizing and try to provide a specific use-case." 41 | validations: 42 | required: true 43 | 44 | - type: textarea 45 | id: suggested-solution 46 | attributes: 47 | label: Suggested Solution(s) 48 | description: "If you have a suggestion for how this use-case can be solved, please feel free to include it." 49 | 50 | - type: textarea 51 | id: alternatives-considered 52 | attributes: 53 | label: Alternatives Considered 54 | description: "Are there any workaround or third party tools to replicate this behavior? Why would adding this feature be preferred over them?" 55 | 56 | - type: textarea 57 | id: additional-details 58 | attributes: 59 | label: Additional Details 60 | description: "Any additional information we should know? Please reference it here (issues, PRs, descriptions, or screenshots)" 61 | ``` -------------------------------------------------------------------------------- /internal/tools/valkey/valkey_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package valkey_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools" 25 | "github.com/googleapis/genai-toolbox/internal/tools/valkey" 26 | ) 27 | 28 | func TestParseFromYamlvalkey(t *testing.T) { 29 | ctx, err := testutils.ContextWithNewLogger() 30 | if err != nil { 31 | t.Fatalf("unexpected error: %s", err) 32 | } 33 | tcs := []struct { 34 | desc string 35 | in string 36 | want server.ToolConfigs 37 | }{ 38 | { 39 | desc: "basic example", 40 | in: ` 41 | tools: 42 | valkey_tool: 43 | kind: valkey 44 | source: my-valkey-instance 45 | description: some description 46 | commands: 47 | - [SET, greeting, "hello, {{.name}}"] 48 | - [GET, id] 49 | parameters: 50 | - name: name 51 | type: string 52 | description: user name 53 | `, 54 | want: server.ToolConfigs{ 55 | "valkey_tool": valkey.Config{ 56 | Name: "valkey_tool", 57 | Kind: "valkey", 58 | Source: "my-valkey-instance", 59 | Description: "some description", 60 | AuthRequired: []string{}, 61 | Commands: [][]string{{"SET", "greeting", "hello, {{.name}}"}, {"GET", "id"}}, 62 | Parameters: []tools.Parameter{ 63 | tools.NewStringParameter("name", "user name"), 64 | }, 65 | }, 66 | }, 67 | }, 68 | } 69 | for _, tc := range tcs { 70 | t.Run(tc.desc, func(t *testing.T) { 71 | got := struct { 72 | Tools server.ToolConfigs `yaml:"tools"` 73 | }{} 74 | // Parse contents 75 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 76 | if err != nil { 77 | t.Fatalf("unable to unmarshal: %s", err) 78 | } 79 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 80 | t.Fatalf("incorrect parse: diff %v", diff) 81 | } 82 | }) 83 | } 84 | 85 | } 86 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-get-looks.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "looker-get-looks" 3 | type: docs 4 | weight: 1 5 | description: > 6 | "looker-get-looks" searches for saved Looks in a Looker 7 | source. 8 | aliases: 9 | - /resources/tools/looker-get-looks 10 | --- 11 | 12 | ## About 13 | 14 | The `looker-get-looks` tool searches for a saved Look by 15 | name or description. 16 | 17 | It's compatible with the following sources: 18 | 19 | - [looker](../../sources/looker.md) 20 | 21 | `looker-get-looks` takes four parameters, the `title`, `desc`, `limit` 22 | and `offset`. 23 | 24 | Title and description use SQL style wildcards and are case insensitive. 25 | 26 | Limit and offset are used to page through a larger set of matches and 27 | default to 100 and 0. 28 | 29 | ## Example 30 | 31 | ```yaml 32 | tools: 33 | get_looks: 34 | kind: looker-get-looks 35 | source: looker-source 36 | description: | 37 | get_looks Tool 38 | 39 | This tool is used to search for saved looks in a Looker instance. 40 | String search params use case-insensitive matching. String search 41 | params can contain % and '_' as SQL LIKE pattern match wildcard 42 | expressions. example="dan%" will match "danger" and "Danzig" but 43 | not "David" example="D_m%" will match "Damage" and "dump". 44 | 45 | Most search params can accept "IS NULL" and "NOT NULL" as special 46 | expressions to match or exclude (respectively) rows where the 47 | column is null. 48 | 49 | The limit and offset are used to paginate the results. 50 | 51 | The result of the get_looks tool is a list of json objects. 52 | ``` 53 | 54 | ## Reference 55 | 56 | | **field** | **type** | **required** | **description** | 57 | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| 58 | | kind | string | true | Must be "looker-get-looks" | 59 | | source | string | true | Name of the source the SQL should execute on. | 60 | | description | string | true | Description of the tool that is passed to the LLM. | 61 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/clickhouse/clickhouse-list-tables.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "clickhouse-list-tables" 3 | type: docs 4 | weight: 4 5 | description: > 6 | A "clickhouse-list-tables" tool lists all tables in a specific ClickHouse database. 7 | aliases: 8 | - /resources/tools/clickhouse-list-tables 9 | --- 10 | 11 | ## About 12 | 13 | A `clickhouse-list-tables` tool lists all available tables in a specified 14 | ClickHouse database. It's compatible with the [clickhouse](../../sources/clickhouse.md) source. 15 | 16 | This tool executes the `SHOW TABLES FROM <database>` command and returns a list 17 | of all tables in the specified database that are accessible to the configured 18 | user, making it useful for schema exploration and table discovery tasks. 19 | 20 | ## Example 21 | 22 | ```yaml 23 | tools: 24 | list_clickhouse_tables: 25 | kind: clickhouse-list-tables 26 | source: my-clickhouse-instance 27 | description: List all tables in a specific ClickHouse database 28 | ``` 29 | 30 | ## Parameters 31 | 32 | | **parameter** | **type** | **required** | **description** | 33 | |---------------|:--------:|:------------:|---------------------------------------------| 34 | | database | string | true | The database to list tables from. | 35 | 36 | ## Return Value 37 | 38 | The tool returns an array of objects, where each object contains: 39 | - `name`: The name of the table 40 | - `database`: The database the table belongs to 41 | 42 | Example response: 43 | ```json 44 | [ 45 | {"name": "users", "database": "analytics"}, 46 | {"name": "events", "database": "analytics"}, 47 | {"name": "products", "database": "analytics"}, 48 | {"name": "orders", "database": "analytics"} 49 | ] 50 | ``` 51 | 52 | ## Reference 53 | 54 | | **field** | **type** | **required** | **description** | 55 | |--------------------|:------------------:|:------------:|-----------------------------------------------------------| 56 | | kind | string | true | Must be "clickhouse-list-tables". | 57 | | source | string | true | Name of the ClickHouse source to list tables from. | 58 | | description | string | true | Description of the tool that is passed to the LLM. | 59 | | authRequired | array of string | false | Authentication services required to use this tool. | 60 | | parameters | array of Parameter | false | Parameters for the tool (see Parameters section above). | 61 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/mongodb/mongodb-insert-one.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "mongodb-insert-one" 3 | type: docs 4 | weight: 1 5 | description: > 6 | A "mongodb-insert-one" tool inserts a single new document into a MongoDB collection. 7 | aliases: 8 | - /resources/tools/mongodb-insert-one 9 | --- 10 | 11 | ## About 12 | 13 | The `mongodb-insert-one` tool inserts a **single new document** into a specified 14 | MongoDB collection. 15 | 16 | This tool takes one required parameter named `data`, which must be a string 17 | containing the JSON object you want to insert. Upon successful insertion, the 18 | tool returns the unique `_id` of the newly created document. 19 | 20 | This tool is compatible with the following source kind: 21 | 22 | * [`mongodb`](../../sources/mongodb.md) 23 | 24 | ## Example 25 | 26 | Here is an example configuration for a tool that adds a new user to a `users` 27 | collection. 28 | 29 | ```yaml 30 | tools: 31 | create_new_user: 32 | kind: mongodb-insert-one 33 | source: my-mongo-source 34 | description: Creates a new user record in the database. 35 | database: user_data 36 | collection: users 37 | canonical: false 38 | ``` 39 | 40 | An LLM would call this tool by providing the document as a JSON string in the 41 | `data` parameter, like this: 42 | `tool_code: create_new_user(data='{"email": "[email protected]", "name": "Jane Doe", "status": "active"}')` 43 | 44 | ## Reference 45 | 46 | | **field** | **type** | **required** | **description** | 47 | |:------------|:---------|:-------------|:---------------------------------------------------------------------------------------------------| 48 | | kind | string | true | Must be `mongodb-insert-one`. | 49 | | source | string | true | The name of the `mongodb` source to use. | 50 | | description | string | true | A description of the tool that is passed to the LLM. | 51 | | database | string | true | The name of the MongoDB database containing the collection. | 52 | | collection | string | true | The name of the MongoDB collection into which the document will be inserted. | 53 | | canonical | bool | true | Determines if the data string is parsed using MongoDB's Canonical or Relaxed Extended JSON format. | 54 | ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/firebird.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "Firebird" 3 | type: docs 4 | weight: 1 5 | description: > 6 | Firebird is a powerful, cross-platform, and open-source relational database. 7 | 8 | --- 9 | 10 | ## About 11 | 12 | [Firebird][fb-docs] is a relational database management system offering many 13 | ANSI SQL standard features that runs on Linux, Windows, and a variety of Unix 14 | platforms. It is known for its small footprint, powerful features, and easy 15 | maintenance. 16 | 17 | [fb-docs]: https://firebirdsql.org/ 18 | 19 | ## Available Tools 20 | 21 | - [`firebird-sql`](../tools/firebird/firebird-sql.md) 22 | Execute SQL queries as prepared statements in Firebird. 23 | 24 | - [`firebird-execute-sql`](../tools/firebird/firebird-execute-sql.md) 25 | Run parameterized SQL statements in Firebird. 26 | 27 | ## Requirements 28 | 29 | ### Database User 30 | 31 | This source uses standard authentication. You will need to [create a Firebird 32 | user][fb-users] to login to the database with. 33 | 34 | [fb-users]: https://www.firebirdsql.org/refdocs/langrefupd25-security-sql-user-mgmt.html#langrefupd25-security-create-user 35 | 36 | ## Example 37 | 38 | ```yaml 39 | sources: 40 | my_firebird_db: 41 | kind: firebird 42 | host: "localhost" 43 | port: 3050 44 | database: "/path/to/your/database.fdb" 45 | user: ${FIREBIRD_USER} 46 | password: ${FIREBIRD_PASS} 47 | ``` 48 | 49 | {{< notice tip >}} 50 | Use environment variable replacement with the format ${ENV_NAME} 51 | instead of hardcoding your secrets into the configuration file. 52 | {{< /notice >}} 53 | 54 | ## Reference 55 | 56 | | **field** | **type** | **required** | **description** | 57 | |-----------|:--------:|:------------:|------------------------------------------------------------------------------| 58 | | kind | string | true | Must be "firebird". | 59 | | host | string | true | IP address to connect to (e.g. "127.0.0.1") | 60 | | port | string | true | Port to connect to (e.g. "3050") | 61 | | database | string | true | Path to the Firebird database file (e.g. "/var/lib/firebird/data/test.fdb"). | 62 | | user | string | true | Name of the Firebird user to connect as (e.g. "SYSDBA"). | 63 | | password | string | true | Password of the Firebird user (e.g. "masterkey"). | ``` -------------------------------------------------------------------------------- /internal/tools/oceanbase/oceanbasesql/oceanbasesql_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package oceanbasesql_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools" 25 | "github.com/googleapis/genai-toolbox/internal/tools/oceanbase/oceanbasesql" 26 | ) 27 | 28 | // Test parsing OceanBase SQL tool config from YAML. 29 | func TestParseFromYamlOceanBaseSql(t *testing.T) { 30 | ctx, err := testutils.ContextWithNewLogger() 31 | if err != nil { 32 | t.Fatalf("unexpected error: %s", err) 33 | } 34 | tcs := []struct { 35 | desc string 36 | in string 37 | want server.ToolConfigs 38 | }{ 39 | { 40 | desc: "basic example", 41 | in: ` 42 | tools: 43 | example_tool: 44 | kind: oceanbase-sql 45 | source: my-instance 46 | description: some description 47 | statement: select * from t where id = ? 48 | parameters: 49 | - name: id 50 | type: string 51 | description: id param 52 | `, 53 | want: server.ToolConfigs{ 54 | "example_tool": oceanbasesql.Config{ 55 | Name: "example_tool", 56 | Kind: "oceanbase-sql", 57 | Source: "my-instance", 58 | Description: "some description", 59 | Statement: "select * from t where id = ?", 60 | AuthRequired: []string{}, 61 | Parameters: []tools.Parameter{ 62 | tools.NewStringParameter("id", "id param"), 63 | }, 64 | }, 65 | }, 66 | }, 67 | } 68 | for _, tc := range tcs { 69 | t.Run(tc.desc, func(t *testing.T) { 70 | got := struct { 71 | Tools server.ToolConfigs `yaml:"tools"` 72 | }{} 73 | // Parse contents 74 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 75 | if err != nil { 76 | t.Fatalf("unable to unmarshal: %s", err) 77 | } 78 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 79 | t.Fatalf("incorrect parse: diff %v", diff) 80 | } 81 | }) 82 | } 83 | } 84 | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/local_quickstart_go.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "Go Quickstart (Local)" 3 | type: docs 4 | weight: 4 5 | description: > 6 | 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). 7 | --- 8 | 9 | ## Before you begin 10 | 11 | This guide assumes you have already done the following: 12 | 13 | 1. Installed [Go (v1.24.2 or higher)]. 14 | 1. Installed [PostgreSQL 16+ and the `psql` client][install-postgres]. 15 | 16 | [Go (v1.24.2 or higher)]: https://go.dev/doc/install 17 | [install-postgres]: https://www.postgresql.org/download/ 18 | 19 | ### Cloud Setup (Optional) 20 | 21 | {{< regionInclude "quickstart/shared/cloud_setup.md" "cloud_setup" >}} 22 | 23 | ## Step 1: Set up your database 24 | 25 | {{< regionInclude "quickstart/shared/database_setup.md" "database_setup" >}} 26 | 27 | ## Step 2: Install and configure Toolbox 28 | 29 | {{< regionInclude "quickstart/shared/configure_toolbox.md" "configure_toolbox" >}} 30 | 31 | ## Step 3: Connect your agent to Toolbox 32 | 33 | In this section, we will write and run an agent that will load the Tools 34 | from Toolbox. 35 | 36 | 1. Initialize a go module: 37 | 38 | ```bash 39 | go mod init main 40 | ``` 41 | 42 | 1. In a new terminal, install the 43 | [SDK](https://pkg.go.dev/github.com/googleapis/mcp-toolbox-sdk-go). 44 | 45 | ```bash 46 | go get github.com/googleapis/mcp-toolbox-sdk-go 47 | ``` 48 | 49 | 1. Create a new file named `hotelagent.go` and copy the following code to create 50 | an agent: 51 | 52 | {{< tabpane persist=header >}} 53 | {{< tab header="LangChain Go" lang="go" >}} 54 | 55 | {{< include "quickstart/go/langchain/quickstart.go" >}} 56 | 57 | {{< /tab >}} 58 | 59 | {{< tab header="Genkit Go" lang="go" >}} 60 | 61 | {{< include "quickstart/go/genkit/quickstart.go" >}} 62 | 63 | {{< /tab >}} 64 | 65 | {{< tab header="Go GenAI" lang="go" >}} 66 | 67 | {{< include "quickstart/go/genAI/quickstart.go" >}} 68 | 69 | {{< /tab >}} 70 | 71 | {{< tab header="OpenAI Go" lang="go" >}} 72 | 73 | {{< include "quickstart/go/openAI/quickstart.go" >}} 74 | 75 | {{< /tab >}} 76 | {{< /tabpane >}} 77 | 78 | 1. Ensure all dependencies are installed: 79 | 80 | ```sh 81 | go mod tidy 82 | ``` 83 | 84 | 1. Run your agent, and observe the results: 85 | 86 | ```sh 87 | go run hotelagent.go 88 | ``` 89 | 90 | {{< notice info >}} 91 | For more information, visit the [Go SDK 92 | repo](https://github.com/googleapis/mcp-toolbox-sdk-go). 93 | {{</ notice >}} 94 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/bigquery/bigquery-get-table-info.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "bigquery-get-table-info" 3 | type: docs 4 | weight: 1 5 | description: > 6 | A "bigquery-get-table-info" tool retrieves metadata for a BigQuery table. 7 | aliases: 8 | - /resources/tools/bigquery-get-table-info 9 | --- 10 | 11 | ## About 12 | 13 | A `bigquery-get-table-info` tool retrieves metadata for a BigQuery table. 14 | It's compatible with the following sources: 15 | 16 | - [bigquery](../../sources/bigquery.md) 17 | 18 | `bigquery-get-table-info` accepts the following parameters: 19 | - **`table`** (required): The name of the table for which to retrieve metadata. 20 | - **`dataset`** (required): The dataset containing the specified table. 21 | - **`project`** (optional): The Google Cloud project ID. If not provided, the 22 | tool defaults to the project from the source configuration. 23 | 24 | The tool's behavior regarding these parameters is influenced by the 25 | `allowedDatasets` restriction on the `bigquery` source: 26 | - **Without `allowedDatasets` restriction:** The tool can retrieve metadata for 27 | any table specified by the `table`, `dataset`, and `project` parameters. 28 | - **With `allowedDatasets` restriction:** Before retrieving metadata, the tool 29 | verifies that the requested dataset is in the allowed list. If it is not, the 30 | request is denied. If only one dataset is specified in the `allowedDatasets` 31 | list, it will be used as the default value for the `dataset` parameter. 32 | 33 | ## Example 34 | 35 | ```yaml 36 | tools: 37 | bigquery_get_table_info: 38 | kind: bigquery-get-table-info 39 | source: my-bigquery-source 40 | description: Use this tool to get table metadata. 41 | ``` 42 | 43 | ## Reference 44 | 45 | | **field** | **type** | **required** | **description** | 46 | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| 47 | | kind | string | true | Must be "bigquery-get-table-info". | 48 | | source | string | true | Name of the source the SQL should execute on. | 49 | | description | string | true | Description of the tool that is passed to the LLM. | 50 | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/go/quickstart_test.go: -------------------------------------------------------------------------------- ```go 1 | // Licensed under the Apache License, Version 2.0 (the "License"); 2 | // you may not use this file except in compliance with the License. 3 | // You may obtain a copy of the License at 4 | // 5 | // http://www.apache.org/licenses/LICENSE-2.0 6 | // 7 | // Unless required by applicable law or agreed to in writing, software 8 | // distributed under the License is distributed on an "AS IS" BASIS, 9 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | // See the License for the specific language governing permissions and 11 | // limitations under the License. 12 | package main 13 | 14 | import ( 15 | "bytes" 16 | "os" 17 | "os/exec" 18 | "path/filepath" 19 | "strings" 20 | "testing" 21 | ) 22 | 23 | func TestQuickstartSample(t *testing.T) { 24 | framework := os.Getenv("ORCH_NAME") 25 | if framework == "" { 26 | t.Skip("Skipping test: ORCH_NAME environment variable is not set.") 27 | } 28 | 29 | t.Logf("--- Testing: %s ---", framework) 30 | 31 | if framework == "openAI" { 32 | if os.Getenv("OPENAI_API_KEY") == "" { 33 | t.Skip("Skipping test: OPENAI_API_KEY environment variable is not set for openAI framework.") 34 | } 35 | } else { 36 | if os.Getenv("GOOGLE_API_KEY") == "" { 37 | t.Skipf("Skipping test for %s: GOOGLE_API_KEY environment variable is not set.", framework) 38 | } 39 | } 40 | 41 | sampleDir := filepath.Join(".", framework) 42 | if _, err := os.Stat(sampleDir); os.IsNotExist(err) { 43 | t.Fatalf("Test setup failed: directory for framework '%s' not found.", framework) 44 | } 45 | 46 | cmd := exec.Command("go", "run", ".") 47 | cmd.Dir = sampleDir 48 | var stdout, stderr bytes.Buffer 49 | cmd.Stdout = &stdout 50 | cmd.Stderr = &stderr 51 | 52 | err := cmd.Run() 53 | actualOutput := stdout.String() 54 | 55 | if err != nil { 56 | t.Fatalf("Script execution failed with error: %v\n--- STDERR ---\n%s", err, stderr.String()) 57 | } 58 | if len(actualOutput) == 0 { 59 | t.Fatal("Script ran successfully but produced no output.") 60 | } 61 | 62 | goldenFile, err := os.ReadFile("../golden.txt") 63 | if err != nil { 64 | t.Fatalf("Could not read golden.txt to check for keywords: %v", err) 65 | } 66 | 67 | keywords := strings.Split(string(goldenFile), "\n") 68 | var missingKeywords []string 69 | outputLower := strings.ToLower(actualOutput) 70 | 71 | for _, keyword := range keywords { 72 | kw := strings.TrimSpace(keyword) 73 | if kw != "" && !strings.Contains(outputLower, strings.ToLower(kw)) { 74 | missingKeywords = append(missingKeywords, kw) 75 | } 76 | } 77 | 78 | if len(missingKeywords) > 0 { 79 | t.Fatalf("FAIL: The following keywords were missing from the output: [%s]", strings.Join(missingKeywords, ", ")) 80 | } 81 | } 82 | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/configure.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "Configuration" 3 | type: docs 4 | weight: 6 5 | description: > 6 | How to configure Toolbox's tools.yaml file. 7 | --- 8 | 9 | The primary way to configure Toolbox is through the `tools.yaml` file. If you 10 | have multiple files, you can tell toolbox which to load with the `--tools-file 11 | tools.yaml` flag. 12 | 13 | You can find more detailed reference documentation to all resource types in the 14 | [Resources](../resources/). 15 | 16 | ### Using Environment Variables 17 | 18 | To avoid hardcoding certain secret fields like passwords, usernames, API keys 19 | etc., you could use environment variables instead with the format `${ENV_NAME}`. 20 | 21 | ```yaml 22 | user: ${USER_NAME} 23 | password: ${PASSWORD} 24 | ``` 25 | 26 | A default value can be specified like `${ENV_NAME:default}`. 27 | 28 | ```yaml 29 | port: ${DB_PORT:3306} 30 | ``` 31 | 32 | ### Sources 33 | 34 | The `sources` section of your `tools.yaml` defines what data sources your 35 | Toolbox should have access to. Most tools will have at least one source to 36 | execute against. 37 | 38 | ```yaml 39 | sources: 40 | my-pg-source: 41 | kind: postgres 42 | host: 127.0.0.1 43 | port: 5432 44 | database: toolbox_db 45 | user: ${USER_NAME} 46 | password: ${PASSWORD} 47 | ``` 48 | 49 | For more details on configuring different types of sources, see the 50 | [Sources](../resources/sources/). 51 | 52 | ### Tools 53 | 54 | The `tools` section of your `tools.yaml` defines the actions your agent can 55 | take: what kind of tool it is, which source(s) it affects, what parameters it 56 | uses, etc. 57 | 58 | ```yaml 59 | tools: 60 | search-hotels-by-name: 61 | kind: postgres-sql 62 | source: my-pg-source 63 | description: Search for hotels based on name. 64 | parameters: 65 | - name: name 66 | type: string 67 | description: The name of the hotel. 68 | statement: SELECT * FROM hotels WHERE name ILIKE '%' || $1 || '%'; 69 | ``` 70 | 71 | For more details on configuring different types of tools, see the 72 | [Tools](../resources/tools/). 73 | 74 | ### Toolsets 75 | 76 | The `toolsets` section of your `tools.yaml` allows you to define groups of tools 77 | that you want to be able to load together. This can be useful for defining 78 | different sets for different agents or different applications. 79 | 80 | ```yaml 81 | toolsets: 82 | my_first_toolset: 83 | - my_first_tool 84 | - my_second_tool 85 | my_second_toolset: 86 | - my_second_tool 87 | - my_third_tool 88 | ``` 89 | 90 | You can load toolsets by name: 91 | 92 | ```python 93 | # This will load all tools 94 | all_tools = client.load_toolset() 95 | 96 | # This will only load the tools listed in 'my_second_toolset' 97 | my_second_toolset = client.load_toolset("my_second_toolset") 98 | ``` 99 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-get-dashboards.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "looker-get-dashboards" 3 | type: docs 4 | weight: 1 5 | description: > 6 | "looker-get-dashboards" tool searches for a saved Dashboard by name or description. 7 | aliases: 8 | - /resources/tools/looker-get-dashboards 9 | --- 10 | 11 | ## About 12 | 13 | The `looker-get-dashboards` tool searches for a saved Dashboard by 14 | name or description. 15 | 16 | It's compatible with the following sources: 17 | 18 | - [looker](../../sources/looker.md) 19 | 20 | `looker-get-dashboards` takes four parameters, the `title`, `desc`, `limit` 21 | and `offset`. 22 | 23 | Title and description use SQL style wildcards and are case insensitive. 24 | 25 | Limit and offset are used to page through a larger set of matches and 26 | default to 100 and 0. 27 | 28 | ## Example 29 | 30 | ```yaml 31 | tools: 32 | get_dashboards: 33 | kind: looker-get-dashboards 34 | source: looker-source 35 | description: | 36 | get_dashboards Tool 37 | 38 | This tool is used to search for saved dashboards in a Looker instance. 39 | String search params use case-insensitive matching. String search 40 | params can contain % and '_' as SQL LIKE pattern match wildcard 41 | expressions. example="dan%" will match "danger" and "Danzig" but 42 | not "David" example="D_m%" will match "Damage" and "dump". 43 | 44 | Most search params can accept "IS NULL" and "NOT NULL" as special 45 | expressions to match or exclude (respectively) rows where the 46 | column is null. 47 | 48 | The limit and offset are used to paginate the results. 49 | 50 | The result of the get_dashboards tool is a list of json objects. 51 | ``` 52 | 53 | ## Reference 54 | 55 | | **field** | **type** | **required** | **description** | 56 | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| 57 | | kind | string | true | Must be "looker-get-dashboards" | 58 | | source | string | true | Name of the source the SQL should execute on. | 59 | | description | string | true | Description of the tool that is passed to the LLM. | 60 | ``` -------------------------------------------------------------------------------- /internal/prebuiltconfigs/tools/bigquery.yaml: -------------------------------------------------------------------------------- ```yaml 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | sources: 16 | bigquery-source: 17 | kind: "bigquery" 18 | project: ${BIGQUERY_PROJECT} 19 | location: ${BIGQUERY_LOCATION:} 20 | useClientOAuth: ${BIGQUERY_USE_CLIENT_OAUTH:false} 21 | 22 | tools: 23 | analyze_contribution: 24 | kind: bigquery-analyze-contribution 25 | source: bigquery-source 26 | description: Use this tool to analyze the contribution about changes to key metrics in multi-dimensional data. 27 | 28 | ask_data_insights: 29 | kind: bigquery-conversational-analytics 30 | source: bigquery-source 31 | description: | 32 | Use this tool to perform data analysis, get insights, 33 | or answer complex questions about the contents of specific 34 | BigQuery tables. 35 | 36 | execute_sql: 37 | kind: bigquery-execute-sql 38 | source: bigquery-source 39 | description: Use this tool to execute sql statement. 40 | 41 | forecast: 42 | kind: bigquery-forecast 43 | source: bigquery-source 44 | description: Use this tool to forecast time series data. 45 | 46 | get_dataset_info: 47 | kind: bigquery-get-dataset-info 48 | source: bigquery-source 49 | description: Use this tool to get dataset metadata. 50 | 51 | get_table_info: 52 | kind: bigquery-get-table-info 53 | source: bigquery-source 54 | description: Use this tool to get table metadata. 55 | 56 | list_dataset_ids: 57 | kind: bigquery-list-dataset-ids 58 | source: bigquery-source 59 | description: Use this tool to list datasets. 60 | 61 | list_table_ids: 62 | kind: bigquery-list-table-ids 63 | source: bigquery-source 64 | description: Use this tool to list tables. 65 | 66 | search_catalog: 67 | kind: bigquery-search-catalog 68 | source: bigquery-source 69 | description: Use this tool to find tables, views, models, routines or connections. 70 | 71 | toolsets: 72 | bigquery_database_tools: 73 | - analyze_contribution 74 | - ask_data_insights 75 | - execute_sql 76 | - forecast 77 | - get_dataset_info 78 | - get_table_info 79 | - list_dataset_ids 80 | - list_table_ids 81 | - search_catalog 82 | ``` -------------------------------------------------------------------------------- /.github/workflows/docs_deploy.yaml: -------------------------------------------------------------------------------- ```yaml 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: "docs" 16 | 17 | permissions: 18 | contents: write 19 | 20 | on: 21 | push: 22 | branches: 23 | - main 24 | paths: 25 | - 'docs/**' 26 | - 'github/workflows/docs**' 27 | - '.hugo/**' 28 | 29 | # Allow triggering manually. 30 | workflow_dispatch: 31 | 32 | jobs: 33 | deploy: 34 | runs-on: ubuntu-24.04 35 | defaults: 36 | run: 37 | working-directory: .hugo 38 | concurrency: 39 | group: ${{ github.workflow }}-${{ github.ref }} 40 | cancel-in-progress: true 41 | steps: 42 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 43 | with: 44 | fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod 45 | 46 | - name: Setup Hugo 47 | uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3 48 | with: 49 | hugo-version: "0.145.0" 50 | extended: true 51 | 52 | - name: Setup Node 53 | uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5 54 | with: 55 | node-version: "22" 56 | 57 | - name: Cache dependencies 58 | uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 59 | with: 60 | path: ~/.npm 61 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 62 | restore-keys: | 63 | ${{ runner.os }}-node- 64 | 65 | - run: npm ci 66 | - run: hugo --minify 67 | env: 68 | HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/ 69 | HUGO_RELATIVEURLS: false 70 | 71 | - name: Deploy 72 | uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4 73 | with: 74 | github_token: ${{ secrets.GITHUB_TOKEN }} 75 | publish_dir: .hugo/public 76 | # Do not delete previews on each production deploy. 77 | # CSS or JS changes will require manual clean-up. 78 | keep_files: true 79 | commit_message: "deploy: ${{ github.event.head_commit.message }}" 80 | ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/sqlite.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "SQLite" 3 | linkTitle: "SQLite" 4 | type: docs 5 | weight: 1 6 | description: > 7 | SQLite is a C-language library that implements a small, fast, self-contained, 8 | high-reliability, full-featured, SQL database engine. 9 | --- 10 | 11 | ## About 12 | 13 | [SQLite](https://sqlite.org/) is a software library that provides a relational 14 | database management system. The lite in SQLite means lightweight in terms of 15 | setup, database administration, and required resources. 16 | 17 | SQLite has the following notable characteristics: 18 | 19 | - Self-contained with no external dependencies 20 | - Serverless - the SQLite library accesses its storage files directly 21 | - Single database file that can be easily copied or moved 22 | - Zero-configuration - no setup or administration needed 23 | - Transactional with ACID properties 24 | 25 | ## Available Tools 26 | 27 | - [`sqlite-sql`](../tools/sqlite/sqlite-sql.md) 28 | Run SQL queries against a local SQLite database. 29 | 30 | - [`sqlite-execute-sql`](../tools/sqlite/sqlite-execute-sql.md) 31 | Run parameterized SQL statements in SQlite. 32 | 33 | ### Pre-built Configurations 34 | 35 | - [SQLite using MCP](../../how-to/connect-ide/sqlite_mcp.md) 36 | Connect your IDE to SQlite using Toolbox. 37 | 38 | ## Requirements 39 | 40 | ### Database File 41 | 42 | You need a SQLite database file. This can be: 43 | 44 | - An existing database file 45 | - A path where a new database file should be created 46 | - `:memory:` for an in-memory database 47 | 48 | ## Example 49 | 50 | ```yaml 51 | sources: 52 | my-sqlite-db: 53 | kind: "sqlite" 54 | database: "/path/to/database.db" 55 | ``` 56 | 57 | For an in-memory database: 58 | 59 | ```yaml 60 | sources: 61 | my-sqlite-memory-db: 62 | kind: "sqlite" 63 | database: ":memory:" 64 | ``` 65 | 66 | ## Reference 67 | 68 | ### Configuration Fields 69 | 70 | | **field** | **type** | **required** | **description** | 71 | |-----------|:--------:|:------------:|---------------------------------------------------------------------------------------------------------------------| 72 | | kind | string | true | Must be "sqlite". | 73 | | database | string | true | Path to SQLite database file, or ":memory:" for an in-memory database. | 74 | 75 | ### Connection Properties 76 | 77 | SQLite connections are configured with these defaults for optimal performance: 78 | 79 | - `MaxOpenConns`: 1 (SQLite only supports one writer at a time) 80 | - `MaxIdleConns`: 1 81 | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/js/llamaindex/quickstart.js: -------------------------------------------------------------------------------- ```javascript 1 | import { gemini, GEMINI_MODEL } from "@llamaindex/google"; 2 | import { agent } from "@llamaindex/workflow"; 3 | import { createMemory, staticBlock, tool } from "llamaindex"; 4 | import { ToolboxClient } from "@toolbox-sdk/core"; 5 | 6 | const TOOLBOX_URL = "http://127.0.0.1:5000"; // Update if needed 7 | const GOOGLE_API_KEY = process.env.GOOGLE_API_KEY || 'your-api-key'; // Replace it with your API key 8 | 9 | const prompt = ` 10 | 11 | You're a helpful hotel assistant. You handle hotel searching, booking and cancellations. 12 | When the user searches for a hotel, mention its name, id, location and price tier. 13 | Always mention hotel ids while performing any searches — this is very important for operations. 14 | For any bookings or cancellations, please provide the appropriate confirmation. 15 | Update check-in or check-out dates if mentioned by the user. 16 | Don't ask for confirmations from the user. 17 | 18 | `; 19 | 20 | const queries = [ 21 | "Find hotels in Basel with Basel in its name.", 22 | "Can you book the Hilton Basel for me?", 23 | "Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.", 24 | "My check in dates would be from April 10, 2024 to April 19, 2024.", 25 | ]; 26 | 27 | export async function main() { 28 | // Connect to MCP Toolbox 29 | const client = new ToolboxClient(TOOLBOX_URL); 30 | const toolboxTools = await client.loadToolset("my-toolset"); 31 | const tools = toolboxTools.map((toolboxTool) => { 32 | return tool({ 33 | name: toolboxTool.getName(), 34 | description: toolboxTool.getDescription(), 35 | parameters: toolboxTool.getParamSchema(), 36 | execute: toolboxTool, 37 | }); 38 | }); 39 | 40 | // Initialize LLM 41 | const llm = gemini({ 42 | model: GEMINI_MODEL.GEMINI_2_0_FLASH, 43 | apiKey: GOOGLE_API_KEY, 44 | }); 45 | 46 | const memory = createMemory({ 47 | memoryBlocks: [ 48 | staticBlock({ 49 | content: prompt, 50 | }), 51 | ], 52 | }); 53 | 54 | // Create the Agent 55 | const myAgent = agent({ 56 | tools: tools, 57 | llm, 58 | memory, 59 | systemPrompt: prompt, 60 | }); 61 | 62 | for (const query of queries) { 63 | const result = await myAgent.run(query); 64 | const output = result.data.result; 65 | 66 | console.log(`\nUser: ${query}`); 67 | if (typeof output === "string") { 68 | console.log(output.trim()); 69 | } else if (typeof output === "object" && "text" in output) { 70 | console.log(output.text.trim()); 71 | } else { 72 | console.log(JSON.stringify(output)); 73 | } 74 | } 75 | //You may observe some extra logs during execution due to the run method provided by Llama. 76 | console.log("Agent run finished."); 77 | } 78 | 79 | main(); ``` -------------------------------------------------------------------------------- /internal/tools/neo4j/neo4jcypher/neo4jcypher_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package neo4jcypher 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools" 25 | ) 26 | 27 | func TestParseFromYamlNeo4j(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | example_tool: 42 | kind: neo4j-cypher 43 | source: my-neo4j-instance 44 | description: some tool description 45 | authRequired: 46 | - my-google-auth-service 47 | - other-auth-service 48 | statement: | 49 | MATCH (c:Country) WHERE c.name = $country RETURN c.id as id; 50 | parameters: 51 | - name: country 52 | type: string 53 | description: country parameter description 54 | `, 55 | want: server.ToolConfigs{ 56 | "example_tool": Config{ 57 | Name: "example_tool", 58 | Kind: "neo4j-cypher", 59 | Source: "my-neo4j-instance", 60 | Description: "some tool description", 61 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 62 | Statement: "MATCH (c:Country) WHERE c.name = $country RETURN c.id as id;\n", 63 | Parameters: []tools.Parameter{ 64 | tools.NewStringParameter("country", "country parameter description"), 65 | }, 66 | }, 67 | }, 68 | }, 69 | } 70 | for _, tc := range tcs { 71 | t.Run(tc.desc, func(t *testing.T) { 72 | got := struct { 73 | Tools server.ToolConfigs `yaml:"tools"` 74 | }{} 75 | // Parse contents 76 | err = yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 77 | if err != nil { 78 | t.Fatalf("unable to unmarshal: %s", err) 79 | } 80 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 81 | t.Fatalf("incorrect parse: diff %v", diff) 82 | } 83 | }) 84 | } 85 | 86 | } 87 | ``` -------------------------------------------------------------------------------- /tests/source.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // Package tests contains end to end tests meant to verify the Toolbox Server 16 | // works as expected when executed as a binary. 17 | 18 | package tests 19 | 20 | import ( 21 | "context" 22 | "fmt" 23 | "regexp" 24 | "strings" 25 | "testing" 26 | "time" 27 | 28 | "cloud.google.com/go/cloudsqlconn" 29 | "github.com/googleapis/genai-toolbox/internal/testutils" 30 | ) 31 | 32 | // RunSourceConnection test for source connection 33 | func RunSourceConnectionTest(t *testing.T, sourceConfig map[string]any, toolKind string) error { 34 | ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 35 | defer cancel() 36 | 37 | var args []string 38 | 39 | // Write config into a file and pass it to command 40 | toolsFile := map[string]any{ 41 | "sources": map[string]any{ 42 | "my-instance": sourceConfig, 43 | }, 44 | "tools": map[string]any{ 45 | "my-simple-tool": map[string]any{ 46 | "kind": toolKind, 47 | "source": "my-instance", 48 | "description": "Simple tool to test end to end functionality.", 49 | "statement": "SELECT 1;", 50 | }, 51 | }, 52 | } 53 | cmd, cleanup, err := StartCmd(ctx, toolsFile, args...) 54 | if err != nil { 55 | return fmt.Errorf("command initialization returned an error: %s", err) 56 | } 57 | defer cleanup() 58 | 59 | waitCtx, cancel := context.WithTimeout(ctx, 10*time.Second) 60 | defer cancel() 61 | out, err := testutils.WaitForString(waitCtx, regexp.MustCompile(`Server ready to serve`), cmd.Out) 62 | if err != nil { 63 | t.Logf("toolbox command logs: \n%s", out) 64 | return fmt.Errorf("toolbox didn't start successfully: %s", err) 65 | } 66 | return nil 67 | } 68 | 69 | // GetCloudSQLDialOpts returns cloud sql connector's dial option for ip type. 70 | func GetCloudSQLDialOpts(ipType string) ([]cloudsqlconn.DialOption, error) { 71 | switch strings.ToLower(ipType) { 72 | case "private": 73 | return []cloudsqlconn.DialOption{cloudsqlconn.WithPrivateIP()}, nil 74 | case "public": 75 | return []cloudsqlconn.DialOption{cloudsqlconn.WithPublicIP()}, nil 76 | default: 77 | return nil, fmt.Errorf("invalid ipType %s", ipType) 78 | } 79 | } 80 | ``` -------------------------------------------------------------------------------- /docs/en/how-to/connect_via_geminicli.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: Connect via Gemini CLI Extensions 3 | type: docs 4 | weight: 2 5 | description: "Connect to Toolbox via Gemini CLI Extensions." 6 | --- 7 | 8 | ## Gemini CLI Extensions 9 | 10 | [Gemini CLI][gemini-cli] is an open-source AI agent designed to assist with development workflows by assisting with coding, debugging, data exploration, and content creation. Its mission is to provide an agentic interface for interacting with database and analytics services and popular open-source databases. 11 | 12 | ### How extensions work 13 | Gemini CLI is highly extensible, allowing for the addition of new tools and capabilities through extensions. You can load the extensions from a GitHub URL, a local directory, or a configurable registry. They provide new tools, slash commands, and prompts to assist with your workflow. 14 | 15 | Use the Gemini CLI Extensions to load prebuilt or custom tools to interact with your databases. 16 | 17 | [gemini-cli]: https://google-gemini.github.io/gemini-cli/ 18 | 19 | Below are a list of Gemini CLI Extensions powered by MCP Toolbox: 20 | 21 | * [alloydb](https://github.com/gemini-cli-extensions/alloydb) 22 | * [alloydb-observability](https://github.com/gemini-cli-extensions/alloydb-observability) 23 | * [bigquery-conversational-analytics](https://github.com/gemini-cli-extensions/bigquery-conversational-analytics) 24 | * [bigquery-data-analytics](https://github.com/gemini-cli-extensions/bigquery-data-analytics) 25 | * [cloud-sql-mysql](https://github.com/gemini-cli-extensions/cloud-sql-mysql) 26 | * [cloud-sql-mysql-observability](https://github.com/gemini-cli-extensions/cloud-sql-mysql-observability) 27 | * [cloud-sql-postgresql](https://github.com/gemini-cli-extensions/cloud-sql-postgresql) 28 | * [cloud-sql-postgresql-observability](https://github.com/gemini-cli-extensions/cloud-sql-postgresql-observability) 29 | * [cloud-sql-sqlserver](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver) 30 | * [cloud-sql-sqlserver-observability](https://github.com/gemini-cli-extensions/cloud-sql-sqlserver-observability) 31 | * [dataplex](https://github.com/gemini-cli-extensions/dataplex) 32 | * [firestore-native](https://github.com/gemini-cli-extensions/firestore-native) 33 | * [looker](https://github.com/gemini-cli-extensions/looker) 34 | * [mcp-toolbox](https://github.com/gemini-cli-extensions/mcp-toolbox) 35 | * [mysql](https://github.com/gemini-cli-extensions/mysql) 36 | * [postgres](https://github.com/gemini-cli-extensions/postgres) 37 | * [spanner](https://github.com/gemini-cli-extensions/spanner) 38 | * [sql-server](https://github.com/gemini-cli-extensions/sql-server) ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-get-dimensions.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "looker-get-dimensions" 3 | type: docs 4 | weight: 1 5 | description: > 6 | A "looker-get-dimensions" tool returns all the dimensions from a given explore 7 | in a given model in the source. 8 | aliases: 9 | - /resources/tools/looker-get-dimensions 10 | --- 11 | 12 | ## About 13 | 14 | A `looker-get-dimensions` tool returns all the dimensions from a given explore 15 | in a given model in the source. 16 | 17 | It's compatible with the following sources: 18 | 19 | - [looker](../../sources/looker.md) 20 | 21 | `looker-get-dimensions` accepts two parameters, the `model` and the `explore`. 22 | 23 | ## Example 24 | 25 | ```yaml 26 | tools: 27 | get_dimensions: 28 | kind: looker-get-dimensions 29 | source: looker-source 30 | description: | 31 | The get_dimensions tool retrieves the list of dimensions defined in 32 | an explore. 33 | 34 | It takes two parameters, the model_name looked up from get_models and the 35 | explore_name looked up from get_explores. 36 | 37 | If this returns a suggestions field for a dimension, the contents of suggestions 38 | can be used as filters for this field. If this returns a suggest_explore and 39 | suggest_dimension, a query against that explore and dimension can be used to find 40 | valid filters for this field. 41 | 42 | ``` 43 | 44 | The response is a json array with the following elements: 45 | 46 | ```json 47 | { 48 | "name": "field name", 49 | "description": "field description", 50 | "type": "field type", 51 | "label": "field label", 52 | "label_short": "field short label", 53 | "tags": ["tags", ...], 54 | "synonyms": ["synonyms", ...], 55 | "suggestions": ["suggestion", ...], 56 | "suggest_explore": "explore", 57 | "suggest_dimension": "dimension" 58 | } 59 | ``` 60 | 61 | ## Reference 62 | 63 | | **field** | **type** | **required** | **description** | 64 | |-------------|:------------------------------------------:|:------------:|--------------------------------------------------------------------------------------------------| 65 | | kind | string | true | Must be "looker-get-dimensions". | 66 | | source | string | true | Name of the source the SQL should execute on. | 67 | | description | string | true | Description of the tool that is passed to the LLM. | 68 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/mysql/mysql-list-tables.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "mysql-list-tables" 3 | type: docs 4 | weight: 1 5 | description: > 6 | The "mysql-list-tables" tool lists schema information for all or specified tables in a MySQL database. 7 | aliases: 8 | - /resources/tools/mysql-list-tables 9 | --- 10 | 11 | ## About 12 | 13 | The `mysql-list-tables` tool retrieves schema information for all or specified 14 | tables in a MySQL database. It is compatible with any of the following sources: 15 | 16 | - [cloud-sql-mysql](../../sources/cloud-sql-mysql.md) 17 | - [mysql](../../sources/mysql.md) 18 | 19 | `mysql-list-tables` lists detailed schema information (object type, columns, 20 | constraints, indexes, triggers, owner, comment) as JSON for user-created tables 21 | (ordinary or partitioned). Filters by a comma-separated list of names. If names 22 | are omitted, it lists all tables in user schemas. The output format can be set 23 | to `simple` which will return only the table names or `detailed` which is the 24 | default. 25 | 26 | The tool takes the following input parameters: 27 | 28 | | Parameter | Type | Description | Required | 29 | |:----------------|:-------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------|:---------| 30 | | `table_names` | string | Filters by a comma-separated list of names. By default, it lists all tables in user schemas. Default: `""` | No | 31 | | `output_format` | string | Indicate the output format of table schema. `simple` will return only the table names, `detailed` will return the full table information. Default: `detailed`. | No | 32 | 33 | ## Example 34 | 35 | ```yaml 36 | tools: 37 | mysql_list_tables: 38 | kind: mysql-list-tables 39 | source: mysql-source 40 | description: Use this tool to retrieve schema information for all or specified tables. Output format can be simple (only table names) or detailed. 41 | ``` 42 | 43 | ## Reference 44 | 45 | | **field** | **type** | **required** | **description** | 46 | |-------------|:--------:|:------------:|------------------------------------------------------| 47 | | kind | string | true | Must be "mysql-list-tables". | 48 | | source | string | true | Name of the source the SQL should execute on. | 49 | | description | string | true | Description of the tool that is passed to the agent. | 50 | ``` -------------------------------------------------------------------------------- /internal/tools/spanner/spannerexecutesql/spannerexecutesql_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package spannerexecutesql_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools/spanner/spannerexecutesql" 25 | ) 26 | 27 | func TestParseFromYamlExecuteSql(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | example_tool: 42 | kind: spanner-execute-sql 43 | source: my-spanner-instance 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "example_tool": spannerexecutesql.Config{ 48 | Name: "example_tool", 49 | Kind: "spanner-execute-sql", 50 | Source: "my-spanner-instance", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | ReadOnly: false, 54 | }, 55 | }, 56 | }, 57 | { 58 | desc: "read only set to true", 59 | in: ` 60 | tools: 61 | example_tool: 62 | kind: spanner-execute-sql 63 | source: my-spanner-instance 64 | description: some description 65 | readOnly: true 66 | `, 67 | want: server.ToolConfigs{ 68 | "example_tool": spannerexecutesql.Config{ 69 | Name: "example_tool", 70 | Kind: "spanner-execute-sql", 71 | Source: "my-spanner-instance", 72 | Description: "some description", 73 | AuthRequired: []string{}, 74 | ReadOnly: true, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | 95 | } 96 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/mongodb/mongodb-insert-many.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "mongodb-insert-many" 3 | type: docs 4 | weight: 1 5 | description: > 6 | A "mongodb-insert-many" tool inserts multiple new documents into a MongoDB collection. 7 | aliases: 8 | - /resources/tools/mongodb-insert-many 9 | --- 10 | 11 | ## About 12 | 13 | The `mongodb-insert-many` tool inserts **multiple new documents** into a 14 | specified MongoDB collection in a single bulk operation. This is highly 15 | efficient for adding large amounts of data at once. 16 | 17 | This tool takes one required parameter named `data`. This `data` parameter must 18 | be a string containing a **JSON array of document objects**. Upon successful 19 | insertion, the tool returns a JSON array containing the unique `_id` of **each** 20 | new document that was created. 21 | 22 | This tool is compatible with the following source kind: 23 | 24 | * [`mongodb`](../../sources/mongodb.md) 25 | 26 | --- 27 | 28 | ## Example 29 | 30 | Here is an example configuration for a tool that logs multiple events at once. 31 | 32 | ```yaml 33 | tools: 34 | log_batch_events: 35 | kind: mongodb-insert-many 36 | source: my-mongo-source 37 | description: Inserts a batch of event logs into the database. 38 | database: logging 39 | collection: events 40 | canonical: true 41 | ``` 42 | 43 | An LLM would call this tool by providing an array of documents as a JSON string 44 | in the `data` parameter, like this: 45 | `tool_code: log_batch_events(data='[{"event": "login", "user": "user1"}, {"event": "click", "user": "user2"}, {"event": "logout", "user": "user1"}]')` 46 | 47 | --- 48 | 49 | ## Reference 50 | 51 | | **field** | **type** | **required** | **description** | 52 | |:------------|:---------|:-------------|:---------------------------------------------------------------------------------------------------| 53 | | kind | string | true | Must be `mongodb-insert-many`. | 54 | | source | string | true | The name of the `mongodb` source to use. | 55 | | description | string | true | A description of the tool that is passed to the LLM. | 56 | | database | string | true | The name of the MongoDB database containing the collection. | 57 | | collection | string | true | The name of the MongoDB collection into which the documents will be inserted. | 58 | | canonical | bool | true | Determines if the data string is parsed using MongoDB's Canonical or Relaxed Extended JSON format. | 59 | ``` -------------------------------------------------------------------------------- /internal/sources/sources.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package sources 16 | 17 | import ( 18 | "context" 19 | 20 | "fmt" 21 | 22 | "github.com/goccy/go-yaml" 23 | "go.opentelemetry.io/otel/attribute" 24 | "go.opentelemetry.io/otel/trace" 25 | ) 26 | 27 | // SourceConfigFactory defines the function signature for creating a SourceConfig. 28 | type SourceConfigFactory func(ctx context.Context, name string, decoder *yaml.Decoder) (SourceConfig, error) 29 | 30 | var sourceRegistry = make(map[string]SourceConfigFactory) 31 | 32 | // Register registers a new source kind with its factory. 33 | // It returns false if the kind is already registered. 34 | func Register(kind string, factory SourceConfigFactory) bool { 35 | if _, exists := sourceRegistry[kind]; exists { 36 | // Source with this kind already exists, do not overwrite. 37 | return false 38 | } 39 | sourceRegistry[kind] = factory 40 | return true 41 | } 42 | 43 | // DecodeConfig decodes a source configuration using the registered factory for the given kind. 44 | func DecodeConfig(ctx context.Context, kind string, name string, decoder *yaml.Decoder) (SourceConfig, error) { 45 | factory, found := sourceRegistry[kind] 46 | if !found { 47 | return nil, fmt.Errorf("unknown source kind: %q", kind) 48 | } 49 | sourceConfig, err := factory(ctx, name, decoder) 50 | if err != nil { 51 | return nil, fmt.Errorf("unable to parse source %q as %q: %w", name, kind, err) 52 | } 53 | return sourceConfig, err 54 | } 55 | 56 | // SourceConfig is the interface for configuring a source. 57 | type SourceConfig interface { 58 | SourceConfigKind() string 59 | Initialize(ctx context.Context, tracer trace.Tracer) (Source, error) 60 | } 61 | 62 | // Source is the interface for the source itself. 63 | type Source interface { 64 | SourceKind() string 65 | } 66 | 67 | // InitConnectionSpan adds a span for database pool connection initialization 68 | func InitConnectionSpan(ctx context.Context, tracer trace.Tracer, sourceKind, sourceName string) (context.Context, trace.Span) { 69 | ctx, span := tracer.Start( 70 | ctx, 71 | "toolbox/server/source/connect", 72 | trace.WithAttributes(attribute.String("source_kind", sourceKind)), 73 | trace.WithAttributes(attribute.String("source_name", sourceName)), 74 | ) 75 | return ctx, span 76 | } 77 | ``` -------------------------------------------------------------------------------- /docs/en/getting-started/quickstart/python/adk/quickstart.py: -------------------------------------------------------------------------------- ```python 1 | from google.adk.agents import Agent 2 | from google.adk.runners import Runner 3 | from google.adk.sessions import InMemorySessionService 4 | from google.adk.artifacts.in_memory_artifact_service import InMemoryArtifactService 5 | from google.genai import types 6 | from toolbox_core import ToolboxSyncClient 7 | 8 | import asyncio 9 | import os 10 | 11 | # TODO(developer): replace this with your Google API key 12 | 13 | api_key = os.environ.get("GOOGLE_API_KEY") or "your-api-key" # Set your API key here 14 | os.environ["GOOGLE_API_KEY"] = api_key 15 | 16 | async def main(): 17 | with ToolboxSyncClient("http://127.0.0.1:5000") as toolbox_client: 18 | 19 | prompt = """ 20 | You're a helpful hotel assistant. You handle hotel searching, booking and 21 | cancellations. When the user searches for a hotel, mention it's name, id, 22 | location and price tier. Always mention hotel ids while performing any 23 | searches. This is very important for any operations. For any bookings or 24 | cancellations, please provide the appropriate confirmation. Be sure to 25 | update checkin or checkout dates if mentioned by the user. 26 | Don't ask for confirmations from the user. 27 | """ 28 | 29 | root_agent = Agent( 30 | model='gemini-2.0-flash-001', 31 | name='hotel_agent', 32 | description='A helpful AI assistant.', 33 | instruction=prompt, 34 | tools=toolbox_client.load_toolset("my-toolset"), 35 | ) 36 | 37 | session_service = InMemorySessionService() 38 | artifacts_service = InMemoryArtifactService() 39 | session = await session_service.create_session( 40 | state={}, app_name='hotel_agent', user_id='123' 41 | ) 42 | runner = Runner( 43 | app_name='hotel_agent', 44 | agent=root_agent, 45 | artifact_service=artifacts_service, 46 | session_service=session_service, 47 | ) 48 | 49 | queries = [ 50 | "Find hotels in Basel with Basel in its name.", 51 | "Can you book the Hilton Basel for me?", 52 | "Oh wait, this is too expensive. Please cancel it and book the Hyatt Regency instead.", 53 | "My check in dates would be from April 10, 2024 to April 19, 2024.", 54 | ] 55 | 56 | for query in queries: 57 | content = types.Content(role='user', parts=[types.Part(text=query)]) 58 | events = runner.run(session_id=session.id, 59 | user_id='123', new_message=content) 60 | 61 | responses = ( 62 | part.text 63 | for event in events 64 | for part in event.content.parts 65 | if part.text is not None 66 | ) 67 | 68 | for text in responses: 69 | print(text) 70 | 71 | asyncio.run(main()) 72 | ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbgetuser/alloydbgetuser_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alloydbgetuser_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | alloydbgetuser "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetuser" 25 | ) 26 | 27 | func TestParseFromYaml(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | get-my-user: 42 | kind: alloydb-get-user 43 | source: my-alloydb-admin-source 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "get-my-user": alloydbgetuser.Config{ 48 | Name: "get-my-user", 49 | Kind: "alloydb-get-user", 50 | Source: "my-alloydb-admin-source", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | }, 54 | }, 55 | }, 56 | { 57 | desc: "with auth required", 58 | in: ` 59 | tools: 60 | get-my-user-auth: 61 | kind: alloydb-get-user 62 | source: my-alloydb-admin-source 63 | description: some description 64 | authRequired: 65 | - my-google-auth-service 66 | - other-auth-service 67 | `, 68 | want: server.ToolConfigs{ 69 | "get-my-user-auth": alloydbgetuser.Config{ 70 | Name: "get-my-user-auth", 71 | Kind: "alloydb-get-user", 72 | Source: "my-alloydb-admin-source", 73 | Description: "some description", 74 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/http.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "HTTP" 3 | linkTitle: "HTTP" 4 | type: docs 5 | weight: 1 6 | description: > 7 | The HTTP source enables the Toolbox to retrieve data from a remote server using HTTP requests. 8 | --- 9 | 10 | ## About 11 | 12 | The HTTP Source allows Toolbox to retrieve data from arbitrary HTTP 13 | endpoints. This enables Generative AI applications to access data from web APIs 14 | and other HTTP-accessible resources. 15 | 16 | ## Available Tools 17 | 18 | - [`http`](../tools/http/http.md) 19 | Make HTTP requests to REST APIs or other web services. 20 | 21 | ## Example 22 | 23 | ```yaml 24 | sources: 25 | my-http-source: 26 | kind: http 27 | baseUrl: https://api.example.com/data 28 | timeout: 10s # default to 30s 29 | headers: 30 | Authorization: Bearer ${API_KEY} 31 | Content-Type: application/json 32 | queryParams: 33 | param1: value1 34 | param2: value2 35 | # disableSslVerification: false 36 | ``` 37 | 38 | {{< notice tip >}} 39 | Use environment variable replacement with the format ${ENV_NAME} 40 | instead of hardcoding your secrets into the configuration file. 41 | {{< /notice >}} 42 | 43 | ## Reference 44 | 45 | | **field** | **type** | **required** | **description** | 46 | |------------------------|:-----------------:|:------------:|------------------------------------------------------------------------------------------------------------------------------------| 47 | | kind | string | true | Must be "http". | 48 | | baseUrl | string | true | The base URL for the HTTP requests (e.g., `https://api.example.com`). | 49 | | timeout | string | false | The timeout for HTTP requests (e.g., "5s", "1m", refer to [ParseDuration][parse-duration-doc] for more examples). Defaults to 30s. | 50 | | headers | map[string]string | false | Default headers to include in the HTTP requests. | 51 | | queryParams | map[string]string | false | Default query parameters to include in the HTTP requests. | 52 | | disableSslVerification | bool | false | Disable SSL certificate verification. This should only be used for local development. Defaults to `false`. | 53 | 54 | [parse-duration-doc]: https://pkg.go.dev/time#ParseDuration 55 | ``` -------------------------------------------------------------------------------- /.github/workflows/deploy_dev_docs.yaml: -------------------------------------------------------------------------------- ```yaml 1 | # Copyright 2025 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: "Deploy In-development docs" 16 | 17 | permissions: 18 | contents: write 19 | 20 | on: 21 | push: 22 | branches: 23 | - main 24 | paths: 25 | - 'docs/**' 26 | - 'github/workflows/docs**' 27 | - '.hugo/**' 28 | 29 | # Allow triggering manually. 30 | workflow_dispatch: 31 | 32 | jobs: 33 | deploy: 34 | runs-on: ubuntu-24.04 35 | defaults: 36 | run: 37 | working-directory: .hugo 38 | # This shared concurrency group ensures only one docs deployment runs at a time. 39 | concurrency: 40 | group: docs-deployment 41 | cancel-in-progress: false 42 | steps: 43 | - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 44 | with: 45 | fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod 46 | 47 | - name: Setup Hugo 48 | uses: peaceiris/actions-hugo@75d2e84710de30f6ff7268e08f310b60ef14033f # v3 49 | with: 50 | hugo-version: "0.145.0" 51 | extended: true 52 | 53 | - name: Setup Node 54 | uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 55 | with: 56 | node-version: "22" 57 | 58 | - name: Cache dependencies 59 | uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 60 | with: 61 | path: ~/.npm 62 | key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} 63 | restore-keys: | 64 | ${{ runner.os }}-node- 65 | 66 | - run: npm ci 67 | - run: hugo --minify 68 | env: 69 | HUGO_BASEURL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}/dev 70 | HUGO_RELATIVEURLS: false 71 | 72 | - name: Create Staging Directory 73 | run: | 74 | mkdir staging 75 | mv public staging/dev 76 | mv staging/dev/releases.releases staging/releases.releases 77 | 78 | - name: Deploy 79 | uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4 80 | with: 81 | github_token: ${{ secrets.GITHUB_TOKEN }} 82 | publish_dir: ./.hugo/staging 83 | publish_branch: versioned-gh-pages 84 | keep_files: true 85 | commit_message: "deploy: ${{ github.event.head_commit.message }}" 86 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/dataplex/dataplex-search-entries.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "dataplex-search-entries" 3 | type: docs 4 | weight: 1 5 | description: > 6 | A "dataplex-search-entries" tool allows to search for entries based on the provided query. 7 | aliases: 8 | - /resources/tools/dataplex-search-entries 9 | --- 10 | 11 | ## About 12 | 13 | A `dataplex-search-entries` tool returns all entries in Dataplex Catalog (e.g. 14 | tables, views, models) that matches given user query. 15 | It's compatible with the following sources: 16 | 17 | - [dataplex](../../sources/dataplex.md) 18 | 19 | `dataplex-search-entries` takes a required `query` parameter based on which 20 | entries are filtered and returned to the user. It also optionally accepts 21 | following parameters: 22 | 23 | - `pageSize` - Number of results in the search page. Defaults to `5`. 24 | - `orderBy` - Specifies the ordering of results. Supported values are: relevance 25 | (default), last_modified_timestamp, last_modified_timestamp asc. 26 | 27 | ## Requirements 28 | 29 | ### IAM Permissions 30 | 31 | Dataplex uses [Identity and Access Management (IAM)][iam-overview] to control 32 | user and group access to Dataplex resources. Toolbox will use your 33 | [Application Default Credentials (ADC)][adc] to authorize and authenticate when 34 | interacting with [Dataplex][dataplex-docs]. 35 | 36 | In addition to [setting the ADC for your server][set-adc], you need to ensure 37 | the IAM identity has been given the correct IAM permissions for the tasks you 38 | intend to perform. See [Dataplex Universal Catalog IAM permissions][iam-permissions] 39 | and [Dataplex Universal Catalog IAM roles][iam-roles] for more information on 40 | applying IAM permissions and roles to an identity. 41 | 42 | [iam-overview]: https://cloud.google.com/dataplex/docs/iam-and-access-control 43 | [adc]: https://cloud.google.com/docs/authentication#adc 44 | [set-adc]: https://cloud.google.com/docs/authentication/provide-credentials-adc 45 | [iam-permissions]: https://cloud.google.com/dataplex/docs/iam-permissions 46 | [iam-roles]: https://cloud.google.com/dataplex/docs/iam-roles 47 | [dataplex-docs]: https://cloud.google.com/dataplex 48 | 49 | ## Example 50 | 51 | ```yaml 52 | tools: 53 | dataplex-search-entries: 54 | kind: dataplex-search-entries 55 | source: my-dataplex-source 56 | description: Use this tool to get all the entries based on the provided query. 57 | ``` 58 | 59 | ## Reference 60 | 61 | | **field** | **type** | **required** | **description** | 62 | |-------------|:--------:|:------------:|----------------------------------------------------| 63 | | kind | string | true | Must be "dataplex-search-entries". | 64 | | source | string | true | Name of the source the tool should execute on. | 65 | | description | string | true | Description of the tool that is passed to the LLM. | 66 | ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydblistusers/alloydblistusers_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alloydblistusers_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | alloydblistusers "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistusers" 25 | ) 26 | 27 | func TestParseFromYaml(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | list-my-users: 42 | kind: alloydb-list-users 43 | source: my-alloydb-admin-source 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "list-my-users": alloydblistusers.Config{ 48 | Name: "list-my-users", 49 | Kind: "alloydb-list-users", 50 | Source: "my-alloydb-admin-source", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | }, 54 | }, 55 | }, 56 | { 57 | desc: "with auth required", 58 | in: ` 59 | tools: 60 | list-my-users-auth: 61 | kind: alloydb-list-users 62 | source: my-alloydb-admin-source 63 | description: some description 64 | authRequired: 65 | - my-google-auth-service 66 | - other-auth-service 67 | `, 68 | want: server.ToolConfigs{ 69 | "list-my-users-auth": alloydblistusers.Config{ 70 | Name: "list-my-users-auth", 71 | Kind: "alloydb-list-users", 72 | Source: "my-alloydb-admin-source", 73 | Description: "some description", 74 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbgetcluster/alloydbgetcluster_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alloydbgetcluster_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | alloydbgetcluster "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetcluster" 25 | ) 26 | 27 | func TestParseFromYaml(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | get-my-cluster: 42 | kind: alloydb-get-cluster 43 | source: my-alloydb-admin-source 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "get-my-cluster": alloydbgetcluster.Config{ 48 | Name: "get-my-cluster", 49 | Kind: "alloydb-get-cluster", 50 | Source: "my-alloydb-admin-source", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | }, 54 | }, 55 | }, 56 | { 57 | desc: "with auth required", 58 | in: ` 59 | tools: 60 | get-my-cluster-auth: 61 | kind: alloydb-get-cluster 62 | source: my-alloydb-admin-source 63 | description: some description 64 | authRequired: 65 | - my-google-auth-service 66 | - other-auth-service 67 | `, 68 | want: server.ToolConfigs{ 69 | "get-my-cluster-auth": alloydbgetcluster.Config{ 70 | Name: "get-my-cluster-auth", 71 | Kind: "alloydb-get-cluster", 72 | Source: "my-alloydb-admin-source", 73 | Description: "some description", 74 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /internal/tools/neo4j/neo4jexecutecypher/neo4jexecutecypher_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package neo4jexecutecypher 16 | 17 | import ( 18 | "testing" 19 | 20 | "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | ) 25 | 26 | func TestParseFromYamlNeo4j(t *testing.T) { 27 | ctx, err := testutils.ContextWithNewLogger() 28 | if err != nil { 29 | t.Fatalf("unexpected error: %s", err) 30 | } 31 | tcs := []struct { 32 | desc string 33 | in string 34 | want server.ToolConfigs 35 | }{ 36 | { 37 | desc: "basic example", 38 | in: ` 39 | tools: 40 | example_tool: 41 | kind: neo4j-execute-cypher 42 | source: my-neo4j-instance 43 | description: some tool description 44 | authRequired: 45 | - my-google-auth-service 46 | - other-auth-service 47 | `, 48 | want: server.ToolConfigs{ 49 | "example_tool": Config{ 50 | Name: "example_tool", 51 | Kind: "neo4j-execute-cypher", 52 | Source: "my-neo4j-instance", 53 | Description: "some tool description", 54 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 55 | }, 56 | }, 57 | }, 58 | { 59 | desc: "readonly example", 60 | in: ` 61 | tools: 62 | example_tool: 63 | kind: neo4j-execute-cypher 64 | source: my-neo4j-instance 65 | description: some tool description 66 | readOnly: true 67 | authRequired: 68 | - my-google-auth-service 69 | - other-auth-service 70 | `, 71 | want: server.ToolConfigs{ 72 | "example_tool": Config{ 73 | Name: "example_tool", 74 | Kind: "neo4j-execute-cypher", 75 | Source: "my-neo4j-instance", 76 | ReadOnly: true, 77 | Description: "some tool description", 78 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 79 | }, 80 | }, 81 | }, 82 | } 83 | for _, tc := range tcs { 84 | t.Run(tc.desc, func(t *testing.T) { 85 | got := struct { 86 | Tools server.ToolConfigs `yaml:"tools"` 87 | }{} 88 | // Parse contents 89 | err = yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 90 | if err != nil { 91 | t.Fatalf("unable to unmarshal: %s", err) 92 | } 93 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 94 | t.Fatalf("incorrect parse: diff %v", diff) 95 | } 96 | }) 97 | } 98 | 99 | } 100 | ``` -------------------------------------------------------------------------------- /.github/workflows/lint.yaml: -------------------------------------------------------------------------------- ```yaml 1 | # Copyright 2024 Google LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | name: lint 16 | on: 17 | pull_request: 18 | pull_request_target: 19 | types: [labeled] 20 | 21 | # Declare default permissions as read only. 22 | permissions: read-all 23 | 24 | jobs: 25 | lint: 26 | if: "${{ github.event.action != 'labeled' || github.event.label.name == 'tests: run' }}" 27 | name: lint 28 | runs-on: ubuntu-latest 29 | concurrency: 30 | group: ${{ github.workflow }}-${{ github.ref }} 31 | cancel-in-progress: true 32 | permissions: 33 | contents: 'read' 34 | issues: 'write' 35 | pull-requests: 'write' 36 | steps: 37 | - name: Remove PR Label 38 | if: "${{ github.event.action == 'labeled' && github.event.label.name == 'tests: run' }}" 39 | uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 40 | with: 41 | github-token: ${{ secrets.GITHUB_TOKEN }} 42 | script: | 43 | try { 44 | await github.rest.issues.removeLabel({ 45 | name: 'tests: run', 46 | owner: context.repo.owner, 47 | repo: context.repo.repo, 48 | issue_number: context.payload.pull_request.number 49 | }); 50 | } catch (e) { 51 | console.log('Failed to remove label. Another job may have already removed it!'); 52 | } 53 | - name: Setup Go 54 | uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6.0.0 55 | with: 56 | go-version: "1.25" 57 | - name: Checkout code 58 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 59 | with: 60 | ref: ${{ github.event.pull_request.head.sha }} 61 | repository: ${{ github.event.pull_request.head.repo.full_name }} 62 | token: ${{ secrets.GITHUB_TOKEN }} 63 | - name: > 64 | Verify go mod tidy. If you're reading this and the check has 65 | failed, run `goimports -w . && go mod tidy && golangci-lint run` 66 | run: | 67 | go mod tidy && git diff --exit-code 68 | - name: golangci-lint 69 | uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0 70 | with: 71 | version: latest 72 | args: --timeout 3m 73 | ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydbgetinstance/alloydbgetinstance_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alloydbgetinstance_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | alloydbgetinstance "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydbgetinstance" 25 | ) 26 | 27 | func TestParseFromYaml(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | get-my-instance: 42 | kind: alloydb-get-instance 43 | source: my-alloydb-admin-source 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "get-my-instance": alloydbgetinstance.Config{ 48 | Name: "get-my-instance", 49 | Kind: "alloydb-get-instance", 50 | Source: "my-alloydb-admin-source", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | }, 54 | }, 55 | }, 56 | { 57 | desc: "with auth required", 58 | in: ` 59 | tools: 60 | get-my-instance-auth: 61 | kind: alloydb-get-instance 62 | source: my-alloydb-admin-source 63 | description: some description 64 | authRequired: 65 | - my-google-auth-service 66 | - other-auth-service 67 | `, 68 | want: server.ToolConfigs{ 69 | "get-my-instance-auth": alloydbgetinstance.Config{ 70 | Name: "get-my-instance-auth", 71 | Kind: "alloydb-get-instance", 72 | Source: "my-alloydb-admin-source", 73 | Description: "some description", 74 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /internal/tools/postgres/postgreslistactivequeries/postgreslistactivequeries_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package postgreslistactivequeries_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistactivequeries" 25 | ) 26 | 27 | func TestParseFromYamlPostgresListTables(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | example_tool: 42 | kind: postgres-list-active-queries 43 | source: my-postgres-instance 44 | description: some description 45 | authRequired: 46 | - my-google-auth-service 47 | - other-auth-service 48 | `, 49 | want: server.ToolConfigs{ 50 | "example_tool": postgreslistactivequeries.Config{ 51 | Name: "example_tool", 52 | Kind: "postgres-list-active-queries", 53 | Source: "my-postgres-instance", 54 | Description: "some description", 55 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 56 | }, 57 | }, 58 | }, 59 | { 60 | desc: "basic example", 61 | in: ` 62 | tools: 63 | example_tool: 64 | kind: postgres-list-active-queries 65 | source: my-postgres-instance 66 | description: some description 67 | `, 68 | want: server.ToolConfigs{ 69 | "example_tool": postgreslistactivequeries.Config{ 70 | Name: "example_tool", 71 | Kind: "postgres-list-active-queries", 72 | Source: "my-postgres-instance", 73 | Description: "some description", 74 | AuthRequired: []string{}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | 95 | } 96 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/looker/looker-health-analyze.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "looker-health-analyze" 3 | type: docs 4 | weight: 1 5 | description: > 6 | "looker-health-analyze" provides a set of analytical commands for a Looker instance, allowing users to analyze projects, models, and explores. 7 | aliases: 8 | - /resources/tools/looker-health-analyze 9 | --- 10 | 11 | ## About 12 | 13 | The `looker-health-analyze` tool performs various analysis tasks on a Looker instance. The `action` parameter selects the type of analysis to perform: 14 | 15 | - `projects`: Analyzes all projects or a specified project, reporting on the number of models and view files, as well as Git connection and validation status. 16 | - `models`: Analyzes all models or a specified model, providing a count of explores, unused explores, and total query counts. 17 | - `explores`: Analyzes all explores or a specified explore, reporting on the number of joins, unused joins, fields, unused fields, and query counts. Being classified as **Unused** is determined by whether a field has been used as a field or filter within the past 90 days in production. 18 | 19 | ## Parameters 20 | 21 | | **field** | **type** | **required** | **description** | 22 | | :--- | :--- | :--- | :--- | 23 | | kind | string | true | Must be "looker-health-analyze" | 24 | | source | string | true | Looker source name | 25 | | action | string | true | The analysis to perform: `projects`, `models`, or `explores`. | 26 | | project | string | false | The name of the Looker project to analyze. | 27 | | model | string | false | The name of the Looker model to analyze. Required for `explores` actions. | 28 | | explore | string | false | The name of the Looker explore to analyze. Required for the `explores` action. | 29 | | timeframe | int | false | The timeframe in days to analyze. Defaults to 90. | 30 | | min_queries | int | false | The minimum number of queries for a model or explore to be considered used. Defaults to 1. | 31 | 32 | ## Example 33 | 34 | Analyze all models in `thelook` project. 35 | 36 | ```yaml 37 | tools: 38 | analyze-tool: 39 | kind: looker-health-analyze 40 | source: looker-source 41 | description: | 42 | Analyzes Looker projects, models, and explores. 43 | Specify the `action` parameter to select the type of analysis. 44 | parameters: 45 | action: models 46 | project: "thelook" 47 | 48 | Analyze all the explores in the `ecomm` model of `thelook` project. Specifically look at usage within the past 20 days. Usage minimum should be at least 10 queries. 49 | 50 | ```yaml 51 | tools: 52 | analyze-tool: 53 | kind: looker-health-analyze 54 | source: looker-source 55 | description: | 56 | Analyzes Looker projects, models, and explores. 57 | Specify the `action` parameter to select the type of analysis. 58 | parameters: 59 | action: explores 60 | project: "thelook" 61 | model: "ecomm" 62 | timeframe: 20 63 | min_queries: 10 ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydblistclusters/alloydblistclusters_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alloydblistclusters_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | alloydblistclusters "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistclusters" 25 | ) 26 | 27 | func TestParseFromYaml(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | list-my-clusters: 42 | kind: alloydb-list-clusters 43 | source: my-alloydb-admin-source 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "list-my-clusters": alloydblistclusters.Config{ 48 | Name: "list-my-clusters", 49 | Kind: "alloydb-list-clusters", 50 | Source: "my-alloydb-admin-source", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | }, 54 | }, 55 | }, 56 | { 57 | desc: "with auth required", 58 | in: ` 59 | tools: 60 | list-my-clusters-auth: 61 | kind: alloydb-list-clusters 62 | source: my-alloydb-admin-source 63 | description: some description 64 | authRequired: 65 | - my-google-auth-service 66 | - other-auth-service 67 | `, 68 | want: server.ToolConfigs{ 69 | "list-my-clusters-auth": alloydblistclusters.Config{ 70 | Name: "list-my-clusters-auth", 71 | Kind: "alloydb-list-clusters", 72 | Source: "my-alloydb-admin-source", 73 | Description: "some description", 74 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /docs/en/resources/tools/dataplex/dataplex-search-aspect-types.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "dataplex-search-aspect-types" 3 | type: docs 4 | weight: 1 5 | description: > 6 | A "dataplex-search-aspect-types" tool allows to to find aspect types relevant to the query. 7 | aliases: 8 | - /resources/tools/dataplex-search-aspect-types 9 | --- 10 | 11 | ## About 12 | 13 | A `dataplex-search-aspect-types` tool allows to fetch the metadata template of 14 | aspect types based on search query. 15 | It's compatible with the following sources: 16 | 17 | - [dataplex](../../sources/dataplex.md) 18 | 19 | `dataplex-search-aspect-types` accepts following parameters optionally: 20 | 21 | - `query` - Narrows down the search of aspect types to value of this parameter. 22 | If not provided, it fetches all aspect types available to the user. 23 | - `pageSize` - Number of returned aspect types in the search page. Defaults to `5`. 24 | - `orderBy` - Specifies the ordering of results. Supported values are: relevance 25 | (default), last_modified_timestamp, last_modified_timestamp asc. 26 | 27 | ## Requirements 28 | 29 | ### IAM Permissions 30 | 31 | Dataplex uses [Identity and Access Management (IAM)][iam-overview] to control 32 | user and group access to Dataplex resources. Toolbox will use your 33 | [Application Default Credentials (ADC)][adc] to authorize and authenticate when 34 | interacting with [Dataplex][dataplex-docs]. 35 | 36 | In addition to [setting the ADC for your server][set-adc], you need to ensure 37 | the IAM identity has been given the correct IAM permissions for the tasks you 38 | intend to perform. See [Dataplex Universal Catalog IAM permissions][iam-permissions] 39 | and [Dataplex Universal Catalog IAM roles][iam-roles] for more information on 40 | applying IAM permissions and roles to an identity. 41 | 42 | [iam-overview]: https://cloud.google.com/dataplex/docs/iam-and-access-control 43 | [adc]: https://cloud.google.com/docs/authentication#adc 44 | [set-adc]: https://cloud.google.com/docs/authentication/provide-credentials-adc 45 | [iam-permissions]: https://cloud.google.com/dataplex/docs/iam-permissions 46 | [iam-roles]: https://cloud.google.com/dataplex/docs/iam-roles 47 | [dataplex-docs]: https://cloud.google.com/dataplex 48 | 49 | ## Example 50 | 51 | ```yaml 52 | tools: 53 | dataplex-search-aspect-types: 54 | kind: dataplex-search-aspect-types 55 | source: my-dataplex-source 56 | description: Use this tool to find aspect types relevant to the query. 57 | ``` 58 | 59 | ## Reference 60 | 61 | | **field** | **type** | **required** | **description** | 62 | |-------------|:--------:|:------------:|----------------------------------------------------| 63 | | kind | string | true | Must be "dataplex-search-aspect-types". | 64 | | source | string | true | Name of the source the tool should execute on. | 65 | | description | string | true | Description of the tool that is passed to the LLM. | 66 | ``` -------------------------------------------------------------------------------- /internal/tools/alloydb/alloydblistinstances/alloydblistinstances_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package alloydblistinstances_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | alloydblistinstances "github.com/googleapis/genai-toolbox/internal/tools/alloydb/alloydblistinstances" 25 | ) 26 | 27 | func TestParseFromYaml(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | list-my-instances: 42 | kind: alloydb-list-instances 43 | source: my-alloydb-admin-source 44 | description: some description 45 | `, 46 | want: server.ToolConfigs{ 47 | "list-my-instances": alloydblistinstances.Config{ 48 | Name: "list-my-instances", 49 | Kind: "alloydb-list-instances", 50 | Source: "my-alloydb-admin-source", 51 | Description: "some description", 52 | AuthRequired: []string{}, 53 | }, 54 | }, 55 | }, 56 | { 57 | desc: "with auth required", 58 | in: ` 59 | tools: 60 | list-my-instances-auth: 61 | kind: alloydb-list-instances 62 | source: my-alloydb-admin-source 63 | description: some description 64 | authRequired: 65 | - my-google-auth-service 66 | - other-auth-service 67 | `, 68 | want: server.ToolConfigs{ 69 | "list-my-instances-auth": alloydblistinstances.Config{ 70 | Name: "list-my-instances-auth", 71 | Kind: "alloydb-list-instances", 72 | Source: "my-alloydb-admin-source", 73 | Description: "some description", 74 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | } 95 | ``` -------------------------------------------------------------------------------- /internal/tools/postgres/postgreslistavailableextensions/postgreslistavailableextensions_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package postgreslistavailableextensions_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistavailableextensions" 25 | ) 26 | 27 | func TestParseFromYamlPostgres(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | example_tool: 42 | kind: postgres-list-available-extensions 43 | source: my-pg-instance 44 | description: "some description" 45 | authRequired: 46 | - my-google-auth-service 47 | - other-auth-service 48 | `, 49 | want: server.ToolConfigs{ 50 | "example_tool": postgreslistavailableextensions.Config{ 51 | Name: "example_tool", 52 | Kind: "postgres-list-available-extensions", 53 | Source: "my-pg-instance", 54 | Description: "some description", 55 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 56 | }, 57 | }, 58 | }, 59 | { 60 | desc: "basic example without authRequired", 61 | in: ` 62 | tools: 63 | example_tool: 64 | kind: postgres-list-available-extensions 65 | source: my-pg-instance 66 | description: "some description" 67 | `, 68 | want: server.ToolConfigs{ 69 | "example_tool": postgreslistavailableextensions.Config{ 70 | Name: "example_tool", 71 | Kind: "postgres-list-available-extensions", 72 | Source: "my-pg-instance", 73 | Description: "some description", 74 | AuthRequired: []string{}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | 95 | } 96 | ``` -------------------------------------------------------------------------------- /internal/tools/postgres/postgreslistinstalledextensions/postgreslistinstalledextensions_test.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2025 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package postgreslistinstalledextensions_test 16 | 17 | import ( 18 | "testing" 19 | 20 | yaml "github.com/goccy/go-yaml" 21 | "github.com/google/go-cmp/cmp" 22 | "github.com/googleapis/genai-toolbox/internal/server" 23 | "github.com/googleapis/genai-toolbox/internal/testutils" 24 | "github.com/googleapis/genai-toolbox/internal/tools/postgres/postgreslistinstalledextensions" 25 | ) 26 | 27 | func TestParseFromYamlPostgres(t *testing.T) { 28 | ctx, err := testutils.ContextWithNewLogger() 29 | if err != nil { 30 | t.Fatalf("unexpected error: %s", err) 31 | } 32 | tcs := []struct { 33 | desc string 34 | in string 35 | want server.ToolConfigs 36 | }{ 37 | { 38 | desc: "basic example", 39 | in: ` 40 | tools: 41 | example_tool: 42 | kind: postgres-list-installed-extensions 43 | source: my-pg-instance 44 | description: "some description" 45 | authRequired: 46 | - my-google-auth-service 47 | - other-auth-service 48 | `, 49 | want: server.ToolConfigs{ 50 | "example_tool": postgreslistinstalledextensions.Config{ 51 | Name: "example_tool", 52 | Kind: "postgres-list-installed-extensions", 53 | Source: "my-pg-instance", 54 | Description: "some description", 55 | AuthRequired: []string{"my-google-auth-service", "other-auth-service"}, 56 | }, 57 | }, 58 | }, 59 | { 60 | desc: "basic example without authRequired", 61 | in: ` 62 | tools: 63 | example_tool: 64 | kind: postgres-list-installed-extensions 65 | source: my-pg-instance 66 | description: "some description" 67 | `, 68 | want: server.ToolConfigs{ 69 | "example_tool": postgreslistinstalledextensions.Config{ 70 | Name: "example_tool", 71 | Kind: "postgres-list-installed-extensions", 72 | Source: "my-pg-instance", 73 | Description: "some description", 74 | AuthRequired: []string{}, 75 | }, 76 | }, 77 | }, 78 | } 79 | for _, tc := range tcs { 80 | t.Run(tc.desc, func(t *testing.T) { 81 | got := struct { 82 | Tools server.ToolConfigs `yaml:"tools"` 83 | }{} 84 | // Parse contents 85 | err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) 86 | if err != nil { 87 | t.Fatalf("unable to unmarshal: %s", err) 88 | } 89 | if diff := cmp.Diff(tc.want, got.Tools); diff != "" { 90 | t.Fatalf("incorrect parse: diff %v", diff) 91 | } 92 | }) 93 | } 94 | 95 | } 96 | ``` -------------------------------------------------------------------------------- /docs/en/resources/sources/dgraph.md: -------------------------------------------------------------------------------- ```markdown 1 | --- 2 | title: "Dgraph" 3 | type: docs 4 | weight: 1 5 | description: > 6 | Dgraph is fully open-source, built-for-scale graph database for Gen AI workloads 7 | 8 | --- 9 | 10 | ## About 11 | 12 | [Dgraph][dgraph-docs] is an open-source graph database. It is designed for 13 | real-time workloads, horizontal scalability, and data flexibility. Implemented 14 | as a distributed system, Dgraph processes queries in parallel to deliver the 15 | fastest result. 16 | 17 | This source can connect to either a self-managed Dgraph cluster or one hosted on 18 | Dgraph Cloud. If you're new to Dgraph, the fastest way to get started is to 19 | [sign up for Dgraph Cloud][dgraph-login]. 20 | 21 | [dgraph-docs]: https://dgraph.io/docs 22 | [dgraph-login]: https://cloud.dgraph.io/login 23 | 24 | ## Available Tools 25 | 26 | - [`dgraph-dql`](../tools/dgraph/dgraph-dql.md) 27 | Run DQL (Dgraph Query Language) queries. 28 | 29 | ## Requirements 30 | 31 | ### Database User 32 | 33 | When **connecting to a hosted Dgraph database**, this source uses the API key 34 | for access. If you are using a dedicated environment, you will additionally need 35 | the namespace and user credentials for that namespace. 36 | 37 | For **connecting to a local or self-hosted Dgraph database**, use the namespace 38 | and user credentials for that namespace. 39 | 40 | ## Example 41 | 42 | ```yaml 43 | sources: 44 | my-dgraph-source: 45 | kind: dgraph 46 | dgraphUrl: https://xxxx.cloud.dgraph.io 47 | user: ${USER_NAME} 48 | password: ${PASSWORD} 49 | apiKey: ${API_KEY} 50 | namespace : 0 51 | ``` 52 | 53 | {{< notice tip >}} 54 | Use environment variable replacement with the format ${ENV_NAME} 55 | instead of hardcoding your secrets into the configuration file. 56 | {{< /notice >}} 57 | 58 | ## Reference 59 | 60 | | **Field** | **Type** | **Required** | **Description** | 61 | |-------------|:--------:|:------------:|--------------------------------------------------------------------------------------------------| 62 | | kind | string | true | Must be "dgraph". | 63 | | dgraphUrl | string | true | Connection URI (e.g. "<https://xxx.cloud.dgraph.io>", "<https://localhost:8080>"). | 64 | | user | string | false | Name of the Dgraph user to connect as (e.g., "groot"). | 65 | | password | string | false | Password of the Dgraph user (e.g., "password"). | 66 | | apiKey | string | false | API key to connect to a Dgraph Cloud instance. | 67 | | namespace | uint64 | false | Dgraph namespace (not required for Dgraph Cloud Shared Clusters). | 68 | ``` -------------------------------------------------------------------------------- /internal/prebuiltconfigs/prebuiltconfigs.go: -------------------------------------------------------------------------------- ```go 1 | // Copyright 2024 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | package prebuiltconfigs 16 | 17 | import ( 18 | "embed" 19 | "fmt" 20 | "path" 21 | "strings" 22 | ) 23 | 24 | var ( 25 | //go:embed tools/*.yaml 26 | prebuiltConfigsFS embed.FS 27 | 28 | // Map of sources to their prebuilt tools 29 | prebuiltToolYAMLs map[string][]byte 30 | // List of sources with prebuilt tools 31 | prebuiltToolsSources []string 32 | ) 33 | 34 | func init() { 35 | var err error 36 | prebuiltToolYAMLs, prebuiltToolsSources, err = loadPrebuiltToolYAMLs() 37 | if err != nil { 38 | panic(fmt.Sprintf("Unexpected Error: %v\n", err)) 39 | } 40 | } 41 | 42 | // Getter for the prebuiltToolsSources 43 | func GetPrebuiltSources() []string { 44 | return prebuiltToolsSources 45 | } 46 | 47 | // Get prebuilt tools for a source 48 | func Get(prebuiltSourceConfig string) ([]byte, error) { 49 | content, ok := prebuiltToolYAMLs[prebuiltSourceConfig] 50 | if !ok { 51 | prebuiltHelpSuffix := "no prebuilt configurations found." 52 | if len(prebuiltToolsSources) > 0 { 53 | prebuiltHelpSuffix = fmt.Sprintf("available: %s", strings.Join(prebuiltToolsSources, ", ")) 54 | } 55 | errMsg := fmt.Errorf("prebuilt source tool for '%s' not found. %s", prebuiltSourceConfig, prebuiltHelpSuffix) 56 | return nil, errMsg 57 | } 58 | return content, nil 59 | } 60 | 61 | // Load all available pre built tools 62 | func loadPrebuiltToolYAMLs() (map[string][]byte, []string, error) { 63 | toolYAMLs := make(map[string][]byte) 64 | var sourceTypes []string 65 | entries, err := prebuiltConfigsFS.ReadDir("tools") 66 | if err != nil { 67 | errMsg := fmt.Errorf("failed to read prebuilt tools %w", err) 68 | return nil, nil, errMsg 69 | } 70 | 71 | for _, entry := range entries { 72 | lowerName := strings.ToLower(entry.Name()) 73 | if !entry.IsDir() && (strings.HasSuffix(lowerName, ".yaml")) { 74 | filePathInFS := path.Join("tools", entry.Name()) 75 | content, err := prebuiltConfigsFS.ReadFile(filePathInFS) 76 | if err != nil { 77 | errMsg := fmt.Errorf("failed to read a prebuilt tool %w", err) 78 | return nil, nil, errMsg 79 | } 80 | sourceTypeKey := entry.Name()[:len(entry.Name())-len(".yaml")] 81 | 82 | sourceTypes = append(sourceTypes, sourceTypeKey) 83 | toolYAMLs[sourceTypeKey] = content 84 | } 85 | } 86 | if len(toolYAMLs) == 0 { 87 | errMsg := fmt.Errorf("no prebuilt tool configurations were loaded.%w", err) 88 | return nil, nil, errMsg 89 | } 90 | 91 | return toolYAMLs, sourceTypes, nil 92 | } 93 | ```