Compare commits

..

1 Commits

Author SHA1 Message Date
Kurtis Van Gent
4e4821eb3e chore: example command 2026-01-29 20:26:21 +00:00
114 changed files with 839 additions and 2515 deletions

View File

@@ -171,23 +171,6 @@ steps:
alloydbainl \ alloydbainl \
alloydbainl alloydbainl
- id: "alloydb-omni"
name: golang:1
waitFor: ["compile-test-binary"]
entrypoint: /bin/bash
env:
- "GOPATH=/gopath"
volumes:
- name: "go"
path: "/gopath"
args:
- -c
- |
.ci/test_with_coverage.sh \
"AlloyDB Omni" \
alloydbomni \
postgres
- id: "bigtable" - id: "bigtable"
name: golang:1 name: golang:1
waitFor: ["compile-test-binary"] waitFor: ["compile-test-binary"]
@@ -923,7 +906,7 @@ steps:
tar -C /usr/local -xzf go.tar.gz tar -C /usr/local -xzf go.tar.gz
export PATH="/usr/local/go/bin:$$PATH" export PATH="/usr/local/go/bin:$$PATH"
go test -v ./tests/oracle/... \ go test -v ./internal/sources/oracle/... \
-coverprofile=oracle_coverage.out \ -coverprofile=oracle_coverage.out \
-coverpkg=./internal/sources/oracle/...,./internal/tools/oracle/... -coverpkg=./internal/sources/oracle/...,./internal/tools/oracle/...
@@ -931,8 +914,8 @@ steps:
total_coverage=$(go tool cover -func=oracle_coverage.out | grep "total:" | awk '{print $3}') total_coverage=$(go tool cover -func=oracle_coverage.out | grep "total:" | awk '{print $3}')
echo "Oracle total coverage: $total_coverage" echo "Oracle total coverage: $total_coverage"
coverage_numeric=$(echo "$total_coverage" | sed 's/%//') coverage_numeric=$(echo "$total_coverage" | sed 's/%//')
if awk -v cov="$coverage_numeric" 'BEGIN {exit !(cov < 60)}'; then if awk -v cov="$coverage_numeric" 'BEGIN {exit !(cov < 20)}'; then
echo "Coverage failure: $total_coverage is below 60%." echo "Coverage failure: $total_coverage is below 20%."
exit 1 exit 1
fi fi

36
cmd/invoke.go Normal file
View File

@@ -0,0 +1,36 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"fmt"
"github.com/spf13/cobra"
)
func newInvokeCmd(root *Command) *cobra.Command {
return &cobra.Command{
Use: "invoke",
Short: "Invoke a tool",
Run: func(cmd *cobra.Command, args []string) {
invoke(root)
},
}
}
func invoke(cmd *Command) {
fmt.Println("Hello, World! Here is one of my flags" + cmd.cfg.Address)
}

View File

@@ -1,131 +0,0 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package cmd
import (
"context"
"os"
"path/filepath"
"strings"
"testing"
)
func TestInvokeTool(t *testing.T) {
// Create a temporary tools file
tmpDir := t.TempDir()
toolsFileContent := `
sources:
my-sqlite:
kind: sqlite
database: test.db
tools:
hello-sqlite:
kind: sqlite-sql
source: my-sqlite
description: "hello tool"
statement: "SELECT 'hello' as greeting"
echo-tool:
kind: sqlite-sql
source: my-sqlite
description: "echo tool"
statement: "SELECT ? as msg"
parameters:
- name: message
type: string
description: message to echo
`
toolsFilePath := filepath.Join(tmpDir, "tools.yaml")
if err := os.WriteFile(toolsFilePath, []byte(toolsFileContent), 0644); err != nil {
t.Fatalf("failed to write tools file: %v", err)
}
tcs := []struct {
desc string
args []string
want string
wantErr bool
errStr string
}{
{
desc: "success - basic tool call",
args: []string{"invoke", "hello-sqlite", "--tools-file", toolsFilePath},
want: `"greeting": "hello"`,
},
{
desc: "success - tool call with parameters",
args: []string{"invoke", "echo-tool", `{"message": "world"}`, "--tools-file", toolsFilePath},
want: `"msg": "world"`,
},
{
desc: "error - tool not found",
args: []string{"invoke", "non-existent", "--tools-file", toolsFilePath},
wantErr: true,
errStr: `tool "non-existent" not found`,
},
{
desc: "error - invalid JSON params",
args: []string{"invoke", "echo-tool", `invalid-json`, "--tools-file", toolsFilePath},
wantErr: true,
errStr: `params must be a valid JSON string`,
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
_, got, err := invokeCommandWithContext(context.Background(), tc.args)
if (err != nil) != tc.wantErr {
t.Fatalf("got error %v, wantErr %v", err, tc.wantErr)
}
if tc.wantErr && !strings.Contains(err.Error(), tc.errStr) {
t.Fatalf("got error %v, want error containing %q", err, tc.errStr)
}
if !tc.wantErr && !strings.Contains(got, tc.want) {
t.Fatalf("got %q, want it to contain %q", got, tc.want)
}
})
}
}
func TestInvokeTool_AuthUnsupported(t *testing.T) {
tmpDir := t.TempDir()
toolsFileContent := `
sources:
my-bq:
kind: bigquery
project: my-project
useClientOAuth: true
tools:
bq-tool:
kind: bigquery-sql
source: my-bq
description: "bq tool"
statement: "SELECT 1"
`
toolsFilePath := filepath.Join(tmpDir, "auth_tools.yaml")
if err := os.WriteFile(toolsFilePath, []byte(toolsFileContent), 0644); err != nil {
t.Fatalf("failed to write tools file: %v", err)
}
args := []string{"invoke", "bq-tool", "--tools-file", toolsFilePath}
_, _, err := invokeCommandWithContext(context.Background(), args)
if err == nil {
t.Fatal("expected error for tool requiring client auth, but got nil")
}
if !strings.Contains(err.Error(), "client authorization is not supported") {
t.Fatalf("unexpected error message: %v", err)
}
}

View File

@@ -34,7 +34,6 @@ import (
"github.com/fsnotify/fsnotify" "github.com/fsnotify/fsnotify"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/auth" "github.com/googleapis/genai-toolbox/internal/auth"
"github.com/googleapis/genai-toolbox/internal/cli/invoke"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/log" "github.com/googleapis/genai-toolbox/internal/log"
"github.com/googleapis/genai-toolbox/internal/prebuiltconfigs" "github.com/googleapis/genai-toolbox/internal/prebuiltconfigs"
@@ -366,41 +365,38 @@ func NewCommand(opts ...Option) *Command {
baseCmd.SetErr(cmd.errStream) baseCmd.SetErr(cmd.errStream)
flags := cmd.Flags() flags := cmd.Flags()
persistentFlags := cmd.PersistentFlags()
flags.StringVarP(&cmd.cfg.Address, "address", "a", "127.0.0.1", "Address of the interface the server will listen on.") flags.StringVarP(&cmd.cfg.Address, "address", "a", "127.0.0.1", "Address of the interface the server will listen on.")
flags.IntVarP(&cmd.cfg.Port, "port", "p", 5000, "Port the server will listen on.") flags.IntVarP(&cmd.cfg.Port, "port", "p", 5000, "Port the server will listen on.")
flags.StringVar(&cmd.tools_file, "tools_file", "", "File path specifying the tool configuration. Cannot be used with --tools-files, or --tools-folder.") flags.StringVar(&cmd.tools_file, "tools_file", "", "File path specifying the tool configuration. Cannot be used with --tools-files, or --tools-folder.")
// deprecate tools_file // deprecate tools_file
_ = flags.MarkDeprecated("tools_file", "please use --tools-file instead") _ = flags.MarkDeprecated("tools_file", "please use --tools-file instead")
persistentFlags.StringVar(&cmd.tools_file, "tools-file", "", "File path specifying the tool configuration. Cannot be used with --tools-files, or --tools-folder.") flags.StringVar(&cmd.tools_file, "tools-file", "", "File path specifying the tool configuration. Cannot be used with --tools-files, or --tools-folder.")
persistentFlags.StringSliceVar(&cmd.tools_files, "tools-files", []string{}, "Multiple file paths specifying tool configurations. Files will be merged. Cannot be used with --tools-file, or --tools-folder.") flags.StringSliceVar(&cmd.tools_files, "tools-files", []string{}, "Multiple file paths specifying tool configurations. Files will be merged. Cannot be used with --tools-file, or --tools-folder.")
persistentFlags.StringVar(&cmd.tools_folder, "tools-folder", "", "Directory path containing YAML tool configuration files. All .yaml and .yml files in the directory will be loaded and merged. Cannot be used with --tools-file, or --tools-files.") flags.StringVar(&cmd.tools_folder, "tools-folder", "", "Directory path containing YAML tool configuration files. All .yaml and .yml files in the directory will be loaded and merged. Cannot be used with --tools-file, or --tools-files.")
persistentFlags.Var(&cmd.cfg.LogLevel, "log-level", "Specify the minimum level logged. Allowed: 'DEBUG', 'INFO', 'WARN', 'ERROR'.") flags.Var(&cmd.cfg.LogLevel, "log-level", "Specify the minimum level logged. Allowed: 'DEBUG', 'INFO', 'WARN', 'ERROR'.")
persistentFlags.Var(&cmd.cfg.LoggingFormat, "logging-format", "Specify logging format to use. Allowed: 'standard' or 'JSON'.") flags.Var(&cmd.cfg.LoggingFormat, "logging-format", "Specify logging format to use. Allowed: 'standard' or 'JSON'.")
persistentFlags.BoolVar(&cmd.cfg.TelemetryGCP, "telemetry-gcp", false, "Enable exporting directly to Google Cloud Monitoring.") flags.BoolVar(&cmd.cfg.TelemetryGCP, "telemetry-gcp", false, "Enable exporting directly to Google Cloud Monitoring.")
persistentFlags.StringVar(&cmd.cfg.TelemetryOTLP, "telemetry-otlp", "", "Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. 'http://127.0.0.1:4318')") flags.StringVar(&cmd.cfg.TelemetryOTLP, "telemetry-otlp", "", "Enable exporting using OpenTelemetry Protocol (OTLP) to the specified endpoint (e.g. 'http://127.0.0.1:4318')")
persistentFlags.StringVar(&cmd.cfg.TelemetryServiceName, "telemetry-service-name", "toolbox", "Sets the value of the service.name resource attribute for telemetry data.") flags.StringVar(&cmd.cfg.TelemetryServiceName, "telemetry-service-name", "toolbox", "Sets the value of the service.name resource attribute for telemetry data.")
// Fetch prebuilt tools sources to customize the help description // Fetch prebuilt tools sources to customize the help description
prebuiltHelp := fmt.Sprintf( prebuiltHelp := fmt.Sprintf(
"Use a prebuilt tool configuration by source type. Allowed: '%s'. Can be specified multiple times.", "Use a prebuilt tool configuration by source type. Allowed: '%s'. Can be specified multiple times.",
strings.Join(prebuiltconfigs.GetPrebuiltSources(), "', '"), strings.Join(prebuiltconfigs.GetPrebuiltSources(), "', '"),
) )
persistentFlags.StringSliceVar(&cmd.prebuiltConfigs, "prebuilt", []string{}, prebuiltHelp) flags.StringSliceVar(&cmd.prebuiltConfigs, "prebuilt", []string{}, prebuiltHelp)
flags.BoolVar(&cmd.cfg.Stdio, "stdio", false, "Listens via MCP STDIO instead of acting as a remote HTTP server.") flags.BoolVar(&cmd.cfg.Stdio, "stdio", false, "Listens via MCP STDIO instead of acting as a remote HTTP server.")
flags.BoolVar(&cmd.cfg.DisableReload, "disable-reload", false, "Disables dynamic reloading of tools file.") flags.BoolVar(&cmd.cfg.DisableReload, "disable-reload", false, "Disables dynamic reloading of tools file.")
flags.BoolVar(&cmd.cfg.UI, "ui", false, "Launches the Toolbox UI web server.") flags.BoolVar(&cmd.cfg.UI, "ui", false, "Launches the Toolbox UI web server.")
// TODO: Insecure by default. Might consider updating this for v1.0.0 // TODO: Insecure by default. Might consider updating this for v1.0.0
flags.StringSliceVar(&cmd.cfg.AllowedOrigins, "allowed-origins", []string{"*"}, "Specifies a list of origins permitted to access this server. Defaults to '*'.") flags.StringSliceVar(&cmd.cfg.AllowedOrigins, "allowed-origins", []string{"*"}, "Specifies a list of origins permitted to access this server. Defaults to '*'.")
flags.StringSliceVar(&cmd.cfg.AllowedHosts, "allowed-hosts", []string{"*"}, "Specifies a list of hosts permitted to access this server. Defaults to '*'.") flags.StringSliceVar(&cmd.cfg.AllowedHosts, "allowed-hosts", []string{"*"}, "Specifies a list of hosts permitted to access this server. Defaults to '*'.")
persistentFlags.StringSliceVar(&cmd.cfg.UserAgentMetadata, "user-agent-metadata", []string{}, "Appends additional metadata to the User-Agent.") flags.StringSliceVar(&cmd.cfg.UserAgentMetadata, "user-agent-metadata", []string{}, "Appends additional metadata to the User-Agent.")
// wrap RunE command so that we have access to original Command object // wrap RunE command so that we have access to original Command object
cmd.RunE = func(*cobra.Command, []string) error { return run(cmd) } cmd.RunE = func(*cobra.Command, []string) error { return run(cmd) }
// Register subcommands for tool invocation baseCmd.AddCommand(newInvokeCmd(cmd))
baseCmd.AddCommand(invoke.NewCommand(cmd))
return cmd return cmd
} }
@@ -925,24 +921,71 @@ func resolveWatcherInputs(toolsFile string, toolsFiles []string, toolsFolder str
return watchDirs, watchedFiles return watchDirs, watchedFiles
} }
func (cmd *Command) Config() server.ServerConfig { func run(cmd *Command) error {
return cmd.cfg ctx, cancel := context.WithCancel(cmd.Context())
} defer cancel()
func (cmd *Command) Out() io.Writer { // watch for sigterm / sigint signals
return cmd.outStream signals := make(chan os.Signal, 1)
} signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
go func(sCtx context.Context) {
var s os.Signal
select {
case <-sCtx.Done():
// this should only happen when the context supplied when testing is canceled
return
case s = <-signals:
}
switch s {
case syscall.SIGINT:
cmd.logger.DebugContext(sCtx, "Received SIGINT signal to shutdown.")
case syscall.SIGTERM:
cmd.logger.DebugContext(sCtx, "Sending SIGTERM signal to shutdown.")
}
cancel()
}(ctx)
func (cmd *Command) Logger() log.Logger { // If stdio, set logger's out stream (usually DEBUG and INFO logs) to errStream
return cmd.logger loggerOut := cmd.outStream
} if cmd.cfg.Stdio {
loggerOut = cmd.errStream
func (cmd *Command) LoadConfig(ctx context.Context) error {
logger, err := util.LoggerFromContext(ctx)
if err != nil {
return err
} }
// Handle logger separately from config
switch strings.ToLower(cmd.cfg.LoggingFormat.String()) {
case "json":
logger, err := log.NewStructuredLogger(loggerOut, cmd.errStream, cmd.cfg.LogLevel.String())
if err != nil {
return fmt.Errorf("unable to initialize logger: %w", err)
}
cmd.logger = logger
case "standard":
logger, err := log.NewStdLogger(loggerOut, cmd.errStream, cmd.cfg.LogLevel.String())
if err != nil {
return fmt.Errorf("unable to initialize logger: %w", err)
}
cmd.logger = logger
default:
return fmt.Errorf("logging format invalid")
}
ctx = util.WithLogger(ctx, cmd.logger)
// Set up OpenTelemetry
otelShutdown, err := telemetry.SetupOTel(ctx, cmd.cfg.Version, cmd.cfg.TelemetryOTLP, cmd.cfg.TelemetryGCP, cmd.cfg.TelemetryServiceName)
if err != nil {
errMsg := fmt.Errorf("error setting up OpenTelemetry: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
return errMsg
}
defer func() {
err := otelShutdown(ctx)
if err != nil {
errMsg := fmt.Errorf("error shutting down OpenTelemetry: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
}
}()
var allToolsFiles []ToolsFile var allToolsFiles []ToolsFile
// Load Prebuilt Configuration // Load Prebuilt Configuration
@@ -951,12 +994,12 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
slices.Sort(cmd.prebuiltConfigs) slices.Sort(cmd.prebuiltConfigs)
sourcesList := strings.Join(cmd.prebuiltConfigs, ", ") sourcesList := strings.Join(cmd.prebuiltConfigs, ", ")
logMsg := fmt.Sprintf("Using prebuilt tool configurations for: %s", sourcesList) logMsg := fmt.Sprintf("Using prebuilt tool configurations for: %s", sourcesList)
logger.InfoContext(ctx, logMsg) cmd.logger.InfoContext(ctx, logMsg)
for _, configName := range cmd.prebuiltConfigs { for _, configName := range cmd.prebuiltConfigs {
buf, err := prebuiltconfigs.Get(configName) buf, err := prebuiltconfigs.Get(configName)
if err != nil { if err != nil {
logger.ErrorContext(ctx, err.Error()) cmd.logger.ErrorContext(ctx, err.Error())
return err return err
} }
@@ -964,7 +1007,7 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
parsed, err := parseToolsFile(ctx, buf) parsed, err := parseToolsFile(ctx, buf)
if err != nil { if err != nil {
errMsg := fmt.Errorf("unable to parse prebuilt tool configuration for '%s': %w", configName, err) errMsg := fmt.Errorf("unable to parse prebuilt tool configuration for '%s': %w", configName, err)
logger.ErrorContext(ctx, errMsg.Error()) cmd.logger.ErrorContext(ctx, errMsg.Error())
return errMsg return errMsg
} }
allToolsFiles = append(allToolsFiles, parsed) allToolsFiles = append(allToolsFiles, parsed)
@@ -990,7 +1033,7 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
(cmd.tools_file != "" && cmd.tools_folder != "") || (cmd.tools_file != "" && cmd.tools_folder != "") ||
(len(cmd.tools_files) > 0 && cmd.tools_folder != "") { (len(cmd.tools_files) > 0 && cmd.tools_folder != "") {
errMsg := fmt.Errorf("--tools-file, --tools-files, and --tools-folder flags cannot be used simultaneously") errMsg := fmt.Errorf("--tools-file, --tools-files, and --tools-folder flags cannot be used simultaneously")
logger.ErrorContext(ctx, errMsg.Error()) cmd.logger.ErrorContext(ctx, errMsg.Error())
return errMsg return errMsg
} }
@@ -999,18 +1042,18 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
if len(cmd.tools_files) > 0 { if len(cmd.tools_files) > 0 {
// Use tools-files // Use tools-files
logger.InfoContext(ctx, fmt.Sprintf("Loading and merging %d tool configuration files", len(cmd.tools_files))) cmd.logger.InfoContext(ctx, fmt.Sprintf("Loading and merging %d tool configuration files", len(cmd.tools_files)))
customTools, err = loadAndMergeToolsFiles(ctx, cmd.tools_files) customTools, err = loadAndMergeToolsFiles(ctx, cmd.tools_files)
} else if cmd.tools_folder != "" { } else if cmd.tools_folder != "" {
// Use tools-folder // Use tools-folder
logger.InfoContext(ctx, fmt.Sprintf("Loading and merging all YAML files from directory: %s", cmd.tools_folder)) cmd.logger.InfoContext(ctx, fmt.Sprintf("Loading and merging all YAML files from directory: %s", cmd.tools_folder))
customTools, err = loadAndMergeToolsFolder(ctx, cmd.tools_folder) customTools, err = loadAndMergeToolsFolder(ctx, cmd.tools_folder)
} else { } else {
// Use single file (tools-file or default `tools.yaml`) // Use single file (tools-file or default `tools.yaml`)
buf, readFileErr := os.ReadFile(cmd.tools_file) buf, readFileErr := os.ReadFile(cmd.tools_file)
if readFileErr != nil { if readFileErr != nil {
errMsg := fmt.Errorf("unable to read tool file at %q: %w", cmd.tools_file, readFileErr) errMsg := fmt.Errorf("unable to read tool file at %q: %w", cmd.tools_file, readFileErr)
logger.ErrorContext(ctx, errMsg.Error()) cmd.logger.ErrorContext(ctx, errMsg.Error())
return errMsg return errMsg
} }
customTools, err = parseToolsFile(ctx, buf) customTools, err = parseToolsFile(ctx, buf)
@@ -1020,7 +1063,7 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
} }
if err != nil { if err != nil {
logger.ErrorContext(ctx, err.Error()) cmd.logger.ErrorContext(ctx, err.Error())
return err return err
} }
allToolsFiles = append(allToolsFiles, customTools) allToolsFiles = append(allToolsFiles, customTools)
@@ -1042,7 +1085,7 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
// This will error if custom tools collide with prebuilt tools // This will error if custom tools collide with prebuilt tools
finalToolsFile, err := mergeToolsFiles(allToolsFiles...) finalToolsFile, err := mergeToolsFiles(allToolsFiles...)
if err != nil { if err != nil {
logger.ErrorContext(ctx, err.Error()) cmd.logger.ErrorContext(ctx, err.Error())
return err return err
} }
@@ -1053,91 +1096,15 @@ func (cmd *Command) LoadConfig(ctx context.Context) error {
cmd.cfg.ToolsetConfigs = finalToolsFile.Toolsets cmd.cfg.ToolsetConfigs = finalToolsFile.Toolsets
cmd.cfg.PromptConfigs = finalToolsFile.Prompts cmd.cfg.PromptConfigs = finalToolsFile.Prompts
return nil instrumentation, err := telemetry.CreateTelemetryInstrumentation(versionString)
}
func (cmd *Command) Setup(ctx context.Context) (context.Context, func(context.Context) error, error) {
// If stdio, set logger's out stream (usually DEBUG and INFO logs) to errStream
loggerOut := cmd.outStream
if cmd.cfg.Stdio {
loggerOut = cmd.errStream
}
// Handle logger separately from config
logger, err := log.NewLogger(cmd.cfg.LoggingFormat.String(), cmd.cfg.LogLevel.String(), loggerOut, cmd.errStream)
if err != nil {
return ctx, nil, fmt.Errorf("unable to initialize logger: %w", err)
}
cmd.logger = logger
ctx = util.WithLogger(ctx, cmd.logger)
// Set up OpenTelemetry
otelShutdown, err := telemetry.SetupOTel(ctx, cmd.cfg.Version, cmd.cfg.TelemetryOTLP, cmd.cfg.TelemetryGCP, cmd.cfg.TelemetryServiceName)
if err != nil {
errMsg := fmt.Errorf("error setting up OpenTelemetry: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
return ctx, nil, errMsg
}
shutdownFunc := func(ctx context.Context) error {
err := otelShutdown(ctx)
if err != nil {
errMsg := fmt.Errorf("error shutting down OpenTelemetry: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error())
return err
}
return nil
}
instrumentation, err := telemetry.CreateTelemetryInstrumentation(cmd.cfg.Version)
if err != nil { if err != nil {
errMsg := fmt.Errorf("unable to create telemetry instrumentation: %w", err) errMsg := fmt.Errorf("unable to create telemetry instrumentation: %w", err)
cmd.logger.ErrorContext(ctx, errMsg.Error()) cmd.logger.ErrorContext(ctx, errMsg.Error())
return ctx, shutdownFunc, errMsg return errMsg
} }
ctx = util.WithInstrumentation(ctx, instrumentation) ctx = util.WithInstrumentation(ctx, instrumentation)
return ctx, shutdownFunc, nil
}
func run(cmd *Command) error {
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()
// watch for sigterm / sigint signals
signals := make(chan os.Signal, 1)
signal.Notify(signals, syscall.SIGTERM, syscall.SIGINT)
go func(sCtx context.Context) {
var s os.Signal
select {
case <-sCtx.Done():
// this should only happen when the context supplied when testing is canceled
return
case s = <-signals:
}
switch s {
case syscall.SIGINT:
cmd.logger.DebugContext(sCtx, "Received SIGINT signal to shutdown.")
case syscall.SIGTERM:
cmd.logger.DebugContext(sCtx, "Sending SIGTERM signal to shutdown.")
}
cancel()
}(ctx)
ctx, shutdown, err := cmd.Setup(ctx)
if err != nil {
return err
}
defer func() {
_ = shutdown(ctx)
}()
if err := cmd.LoadConfig(ctx); err != nil {
return err
}
// start server // start server
s, err := server.NewServer(ctx, cmd.cfg) s, err := server.NewServer(ctx, cmd.cfg)
if err != nil { if err != nil {
@@ -1177,9 +1144,6 @@ func run(cmd *Command) error {
}() }()
} }
// Determine if Custom Files are configured (re-check as loadAndMergeConfig might have updated defaults)
isCustomConfigured := cmd.tools_file != "" || len(cmd.tools_files) > 0 || cmd.tools_folder != ""
if isCustomConfigured && !cmd.cfg.DisableReload { if isCustomConfigured && !cmd.cfg.DisableReload {
watchDirs, watchedFiles := resolveWatcherInputs(cmd.tools_file, cmd.tools_files, cmd.tools_folder) watchDirs, watchedFiles := resolveWatcherInputs(cmd.tools_file, cmd.tools_files, cmd.tools_folder)
// start watching the file(s) or folder for changes to trigger dynamic reloading // start watching the file(s) or folder for changes to trigger dynamic reloading

View File

@@ -2054,7 +2054,6 @@ func TestSingleEdit(t *testing.T) {
func TestPrebuiltTools(t *testing.T) { func TestPrebuiltTools(t *testing.T) {
// Get prebuilt configs // Get prebuilt configs
alloydb_omni_config, _ := prebuiltconfigs.Get("alloydb-omni")
alloydb_admin_config, _ := prebuiltconfigs.Get("alloydb-postgres-admin") alloydb_admin_config, _ := prebuiltconfigs.Get("alloydb-postgres-admin")
alloydb_config, _ := prebuiltconfigs.Get("alloydb-postgres") alloydb_config, _ := prebuiltconfigs.Get("alloydb-postgres")
bigquery_config, _ := prebuiltconfigs.Get("bigquery") bigquery_config, _ := prebuiltconfigs.Get("bigquery")
@@ -2105,12 +2104,6 @@ func TestPrebuiltTools(t *testing.T) {
t.Setenv("ALLOYDB_POSTGRES_USER", "your_alloydb_user") t.Setenv("ALLOYDB_POSTGRES_USER", "your_alloydb_user")
t.Setenv("ALLOYDB_POSTGRES_PASSWORD", "your_alloydb_password") t.Setenv("ALLOYDB_POSTGRES_PASSWORD", "your_alloydb_password")
t.Setenv("ALLOYDB_OMNI_HOST", "localhost")
t.Setenv("ALLOYDB_OMNI_PORT", "5432")
t.Setenv("ALLOYDB_OMNI_DATABASE", "your_alloydb_db")
t.Setenv("ALLOYDB_OMNI_USER", "your_alloydb_user")
t.Setenv("ALLOYDB_OMNI_PASSWORD", "your_alloydb_password")
t.Setenv("CLICKHOUSE_PROTOCOL", "your_clickhouse_protocol") t.Setenv("CLICKHOUSE_PROTOCOL", "your_clickhouse_protocol")
t.Setenv("CLICKHOUSE_DATABASE", "your_clickhouse_database") t.Setenv("CLICKHOUSE_DATABASE", "your_clickhouse_database")
t.Setenv("CLICKHOUSE_PASSWORD", "your_clickhouse_password") t.Setenv("CLICKHOUSE_PASSWORD", "your_clickhouse_password")
@@ -2204,16 +2197,6 @@ func TestPrebuiltTools(t *testing.T) {
in []byte in []byte
wantToolset server.ToolsetConfigs wantToolset server.ToolsetConfigs
}{ }{
{
name: "alloydb omni prebuilt tools",
in: alloydb_omni_config,
wantToolset: server.ToolsetConfigs{
"alloydb_omni_database_tools": tools.ToolsetConfig{
Name: "alloydb_omni_database_tools",
ToolNames: []string{"execute_sql", "list_tables", "list_active_queries", "list_available_extensions", "list_installed_extensions", "list_autovacuum_configurations", "list_columnar_configurations", "list_columnar_recommended_columns", "list_memory_configurations", "list_top_bloated_tables", "list_replication_slots", "list_invalid_indexes", "get_query_plan", "list_views", "list_schemas", "database_overview", "list_triggers", "list_indexes", "list_sequences", "long_running_transactions", "list_locks", "replication_stats", "list_query_stats", "get_column_cardinality", "list_publication_tables", "list_tablespaces", "list_pg_settings", "list_database_stats", "list_roles", "list_table_stats", "list_stored_procedure"},
},
},
},
{ {
name: "alloydb postgres admin prebuilt tools", name: "alloydb postgres admin prebuilt tools",
in: alloydb_admin_config, in: alloydb_admin_config,

View File

@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
In the Antigravity MCP Store, click the "Install" button. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt alloydb-postgres-admin```.
You'll now be able to see all enabled tools in the "Tools" tab. You'll now be able to see all enabled tools in the "Tools" tab.
> [!NOTE] > [!NOTE]

View File

@@ -27,13 +27,6 @@ For AlloyDB infrastructure management, search the MCP store for the AlloyDB for
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt alloydb-postgres```.
2. Add the required inputs for your [cluster](https://docs.cloud.google.com/alloydb/docs/cluster-list) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs for your [cluster](https://docs.cloud.google.com/alloydb/docs/cluster-list) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -21,13 +21,6 @@ An editor configured to use the BigQuery MCP server can use its AI capabilities
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt bigquery```.
2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
In the Antigravity MCP Store, click the "Install" button. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mssql-admin```.
You'll now be able to see all enabled tools in the "Tools" tab. You'll now be able to see all enabled tools in the "Tools" tab.
> [!NOTE] > [!NOTE]

View File

@@ -24,13 +24,6 @@ For Cloud SQL infrastructure management, search the MCP store for the Cloud SQL
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mssql```.
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/sqlserver/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/sqlserver/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
In the Antigravity MCP Store, click the "Install" button. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mysql-admin```.
You'll now be able to see all enabled tools in the "Tools" tab. You'll now be able to see all enabled tools in the "Tools" tab.
> [!NOTE] > [!NOTE]

View File

@@ -26,13 +26,6 @@ For Cloud SQL infrastructure management, search the MCP store for the Cloud SQL
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mysql```.
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/mysql/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/mysql/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
In the Antigravity MCP Store, click the "Install" button. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-postgres-admin```.
You'll now be able to see all enabled tools in the "Tools" tab. You'll now be able to see all enabled tools in the "Tools" tab.
> [!NOTE] > [!NOTE]

View File

@@ -26,13 +26,6 @@ For Cloud SQL infrastructure management, search the MCP store for the Cloud SQL
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-postgres```.
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/postgres/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/postgres/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -20,13 +20,6 @@ An editor configured to use the Dataplex MCP server can use its AI capabilities
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt dataplex```.
2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -21,13 +21,6 @@ An editor configured to use the Looker MCP server can use its AI capabilities to
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt looker```.
2. Add the required inputs for your [instance](https://docs.cloud.google.com/looker/docs/set-up-and-administer-looker) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs for your [instance](https://docs.cloud.google.com/looker/docs/set-up-and-administer-looker) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -21,13 +21,6 @@ An editor configured to use the Cloud Spanner MCP server can use its AI capabili
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the "Install" button. 1. In the Antigravity MCP Store, click the "Install" button.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest --prebuilt spanner```.
2. Add the required inputs for your [instance](https://docs.cloud.google.com/spanner/docs/instances) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab. 2. Add the required inputs for your [instance](https://docs.cloud.google.com/spanner/docs/instances) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.

View File

@@ -12,17 +12,10 @@ The MCP Toolbox for Databases Server gives AI-powered development tools the abil
## Install & Configuration ## Install & Configuration
1. In the Antigravity MCP Store, click the **Install** button. A configuration window will appear. 1. In the Antigravity MCP Store, click the **Install** button. A configuration window will appear.
> [!NOTE]
> On first use, the installation process automatically downloads and uses
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
> `>=0.26.0`. To update MCP Toolbox, use:
> ```npm i -g @toolbox-sdk/server@latest```
> To always run the latest version, update the MCP server configuration to use:
> ```npx -y @toolbox-sdk/server@latest```.
3. Create your [`tools.yaml` configuration file](https://googleapis.github.io/genai-toolbox/getting-started/configure/). 2. Create your [`tools.yaml` configuration file](https://googleapis.github.io/genai-toolbox/getting-started/configure/).
4. In the configuration window, enter the full absolute path to your `tools.yaml` file and click **Save**. 3. In the configuration window, enter the full absolute path to your `tools.yaml` file and click **Save**.
> [!NOTE] > [!NOTE]
> If you encounter issues with Windows Defender blocking the execution, you may need to configure an allowlist. See [Configure exclusions for Microsoft Defender Antivirus](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/configure-exclusions-microsoft-defender-antivirus?view=o365-worldwide) for more details. > If you encounter issues with Windows Defender blocking the execution, you may need to configure an allowlist. See [Configure exclusions for Microsoft Defender Antivirus](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/configure-exclusions-microsoft-defender-antivirus?view=o365-worldwide) for more details.

View File

@@ -1,74 +0,0 @@
---
title: "Invoke Tools via CLI"
type: docs
weight: 10
description: >
Learn how to invoke your tools directly from the command line using the `invoke` command.
---
The `invoke` command allows you to invoke tools defined in your configuration directly from the CLI. This is useful for:
- **Ephemeral Invocation:** Executing a tool without spinning up a full MCP server/client.
- **Debugging:** Isolating tool execution logic and testing with various parameter combinations.
{{< notice tip >}}
**Keep configurations minimal:** The `invoke` command initializes *all* resources (sources, tools, etc.) defined in your configuration files during execution. To ensure fast response times, consider using a minimal configuration file containing only the tools you need for the specific invocation.
{{< notice tip >}}
## Prerequisites
- You have the `toolbox` binary installed or built.
- You have a valid tool configuration file (e.g., `tools.yaml`).
## Basic Usage
The basic syntax for the command is:
```bash
toolbox [--tools-file <path> | --prebuilt <name>] invoke <tool-name> [params]
```
- `<tool-name>`: The name of the tool you want to call. This must match the name defined in your `tools.yaml`.
- `[params]`: (Optional) A JSON string representing the arguments for the tool.
## Examples
### 1. Calling a Tool without Parameters
If your tool takes no parameters, simply provide the tool name:
```bash
toolbox --tools-file tools.yaml invoke my-simple-tool
```
### 2. Calling a Tool with Parameters
For tools that require arguments, pass them as a JSON string. Ensure you escape quotes correctly for your shell.
**Example: A tool that takes parameters**
Assuming a tool named `mytool` taking `a` and `b`:
```bash
toolbox --tools-file tools.yaml invoke mytool '{"a": 10, "b": 20}'
```
**Example: A tool that queries a database**
```bash
toolbox --tools-file tools.yaml invoke db-query '{"sql": "SELECT * FROM users LIMIT 5"}'
```
### 3. Using Prebuilt Configurations
You can also use the `--prebuilt` flag to load prebuilt toolsets.
```bash
toolbox --prebuilt cloudsql-postgres invoke cloudsql-postgres-list-instances
```
## Troubleshooting
- **Tool not found:** Ensure the `<tool-name>` matches exactly what is in your YAML file and that the file is correctly loaded via `--tools-file`.
- **Invalid parameters:** Double-check your JSON syntax. The error message will usually indicate if the JSON parsing failed or if the parameters didn't match the tool's schema.
- **Auth errors:** The `invoke` command currently does not support flows requiring client-side authorization (like OAuth flow initiation via the CLI). It works best for tools using service-side authentication (e.g., Application Default Credentials).

View File

@@ -30,21 +30,6 @@ description: >
| | `--user-agent-metadata` | Appends additional metadata to the User-Agent. | | | | `--user-agent-metadata` | Appends additional metadata to the User-Agent. | |
| `-v` | `--version` | version for toolbox | | | `-v` | `--version` | version for toolbox | |
## Sub Commands
### `invoke`
Executes a tool directly with the provided parameters. This is useful for testing tool configurations and parameters without needing a full client setup.
**Syntax:**
```bash
toolbox invoke <tool-name> [params]
```
- `<tool-name>`: The name of the tool to execute (as defined in your configuration).
- `[params]`: (Optional) A JSON string containing the parameters for the tool.
## Examples ## Examples
### Transport Configuration ### Transport Configuration

View File

@@ -100,43 +100,6 @@ See [Usage Examples](../reference/cli.md#examples).
(timeseries metrics) for queries running in an AlloyDB instance using a (timeseries metrics) for queries running in an AlloyDB instance using a
PromQL query. PromQL query.
## AlloyDB Omni
* `--prebuilt` value: `alloydb-omni`
* **Environment Variables:**
* `ALLOYDB_OMNI_HOST`: (Optional) The hostname or IP address (Default: localhost).
* `ALLOYDB_OMNI_PORT`: (Optional) The port number (Default: 5432).
* `ALLOYDB_OMNI_DATABASE`: The name of the database to connect to.
* `ALLOYDB_OMNI_USER`: The database username.
* `ALLOYDB_OMNI_PASSWORD`: (Optional) The password for the database user.
* `ALLOYDB_OMNI_QUERY_PARAMS`: (Optional) Connection query parameters.
* **Tools:**
* `execute_sql`: Executes a SQL query.
* `list_tables`: Lists tables in the database.
* `list_autovacuum_configurations`: Lists autovacuum configurations in the
database.
* `list_columnar_configurations`: List AlloyDB Omni columnar-related configurations.
* `list_columnar_recommended_columns`: Lists columns that AlloyDB Omni recommends adding to the columnar engine.
* `list_memory_configurations`: Lists memory-related configurations in the
database.
* `list_top_bloated_tables`: List top bloated tables in the database.
* `list_replication_slots`: Lists replication slots in the database.
* `list_invalid_indexes`: Lists invalid indexes in the database.
* `get_query_plan`: Generate the execution plan of a statement.
* `list_views`: Lists views in the database from pg_views with a default
limit of 50 rows. Returns schemaname, viewname and the ownername.
* `list_schemas`: Lists schemas in the database.
* `database_overview`: Fetches the current state of the PostgreSQL server.
* `list_triggers`: Lists triggers in the database.
* `list_indexes`: List available user indexes in a PostgreSQL database.
* `list_sequences`: List sequences in a PostgreSQL database.
* `list_publication_tables`: List publication tables in a PostgreSQL database.
* `list_tablespaces`: Lists tablespaces in the database.
* `list_pg_settings`: List configuration parameters for the PostgreSQL server.
* `list_database_stats`: Lists the key performance and activity statistics for
each database in the AlloyDB instance.
* `list_roles`: Lists all the user-created roles in PostgreSQL database.
## BigQuery ## BigQuery
* `--prebuilt` value: `bigquery` * `--prebuilt` value: `bigquery`
@@ -414,10 +377,10 @@ See [Usage Examples](../reference/cli.md#examples).
entries. entries.
* **Dataplex Editor** (`roles/dataplex.editor`) to modify entries. * **Dataplex Editor** (`roles/dataplex.editor`) to modify entries.
* **Tools:** * **Tools:**
* `search_entries`: Searches for entries in Dataplex Catalog. * `dataplex_search_entries`: Searches for entries in Dataplex Catalog.
* `lookup_entry`: Retrieves a specific entry from Dataplex * `dataplex_lookup_entry`: Retrieves a specific entry from Dataplex
Catalog. Catalog.
* `search_aspect_types`: Finds aspect types relevant to the * `dataplex_search_aspect_types`: Finds aspect types relevant to the
query. query.
## Firestore ## Firestore

41
go.mod
View File

@@ -47,12 +47,11 @@ require (
github.com/sijms/go-ora/v2 v2.9.0 github.com/sijms/go-ora/v2 v2.9.0
github.com/snowflakedb/gosnowflake v1.18.1 github.com/snowflakedb/gosnowflake v1.18.1
github.com/spf13/cobra v1.10.1 github.com/spf13/cobra v1.10.1
github.com/testcontainers/testcontainers-go v0.40.0
github.com/thlib/go-timezone-local v0.0.7 github.com/thlib/go-timezone-local v0.0.7
github.com/trinodb/trino-go-client v0.330.0 github.com/trinodb/trino-go-client v0.330.0
github.com/valkey-io/valkey-go v1.0.68 github.com/valkey-io/valkey-go v1.0.68
github.com/yugabyte/pgx/v5 v5.5.3-yb-5 github.com/yugabyte/pgx/v5 v5.5.3-yb-5
go.mongodb.org/mongo-driver/v2 v2.4.2 go.mongodb.org/mongo-driver v1.17.4
go.opentelemetry.io/contrib/propagators/autoprop v0.62.0 go.opentelemetry.io/contrib/propagators/autoprop v0.62.0
go.opentelemetry.io/otel v1.38.0 go.opentelemetry.io/otel v1.38.0
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0 go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetrichttp v1.38.0
@@ -92,19 +91,16 @@ require (
cloud.google.com/go/iam v1.5.3 // indirect cloud.google.com/go/iam v1.5.3 // indirect
cloud.google.com/go/monitoring v1.24.3 // indirect cloud.google.com/go/monitoring v1.24.3 // indirect
cloud.google.com/go/trace v1.11.7 // indirect cloud.google.com/go/trace v1.11.7 // indirect
dario.cat/mergo v1.0.2 // indirect
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
github.com/99designs/keyring v1.2.2 // indirect github.com/99designs/keyring v1.2.2 // indirect
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 // indirect
github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.11.1 // indirect
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
github.com/BurntSushi/toml v1.4.0 // indirect github.com/BurntSushi/toml v1.4.0 // indirect
github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect github.com/GoogleCloudPlatform/grpc-gcp-go/grpcgcp v1.5.3 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.29.0 // indirect
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.54.0 // indirect
github.com/Microsoft/go-winio v0.6.2 // indirect
github.com/PuerkitoBio/goquery v1.10.3 // indirect github.com/PuerkitoBio/goquery v1.10.3 // indirect
github.com/VictoriaMetrics/easyproto v0.1.4 // indirect github.com/VictoriaMetrics/easyproto v0.1.4 // indirect
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
@@ -130,29 +126,17 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.4 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.34.4 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.38.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.38.4 // indirect
github.com/aws/smithy-go v1.23.0 // indirect github.com/aws/smithy-go v1.23.0 // indirect
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/containerd/platforms v0.2.1 // indirect
github.com/couchbase/gocbcore/v10 v10.8.1 // indirect github.com/couchbase/gocbcore/v10 v10.8.1 // indirect
github.com/couchbase/gocbcoreps v0.1.4 // indirect github.com/couchbase/gocbcoreps v0.1.4 // indirect
github.com/couchbase/goprotostellar v1.0.2 // indirect github.com/couchbase/goprotostellar v1.0.2 // indirect
github.com/couchbase/tools-common/errors v1.0.0 // indirect github.com/couchbase/tools-common/errors v1.0.0 // indirect
github.com/couchbaselabs/gocbconnstr/v2 v2.0.0 // indirect github.com/couchbaselabs/gocbconnstr/v2 v2.0.0 // indirect
github.com/cpuguy83/dockercfg v0.3.2 // indirect
github.com/danieljoos/wincred v1.2.2 // indirect github.com/danieljoos/wincred v1.2.2 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/docker v28.5.1+incompatible // indirect
github.com/docker/go-connections v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dvsekhvalnov/jose2go v1.7.0 // indirect github.com/dvsekhvalnov/jose2go v1.7.0 // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect
github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect
@@ -161,7 +145,6 @@ require (
github.com/go-logfmt/logfmt v0.6.0 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/logr v1.4.3 // indirect
github.com/go-logr/stdr v1.2.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
@@ -197,46 +180,27 @@ require (
github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/klauspost/cpuid/v2 v2.2.11 // indirect github.com/klauspost/cpuid/v2 v2.2.11 // indirect
github.com/leodido/go-urn v1.4.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.10 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect github.com/minio/asm2plan9s v0.0.0-20200509001527-cdd76441f9d8 // indirect
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/go-archive v0.1.0 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.6.0 // indirect
github.com/moby/sys/user v0.4.0 // indirect
github.com/moby/sys/userns v0.1.0 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect github.com/montanaflynn/stats v0.7.1 // indirect
github.com/mtibben/percent v0.2.1 // indirect github.com/mtibben/percent v0.2.1 // indirect
github.com/nakagami/chacha20 v0.1.0 // indirect github.com/nakagami/chacha20 v0.1.0 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pierrec/lz4 v2.6.1+incompatible // indirect github.com/pierrec/lz4 v2.6.1+incompatible // indirect
github.com/pierrec/lz4/v4 v4.1.22 // indirect github.com/pierrec/lz4/v4 v4.1.22 // indirect
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/shirou/gopsutil/v4 v4.25.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/pflag v1.0.9 // indirect github.com/spf13/pflag v1.0.9 // indirect
github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect
github.com/stretchr/testify v1.11.1 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/scram v1.1.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
github.com/yusufpapurcu/wmi v1.2.4 // indirect
github.com/zeebo/errs v1.4.0 // indirect github.com/zeebo/errs v1.4.0 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect github.com/zeebo/xxh3 v1.0.2 // indirect
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b // indirect gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b // indirect
@@ -269,7 +233,6 @@ require (
google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251103181224-f26f9409b101 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
modernc.org/libc v1.66.10 // indirect modernc.org/libc v1.66.10 // indirect
modernc.org/mathutil v1.7.1 // indirect modernc.org/mathutil v1.7.1 // indirect
modernc.org/memory v1.11.0 // indirect modernc.org/memory v1.11.0 // indirect

63
go.sum
View File

@@ -647,8 +647,6 @@ github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 h1:/vQbFIOMb
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4= github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4/go.mod h1:hN7oaIRCjzsZ2dE+yG5k+rsdt3qcwykqK6HVGcKwsw4=
github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0= github.com/99designs/keyring v1.2.2 h1:pZd3neh/EmUzWONb35LxQfvuY7kiSXAq3HQd97+XBn0=
github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk= github.com/99designs/keyring v1.2.2/go.mod h1:wes/FrByc8j7lFOAGLGSNEg8f/PaI3cgTBqhFkHUrPk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6 h1:He8afgbRMd7mFxO99hRNu+6tazq8nFF9lIwo9JFroBk=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20240806141605-e8a1dd7889d6/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0 h1:Gt0j3wceWMwPmiazCa8MzMA0MfhmPIz0Qp0FJ6qcM0U=
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.18.0/go.mod h1:Ot/6aikWnKWi4l9QB7qVSwa8iMphQNqkWALMoNT3rzM=
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.10.1 h1:B+blDbyVIG3WaikNxPnhPiJ1MThR03b3vKGtER95TP4=
@@ -802,14 +800,6 @@ github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv
github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8= github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4= github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE= github.com/containerd/continuity v0.4.5/go.mod h1:/lNJvtJKUQStBzpVQ1+rasXO1LAWtUQssk28EZvJ3nE=
github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI=
github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M=
github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE=
github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
github.com/couchbase/gocb/v2 v2.11.1 h1:xWDco7Qk/XSvGUjbUWRaXi0V35nsMijJnm4vHXN/rqY= github.com/couchbase/gocb/v2 v2.11.1 h1:xWDco7Qk/XSvGUjbUWRaXi0V35nsMijJnm4vHXN/rqY=
github.com/couchbase/gocb/v2 v2.11.1/go.mod h1:aSh1Cmd1sPRpYyiBD5iWPehPWaTVF/oYhrtOAITWb/4= github.com/couchbase/gocb/v2 v2.11.1/go.mod h1:aSh1Cmd1sPRpYyiBD5iWPehPWaTVF/oYhrtOAITWb/4=
github.com/couchbase/gocbcore/v10 v10.8.1 h1:i4SnH0DH9APGC4GS2vS2m+3u08V7oJwviamOXdgAZOQ= github.com/couchbase/gocbcore/v10 v10.8.1 h1:i4SnH0DH9APGC4GS2vS2m+3u08V7oJwviamOXdgAZOQ=
@@ -826,12 +816,8 @@ github.com/couchbaselabs/gocaves/client v0.0.0-20250107114554-f96479220ae8 h1:MQ
github.com/couchbaselabs/gocaves/client v0.0.0-20250107114554-f96479220ae8/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY= github.com/couchbaselabs/gocaves/client v0.0.0-20250107114554-f96479220ae8/go.mod h1:AVekAZwIY2stsJOMWLAS/0uA/+qdp7pjO8EHnl61QkY=
github.com/couchbaselabs/gocbconnstr/v2 v2.0.0 h1:HU9DlAYYWR69jQnLN6cpg0fh0hxW/8d5hnglCXXjW78= github.com/couchbaselabs/gocbconnstr/v2 v2.0.0 h1:HU9DlAYYWR69jQnLN6cpg0fh0hxW/8d5hnglCXXjW78=
github.com/couchbaselabs/gocbconnstr/v2 v2.0.0/go.mod h1:o7T431UOfFVHDNvMBUmUxpHnhivwv7BziUao/nMl81E= github.com/couchbaselabs/gocbconnstr/v2 v2.0.0/go.mod h1:o7T431UOfFVHDNvMBUmUxpHnhivwv7BziUao/nMl81E=
github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA=
github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0= github.com/danieljoos/wincred v1.2.2 h1:774zMFJrqaeYCK2W57BgAem/MLi6mtSE47MB6BOJ0i0=
github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8= github.com/danieljoos/wincred v1.2.2/go.mod h1:w7w4Utbrz8lqeMbDAK0lkNJUv5sAOkFi7nd/ogr0Uh8=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -840,12 +826,10 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY= github.com/docker/cli v28.4.0+incompatible h1:RBcf3Kjw2pMtwui5V0DIMdyeab8glEw5QY0UUU4C9kY=
github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/cli v28.4.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v28.5.1+incompatible h1:Bm8DchhSD2J6PsFzxC35TZo4TLGR2PdW/E69rU45NhM= github.com/docker/docker v28.4.0+incompatible h1:KVC7bz5zJY/4AZe/78BIvCnPsLaC9T/zh72xnlrTTOk=
github.com/docker/docker v28.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker v28.4.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94= github.com/docker/go-connections v0.6.0 h1:LlMG9azAe1TqfR7sO+NJttz1gy6KO7VJBh+pMmjSD94=
github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE= github.com/docker/go-connections v0.6.0/go.mod h1:AahvXYshr6JgfUJGdDCs2b5EZG/vmaMAntpSFH5BFKE=
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
@@ -856,8 +840,6 @@ github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkp
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo= github.com/dvsekhvalnov/jose2go v1.7.0 h1:bnQc8+GMnidJZA8zc6lLEAb4xNrIqHwO+9TzqvtQZPo=
github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU= github.com/dvsekhvalnov/jose2go v1.7.0/go.mod h1:QsHjhyTlD/lAVqn/NSbVZmSCGeDehTB/mPZadG+mhXU=
github.com/ebitengine/purego v0.8.4 h1:CF7LEKg5FFOsASUj0+QwaXf8Ht6TlFxg09+S9wz0omw=
github.com/ebitengine/purego v0.8.4/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
github.com/elastic/elastic-transport-go/v8 v8.8.0 h1:7k1Ua+qluFr6p1jfJjGDl97ssJS/P7cHNInzfxgBQAo= github.com/elastic/elastic-transport-go/v8 v8.8.0 h1:7k1Ua+qluFr6p1jfJjGDl97ssJS/P7cHNInzfxgBQAo=
github.com/elastic/elastic-transport-go/v8 v8.8.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk= github.com/elastic/elastic-transport-go/v8 v8.8.0/go.mod h1:YLHer5cj0csTzNFXoNQ8qhtGY1GTvSqPnKWKaqQE3Hk=
github.com/elastic/go-elasticsearch/v9 v9.2.0 h1:COeL/g20+ixnUbffe4Wfbu88emrHjAq/LhVfmrjqRQs= github.com/elastic/go-elasticsearch/v9 v9.2.0 h1:COeL/g20+ixnUbffe4Wfbu88emrHjAq/LhVfmrjqRQs=
@@ -931,8 +913,6 @@ github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.5.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M= github.com/go-pdf/fpdf v0.6.0/go.mod h1:HzcnA+A23uwogo0tp9yU+l3V+KXhiESpt1PMayhOh5M=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
@@ -1194,13 +1174,9 @@ github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/looker-open-source/sdk-codegen/go v0.25.22 h1:DGYt1v2R2uE/m71sWAvgxsJnDLM9B7C40N5/CTDlE2A= github.com/looker-open-source/sdk-codegen/go v0.25.22 h1:DGYt1v2R2uE/m71sWAvgxsJnDLM9B7C40N5/CTDlE2A=
github.com/looker-open-source/sdk-codegen/go v0.25.22/go.mod h1:Br1ntSiruDJ/4nYNjpYyWyCbqJ7+GQceWbIgn0hYims= github.com/looker-open-source/sdk-codegen/go v0.25.22/go.mod h1:Br1ntSiruDJ/4nYNjpYyWyCbqJ7+GQceWbIgn0hYims=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4=
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I=
github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.0/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA= github.com/lyft/protoc-gen-star v0.6.1/go.mod h1:TGAoBVkt8w7MPG72TrKIu85MIdXwDuzJYeZuUPFPNwA=
github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o= github.com/lyft/protoc-gen-star/v2 v2.0.1/go.mod h1:RcCdONR2ScXaYnQC5tUzxzlpA3WVYF7/opLeUgcQs/o=
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
@@ -1218,18 +1194,8 @@ github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3 h1:+n/aFZefKZp7spd8D
github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE= github.com/minio/c2goasm v0.0.0-20190812172519-36a3d3bbc4f3/go.mod h1:RagcQ7I8IeTMnF8JTXieKnO4Z6JCsikNEzj0DwauVzE=
github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
github.com/moby/go-archive v0.1.0 h1:Kk/5rdW/g+H8NHdJW2gsXyZ7UnzvJNOy6VKJqueWdcQ=
github.com/moby/go-archive v0.1.0/go.mod h1:G9B+YoujNohJmrIYFBpSd54GTUB4lt9S+xVQvsJyFuo=
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs= github.com/moby/sys/user v0.4.0 h1:jhcMKit7SA80hivmFJcbB1vqmw//wU61Zdui2eQXuMs=
github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= github.com/moby/sys/user v0.4.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs=
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -1238,8 +1204,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow=
github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs= github.com/mtibben/percent v0.2.1 h1:5gssi8Nqo8QU/r2pynCm+hBQHpkB/uNK7BJCFogWdzs=
github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns= github.com/mtibben/percent v0.2.1/go.mod h1:KG9uO+SZkUp+VkRHsCdYQV3XSZrrSpR3O9ibNBTZrns=
github.com/nakagami/chacha20 v0.1.0 h1:2fbf5KeVUw7oRpAe6/A7DqvBJLYYu0ka5WstFbnkEVo= github.com/nakagami/chacha20 v0.1.0 h1:2fbf5KeVUw7oRpAe6/A7DqvBJLYYu0ka5WstFbnkEVo=
@@ -1288,8 +1254,6 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw=
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
@@ -1311,8 +1275,6 @@ github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfF
github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk= github.com/ruudk/golang-pdf417 v0.0.0-20201230142125-a7e3863a1245/go.mod h1:pQAZKsJ8yyVxGRWYNEm9oFB8ieLgKFnamEyDmSA0BRk=
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
github.com/sijms/go-ora/v2 v2.9.0 h1:+iQbUeTeCOFMb5BsOMgUhV8KWyrv9yjKpcK4x7+MFrg= github.com/sijms/go-ora/v2 v2.9.0 h1:+iQbUeTeCOFMb5BsOMgUhV8KWyrv9yjKpcK4x7+MFrg=
@@ -1350,15 +1312,9 @@ github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/testcontainers/testcontainers-go v0.40.0 h1:pSdJYLOVgLE8YdUY2FHQ1Fxu+aMnb6JfVz1mxk7OeMU=
github.com/testcontainers/testcontainers-go v0.40.0/go.mod h1:FSXV5KQtX2HAMlm7U3APNyLkkap35zNLxukw9oBi/MY=
github.com/thlib/go-timezone-local v0.0.7 h1:fX8zd3aJydqLlTs/TrROrIIdztzsdFV23OzOQx31jII= github.com/thlib/go-timezone-local v0.0.7 h1:fX8zd3aJydqLlTs/TrROrIIdztzsdFV23OzOQx31jII=
github.com/thlib/go-timezone-local v0.0.7/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI= github.com/thlib/go-timezone-local v0.0.7/go.mod h1:/Tnicc6m/lsJE0irFMA0LfIwTBo4QP7A8IfyIv4zZKI=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU=
github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk=
github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY=
github.com/trinodb/trino-go-client v0.330.0 h1:TBbHjFBuRjYbGtkNyRAJfzLOcwvz8ECihtMtxSzXqOc= github.com/trinodb/trino-go-client v0.330.0 h1:TBbHjFBuRjYbGtkNyRAJfzLOcwvz8ECihtMtxSzXqOc=
github.com/trinodb/trino-go-client v0.330.0/go.mod h1:BXj9QNy6pA4Gn8eIu9dVdRhetABCjFAOZ6xxsVsOZJE= github.com/trinodb/trino-go-client v0.330.0/go.mod h1:BXj9QNy6pA4Gn8eIu9dVdRhetABCjFAOZ6xxsVsOZJE=
github.com/valkey-io/valkey-go v1.0.68 h1:bTbfonp49b41DqrF30q+y2JL3gcbjd2IiacFAtO4JBA= github.com/valkey-io/valkey-go v1.0.68 h1:bTbfonp49b41DqrF30q+y2JL3gcbjd2IiacFAtO4JBA=
@@ -1391,8 +1347,6 @@ github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9dec
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ= github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0= github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM= github.com/zeebo/errs v1.4.0 h1:XNdoD/RRMKP7HD0UhJnIzUy74ISdGGxURlYG8HSWSfM=
@@ -1402,8 +1356,8 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b h1:7gd+rd8P3bqcn/96gOZa3F5dpJr/vEiDQYlNb/y2uNs=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g= go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
go.mongodb.org/mongo-driver/v2 v2.4.2 h1:HrJ+Auygxceby9MLp3YITobef5a8Bv4HcPFIkml1U7U= go.mongodb.org/mongo-driver v1.17.4 h1:jUorfmVzljjr0FLzYQsGP8cgN/qzzxlY9Vh0C9KFXVw=
go.mongodb.org/mongo-driver/v2 v2.4.2/go.mod h1:jHeEDJHJq7tm6ZF45Issun9dbogjfnPySb1vXA7EeAI= go.mongodb.org/mongo-driver v1.17.4/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
@@ -1673,7 +1627,6 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1695,7 +1648,6 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1748,7 +1700,6 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
@@ -2178,8 +2129,6 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q=
gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -1,161 +0,0 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package invoke
import (
"context"
"encoding/json"
"fmt"
"io"
"github.com/googleapis/genai-toolbox/internal/log"
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/server/resources"
"github.com/googleapis/genai-toolbox/internal/util/parameters"
"github.com/spf13/cobra"
)
// RootCommand defines the interface for required by invoke subcommand.
// This allows subcommands to access shared resources and functionality without
// direct coupling to the root command's implementation.
type RootCommand interface {
// Config returns a copy of the current server configuration.
Config() server.ServerConfig
// Out returns the writer used for standard output.
Out() io.Writer
// LoadConfig loads and merges the configuration from files, folders, and prebuilts.
LoadConfig(ctx context.Context) error
// Setup initializes the runtime environment, including logging and telemetry.
// It returns the updated context and a shutdown function to be called when finished.
Setup(ctx context.Context) (context.Context, func(context.Context) error, error)
// Logger returns the logger instance.
Logger() log.Logger
}
func NewCommand(rootCmd RootCommand) *cobra.Command {
cmd := &cobra.Command{
Use: "invoke <tool-name> [params]",
Short: "Execute a tool directly",
Long: `Execute a tool directly with parameters.
Params must be a JSON string.
Example:
toolbox invoke my-tool '{"param1": "value1"}'`,
Args: cobra.MinimumNArgs(1),
RunE: func(c *cobra.Command, args []string) error {
return runInvoke(c, args, rootCmd)
},
}
return cmd
}
func runInvoke(cmd *cobra.Command, args []string, rootCmd RootCommand) error {
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()
ctx, shutdown, err := rootCmd.Setup(ctx)
if err != nil {
return err
}
defer func() {
_ = shutdown(ctx)
}()
// Load and merge tool configurations
if err := rootCmd.LoadConfig(ctx); err != nil {
return err
}
// Initialize Resources
sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, toolsetsMap, promptsMap, promptsetsMap, err := server.InitializeConfigs(ctx, rootCmd.Config())
if err != nil {
errMsg := fmt.Errorf("failed to initialize resources: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
resourceMgr := resources.NewResourceManager(sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, toolsetsMap, promptsMap, promptsetsMap)
// Execute Tool
toolName := args[0]
tool, ok := resourceMgr.GetTool(toolName)
if !ok {
errMsg := fmt.Errorf("tool %q not found", toolName)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
var paramsInput string
if len(args) > 1 {
paramsInput = args[1]
}
params := make(map[string]any)
if paramsInput != "" {
if err := json.Unmarshal([]byte(paramsInput), &params); err != nil {
errMsg := fmt.Errorf("params must be a valid JSON string: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
}
parsedParams, err := parameters.ParseParams(tool.GetParameters(), params, nil)
if err != nil {
errMsg := fmt.Errorf("invalid parameters: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
parsedParams, err = tool.EmbedParams(ctx, parsedParams, resourceMgr.GetEmbeddingModelMap())
if err != nil {
errMsg := fmt.Errorf("error embedding parameters: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
// Client Auth not supported for ephemeral CLI call
requiresAuth, err := tool.RequiresClientAuthorization(resourceMgr)
if err != nil {
errMsg := fmt.Errorf("failed to check auth requirements: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
if requiresAuth {
errMsg := fmt.Errorf("client authorization is not supported")
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
result, err := tool.Invoke(ctx, resourceMgr, parsedParams, "")
if err != nil {
errMsg := fmt.Errorf("tool execution failed: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
// Print Result
output, err := json.MarshalIndent(result, "", " ")
if err != nil {
errMsg := fmt.Errorf("failed to marshal result: %w", err)
rootCmd.Logger().ErrorContext(ctx, errMsg.Error())
return errMsg
}
fmt.Fprintln(rootCmd.Out(), string(output))
return nil
}

View File

@@ -22,18 +22,6 @@ import (
"strings" "strings"
) )
// NewLogger creates a new logger based on the provided format and level.
func NewLogger(format, level string, out, err io.Writer) (Logger, error) {
switch strings.ToLower(format) {
case "json":
return NewStructuredLogger(out, err, level)
case "standard":
return NewStdLogger(out, err, level)
default:
return nil, fmt.Errorf("logging format invalid: %s", format)
}
}
// StdLogger is the standard logger // StdLogger is the standard logger
type StdLogger struct { type StdLogger struct {
outLogger *slog.Logger outLogger *slog.Logger

View File

@@ -21,7 +21,6 @@ import (
) )
var expectedToolSources = []string{ var expectedToolSources = []string{
"alloydb-omni",
"alloydb-postgres-admin", "alloydb-postgres-admin",
"alloydb-postgres-observability", "alloydb-postgres-observability",
"alloydb-postgres", "alloydb-postgres",
@@ -100,40 +99,36 @@ func TestLoadPrebuiltToolYAMLs(t *testing.T) {
} }
func TestGetPrebuiltTool(t *testing.T) { func TestGetPrebuiltTool(t *testing.T) {
alloydb_omni_config := getOrFatal(t, "alloydb-omni") alloydb_admin_config, _ := Get("alloydb-postgres-admin")
alloydb_admin_config := getOrFatal(t, "alloydb-postgres-admin") alloydb_observability_config, _ := Get("alloydb-postgres-observability")
alloydb_observability_config := getOrFatal(t, "alloydb-postgres-observability") alloydb_config, _ := Get("alloydb-postgres")
alloydb_config := getOrFatal(t, "alloydb-postgres") bigquery_config, _ := Get("bigquery")
bigquery_config := getOrFatal(t, "bigquery") clickhouse_config, _ := Get("clickhouse")
clickhouse_config := getOrFatal(t, "clickhouse") cloudsqlpg_observability_config, _ := Get("cloud-sql-postgres-observability")
cloudsqlpg_observability_config := getOrFatal(t, "cloud-sql-postgres-observability") cloudsqlpg_config, _ := Get("cloud-sql-postgres")
cloudsqlpg_config := getOrFatal(t, "cloud-sql-postgres") cloudsqlpg_admin_config, _ := Get("cloud-sql-postgres-admin")
cloudsqlpg_admin_config := getOrFatal(t, "cloud-sql-postgres-admin") cloudsqlmysql_admin_config, _ := Get("cloud-sql-mysql-admin")
cloudsqlmysql_admin_config := getOrFatal(t, "cloud-sql-mysql-admin") cloudsqlmssql_admin_config, _ := Get("cloud-sql-mssql-admin")
cloudsqlmssql_admin_config := getOrFatal(t, "cloud-sql-mssql-admin") cloudsqlmysql_observability_config, _ := Get("cloud-sql-mysql-observability")
cloudsqlmysql_observability_config := getOrFatal(t, "cloud-sql-mysql-observability") cloudsqlmysql_config, _ := Get("cloud-sql-mysql")
cloudsqlmysql_config := getOrFatal(t, "cloud-sql-mysql") cloudsqlmssql_observability_config, _ := Get("cloud-sql-mssql-observability")
cloudsqlmssql_observability_config := getOrFatal(t, "cloud-sql-mssql-observability") cloudsqlmssql_config, _ := Get("cloud-sql-mssql")
cloudsqlmssql_config := getOrFatal(t, "cloud-sql-mssql") dataplex_config, _ := Get("dataplex")
dataplex_config := getOrFatal(t, "dataplex") firestoreconfig, _ := Get("firestore")
firestoreconfig := getOrFatal(t, "firestore") looker_config, _ := Get("looker")
looker_config := getOrFatal(t, "looker") lookerca_config, _ := Get("looker-conversational-analytics")
lookerca_config := getOrFatal(t, "looker-conversational-analytics") mysql_config, _ := Get("mysql")
mysql_config := getOrFatal(t, "mysql") mssql_config, _ := Get("mssql")
mssql_config := getOrFatal(t, "mssql") oceanbase_config, _ := Get("oceanbase")
oceanbase_config := getOrFatal(t, "oceanbase") postgresconfig, _ := Get("postgres")
postgresconfig := getOrFatal(t, "postgres") singlestore_config, _ := Get("singlestore")
singlestore_config := getOrFatal(t, "singlestore") spanner_config, _ := Get("spanner")
spanner_config := getOrFatal(t, "spanner") spannerpg_config, _ := Get("spanner-postgres")
spannerpg_config := getOrFatal(t, "spanner-postgres") mindsdb_config, _ := Get("mindsdb")
mindsdb_config := getOrFatal(t, "mindsdb") sqlite_config, _ := Get("sqlite")
sqlite_config := getOrFatal(t, "sqlite") neo4jconfig, _ := Get("neo4j")
neo4jconfig := getOrFatal(t, "neo4j") healthcare_config, _ := Get("cloud-healthcare")
healthcare_config := getOrFatal(t, "cloud-healthcare") snowflake_config, _ := Get("snowflake")
snowflake_config := getOrFatal(t, "snowflake")
if len(alloydb_omni_config) <= 0 {
t.Fatalf("unexpected error: could not fetch alloydb omni prebuilt tools yaml")
}
if len(alloydb_admin_config) <= 0 { if len(alloydb_admin_config) <= 0 {
t.Fatalf("unexpected error: could not fetch alloydb admin prebuilt tools yaml") t.Fatalf("unexpected error: could not fetch alloydb admin prebuilt tools yaml")
} }
@@ -238,11 +233,3 @@ func TestFailGetPrebuiltTool(t *testing.T) {
t.Fatalf("unexpected an error but got nil.") t.Fatalf("unexpected an error but got nil.")
} }
} }
func getOrFatal(t *testing.T, prebuiltSourceConfig string) []byte {
bytes, err := Get(prebuiltSourceConfig)
if err != nil {
t.Fatalf("Cannot get prebuilt config for %q, error %v", prebuiltSourceConfig, err)
}
return bytes
}

View File

@@ -1,277 +0,0 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
sources:
alloydb-omni-source:
kind: postgres
host: ${ALLOYDB_OMNI_HOST:localhost}
port: ${ALLOYDB_OMNI_PORT:5432}
database: ${ALLOYDB_OMNI_DATABASE}
user: ${ALLOYDB_OMNI_USER}
password: ${ALLOYDB_OMNI_PASSWORD:}
queryParams: ${ALLOYDB_OMNI_QUERY_PARAMS:}
tools:
execute_sql:
kind: postgres-execute-sql
source: alloydb-omni-source
description: Use this tool to execute sql.
list_tables:
kind: postgres-list-tables
source: alloydb-omni-source
description: "Lists detailed schema information (object type, columns, constraints, indexes, triggers, owner, comment) as JSON for user-created tables (ordinary or partitioned). Filters by a comma-separated list of names. If names are omitted, lists all tables in user schemas."
list_active_queries:
kind: postgres-list-active-queries
source: alloydb-omni-source
description: "List the top N (default 50) currently running queries (state='active') from pg_stat_activity, ordered by longest-running first. Returns pid, user, database, application_name, client_addr, state, wait_event_type/wait_event, backend/xact/query start times, computed query_duration, and the SQL text."
list_available_extensions:
kind: postgres-list-available-extensions
source: alloydb-omni-source
description: "Discover all PostgreSQL extensions available for installation on this server, returning name, default_version, and description."
list_installed_extensions:
kind: postgres-list-installed-extensions
source: alloydb-omni-source
description: "List all installed PostgreSQL extensions with their name, version, schema, owner, and description."
long_running_transactions:
kind: postgres-long-running-transactions
source: alloydb-omni-source
list_locks:
kind: postgres-list-locks
source: alloydb-omni-source
replication_stats:
kind: postgres-replication-stats
source: alloydb-omni-source
list_autovacuum_configurations:
kind: postgres-sql
source: alloydb-omni-source
description: "List PostgreSQL autovacuum-related configurations (name and current setting) from pg_settings."
statement: |
SELECT name,
setting
FROM pg_settings
WHERE category = 'Autovacuum';
list_columnar_configurations:
kind: postgres-sql
source: alloydb-omni-source
description: "List AlloyDB Omni columnar-related configurations (name and current setting) from pg_settings."
statement: |
SELECT name,
setting
FROM pg_settings
WHERE name like 'google_columnar_engine.%';
list_columnar_recommended_columns:
kind: postgres-sql
source: alloydb-omni-source
description: "Lists columns that AlloyDB Omni recommends adding to the columnar engine to improve query performance."
statement: select * from g_columnar_recommended_columns;
list_memory_configurations:
kind: postgres-sql
source: alloydb-omni-source
description: "List PostgreSQL memory-related configurations (name and current setting) from pg_settings."
statement: |
(
SELECT
name,
pg_size_pretty((setting::bigint * 1024)::bigint) setting
FROM pg_settings
WHERE name IN ('work_mem', 'maintenance_work_mem')
)
UNION ALL
(
SELECT
name,
pg_size_pretty((((setting::bigint) * 8) * 1024)::bigint)
FROM pg_settings
WHERE name IN ('shared_buffers', 'wal_buffers', 'effective_cache_size', 'temp_buffers')
)
ORDER BY 1 DESC;
list_top_bloated_tables:
kind: postgres-sql
source: alloydb-omni-source
description: |
List the top tables by dead-tuple (approximate bloat signal), returning schema, table, live/dead tuples, percentage, and last vacuum/analyze times.
statement: |
SELECT
schemaname AS schema_name,
relname AS relation_name,
n_live_tup AS live_tuples,
n_dead_tup AS dead_tuples,
TRUNC((n_dead_tup::NUMERIC / NULLIF(n_live_tup + n_dead_tup, 0)) * 100, 2) AS dead_tuple_percentage,
last_vacuum,
last_autovacuum,
last_analyze,
last_autoanalyze
FROM pg_stat_user_tables
ORDER BY n_dead_tup DESC
LIMIT COALESCE($1::int, 50);
parameters:
- name: limit
description: "The maximum number of results to return."
type: integer
default: 50
list_replication_slots:
kind: postgres-sql
source: alloydb-omni-source
description: "List key details for all PostgreSQL replication slots (e.g., type, database, active status) and calculates the size of the outstanding WAL that is being prevented from removal by the slot."
statement: |
SELECT
slot_name,
slot_type,
plugin,
database,
temporary,
active,
restart_lsn,
confirmed_flush_lsn,
xmin,
catalog_xmin,
pg_size_pretty(pg_wal_lsn_diff(pg_current_wal_lsn(), restart_lsn)) AS retained_wal
FROM pg_replication_slots;
list_invalid_indexes:
kind: postgres-sql
source: alloydb-omni-source
description: "Lists all invalid PostgreSQL indexes which are taking up disk space but are unusable by the query planner. Typically created by failed CREATE INDEX CONCURRENTLY operations."
statement: |
SELECT
nspname AS schema_name,
indexrelid::regclass AS index_name,
indrelid::regclass AS table_name,
pg_size_pretty(pg_total_relation_size(indexrelid)) AS index_size,
indisready,
indisvalid,
pg_get_indexdef(pg_class.oid) AS index_def
FROM pg_index
JOIN pg_class ON pg_class.oid = pg_index.indexrelid
JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE indisvalid = FALSE;
get_query_plan:
kind: postgres-sql
source: alloydb-omni-source
description: "Generate a PostgreSQL EXPLAIN plan in JSON format for a single SQL statement—without executing it. This returns the optimizer's estimated plan, costs, and rows (no ANALYZE, no extra options). Use in production safely for plan inspection, regression checks, and query tuning workflows."
statement: |
EXPLAIN (FORMAT JSON) {{.query}};
templateParameters:
- name: query
type: string
description: "The SQL statement for which you want to generate plan (omit the EXPLAIN keyword)."
required: true
list_views:
kind: postgres-list-views
source: alloydb-omni-source
list_schemas:
kind: postgres-list-schemas
source: alloydb-omni-source
list_indexes:
kind: postgres-list-indexes
source: alloydb-omni-source
list_sequences:
kind: postgres-list-sequences
source: alloydb-omni-source
database_overview:
kind: postgres-database-overview
source: alloydb-omni-source
list_triggers:
kind: postgres-list-triggers
source: alloydb-omni-source
list_query_stats:
kind: postgres-list-query-stats
source: alloydb-omni-source
get_column_cardinality:
kind: postgres-get-column-cardinality
source: alloydb-omni-source
list_table_stats:
kind: postgres-list-table-stats
source: alloydb-omni-source
list_publication_tables:
kind: postgres-list-publication-tables
source: alloydb-omni-source
list_tablespaces:
kind: postgres-list-tablespaces
source: alloydb-omni-source
list_pg_settings:
kind: postgres-list-pg-settings
source: alloydb-omni-source
list_database_stats:
kind: postgres-list-database-stats
source: alloydb-omni-source
list_roles:
kind: postgres-list-roles
source: alloydb-omni-source
list_stored_procedure:
kind: postgres-list-stored-procedure
source: alloydb-omni-source
toolsets:
alloydb_omni_database_tools:
- execute_sql
- list_tables
- list_active_queries
- list_available_extensions
- list_installed_extensions
- list_autovacuum_configurations
- list_columnar_configurations
- list_columnar_recommended_columns
- list_memory_configurations
- list_top_bloated_tables
- list_replication_slots
- list_invalid_indexes
- get_query_plan
- list_views
- list_schemas
- database_overview
- list_triggers
- list_indexes
- list_sequences
- long_running_transactions
- list_locks
- replication_stats
- list_query_stats
- get_column_cardinality
- list_publication_tables
- list_tablespaces
- list_pg_settings
- list_database_stats
- list_roles
- list_table_stats
- list_stored_procedure

View File

@@ -19,6 +19,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware" "github.com/go-chi/chi/v5/middleware"
@@ -234,10 +235,8 @@ func toolInvokeHandler(s *Server, w http.ResponseWriter, r *http.Request) {
params, err := parameters.ParseParams(tool.GetParameters(), data, claimsFromAuth) params, err := parameters.ParseParams(tool.GetParameters(), data, claimsFromAuth)
if err != nil { if err != nil {
// If auth error, return 401 // If auth error, return 401
errMsg := fmt.Sprintf("error parsing authenticated parameters from ID token: %w", err) if errors.Is(err, util.ErrUnauthorized) {
var clientServerErr *util.ClientServerError s.logger.DebugContext(ctx, fmt.Sprintf("error parsing authenticated parameters from ID token: %s", err))
if errors.As(err, &clientServerErr) && clientServerErr.Code == http.StatusUnauthorized {
s.logger.DebugContext(ctx, errMsg)
_ = render.Render(w, r, newErrResponse(err, http.StatusUnauthorized)) _ = render.Render(w, r, newErrResponse(err, http.StatusUnauthorized))
return return
} }
@@ -260,49 +259,34 @@ func toolInvokeHandler(s *Server, w http.ResponseWriter, r *http.Request) {
// Determine what error to return to the users. // Determine what error to return to the users.
if err != nil { if err != nil {
var tbErr util.ToolboxError errStr := err.Error()
var statusCode int
if errors.As(err, &tbErr) { // Upstream API auth error propagation
switch tbErr.Category() { switch {
case util.CategoryAgent: case strings.Contains(errStr, "Error 401"):
// Agent Errors -> 200 OK statusCode = http.StatusUnauthorized
s.logger.DebugContext(ctx, fmt.Sprintf("Tool invocation agent error: %v", err)) case strings.Contains(errStr, "Error 403"):
_ = render.Render(w, r, newErrResponse(err, http.StatusOK)) statusCode = http.StatusForbidden
return }
case util.CategoryServer: if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden {
// Server Errors -> Check the specific code inside if clientAuth {
var clientServerErr *util.ClientServerError // Propagate the original 401/403 error.
statusCode := http.StatusInternalServerError // Default to 500 s.logger.DebugContext(ctx, fmt.Sprintf("error invoking tool. Client credentials lack authorization to the source: %v", err))
if errors.As(err, &clientServerErr) {
if clientServerErr.Code != 0 {
statusCode = clientServerErr.Code
}
}
// Process auth error
if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden {
if clientAuth {
// Token error, pass through 401/403
s.logger.DebugContext(ctx, fmt.Sprintf("Client credentials lack authorization: %v", err))
_ = render.Render(w, r, newErrResponse(err, statusCode))
return
}
// ADC/Config error, return 500
statusCode = http.StatusInternalServerError
}
s.logger.ErrorContext(ctx, fmt.Sprintf("Tool invocation server error: %v", err))
_ = render.Render(w, r, newErrResponse(err, statusCode)) _ = render.Render(w, r, newErrResponse(err, statusCode))
return return
} }
} else { // ADC lacking permission or credentials configuration error.
// Unknown error -> 500 internalErr := fmt.Errorf("unexpected auth error occured during Tool invocation: %w", err)
s.logger.ErrorContext(ctx, fmt.Sprintf("Tool invocation unknown error: %v", err)) s.logger.ErrorContext(ctx, internalErr.Error())
_ = render.Render(w, r, newErrResponse(err, http.StatusInternalServerError)) _ = render.Render(w, r, newErrResponse(internalErr, http.StatusInternalServerError))
return return
} }
err = fmt.Errorf("error while invoking tool: %w", err)
s.logger.DebugContext(ctx, err.Error())
_ = render.Render(w, r, newErrResponse(err, http.StatusBadRequest))
return
} }
resMarshal, err := json.Marshal(res) resMarshal, err := json.Marshal(res)

View File

@@ -30,7 +30,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/server/resources" "github.com/googleapis/genai-toolbox/internal/server/resources"
"github.com/googleapis/genai-toolbox/internal/telemetry" "github.com/googleapis/genai-toolbox/internal/telemetry"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -52,7 +51,7 @@ type MockTool struct {
requiresClientAuthrorization bool requiresClientAuthrorization bool
} }
func (t MockTool) Invoke(context.Context, tools.SourceProvider, parameters.ParamValues, tools.AccessToken) (any, util.ToolboxError) { func (t MockTool) Invoke(context.Context, tools.SourceProvider, parameters.ParamValues, tools.AccessToken) (any, error) {
mock := []any{t.Name} mock := []any{t.Name}
return mock, nil return mock, nil
} }

View File

@@ -23,6 +23,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"strings"
"sync" "sync"
"time" "time"
@@ -443,17 +444,15 @@ func httpHandler(s *Server, w http.ResponseWriter, r *http.Request) {
code := rpcResponse.Error.Code code := rpcResponse.Error.Code
switch code { switch code {
case jsonrpc.INTERNAL_ERROR: case jsonrpc.INTERNAL_ERROR:
// Map Internal RPC Error (-32603) to HTTP 500
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
case jsonrpc.INVALID_REQUEST: case jsonrpc.INVALID_REQUEST:
var clientServerErr *util.ClientServerError errStr := err.Error()
if errors.As(err, &clientServerErr) { if errors.Is(err, util.ErrUnauthorized) {
switch clientServerErr.Code { w.WriteHeader(http.StatusUnauthorized)
case http.StatusUnauthorized: } else if strings.Contains(errStr, "Error 401") {
w.WriteHeader(http.StatusUnauthorized) w.WriteHeader(http.StatusUnauthorized)
case http.StatusForbidden: } else if strings.Contains(errStr, "Error 403") {
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
}
} }
} }
} }

View File

@@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"github.com/googleapis/genai-toolbox/internal/prompts" "github.com/googleapis/genai-toolbox/internal/prompts"
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc" "github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
@@ -123,11 +124,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
} }
if clientAuth { if clientAuth {
if accessToken == "" { if accessToken == "" {
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.NewClientServerError( return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
"missing access token in the 'Authorization' header",
http.StatusUnauthorized,
nil,
)
} }
} }
@@ -175,11 +172,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// Check if any of the specified auth services is verified // Check if any of the specified auth services is verified
isAuthorized := tool.Authorized(verifiedAuthServices) isAuthorized := tool.Authorized(verifiedAuthServices)
if !isAuthorized { if !isAuthorized {
err = util.NewClientServerError( err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
"unauthorized Tool call: Please make sure you specify correct auth headers",
http.StatusUnauthorized,
nil,
)
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
} }
logger.DebugContext(ctx, "tool invocation authorized") logger.DebugContext(ctx, "tool invocation authorized")
@@ -201,44 +194,30 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// run tool invocation and generate response. // run tool invocation and generate response.
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken) results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
if err != nil { if err != nil {
var tbErr util.ToolboxError errStr := err.Error()
// Missing authService tokens.
if errors.As(err, &tbErr) { if errors.Is(err, util.ErrUnauthorized) {
switch tbErr.Category() { return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
case util.CategoryAgent: }
// MCP - Tool execution error // Upstream auth error
// Return SUCCESS but with IsError: true if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
text := TextContent{ if clientAuth {
Type: "text", // Error with client credentials should pass down to the client
Text: err.Error(), return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
case util.CategoryServer:
// MCP Spec - Protocol error
// Return JSON-RPC ERROR
var clientServerErr *util.ClientServerError
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
if errors.As(err, &clientServerErr) {
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
if clientAuth {
rpcCode = jsonrpc.INVALID_REQUEST
} else {
rpcCode = jsonrpc.INTERNAL_ERROR
}
}
}
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
} }
} else { // Auth error with ADC should raise internal 500 error
// Unknown error -> 500
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
} }
text := TextContent{
Type: "text",
Text: err.Error(),
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
} }
content := make([]TextContent, 0) content := make([]TextContent, 0)

View File

@@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"github.com/googleapis/genai-toolbox/internal/prompts" "github.com/googleapis/genai-toolbox/internal/prompts"
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc" "github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
@@ -123,11 +124,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
} }
if clientAuth { if clientAuth {
if accessToken == "" { if accessToken == "" {
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.NewClientServerError( return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
"missing access token in the 'Authorization' header",
http.StatusUnauthorized,
nil,
)
} }
} }
@@ -175,11 +172,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// Check if any of the specified auth services is verified // Check if any of the specified auth services is verified
isAuthorized := tool.Authorized(verifiedAuthServices) isAuthorized := tool.Authorized(verifiedAuthServices)
if !isAuthorized { if !isAuthorized {
err = util.NewClientServerError( err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
"unauthorized Tool call: Please make sure you specify correct auth headers",
http.StatusUnauthorized,
nil,
)
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
} }
logger.DebugContext(ctx, "tool invocation authorized") logger.DebugContext(ctx, "tool invocation authorized")
@@ -201,45 +194,31 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// run tool invocation and generate response. // run tool invocation and generate response.
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken) results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
if err != nil { if err != nil {
var tbErr util.ToolboxError errStr := err.Error()
// Missing authService tokens.
if errors.As(err, &tbErr) { if errors.Is(err, util.ErrUnauthorized) {
switch tbErr.Category() { return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
case util.CategoryAgent: }
// MCP - Tool execution error // Upstream auth error
// Return SUCCESS but with IsError: true if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
text := TextContent{ if clientAuth {
Type: "text", // Error with client credentials should pass down to the client
Text: err.Error(), return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
case util.CategoryServer:
// MCP Spec - Protocol error
// Return JSON-RPC ERROR
var clientServerErr *util.ClientServerError
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
if errors.As(err, &clientServerErr) {
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
if clientAuth {
rpcCode = jsonrpc.INVALID_REQUEST
} else {
rpcCode = jsonrpc.INTERNAL_ERROR
}
}
}
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
} }
} else { // Auth error with ADC should raise internal 500 error
// Unknown error -> 500
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
} }
text := TextContent{
Type: "text",
Text: err.Error(),
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
} }
content := make([]TextContent, 0) content := make([]TextContent, 0)
sliceRes, ok := results.([]any) sliceRes, ok := results.([]any)

View File

@@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"github.com/googleapis/genai-toolbox/internal/prompts" "github.com/googleapis/genai-toolbox/internal/prompts"
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc" "github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
@@ -116,12 +117,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
} }
if clientAuth { if clientAuth {
if accessToken == "" { if accessToken == "" {
errMsg := "missing access token in the 'Authorization' header" return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, errMsg, nil), util.NewClientServerError(
errMsg,
http.StatusUnauthorized,
nil,
)
} }
} }
@@ -169,11 +165,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// Check if any of the specified auth services is verified // Check if any of the specified auth services is verified
isAuthorized := tool.Authorized(verifiedAuthServices) isAuthorized := tool.Authorized(verifiedAuthServices)
if !isAuthorized { if !isAuthorized {
err = util.NewClientServerError( err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
"unauthorized Tool call: Please make sure you specify correct auth headers",
http.StatusUnauthorized,
nil,
)
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
} }
logger.DebugContext(ctx, "tool invocation authorized") logger.DebugContext(ctx, "tool invocation authorized")
@@ -195,44 +187,29 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// run tool invocation and generate response. // run tool invocation and generate response.
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken) results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
if err != nil { if err != nil {
var tbErr util.ToolboxError errStr := err.Error()
// Missing authService tokens.
if errors.As(err, &tbErr) { if errors.Is(err, util.ErrUnauthorized) {
switch tbErr.Category() { return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
case util.CategoryAgent: }
// MCP - Tool execution error // Upstream auth error
// Return SUCCESS but with IsError: true if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
text := TextContent{ if clientAuth {
Type: "text", // Error with client credentials should pass down to the client
Text: err.Error(), return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
case util.CategoryServer:
// MCP Spec - Protocol error
// Return JSON-RPC ERROR
var clientServerErr *util.ClientServerError
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
if errors.As(err, &clientServerErr) {
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
if clientAuth {
rpcCode = jsonrpc.INVALID_REQUEST
} else {
rpcCode = jsonrpc.INTERNAL_ERROR
}
}
}
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
} }
} else { // Auth error with ADC should raise internal 500 error
// Unknown error -> 500
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
} }
text := TextContent{
Type: "text",
Text: err.Error(),
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
} }
content := make([]TextContent, 0) content := make([]TextContent, 0)

View File

@@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
"strings"
"github.com/googleapis/genai-toolbox/internal/prompts" "github.com/googleapis/genai-toolbox/internal/prompts"
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc" "github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
@@ -116,11 +117,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
} }
if clientAuth { if clientAuth {
if accessToken == "" { if accessToken == "" {
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.NewClientServerError( return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
"missing access token in the 'Authorization' header",
http.StatusUnauthorized,
nil,
)
} }
} }
@@ -168,11 +165,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// Check if any of the specified auth services is verified // Check if any of the specified auth services is verified
isAuthorized := tool.Authorized(verifiedAuthServices) isAuthorized := tool.Authorized(verifiedAuthServices)
if !isAuthorized { if !isAuthorized {
err = util.NewClientServerError( err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
"unauthorized Tool call: Please make sure you specify correct auth headers",
http.StatusUnauthorized,
nil,
)
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
} }
logger.DebugContext(ctx, "tool invocation authorized") logger.DebugContext(ctx, "tool invocation authorized")
@@ -194,44 +187,29 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
// run tool invocation and generate response. // run tool invocation and generate response.
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken) results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
if err != nil { if err != nil {
var tbErr util.ToolboxError errStr := err.Error()
// Missing authService tokens.
if errors.As(err, &tbErr) { if errors.Is(err, util.ErrUnauthorized) {
switch tbErr.Category() { return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
case util.CategoryAgent: }
// MCP - Tool execution error // Upstream auth error
// Return SUCCESS but with IsError: true if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
text := TextContent{ if clientAuth {
Type: "text", // Error with client credentials should pass down to the client
Text: err.Error(), return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
case util.CategoryServer:
// MCP Spec - Protocol error
// Return JSON-RPC ERROR
var clientServerErr *util.ClientServerError
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
if errors.As(err, &clientServerErr) {
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
if clientAuth {
rpcCode = jsonrpc.INVALID_REQUEST
} else {
rpcCode = jsonrpc.INTERNAL_ERROR
}
}
}
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
} }
} else { // Auth error with ADC should raise internal 500 error
// Unknown error -> 500
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
} }
text := TextContent{
Type: "text",
Text: err.Error(),
}
return jsonrpc.JSONRPCResponse{
Jsonrpc: jsonrpc.JSONRPC_VERSION,
Id: id,
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
}, nil
} }
content := make([]TextContent, 0) content := make([]TextContent, 0)

View File

@@ -23,9 +23,9 @@ import (
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util"
"go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/v2/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/trace"
) )
@@ -148,7 +148,7 @@ func (s *Source) Aggregate(ctx context.Context, pipelineString string, canonical
return res, err return res, err
} }
func (s *Source) Find(ctx context.Context, filterString, database, collection string, opts *options.FindOptionsBuilder) ([]any, error) { func (s *Source) Find(ctx context.Context, filterString, database, collection string, opts *options.FindOptions) ([]any, error) {
var filter = bson.D{} var filter = bson.D{}
err := bson.UnmarshalExtJSON([]byte(filterString), false, &filter) err := bson.UnmarshalExtJSON([]byte(filterString), false, &filter)
if err != nil { if err != nil {
@@ -163,7 +163,7 @@ func (s *Source) Find(ctx context.Context, filterString, database, collection st
return parseData(ctx, cur) return parseData(ctx, cur)
} }
func (s *Source) FindOne(ctx context.Context, filterString, database, collection string, opts *options.FindOneOptionsBuilder) ([]any, error) { func (s *Source) FindOne(ctx context.Context, filterString, database, collection string, opts *options.FindOneOptions) ([]any, error) {
var filter = bson.D{} var filter = bson.D{}
err := bson.UnmarshalExtJSON([]byte(filterString), false, &filter) err := bson.UnmarshalExtJSON([]byte(filterString), false, &filter)
if err != nil { if err != nil {
@@ -233,7 +233,7 @@ func (s *Source) UpdateMany(ctx context.Context, filterString string, canonical
return nil, fmt.Errorf("unable to unmarshal update string: %w", err) return nil, fmt.Errorf("unable to unmarshal update string: %w", err)
} }
res, err := s.MongoClient().Database(database).Collection(collection).UpdateMany(ctx, filter, update, options.UpdateMany().SetUpsert(upsert)) res, err := s.MongoClient().Database(database).Collection(collection).UpdateMany(ctx, filter, update, options.Update().SetUpsert(upsert))
if err != nil { if err != nil {
return nil, fmt.Errorf("error updating collection: %w", err) return nil, fmt.Errorf("error updating collection: %w", err)
} }
@@ -252,7 +252,7 @@ func (s *Source) UpdateOne(ctx context.Context, filterString string, canonical b
return nil, fmt.Errorf("unable to unmarshal update string: %w", err) return nil, fmt.Errorf("unable to unmarshal update string: %w", err)
} }
res, err := s.MongoClient().Database(database).Collection(collection).UpdateOne(ctx, filter, update, options.UpdateOne().SetUpsert(upsert)) res, err := s.MongoClient().Database(database).Collection(collection).UpdateOne(ctx, filter, update, options.Update().SetUpsert(upsert))
if err != nil { if err != nil {
return nil, fmt.Errorf("error updating collection: %w", err) return nil, fmt.Errorf("error updating collection: %w", err)
} }
@@ -266,7 +266,7 @@ func (s *Source) DeleteMany(ctx context.Context, filterString, database, collect
return nil, err return nil, err
} }
res, err := s.MongoClient().Database(database).Collection(collection).DeleteMany(ctx, filter, options.DeleteMany()) res, err := s.MongoClient().Database(database).Collection(collection).DeleteMany(ctx, filter, options.Delete())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -284,7 +284,7 @@ func (s *Source) DeleteOne(ctx context.Context, filterString, database, collecti
return nil, err return nil, err
} }
res, err := s.MongoClient().Database(database).Collection(collection).DeleteOne(ctx, filter, options.DeleteOne()) res, err := s.MongoClient().Database(database).Collection(collection).DeleteOne(ctx, filter, options.Delete())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -303,7 +303,7 @@ func initMongoDBClient(ctx context.Context, tracer trace.Tracer, name, uri strin
// Create a new MongoDB client // Create a new MongoDB client
clientOpts := options.Client().ApplyURI(uri).SetAppName(userAgent) clientOpts := options.Client().ApplyURI(uri).SetAppName(userAgent)
client, err := mongo.Connect(clientOpts) client, err := mongo.Connect(ctx, clientOpts)
if err != nil { if err != nil {
return nil, fmt.Errorf("unable to create MongoDB client: %w", err) return nil, fmt.Errorf("unable to create MongoDB client: %w", err)
} }

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -123,49 +122,44 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok || project == "" {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a non-empty string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
clusterID, ok := paramsMap["cluster"].(string) clusterID, ok := paramsMap["cluster"].(string)
if !ok || clusterID == "" { if !ok || clusterID == "" {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'cluster' parameter; expected a non-empty string")
} }
password, ok := paramsMap["password"].(string) password, ok := paramsMap["password"].(string)
if !ok || password == "" { if !ok || password == "" {
return nil, util.NewAgentError("invalid or missing 'password' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'password' parameter; expected a non-empty string")
} }
network, ok := paramsMap["network"].(string) network, ok := paramsMap["network"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'network' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'network' parameter; expected a string")
} }
user, ok := paramsMap["user"].(string) user, ok := paramsMap["user"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'user' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'user' parameter; expected a string")
}
resp, err := source.CreateCluster(ctx, project, location, network, user, password, clusterID, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
} }
return resp, nil return source.CreateCluster(ctx, project, location, network, user, password, clusterID, string(accessToken))
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -124,36 +123,36 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok || project == "" {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a non-empty string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok || location == "" { if !ok || location == "" {
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'location' parameter; expected a non-empty string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok || cluster == "" { if !ok || cluster == "" {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'cluster' parameter; expected a non-empty string")
} }
instanceID, ok := paramsMap["instance"].(string) instanceID, ok := paramsMap["instance"].(string)
if !ok || instanceID == "" { if !ok || instanceID == "" {
return nil, util.NewAgentError("invalid or missing 'instance' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'instance' parameter; expected a non-empty string")
} }
instanceType, ok := paramsMap["instanceType"].(string) instanceType, ok := paramsMap["instanceType"].(string)
if !ok || (instanceType != "READ_POOL" && instanceType != "PRIMARY") { if !ok || (instanceType != "READ_POOL" && instanceType != "PRIMARY") {
return nil, util.NewAgentError("invalid 'instanceType' parameter; expected 'PRIMARY' or 'READ_POOL'", nil) return nil, fmt.Errorf("invalid 'instanceType' parameter; expected 'PRIMARY' or 'READ_POOL'")
} }
displayName, _ := paramsMap["displayName"].(string) displayName, _ := paramsMap["displayName"].(string)
@@ -162,15 +161,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if instanceType == "READ_POOL" { if instanceType == "READ_POOL" {
nodeCount, ok = paramsMap["nodeCount"].(int) nodeCount, ok = paramsMap["nodeCount"].(int)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'nodeCount' parameter; expected an integer for READ_POOL", nil) return nil, fmt.Errorf("invalid 'nodeCount' parameter; expected an integer for READ_POOL")
} }
} }
resp, err := source.CreateInstance(ctx, project, location, cluster, instanceID, instanceType, displayName, nodeCount, string(accessToken)) return source.CreateInstance(ctx, project, location, cluster, instanceID, instanceType, displayName, nodeCount, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -123,43 +122,43 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok || project == "" {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a non-empty string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok || location == "" { if !ok || location == "" {
return nil, util.NewAgentError("invalid or missing'location' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing'location' parameter; expected a non-empty string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok || cluster == "" { if !ok || cluster == "" {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'cluster' parameter; expected a non-empty string")
} }
userID, ok := paramsMap["user"].(string) userID, ok := paramsMap["user"].(string)
if !ok || userID == "" { if !ok || userID == "" {
return nil, util.NewAgentError("invalid or missing 'user' parameter; expected a non-empty string", nil) return nil, fmt.Errorf("invalid or missing 'user' parameter; expected a non-empty string")
} }
userType, ok := paramsMap["userType"].(string) userType, ok := paramsMap["userType"].(string)
if !ok || (userType != "ALLOYDB_BUILT_IN" && userType != "ALLOYDB_IAM_USER") { if !ok || (userType != "ALLOYDB_BUILT_IN" && userType != "ALLOYDB_IAM_USER") {
return nil, util.NewAgentError("invalid or missing 'userType' parameter; expected 'ALLOYDB_BUILT_IN' or 'ALLOYDB_IAM_USER'", nil) return nil, fmt.Errorf("invalid or missing 'userType' parameter; expected 'ALLOYDB_BUILT_IN' or 'ALLOYDB_IAM_USER'")
} }
var password string var password string
if userType == "ALLOYDB_BUILT_IN" { if userType == "ALLOYDB_BUILT_IN" {
password, ok = paramsMap["password"].(string) password, ok = paramsMap["password"].(string)
if !ok || password == "" { if !ok || password == "" {
return nil, util.NewAgentError("password is required when userType is ALLOYDB_BUILT_IN", nil) return nil, fmt.Errorf("password is required when userType is ALLOYDB_BUILT_IN")
} }
} }
@@ -171,11 +170,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
} }
} }
resp, err := source.CreateUser(ctx, userType, password, roles, string(accessToken), project, location, cluster, userID) return source.CreateUser(ctx, userType, password, roles, string(accessToken), project, location, cluster, userID)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -121,32 +120,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok || location == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok || cluster == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
} }
resp, err := source.GetCluster(ctx, project, location, cluster, string(accessToken)) return source.GetCluster(ctx, project, location, cluster, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -121,36 +120,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok || location == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok || cluster == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
} }
instance, ok := paramsMap["instance"].(string) instance, ok := paramsMap["instance"].(string)
if !ok || instance == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'instance' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'instance' parameter; expected a string")
} }
resp, err := source.GetInstance(ctx, project, location, cluster, instance, string(accessToken)) return source.GetInstance(ctx, project, location, cluster, instance, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -121,36 +120,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok || location == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok || cluster == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
} }
user, ok := paramsMap["user"].(string) user, ok := paramsMap["user"].(string)
if !ok || user == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'user' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'user' parameter; expected a string")
} }
resp, err := source.GetUsers(ctx, project, location, cluster, user, string(accessToken)) return source.GetUsers(ctx, project, location, cluster, user, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -119,28 +118,24 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
resp, err := source.ListCluster(ctx, project, location, string(accessToken)) return source.ListCluster(ctx, project, location, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -120,32 +119,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("invalid 'cluster' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
} }
resp, err := source.ListInstance(ctx, project, location, cluster, string(accessToken)) return source.ListInstance(ctx, project, location, cluster, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -22,7 +22,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -120,32 +119,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil) return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok || location == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
} }
cluster, ok := paramsMap["cluster"].(string) cluster, ok := paramsMap["cluster"].(string)
if !ok || cluster == "" { if !ok {
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil) return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
} }
resp, err := source.ListUsers(ctx, project, location, cluster, string(accessToken)) return source.ListUsers(ctx, project, location, cluster, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -24,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -214,25 +213,25 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
location, ok := paramsMap["location"].(string) location, ok := paramsMap["location"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'location' parameter", nil) return nil, fmt.Errorf("missing 'location' parameter")
} }
operation, ok := paramsMap["operation"].(string) operation, ok := paramsMap["operation"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'operation' parameter", nil) return nil, fmt.Errorf("missing 'operation' parameter")
} }
ctx, cancel := context.WithTimeout(ctx, 30*time.Minute) ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
@@ -247,15 +246,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
for retries < maxRetries { for retries < maxRetries {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, util.NewAgentError("timed out waiting for operation %s", ctx.Err()) return nil, fmt.Errorf("timed out waiting for operation: %w", ctx.Err())
default: default:
} }
op, err := source.GetOperations(ctx, project, location, operation, alloyDBConnectionMessageTemplate, delay, string(accessToken)) op, err := source.GetOperations(ctx, project, location, operation, alloyDBConnectionMessageTemplate, delay, string(accessToken))
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, err
} } else if op != nil {
if op != nil {
return op, nil return op, nil
} }
@@ -266,7 +264,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
retries++ retries++
} }
return nil, util.NewAgentError("exceeded max retries waiting for operation", nil) return nil, fmt.Errorf("exceeded max retries waiting for operation")
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package alloydbainl
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
) )
@@ -129,10 +127,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
sliceParams := params.AsSlice() sliceParams := params.AsSlice()
@@ -145,7 +143,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
resp, err := source.RunSQL(ctx, t.Statement, allParamValues) resp, err := source.RunSQL(ctx, t.Statement, allParamValues)
if err != nil { if err != nil {
return nil, util.NewClientServerError(fmt.Sprintf("error running SQL query: %v. Query: %v , Values: %v. Toolbox v0.19.0+ is only compatible with AlloyDB AI NL v1.0.3+. Please ensure that you are using the latest AlloyDB AI NL extension", err, t.Statement, allParamValues), http.StatusBadRequest, err) return nil, fmt.Errorf("%w. Query: %v , Values: %v. Toolbox v0.19.0+ is only compatible with AlloyDB AI NL v1.0.3+. Please ensure that you are using the latest AlloyDB AI NL extension", err, t.Statement, allParamValues)
} }
return resp, nil return resp, nil
} }

View File

@@ -17,7 +17,6 @@ package bigqueryanalyzecontribution
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
@@ -28,7 +27,6 @@ import (
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery" bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon" bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
bigqueryrestapi "google.golang.org/api/bigquery/v2" bigqueryrestapi "google.golang.org/api/bigquery/v2"
) )
@@ -156,21 +154,21 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke runs the contribution analysis. // Invoke runs the contribution analysis.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
inputData, ok := paramsMap["input_data"].(string) inputData, ok := paramsMap["input_data"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast input_data parameter %s", paramsMap["input_data"]), nil) return nil, fmt.Errorf("unable to cast input_data parameter %s", paramsMap["input_data"])
} }
bqClient, restService, err := source.RetrieveClientAndService(accessToken) bqClient, restService, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
modelID := fmt.Sprintf("contribution_analysis_model_%s", strings.ReplaceAll(uuid.New().String(), "-", "")) modelID := fmt.Sprintf("contribution_analysis_model_%s", strings.ReplaceAll(uuid.New().String(), "-", ""))
@@ -188,7 +186,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
options = append(options, fmt.Sprintf("DIMENSION_ID_COLS = [%s]", strings.Join(strCols, ", "))) options = append(options, fmt.Sprintf("DIMENSION_ID_COLS = [%s]", strings.Join(strCols, ", ")))
} else { } else {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast dimension_id_cols parameter %s", paramsMap["dimension_id_cols"]), nil) return nil, fmt.Errorf("unable to cast dimension_id_cols parameter %s", paramsMap["dimension_id_cols"])
} }
} }
if val, ok := paramsMap["top_k_insights_by_apriori_support"]; ok { if val, ok := paramsMap["top_k_insights_by_apriori_support"]; ok {
@@ -197,7 +195,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if val, ok := paramsMap["pruning_method"].(string); ok { if val, ok := paramsMap["pruning_method"].(string); ok {
upperVal := strings.ToUpper(val) upperVal := strings.ToUpper(val)
if upperVal != "NO_PRUNING" && upperVal != "PRUNE_REDUNDANT_INSIGHTS" { if upperVal != "NO_PRUNING" && upperVal != "PRUNE_REDUNDANT_INSIGHTS" {
return nil, util.NewAgentError(fmt.Sprintf("invalid pruning_method: %s", val), nil) return nil, fmt.Errorf("invalid pruning_method: %s", val)
} }
options = append(options, fmt.Sprintf("PRUNING_METHOD = '%s'", upperVal)) options = append(options, fmt.Sprintf("PRUNING_METHOD = '%s'", upperVal))
} }
@@ -209,7 +207,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var connProps []*bigqueryapi.ConnectionProperty var connProps []*bigqueryapi.ConnectionProperty
session, err := source.BigQuerySession()(ctx) session, err := source.BigQuerySession()(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
} }
if session != nil { if session != nil {
connProps = []*bigqueryapi.ConnectionProperty{ connProps = []*bigqueryapi.ConnectionProperty{
@@ -218,22 +216,22 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, inputData, nil, connProps) dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, inputData, nil, connProps)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("query validation failed: %w", err)
} }
statementType := dryRunJob.Statistics.Query.StatementType statementType := dryRunJob.Statistics.Query.StatementType
if statementType != "SELECT" { if statementType != "SELECT" {
return nil, util.NewAgentError(fmt.Sprintf("the 'input_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType), nil) return nil, fmt.Errorf("the 'input_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType)
} }
queryStats := dryRunJob.Statistics.Query queryStats := dryRunJob.Statistics.Query
if queryStats != nil { if queryStats != nil {
for _, tableRef := range queryStats.ReferencedTables { for _, tableRef := range queryStats.ReferencedTables {
if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) { if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) {
return nil, util.NewAgentError(fmt.Sprintf("query in input_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId), nil) return nil, fmt.Errorf("query in input_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId)
} }
} }
} else { } else {
return nil, util.NewAgentError("could not analyze query in input_data to validate against allowed datasets", nil) return nil, fmt.Errorf("could not analyze query in input_data to validate against allowed datasets")
} }
} }
inputDataSource = fmt.Sprintf("(%s)", inputData) inputDataSource = fmt.Sprintf("(%s)", inputData)
@@ -247,10 +245,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
case 2: // dataset.table case 2: // dataset.table
projectID, datasetID = source.BigQueryClient().Project(), parts[0] projectID, datasetID = source.BigQueryClient().Project(), parts[0]
default: default:
return nil, util.NewAgentError(fmt.Sprintf("invalid table ID format for 'input_data': %q. Expected 'dataset.table' or 'project.dataset.table'", inputData), nil) return nil, fmt.Errorf("invalid table ID format for 'input_data': %q. Expected 'dataset.table' or 'project.dataset.table'", inputData)
} }
if !source.IsDatasetAllowed(projectID, datasetID) { if !source.IsDatasetAllowed(projectID, datasetID) {
return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, inputData), nil) return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, inputData)
} }
} }
inputDataSource = fmt.Sprintf("SELECT * FROM `%s`", inputData) inputDataSource = fmt.Sprintf("SELECT * FROM `%s`", inputData)
@@ -270,7 +268,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Otherwise, a new session will be created by the first query. // Otherwise, a new session will be created by the first query.
session, err := source.BigQuerySession()(ctx) session, err := source.BigQuerySession()(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
} }
if session != nil { if session != nil {
@@ -283,15 +281,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
createModelJob, err := createModelQuery.Run(ctx) createModelJob, err := createModelQuery.Run(ctx)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to start create model job: %w", err)
} }
status, err := createModelJob.Wait(ctx) status, err := createModelJob.Wait(ctx)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to wait for create model job: %w", err)
} }
if err := status.Err(); err != nil { if err := status.Err(); err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("create model job failed: %w", err)
} }
// Determine the session ID to use for subsequent queries. // Determine the session ID to use for subsequent queries.
@@ -302,17 +300,12 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} else if status.Statistics != nil && status.Statistics.SessionInfo != nil { } else if status.Statistics != nil && status.Statistics.SessionInfo != nil {
sessionID = status.Statistics.SessionInfo.SessionID sessionID = status.Statistics.SessionInfo.SessionID
} else { } else {
return nil, util.NewClientServerError("failed to get or create a BigQuery session ID", http.StatusInternalServerError, nil) return nil, fmt.Errorf("failed to get or create a BigQuery session ID")
} }
getInsightsSQL := fmt.Sprintf("SELECT * FROM ML.GET_INSIGHTS(MODEL %s)", modelID) getInsightsSQL := fmt.Sprintf("SELECT * FROM ML.GET_INSIGHTS(MODEL %s)", modelID)
connProps := []*bigqueryapi.ConnectionProperty{{Key: "session_id", Value: sessionID}} connProps := []*bigqueryapi.ConnectionProperty{{Key: "session_id", Value: sessionID}}
return source.RunSQL(ctx, bqClient, getInsightsSQL, "SELECT", nil, connProps)
resp, err := source.RunSQL(ctx, bqClient, getInsightsSQL, "SELECT", nil, connProps)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -172,10 +172,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
var tokenStr string var tokenStr string
@@ -184,26 +184,26 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
// Use client-side access token // Use client-side access token
if accessToken == "" { if accessToken == "" {
return nil, util.NewClientServerError("tool is configured for client OAuth but no token was provided in the request header", http.StatusUnauthorized, nil) return nil, fmt.Errorf("tool is configured for client OAuth but no token was provided in the request header: %w", util.ErrUnauthorized)
} }
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} else { } else {
// Get a token source for the Gemini Data Analytics API. // Get a token source for the Gemini Data Analytics API.
tokenSource, err := source.BigQueryTokenSourceWithScope(ctx, nil) tokenSource, err := source.BigQueryTokenSourceWithScope(ctx, nil)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get token source", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get token source: %w", err)
} }
// Use cloud-platform token source for Gemini Data Analytics API // Use cloud-platform token source for Gemini Data Analytics API
if tokenSource == nil { if tokenSource == nil {
return nil, util.NewClientServerError("cloud-platform token source is missing", http.StatusInternalServerError, nil) return nil, fmt.Errorf("cloud-platform token source is missing")
} }
token, err := tokenSource.Token() token, err := tokenSource.Token()
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get token from cloud-platform token source", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get token from cloud-platform token source: %w", err)
} }
tokenStr = token.AccessToken tokenStr = token.AccessToken
} }
@@ -218,14 +218,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var tableRefs []BQTableReference var tableRefs []BQTableReference
if tableRefsJSON != "" { if tableRefsJSON != "" {
if err := json.Unmarshal([]byte(tableRefsJSON), &tableRefs); err != nil { if err := json.Unmarshal([]byte(tableRefsJSON), &tableRefs); err != nil {
return nil, util.NewAgentError("failed to parse 'table_references' JSON string", err) return nil, fmt.Errorf("failed to parse 'table_references' JSON string: %w", err)
} }
} }
if len(source.BigQueryAllowedDatasets()) > 0 { if len(source.BigQueryAllowedDatasets()) > 0 {
for _, tableRef := range tableRefs { for _, tableRef := range tableRefs {
if !source.IsDatasetAllowed(tableRef.ProjectID, tableRef.DatasetID) { if !source.IsDatasetAllowed(tableRef.ProjectID, tableRef.DatasetID) {
return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", tableRef.ProjectID, tableRef.DatasetID, tableRef.TableID), nil) return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", tableRef.ProjectID, tableRef.DatasetID, tableRef.TableID)
} }
} }
} }
@@ -258,8 +258,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Call the streaming API // Call the streaming API
response, err := getStream(caURL, payload, headers, source.GetMaxQueryResultRows()) response, err := getStream(caURL, payload, headers, source.GetMaxQueryResultRows())
if err != nil { if err != nil {
// getStream wraps network errors or non-200 responses return nil, fmt.Errorf("failed to get response from conversational analytics API: %w", err)
return nil, util.NewClientServerError("failed to get response from conversational analytics API", http.StatusInternalServerError, err)
} }
return response, nil return response, nil

View File

@@ -18,7 +18,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"strings" "strings"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
@@ -153,25 +152,25 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
sql, ok := paramsMap["sql"].(string) sql, ok := paramsMap["sql"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast sql parameter %s", paramsMap["sql"]), nil) return nil, fmt.Errorf("unable to cast sql parameter %s", paramsMap["sql"])
} }
dryRun, ok := paramsMap["dry_run"].(bool) dryRun, ok := paramsMap["dry_run"].(bool)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast dry_run parameter %s", paramsMap["dry_run"]), nil) return nil, fmt.Errorf("unable to cast dry_run parameter %s", paramsMap["dry_run"])
} }
bqClient, restService, err := source.RetrieveClientAndService(accessToken) bqClient, restService, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
var connProps []*bigqueryapi.ConnectionProperty var connProps []*bigqueryapi.ConnectionProperty
@@ -179,7 +178,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if source.BigQueryWriteMode() == bigqueryds.WriteModeProtected { if source.BigQueryWriteMode() == bigqueryds.WriteModeProtected {
session, err = source.BigQuerySession()(ctx) session, err = source.BigQuerySession()(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get BigQuery session for protected mode", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get BigQuery session for protected mode: %w", err)
} }
connProps = []*bigqueryapi.ConnectionProperty{ connProps = []*bigqueryapi.ConnectionProperty{
{Key: "session_id", Value: session.ID}, {Key: "session_id", Value: session.ID},
@@ -188,7 +187,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, sql, nil, connProps) dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, sql, nil, connProps)
if err != nil { if err != nil {
return nil, util.NewClientServerError("query validation failed", http.StatusInternalServerError, err) return nil, fmt.Errorf("query validation failed: %w", err)
} }
statementType := dryRunJob.Statistics.Query.StatementType statementType := dryRunJob.Statistics.Query.StatementType
@@ -196,13 +195,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
switch source.BigQueryWriteMode() { switch source.BigQueryWriteMode() {
case bigqueryds.WriteModeBlocked: case bigqueryds.WriteModeBlocked:
if statementType != "SELECT" { if statementType != "SELECT" {
return nil, util.NewAgentError("write mode is 'blocked', only SELECT statements are allowed", nil) return nil, fmt.Errorf("write mode is 'blocked', only SELECT statements are allowed")
} }
case bigqueryds.WriteModeProtected: case bigqueryds.WriteModeProtected:
if dryRunJob.Configuration != nil && dryRunJob.Configuration.Query != nil { if dryRunJob.Configuration != nil && dryRunJob.Configuration.Query != nil {
if dest := dryRunJob.Configuration.Query.DestinationTable; dest != nil && dest.DatasetId != session.DatasetID { if dest := dryRunJob.Configuration.Query.DestinationTable; dest != nil && dest.DatasetId != session.DatasetID {
return nil, util.NewAgentError(fmt.Sprintf("protected write mode only supports SELECT statements, or write operations in the anonymous "+ return nil, fmt.Errorf("protected write mode only supports SELECT statements, or write operations in the anonymous "+
"dataset of a BigQuery session, but destination was %q", dest.DatasetId), nil) "dataset of a BigQuery session, but destination was %q", dest.DatasetId)
} }
} }
} }
@@ -210,11 +209,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if len(source.BigQueryAllowedDatasets()) > 0 { if len(source.BigQueryAllowedDatasets()) > 0 {
switch statementType { switch statementType {
case "CREATE_SCHEMA", "DROP_SCHEMA", "ALTER_SCHEMA": case "CREATE_SCHEMA", "DROP_SCHEMA", "ALTER_SCHEMA":
return nil, util.NewAgentError(fmt.Sprintf("dataset-level operations like '%s' are not allowed when dataset restrictions are in place", statementType), nil) return nil, fmt.Errorf("dataset-level operations like '%s' are not allowed when dataset restrictions are in place", statementType)
case "CREATE_FUNCTION", "CREATE_TABLE_FUNCTION", "CREATE_PROCEDURE": case "CREATE_FUNCTION", "CREATE_TABLE_FUNCTION", "CREATE_PROCEDURE":
return nil, util.NewAgentError(fmt.Sprintf("creating stored routines ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType), nil) return nil, fmt.Errorf("creating stored routines ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType)
case "CALL": case "CALL":
return nil, util.NewAgentError(fmt.Sprintf("calling stored procedures ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType), nil) return nil, fmt.Errorf("calling stored procedures ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType)
} }
// Use a map to avoid duplicate table names. // Use a map to avoid duplicate table names.
@@ -245,7 +244,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
parsedTables, parseErr := bqutil.TableParser(sql, source.BigQueryClient().Project()) parsedTables, parseErr := bqutil.TableParser(sql, source.BigQueryClient().Project())
if parseErr != nil { if parseErr != nil {
// If parsing fails (e.g., EXECUTE IMMEDIATE), we cannot guarantee safety, so we must fail. // If parsing fails (e.g., EXECUTE IMMEDIATE), we cannot guarantee safety, so we must fail.
return nil, util.NewAgentError("could not parse tables from query to validate against allowed datasets", parseErr) return nil, fmt.Errorf("could not parse tables from query to validate against allowed datasets: %w", parseErr)
} }
tableNames = parsedTables tableNames = parsedTables
} }
@@ -255,7 +254,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if len(parts) == 3 { if len(parts) == 3 {
projectID, datasetID := parts[0], parts[1] projectID, datasetID := parts[0], parts[1]
if !source.IsDatasetAllowed(projectID, datasetID) { if !source.IsDatasetAllowed(projectID, datasetID) {
return nil, util.NewAgentError(fmt.Sprintf("query accesses dataset '%s.%s', which is not in the allowed list", projectID, datasetID), nil) return nil, fmt.Errorf("query accesses dataset '%s.%s', which is not in the allowed list", projectID, datasetID)
} }
} }
} }
@@ -265,7 +264,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if dryRunJob != nil { if dryRunJob != nil {
jobJSON, err := json.MarshalIndent(dryRunJob, "", " ") jobJSON, err := json.MarshalIndent(dryRunJob, "", " ")
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to marshal dry run job to JSON", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to marshal dry run job to JSON: %w", err)
} }
return string(jobJSON), nil return string(jobJSON), nil
} }
@@ -276,14 +275,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Log the query executed for debugging. // Log the query executed for debugging.
logger, err := util.LoggerFromContext(ctx) logger, err := util.LoggerFromContext(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("error getting logger", http.StatusInternalServerError, err) return nil, fmt.Errorf("error getting logger: %s", err)
} }
logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql)) logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql))
resp, err := source.RunSQL(ctx, bqClient, sql, statementType, nil, connProps) return source.RunSQL(ctx, bqClient, sql, statementType, nil, connProps)
if err != nil {
return nil, util.NewClientServerError("error running sql", http.StatusInternalServerError, err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,7 +17,6 @@ package bigqueryforecast
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
@@ -134,34 +133,34 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
historyData, ok := paramsMap["history_data"].(string) historyData, ok := paramsMap["history_data"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast history_data parameter %v", paramsMap["history_data"]), nil) return nil, fmt.Errorf("unable to cast history_data parameter %v", paramsMap["history_data"])
} }
timestampCol, ok := paramsMap["timestamp_col"].(string) timestampCol, ok := paramsMap["timestamp_col"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast timestamp_col parameter %v", paramsMap["timestamp_col"]), nil) return nil, fmt.Errorf("unable to cast timestamp_col parameter %v", paramsMap["timestamp_col"])
} }
dataCol, ok := paramsMap["data_col"].(string) dataCol, ok := paramsMap["data_col"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast data_col parameter %v", paramsMap["data_col"]), nil) return nil, fmt.Errorf("unable to cast data_col parameter %v", paramsMap["data_col"])
} }
idColsRaw, ok := paramsMap["id_cols"].([]any) idColsRaw, ok := paramsMap["id_cols"].([]any)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast id_cols parameter %v", paramsMap["id_cols"]), nil) return nil, fmt.Errorf("unable to cast id_cols parameter %v", paramsMap["id_cols"])
} }
var idCols []string var idCols []string
for _, v := range idColsRaw { for _, v := range idColsRaw {
s, ok := v.(string) s, ok := v.(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("id_cols contains non-string value: %v", v), nil) return nil, fmt.Errorf("id_cols contains non-string value: %v", v)
} }
idCols = append(idCols, s) idCols = append(idCols, s)
} }
@@ -170,13 +169,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if h, ok := paramsMap["horizon"].(float64); ok { if h, ok := paramsMap["horizon"].(float64); ok {
horizon = int(h) horizon = int(h)
} else { } else {
return nil, util.NewAgentError(fmt.Sprintf("unable to cast horizon parameter %v", paramsMap["horizon"]), nil) return nil, fmt.Errorf("unable to cast horizon parameter %v", paramsMap["horizon"])
} }
} }
bqClient, restService, err := source.RetrieveClientAndService(accessToken) bqClient, restService, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
var historyDataSource string var historyDataSource string
@@ -186,7 +185,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var connProps []*bigqueryapi.ConnectionProperty var connProps []*bigqueryapi.ConnectionProperty
session, err := source.BigQuerySession()(ctx) session, err := source.BigQuerySession()(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
} }
if session != nil { if session != nil {
connProps = []*bigqueryapi.ConnectionProperty{ connProps = []*bigqueryapi.ConnectionProperty{
@@ -195,22 +194,22 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, historyData, nil, connProps) dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, historyData, nil, connProps)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("query validation failed: %w", err)
} }
statementType := dryRunJob.Statistics.Query.StatementType statementType := dryRunJob.Statistics.Query.StatementType
if statementType != "SELECT" { if statementType != "SELECT" {
return nil, util.NewAgentError(fmt.Sprintf("the 'history_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType), nil) return nil, fmt.Errorf("the 'history_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType)
} }
queryStats := dryRunJob.Statistics.Query queryStats := dryRunJob.Statistics.Query
if queryStats != nil { if queryStats != nil {
for _, tableRef := range queryStats.ReferencedTables { for _, tableRef := range queryStats.ReferencedTables {
if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) { if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) {
return nil, util.NewAgentError(fmt.Sprintf("query in history_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId), nil) return nil, fmt.Errorf("query in history_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId)
} }
} }
} else { } else {
return nil, util.NewAgentError("could not analyze query in history_data to validate against allowed datasets", nil) return nil, fmt.Errorf("could not analyze query in history_data to validate against allowed datasets")
} }
} }
historyDataSource = fmt.Sprintf("(%s)", historyData) historyDataSource = fmt.Sprintf("(%s)", historyData)
@@ -227,11 +226,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
projectID = source.BigQueryClient().Project() projectID = source.BigQueryClient().Project()
datasetID = parts[0] datasetID = parts[0]
default: default:
return nil, util.NewAgentError(fmt.Sprintf("invalid table ID format for 'history_data': %q. Expected 'dataset.table' or 'project.dataset.table'", historyData), nil) return nil, fmt.Errorf("invalid table ID format for 'history_data': %q. Expected 'dataset.table' or 'project.dataset.table'", historyData)
} }
if !source.IsDatasetAllowed(projectID, datasetID) { if !source.IsDatasetAllowed(projectID, datasetID) {
return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, historyData), nil) return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, historyData)
} }
} }
historyDataSource = fmt.Sprintf("TABLE `%s`", historyData) historyDataSource = fmt.Sprintf("TABLE `%s`", historyData)
@@ -244,15 +243,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
sql := fmt.Sprintf(`SELECT * sql := fmt.Sprintf(`SELECT *
FROM AI.FORECAST( FROM AI.FORECAST(
%s, %s,
data_col => '%s', data_col => '%s',
timestamp_col => '%s', timestamp_col => '%s',
horizon => %d%s)`, horizon => %d%s)`,
historyDataSource, dataCol, timestampCol, horizon, idColsArg) historyDataSource, dataCol, timestampCol, horizon, idColsArg)
session, err := source.BigQuerySession()(ctx) session, err := source.BigQuerySession()(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
} }
var connProps []*bigqueryapi.ConnectionProperty var connProps []*bigqueryapi.ConnectionProperty
if session != nil { if session != nil {
@@ -265,15 +264,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Log the query executed for debugging. // Log the query executed for debugging.
logger, err := util.LoggerFromContext(ctx) logger, err := util.LoggerFromContext(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("error getting logger", http.StatusInternalServerError, err) return nil, fmt.Errorf("error getting logger: %s", err)
} }
logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql)) logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql))
resp, err := source.RunSQL(ctx, bqClient, sql, "SELECT", nil, connProps) return source.RunSQL(ctx, bqClient, sql, "SELECT", nil, connProps)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,7 +17,6 @@ package bigquerygetdatasetinfo
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
@@ -25,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon" bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
bigqueryrestapi "google.golang.org/api/bigquery/v2" bigqueryrestapi "google.golang.org/api/bigquery/v2"
) )
@@ -122,38 +120,38 @@ type Tool struct {
func (t Tool) ToConfig() tools.ToolConfig { func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
projectId, ok := mapParams[projectKey].(string) projectId, ok := mapParams[projectKey].(string)
if !ok { if !ok {
// Updated: Use fmt.Sprintf for formatting, pass nil as cause return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil)
} }
datasetId, ok := mapParams[datasetKey].(string) datasetId, ok := mapParams[datasetKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", datasetKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", datasetKey)
} }
bqClient, _, err := source.RetrieveClientAndService(accessToken) bqClient, _, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
if !source.IsDatasetAllowed(projectId, datasetId) { if !source.IsDatasetAllowed(projectId, datasetId) {
return nil, util.NewClientServerError(fmt.Sprintf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId), http.StatusInternalServerError, nil) return nil, fmt.Errorf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId)
} }
dsHandle := bqClient.DatasetInProject(projectId, datasetId) dsHandle := bqClient.DatasetInProject(projectId, datasetId)
metadata, err := dsHandle.Metadata(ctx) metadata, err := dsHandle.Metadata(ctx)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to get metadata for dataset %s (in project %s): %w", datasetId, projectId, err)
} }
return metadata, nil return metadata, nil

View File

@@ -17,7 +17,6 @@ package bigquerygettableinfo
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
@@ -25,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon" bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
bigqueryrestapi "google.golang.org/api/bigquery/v2" bigqueryrestapi "google.golang.org/api/bigquery/v2"
) )
@@ -127,35 +125,35 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
projectId, ok := mapParams[projectKey].(string) projectId, ok := mapParams[projectKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
} }
datasetId, ok := mapParams[datasetKey].(string) datasetId, ok := mapParams[datasetKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", datasetKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", datasetKey)
} }
tableId, ok := mapParams[tableKey].(string) tableId, ok := mapParams[tableKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", tableKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", tableKey)
} }
if !source.IsDatasetAllowed(projectId, datasetId) { if !source.IsDatasetAllowed(projectId, datasetId) {
return nil, util.NewClientServerError(fmt.Sprintf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId), http.StatusInternalServerError, nil) return nil, fmt.Errorf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId)
} }
bqClient, _, err := source.RetrieveClientAndService(accessToken) bqClient, _, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
dsHandle := bqClient.DatasetInProject(projectId, datasetId) dsHandle := bqClient.DatasetInProject(projectId, datasetId)
@@ -163,7 +161,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
metadata, err := tableHandle.Metadata(ctx) metadata, err := tableHandle.Metadata(ctx)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to get metadata for table %s.%s.%s: %w", projectId, datasetId, tableId, err)
} }
return metadata, nil return metadata, nil

View File

@@ -17,14 +17,12 @@ package bigquerylistdatasetids
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
bigqueryrestapi "google.golang.org/api/bigquery/v2" bigqueryrestapi "google.golang.org/api/bigquery/v2"
"google.golang.org/api/iterator" "google.golang.org/api/iterator"
@@ -122,10 +120,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
if len(source.BigQueryAllowedDatasets()) > 0 { if len(source.BigQueryAllowedDatasets()) > 0 {
@@ -134,12 +132,12 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
mapParams := params.AsMap() mapParams := params.AsMap()
projectId, ok := mapParams[projectKey].(string) projectId, ok := mapParams[projectKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
} }
bqClient, _, err := source.RetrieveClientAndService(accessToken) bqClient, _, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
datasetIterator := bqClient.Datasets(ctx) datasetIterator := bqClient.Datasets(ctx)
datasetIterator.ProjectID = projectId datasetIterator.ProjectID = projectId
@@ -151,7 +149,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
break break
} }
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("unable to iterate through datasets: %w", err)
} }
// Remove leading and trailing quotes // Remove leading and trailing quotes

View File

@@ -17,7 +17,6 @@ package bigquerylisttableids
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
bigqueryapi "cloud.google.com/go/bigquery" bigqueryapi "cloud.google.com/go/bigquery"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
@@ -25,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon" bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
bigqueryrestapi "google.golang.org/api/bigquery/v2" bigqueryrestapi "google.golang.org/api/bigquery/v2"
"google.golang.org/api/iterator" "google.golang.org/api/iterator"
@@ -125,30 +123,31 @@ type Tool struct {
func (t Tool) ToConfig() tools.ToolConfig { func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
projectId, ok := mapParams[projectKey].(string) projectId, ok := mapParams[projectKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
} }
datasetId, ok := mapParams[datasetKey].(string) datasetId, ok := mapParams[datasetKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", datasetKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", datasetKey)
} }
if !source.IsDatasetAllowed(projectId, datasetId) { if !source.IsDatasetAllowed(projectId, datasetId) {
return nil, util.NewClientServerError(fmt.Sprintf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId), http.StatusInternalServerError, nil) return nil, fmt.Errorf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId)
} }
bqClient, _, err := source.RetrieveClientAndService(accessToken) bqClient, _, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
dsHandle := bqClient.DatasetInProject(projectId, datasetId) dsHandle := bqClient.DatasetInProject(projectId, datasetId)
@@ -161,7 +160,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
break break
} }
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to iterate through tables in dataset %s.%s: %w", projectId, datasetId, err)
} }
// Remove leading and trailing quotes // Remove leading and trailing quotes

View File

@@ -17,7 +17,6 @@ package bigquerysearchcatalog
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
dataplexapi "cloud.google.com/go/dataplex/apiv1" dataplexapi "cloud.google.com/go/dataplex/apiv1"
@@ -27,7 +26,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery" bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/iterator" "google.golang.org/api/iterator"
) )
@@ -188,31 +186,28 @@ func ExtractType(resourceString string) string {
return typeMap[resourceString[lastIndex+1:]] return typeMap[resourceString[lastIndex+1:]]
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
pageSize := int32(paramsMap["pageSize"].(int)) pageSize := int32(paramsMap["pageSize"].(int))
prompt, _ := paramsMap["prompt"].(string) prompt, _ := paramsMap["prompt"].(string)
projectIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["projectIds"].([]any), "string") projectIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["projectIds"].([]any), "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert projectIds to array of strings: %s", err), err) return nil, fmt.Errorf("can't convert projectIds to array of strings: %s", err)
} }
projectIds := projectIdSlice.([]string) projectIds := projectIdSlice.([]string)
datasetIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["datasetIds"].([]any), "string") datasetIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["datasetIds"].([]any), "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert datasetIds to array of strings: %s", err), err) return nil, fmt.Errorf("can't convert datasetIds to array of strings: %s", err)
} }
datasetIds := datasetIdSlice.([]string) datasetIds := datasetIdSlice.([]string)
typesSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["types"].([]any), "string") typesSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["types"].([]any), "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert types to array of strings: %s", err), err) return nil, fmt.Errorf("can't convert types to array of strings: %s", err)
} }
types := typesSlice.([]string) types := typesSlice.([]string)
@@ -228,17 +223,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err := accessToken.ParseBearerToken() tokenStr, err := accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
catalogClient, err = dataplexClientCreator(tokenStr) catalogClient, err = dataplexClientCreator(tokenStr)
if err != nil { if err != nil {
return nil, util.NewClientServerError("error creating client from OAuth access token", http.StatusInternalServerError, err) return nil, fmt.Errorf("error creating client from OAuth access token: %w", err)
} }
} }
it := catalogClient.SearchEntries(ctx, req) it := catalogClient.SearchEntries(ctx, req)
if it == nil { if it == nil {
return nil, util.NewClientServerError(fmt.Sprintf("failed to create search entries iterator for project %q", source.BigQueryProject()), http.StatusInternalServerError, nil) return nil, fmt.Errorf("failed to create search entries iterator for project %q", source.BigQueryProject())
} }
var results []Response var results []Response
@@ -248,7 +243,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
break break
} }
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) break
} }
entrySource := entry.DataplexEntry.GetEntrySource() entrySource := entry.DataplexEntry.GetEntrySource()
resp := Response{ resp := Response{

View File

@@ -17,7 +17,6 @@ package bigquerysql
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"reflect" "reflect"
"strings" "strings"
@@ -28,7 +27,6 @@ import (
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery" bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon" bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
bigqueryrestapi "google.golang.org/api/bigquery/v2" bigqueryrestapi "google.golang.org/api/bigquery/v2"
) )
@@ -105,10 +103,11 @@ type Tool struct {
func (t Tool) ToConfig() tools.ToolConfig { func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
highLevelParams := make([]bigqueryapi.QueryParameter, 0, len(t.Parameters)) highLevelParams := make([]bigqueryapi.QueryParameter, 0, len(t.Parameters))
@@ -117,7 +116,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
paramsMap := params.AsMap() paramsMap := params.AsMap()
newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap) newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError("unable to extract template params", err) return nil, fmt.Errorf("unable to extract template params %w", err)
} }
for _, p := range t.Parameters { for _, p := range t.Parameters {
@@ -128,13 +127,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if arrayParam, ok := p.(*parameters.ArrayParameter); ok { if arrayParam, ok := p.(*parameters.ArrayParameter); ok {
arrayParamValue, ok := value.([]any) arrayParamValue, ok := value.([]any)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("unable to convert parameter `%s` to []any", name), nil) return nil, fmt.Errorf("unable to convert parameter `%s` to []any", name)
} }
itemType := arrayParam.GetItems().GetType() itemType := arrayParam.GetItems().GetType()
var err error var err error
value, err = parameters.ConvertAnySliceToTyped(arrayParamValue, itemType) value, err = parameters.ConvertAnySliceToTyped(arrayParamValue, itemType)
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("unable to convert parameter `%s` from []any to typed slice", name), err) return nil, fmt.Errorf("unable to convert parameter `%s` from []any to typed slice: %w", name, err)
} }
} }
@@ -162,7 +161,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
lowLevelParam.ParameterType.Type = "ARRAY" lowLevelParam.ParameterType.Type = "ARRAY"
itemType, err := bqutil.BQTypeStringFromToolType(arrayParam.GetItems().GetType()) itemType, err := bqutil.BQTypeStringFromToolType(arrayParam.GetItems().GetType())
if err != nil { if err != nil {
return nil, util.NewAgentError("unable to get BigQuery type from tool parameter type", err) return nil, err
} }
lowLevelParam.ParameterType.ArrayType = &bigqueryrestapi.QueryParameterType{Type: itemType} lowLevelParam.ParameterType.ArrayType = &bigqueryrestapi.QueryParameterType{Type: itemType}
@@ -179,7 +178,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Handle scalar types based on their defined type. // Handle scalar types based on their defined type.
bqType, err := bqutil.BQTypeStringFromToolType(p.GetType()) bqType, err := bqutil.BQTypeStringFromToolType(p.GetType())
if err != nil { if err != nil {
return nil, util.NewAgentError("unable to get BigQuery type from tool parameter type", err) return nil, err
} }
lowLevelParam.ParameterType.Type = bqType lowLevelParam.ParameterType.Type = bqType
lowLevelParam.ParameterValue.Value = fmt.Sprintf("%v", value) lowLevelParam.ParameterValue.Value = fmt.Sprintf("%v", value)
@@ -191,7 +190,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if source.BigQuerySession() != nil { if source.BigQuerySession() != nil {
session, err := source.BigQuerySession()(ctx) session, err := source.BigQuerySession()(ctx)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
} }
if session != nil { if session != nil {
// Add session ID to the connection properties for subsequent calls. // Add session ID to the connection properties for subsequent calls.
@@ -201,20 +200,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
bqClient, restService, err := source.RetrieveClientAndService(accessToken) bqClient, restService, err := source.RetrieveClientAndService(accessToken)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) return nil, err
} }
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, newStatement, lowLevelParams, connProps) dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, newStatement, lowLevelParams, connProps)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("query validation failed: %w", err)
} }
statementType := dryRunJob.Statistics.Query.StatementType statementType := dryRunJob.Statistics.Query.StatementType
resp, err := source.RunSQL(ctx, bqClient, newStatement, statementType, highLevelParams, connProps)
if err != nil { return source.RunSQL(ctx, bqClient, newStatement, statementType, highLevelParams, connProps)
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package bigtable
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"cloud.google.com/go/bigtable" "cloud.google.com/go/bigtable"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -98,28 +96,24 @@ type Tool struct {
func (t Tool) ToConfig() tools.ToolConfig { func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap) newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError("unable to extract template params", err) return nil, fmt.Errorf("unable to extract template params %w", err)
} }
newParams, err := parameters.GetParams(t.Parameters, paramsMap) newParams, err := parameters.GetParams(t.Parameters, paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError("unable to extract standard params", err) return nil, fmt.Errorf("unable to extract standard params %w", err)
} }
return source.RunSQL(ctx, newStatement, t.Parameters, newParams)
resp, err := source.RunSQL(ctx, newStatement, t.Parameters, newParams)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -18,13 +18,11 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -121,16 +119,17 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { // Invoke executes the tool logic
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
query, ok := paramsMap["query"].(string) query, ok := paramsMap["query"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("query parameter not found or not a string", nil) return nil, fmt.Errorf("query parameter not found or not a string")
} }
// Parse the access token if provided // Parse the access token if provided
@@ -139,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var err error var err error
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
@@ -155,14 +154,9 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
bodyBytes, err := json.Marshal(payload) bodyBytes, err := json.Marshal(payload)
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to marshal request payload", http.StatusInternalServerError, err) return nil, fmt.Errorf("failed to marshal request payload: %w", err)
} }
return source.RunQuery(ctx, tokenStr, bodyBytes)
resp, err := source.RunQuery(ctx, tokenStr, bodyBytes)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package fhirfetchpage
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -95,31 +93,24 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
url, ok := params.AsMap()[pageURLKey].(string) url, ok := params.AsMap()[pageURLKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", pageURLKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", pageURLKey)
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
return source.FHIRFetchPage(ctx, url, tokenStr)
resp, err := source.FHIRFetchPage(ctx, url, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,7 +17,6 @@ package fhirpatienteverything
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
@@ -25,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )
@@ -118,27 +116,26 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
if err != nil { if err != nil {
// ValidateAndFetchStoreID usually returns input validation errors return nil, err
return nil, util.NewAgentError("failed to validate store ID", err)
} }
patientID, ok := params.AsMap()[patientIDKey].(string) patientID, ok := params.AsMap()[patientIDKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", patientIDKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", patientIDKey)
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
@@ -146,11 +143,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if val, ok := params.AsMap()[typeFilterKey]; ok { if val, ok := params.AsMap()[typeFilterKey]; ok {
types, ok := val.([]any) types, ok := val.([]any)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string array", typeFilterKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string array", typeFilterKey)
} }
typeFilterSlice, err := parameters.ConvertAnySliceToTyped(types, "string") typeFilterSlice, err := parameters.ConvertAnySliceToTyped(types, "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert '%s' to array of strings: %s", typeFilterKey, err), err) return nil, fmt.Errorf("can't convert '%s' to array of strings: %s", typeFilterKey, err)
} }
if len(typeFilterSlice.([]string)) != 0 { if len(typeFilterSlice.([]string)) != 0 {
opts = append(opts, googleapi.QueryParameter("_type", strings.Join(typeFilterSlice.([]string), ","))) opts = append(opts, googleapi.QueryParameter("_type", strings.Join(typeFilterSlice.([]string), ",")))
@@ -159,18 +156,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if since, ok := params.AsMap()[sinceFilterKey]; ok { if since, ok := params.AsMap()[sinceFilterKey]; ok {
sinceStr, ok := since.(string) sinceStr, ok := since.(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", sinceFilterKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", sinceFilterKey)
} }
if sinceStr != "" { if sinceStr != "" {
opts = append(opts, googleapi.QueryParameter("_since", sinceStr)) opts = append(opts, googleapi.QueryParameter("_since", sinceStr))
} }
} }
return source.FHIRPatientEverything(storeID, patientID, tokenStr, opts)
resp, err := source.FHIRPatientEverything(storeID, patientID, tokenStr, opts)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,7 +17,6 @@ package fhirpatientsearch
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
@@ -25,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )
@@ -152,22 +150,22 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
@@ -181,14 +179,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var ok bool var ok bool
summary, ok = v.(bool) summary, ok = v.(bool)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a boolean", summaryKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a boolean", summaryKey)
} }
continue continue
} }
val, ok := v.(string) val, ok := v.(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid parameter '%s'; expected a string", k), nil) return nil, fmt.Errorf("invalid parameter '%s'; expected a string", k)
} }
if val == "" { if val == "" {
continue continue
@@ -207,7 +205,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
parts := strings.Split(val, "/") parts := strings.Split(val, "/")
if len(parts) != 2 { if len(parts) != 2 {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' format; expected YYYY-MM-DD/YYYY-MM-DD", k), nil) return nil, fmt.Errorf("invalid '%s' format; expected YYYY-MM-DD/YYYY-MM-DD", k)
} }
var values []string var values []string
if parts[0] != "" { if parts[0] != "" {
@@ -231,17 +229,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
case familyNameKey: case familyNameKey:
opts = append(opts, googleapi.QueryParameter("family", val)) opts = append(opts, googleapi.QueryParameter("family", val))
default: default:
return nil, util.NewAgentError(fmt.Sprintf("unexpected parameter key %q", k), nil) return nil, fmt.Errorf("unexpected parameter key %q", k)
} }
} }
if summary { if summary {
opts = append(opts, googleapi.QueryParameter("_summary", "text")) opts = append(opts, googleapi.QueryParameter("_summary", "text"))
} }
resp, err := source.FHIRPatientSearch(storeID, tokenStr, opts) return source.FHIRPatientSearch(storeID, tokenStr, opts)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package gethealthcaredataset
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -92,23 +90,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.GetDataset(tokenStr) return source.GetDataset(tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package getdicomstore
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.GetDICOMStore(storeID, tokenStr) return source.GetDICOMStore(storeID, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package getdicomstoremetrics
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.GetDICOMStoreMetrics(storeID, tokenStr) return source.GetDICOMStoreMetrics(storeID, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package getfhirresource
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -114,36 +112,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
resType, ok := params.AsMap()[typeKey].(string) resType, ok := params.AsMap()[typeKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", typeKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", typeKey)
} }
resID, ok := params.AsMap()[idKey].(string) resID, ok := params.AsMap()[idKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", idKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", idKey)
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.GetFHIRResource(storeID, resType, resID, tokenStr) return source.GetFHIRResource(storeID, resType, resID, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package getfhirstore
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.GetFHIRStore(storeID, tokenStr) return source.GetFHIRStore(storeID, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package getfhirstoremetrics
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.GetFHIRStoreMetrics(storeID, tokenStr) return source.GetFHIRStoreMetrics(storeID, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package listdicomstores
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -92,23 +90,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.ListDICOMStores(tokenStr) return source.ListDICOMStores(tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package listfhirstores
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/healthcare/v1" "google.golang.org/api/healthcare/v1"
) )
@@ -92,23 +90,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
resp, err := source.ListFHIRStores(tokenStr) return source.ListFHIRStores(tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package retrieverendereddicominstance
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -119,44 +117,40 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
study, ok := params.AsMap()[studyInstanceUIDKey].(string) study, ok := params.AsMap()[studyInstanceUIDKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey)
} }
series, ok := params.AsMap()[seriesInstanceUIDKey].(string) series, ok := params.AsMap()[seriesInstanceUIDKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey)
} }
sop, ok := params.AsMap()[sopInstanceUIDKey].(string) sop, ok := params.AsMap()[sopInstanceUIDKey].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", sopInstanceUIDKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", sopInstanceUIDKey)
} }
frame, ok := params.AsMap()[frameNumberKey].(int) frame, ok := params.AsMap()[frameNumberKey].(int)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected an integer", frameNumberKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected an integer", frameNumberKey)
} }
resp, err := source.RetrieveRenderedDICOMInstance(storeID, study, series, sop, frame, tokenStr) return source.RetrieveRenderedDICOMInstance(storeID, study, series, sop, frame, tokenStr)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,7 +17,6 @@ package searchdicominstances
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
@@ -25,7 +24,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )
@@ -133,33 +131,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
opts, err := common.ParseDICOMSearchParameters(params, []string{sopInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey}) opts, err := common.ParseDICOMSearchParameters(params, []string{sopInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey})
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to parse DICOM search parameters", err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
dicomWebPath := "instances" dicomWebPath := "instances"
if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok { if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok {
id, ok := studyInstanceUID.(string) id, ok := studyInstanceUID.(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey)
} }
if id != "" { if id != "" {
dicomWebPath = fmt.Sprintf("studies/%s/instances", id) dicomWebPath = fmt.Sprintf("studies/%s/instances", id)
@@ -168,7 +166,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if seriesInstanceUID, ok := paramsMap[seriesInstanceUIDKey]; ok { if seriesInstanceUID, ok := paramsMap[seriesInstanceUIDKey]; ok {
id, ok := seriesInstanceUID.(string) id, ok := seriesInstanceUID.(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey)
} }
if id != "" { if id != "" {
if dicomWebPath != "instances" { if dicomWebPath != "instances" {
@@ -178,11 +176,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
} }
} }
resp, err := source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts) return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package searchdicomseries
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )
@@ -130,44 +128,40 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
opts, err := common.ParseDICOMSearchParameters(params, []string{seriesInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey}) opts, err := common.ParseDICOMSearchParameters(params, []string{seriesInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey})
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to parse DICOM search parameters", err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
dicomWebPath := "series" dicomWebPath := "series"
if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok { if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok {
id, ok := studyInstanceUID.(string) id, ok := studyInstanceUID.(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil) return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey)
} }
if id != "" { if id != "" {
dicomWebPath = fmt.Sprintf("studies/%s/series", id) dicomWebPath = fmt.Sprintf("studies/%s/series", id)
} }
} }
resp, err := source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts) return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package searchdicomstudies
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
) )
@@ -126,32 +124,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to validate store ID", err) return nil, err
} }
var tokenStr string var tokenStr string
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenStr, err = accessToken.ParseBearerToken() tokenStr, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("error parsing access token: %w", err)
} }
} }
opts, err := common.ParseDICOMSearchParameters(params, []string{studyInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey}) opts, err := common.ParseDICOMSearchParameters(params, []string{studyInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey})
if err != nil { if err != nil {
return nil, util.NewAgentError("failed to parse DICOM search parameters", err) return nil, err
} }
dicomWebPath := "studies" dicomWebPath := "studies"
resp, err := source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts) return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -16,13 +16,11 @@ package cloudloggingadminlistlognames
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -91,10 +89,10 @@ type Tool struct {
Parameters parameters.Parameters `yaml:"parameters"` Parameters parameters.Parameters `yaml:"parameters"`
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
limit := defaultLimit limit := defaultLimit
@@ -102,22 +100,18 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if val, ok := paramsMap["limit"].(int); ok && val > 0 { if val, ok := paramsMap["limit"].(int); ok && val > 0 {
limit = val limit = val
} else if ok && val < 0 { } else if ok && val < 0 {
return nil, util.NewAgentError("limit must be greater than or equal to 1", nil) return nil, fmt.Errorf("limit must be greater than or equal to 1")
} }
tokenString := "" tokenString := ""
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenString, err = accessToken.ParseBearerToken() tokenString, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("failed to parse access token: %w", err)
} }
} }
resp, err := source.ListLogNames(ctx, limit, tokenString) return source.ListLogNames(ctx, limit, tokenString)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) { func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {

View File

@@ -16,13 +16,11 @@ package cloudloggingadminlistresourcetypes
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -86,25 +84,21 @@ type Tool struct {
mcpManifest tools.McpManifest mcpManifest tools.McpManifest
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
tokenString := "" tokenString := ""
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenString, err = accessToken.ParseBearerToken() tokenString, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("failed to parse access token: %w", err)
} }
} }
resp, err := source.ListResourceTypes(ctx, tokenString) return source.ListResourceTypes(ctx, tokenString)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) { func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {

View File

@@ -16,7 +16,6 @@ package cloudloggingadminquerylogs
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"time" "time"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
@@ -24,7 +23,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
cla "github.com/googleapis/genai-toolbox/internal/sources/cloudloggingadmin" cla "github.com/googleapis/genai-toolbox/internal/sources/cloudloggingadmin"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -106,10 +104,10 @@ type Tool struct {
mcpManifest tools.McpManifest mcpManifest tools.McpManifest
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
// Parse parameters // Parse parameters
@@ -121,7 +119,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if val, ok := paramsMap["limit"].(int); ok && val > 0 { if val, ok := paramsMap["limit"].(int); ok && val > 0 {
limit = val limit = val
} else if ok && val < 0 { } else if ok && val < 0 {
return nil, util.NewAgentError("limit must be greater than or equal to 1", nil) return nil, fmt.Errorf("limit must be greater than or equal to 1")
} }
// Check for verbosity of output // Check for verbosity of output
@@ -131,7 +129,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var filter string var filter string
if f, ok := paramsMap["filter"].(string); ok { if f, ok := paramsMap["filter"].(string); ok {
if len(f) == 0 { if len(f) == 0 {
return nil, util.NewAgentError("filter cannot be empty if provided", nil) return nil, fmt.Errorf("filter cannot be empty if provided")
} }
filter = f filter = f
} }
@@ -140,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var startTime string var startTime string
if val, ok := paramsMap["startTime"].(string); ok && val != "" { if val, ok := paramsMap["startTime"].(string); ok && val != "" {
if _, err := time.Parse(time.RFC3339, val); err != nil { if _, err := time.Parse(time.RFC3339, val); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("startTime must be in RFC3339 format (e.g., 2025-12-09T00:00:00Z): %v", err), err) return nil, fmt.Errorf("startTime must be in RFC3339 format (e.g., 2025-12-09T00:00:00Z): %w", err)
} }
startTime = val startTime = val
} else { } else {
@@ -151,7 +149,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
var endTime string var endTime string
if val, ok := paramsMap["endTime"].(string); ok && val != "" { if val, ok := paramsMap["endTime"].(string); ok && val != "" {
if _, err := time.Parse(time.RFC3339, val); err != nil { if _, err := time.Parse(time.RFC3339, val); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("endTime must be in RFC3339 format (e.g., 2025-12-09T23:59:59Z): %v", err), err) return nil, fmt.Errorf("endTime must be in RFC3339 format (e.g., 2025-12-09T23:59:59Z): %w", err)
} }
endTime = val endTime = val
} }
@@ -160,7 +158,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if source.UseClientAuthorization() { if source.UseClientAuthorization() {
tokenString, err = accessToken.ParseBearerToken() tokenString, err = accessToken.ParseBearerToken()
if err != nil { if err != nil {
return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err) return nil, fmt.Errorf("failed to parse access token: %w", err)
} }
} }
@@ -173,11 +171,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
Limit: limit, Limit: limit,
} }
resp, err := source.QueryLogs(ctx, queryParams, tokenString) return source.QueryLogs(ctx, queryParams, tokenString)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) { func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {

View File

@@ -23,7 +23,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -94,26 +93,22 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
projectID, ok := paramsMap["projectId"].(string) projectID, ok := paramsMap["projectId"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("projectId parameter not found or not a string", nil) return nil, fmt.Errorf("projectId parameter not found or not a string")
} }
query, ok := paramsMap["query"].(string) query, ok := paramsMap["query"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("query parameter not found or not a string", nil) return nil, fmt.Errorf("query parameter not found or not a string")
} }
resp, err := source.RunQuery(projectID, query) return source.RunQuery(projectID, query)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqlcloneinstance
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
sqladmin "google.golang.org/api/sqladmin/v1" sqladmin "google.golang.org/api/sqladmin/v1"
) )
@@ -126,35 +124,31 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %v", paramsMap["project"]), nil) return nil, fmt.Errorf("error casting 'project' parameter: %v", paramsMap["project"])
} }
sourceInstanceName, ok := paramsMap["sourceInstanceName"].(string) sourceInstanceName, ok := paramsMap["sourceInstanceName"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'sourceInstanceName' parameter: %v", paramsMap["sourceInstanceName"]), nil) return nil, fmt.Errorf("error casting 'sourceInstanceName' parameter: %v", paramsMap["sourceInstanceName"])
} }
destinationInstanceName, ok := paramsMap["destinationInstanceName"].(string) destinationInstanceName, ok := paramsMap["destinationInstanceName"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'destinationInstanceName' parameter: %v", paramsMap["destinationInstanceName"]), nil) return nil, fmt.Errorf("error casting 'destinationInstanceName' parameter: %v", paramsMap["destinationInstanceName"])
} }
pointInTime, _ := paramsMap["pointInTime"].(string) pointInTime, _ := paramsMap["pointInTime"].(string)
preferredZone, _ := paramsMap["preferredZone"].(string) preferredZone, _ := paramsMap["preferredZone"].(string)
preferredSecondaryZone, _ := paramsMap["preferredSecondaryZone"].(string) preferredSecondaryZone, _ := paramsMap["preferredSecondaryZone"].(string)
resp, err := source.CloneInstance(ctx, project, sourceInstanceName, destinationInstanceName, pointInTime, preferredZone, preferredSecondaryZone, string(accessToken)) return source.CloneInstance(ctx, project, sourceInstanceName, destinationInstanceName, pointInTime, preferredZone, preferredSecondaryZone, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqlcreatebackup
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/sqladmin/v1" "google.golang.org/api/sqladmin/v1"
) )
@@ -122,30 +120,26 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %v", paramsMap["project"]), nil) return nil, fmt.Errorf("error casting 'project' parameter: %v", paramsMap["project"])
} }
instance, ok := paramsMap["instance"].(string) instance, ok := paramsMap["instance"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'instance' parameter: %v", paramsMap["instance"]), nil) return nil, fmt.Errorf("error casting 'instance' parameter: %v", paramsMap["instance"])
} }
location, _ := paramsMap["location"].(string) location, _ := paramsMap["location"].(string)
description, _ := paramsMap["backup_description"].(string) description, _ := paramsMap["backup_description"].(string)
resp, err := source.InsertBackupRun(ctx, project, instance, location, description, string(accessToken)) return source.InsertBackupRun(ctx, project, instance, location, description, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqlcreatedatabase
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -119,31 +117,27 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
instance, ok := paramsMap["instance"].(string) instance, ok := paramsMap["instance"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'instance' parameter", nil) return nil, fmt.Errorf("missing 'instance' parameter")
} }
name, ok := paramsMap["name"].(string) name, ok := paramsMap["name"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'name' parameter", nil) return nil, fmt.Errorf("missing 'name' parameter")
} }
resp, err := source.CreateDatabase(ctx, name, project, instance, string(accessToken)) return source.CreateDatabase(ctx, name, project, instance, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqlcreateusers
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -121,34 +119,30 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
instance, ok := paramsMap["instance"].(string) instance, ok := paramsMap["instance"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'instance' parameter", nil) return nil, fmt.Errorf("missing 'instance' parameter")
} }
name, ok := paramsMap["name"].(string) name, ok := paramsMap["name"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'name' parameter", nil) return nil, fmt.Errorf("missing 'name' parameter")
} }
iamUser, _ := paramsMap["iamUser"].(bool) iamUser, _ := paramsMap["iamUser"].(bool)
password, _ := paramsMap["password"].(string) password, _ := paramsMap["password"].(string)
resp, err := source.CreateUsers(ctx, project, instance, name, password, iamUser, string(accessToken)) return source.CreateUsers(ctx, project, instance, name, password, iamUser, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqlgetinstances
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -119,27 +117,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
projectId, ok := paramsMap["projectId"].(string) projectId, ok := paramsMap["projectId"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'projectId' parameter", nil) return nil, fmt.Errorf("missing 'projectId' parameter")
} }
instanceId, ok := paramsMap["instanceId"].(string) instanceId, ok := paramsMap["instanceId"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'instanceId' parameter", nil) return nil, fmt.Errorf("missing 'instanceId' parameter")
} }
resp, err := source.GetInstance(ctx, projectId, instanceId, string(accessToken)) return source.GetInstance(ctx, projectId, instanceId, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqllistdatabases
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -118,27 +116,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
instance, ok := paramsMap["instance"].(string) instance, ok := paramsMap["instance"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'instance' parameter", nil) return nil, fmt.Errorf("missing 'instance' parameter")
} }
resp, err := source.ListDatabase(ctx, project, instance, string(accessToken)) return source.ListDatabase(ctx, project, instance, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqllistinstances
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -117,23 +115,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
resp, err := source.ListInstance(ctx, project, string(accessToken)) return source.ListInstance(ctx, project, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package cloudsqlrestorebackup
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/sqladmin/v1" "google.golang.org/api/sqladmin/v1"
) )
@@ -122,33 +120,29 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
targetProject, ok := paramsMap["target_project"].(string) targetProject, ok := paramsMap["target_project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'target_project' parameter: %v", paramsMap["target_project"]), nil) return nil, fmt.Errorf("error casting 'target_project' parameter: %v", paramsMap["target_project"])
} }
targetInstance, ok := paramsMap["target_instance"].(string) targetInstance, ok := paramsMap["target_instance"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'target_instance' parameter: %v", paramsMap["target_instance"]), nil) return nil, fmt.Errorf("error casting 'target_instance' parameter: %v", paramsMap["target_instance"])
} }
backupID, ok := paramsMap["backup_id"].(string) backupID, ok := paramsMap["backup_id"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'backup_id' parameter: %v", paramsMap["backup_id"]), nil) return nil, fmt.Errorf("error casting 'backup_id' parameter: %v", paramsMap["backup_id"])
} }
sourceProject, _ := paramsMap["source_project"].(string) sourceProject, _ := paramsMap["source_project"].(string)
sourceInstance, _ := paramsMap["source_instance"].(string) sourceInstance, _ := paramsMap["source_instance"].(string)
resp, err := source.RestoreBackup(ctx, targetProject, targetInstance, sourceProject, sourceInstance, backupID, string(accessToken)) return source.RestoreBackup(ctx, targetProject, targetInstance, sourceProject, sourceInstance, backupID, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package cloudsqlwaitforoperation
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"time" "time"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/sqladmin/v1" "google.golang.org/api/sqladmin/v1"
) )
@@ -212,21 +210,21 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
operationID, ok := paramsMap["operation"].(string) operationID, ok := paramsMap["operation"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'operation' parameter", nil) return nil, fmt.Errorf("missing 'operation' parameter")
} }
ctx, cancel := context.WithTimeout(ctx, 30*time.Minute) ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
@@ -234,7 +232,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
service, err := source.GetService(ctx, string(accessToken)) service, err := source.GetService(ctx, string(accessToken))
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, err
} }
delay := t.Delay delay := t.Delay
@@ -246,13 +244,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
for retries < maxRetries { for retries < maxRetries {
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, util.NewClientServerError("timed out waiting for operation", http.StatusRequestTimeout, ctx.Err()) return nil, fmt.Errorf("timed out waiting for operation: %w", ctx.Err())
default: default:
} }
op, err := source.GetWaitForOperations(ctx, service, project, operationID, cloudSQLConnectionMessageTemplate, delay) op, err := source.GetWaitForOperations(ctx, service, project, operationID, cloudSQLConnectionMessageTemplate, delay)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, err
} else if op != nil { } else if op != nil {
return op, nil return op, nil
} }
@@ -264,7 +262,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
} }
retries++ retries++
} }
return nil, util.NewClientServerError("exceeded max retries waiting for operation", http.StatusGatewayTimeout, fmt.Errorf("exceeded max retries")) return nil, fmt.Errorf("exceeded max retries waiting for operation")
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package cloudsqlmssqlcreateinstance
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/sqladmin/v1" "google.golang.org/api/sqladmin/v1"
) )
@@ -123,33 +121,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %s", paramsMap["project"]), nil) return nil, fmt.Errorf("error casting 'project' parameter: %s", paramsMap["project"])
} }
name, ok := paramsMap["name"].(string) name, ok := paramsMap["name"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'name' parameter: %s", paramsMap["name"]), nil) return nil, fmt.Errorf("error casting 'name' parameter: %s", paramsMap["name"])
} }
dbVersion, ok := paramsMap["databaseVersion"].(string) dbVersion, ok := paramsMap["databaseVersion"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'databaseVersion' parameter: %s", paramsMap["databaseVersion"]), nil) return nil, fmt.Errorf("error casting 'databaseVersion' parameter: %s", paramsMap["databaseVersion"])
} }
rootPassword, ok := paramsMap["rootPassword"].(string) rootPassword, ok := paramsMap["rootPassword"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'rootPassword' parameter: %s", paramsMap["rootPassword"]), nil) return nil, fmt.Errorf("error casting 'rootPassword' parameter: %s", paramsMap["rootPassword"])
} }
editionPreset, ok := paramsMap["editionPreset"].(string) editionPreset, ok := paramsMap["editionPreset"].(string)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'editionPreset' parameter: %s", paramsMap["editionPreset"]), nil) return nil, fmt.Errorf("error casting 'editionPreset' parameter: %s", paramsMap["editionPreset"])
} }
settings := sqladmin.Settings{} settings := sqladmin.Settings{}
switch strings.ToLower(editionPreset) { switch strings.ToLower(editionPreset) {
@@ -166,13 +164,9 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
settings.DataDiskSizeGb = 100 settings.DataDiskSizeGb = 100
settings.DataDiskType = "PD_SSD" settings.DataDiskType = "PD_SSD"
default: default:
return nil, util.NewAgentError(fmt.Sprintf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset), nil) return nil, fmt.Errorf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset)
} }
resp, err := source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken)) return source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package cloudsqlmysqlcreateinstance
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
sqladmin "google.golang.org/api/sqladmin/v1" sqladmin "google.golang.org/api/sqladmin/v1"
) )
@@ -123,33 +121,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
name, ok := paramsMap["name"].(string) name, ok := paramsMap["name"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'name' parameter", nil) return nil, fmt.Errorf("missing 'name' parameter")
} }
dbVersion, ok := paramsMap["databaseVersion"].(string) dbVersion, ok := paramsMap["databaseVersion"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'databaseVersion' parameter", nil) return nil, fmt.Errorf("missing 'databaseVersion' parameter")
} }
rootPassword, ok := paramsMap["rootPassword"].(string) rootPassword, ok := paramsMap["rootPassword"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'rootPassword' parameter", nil) return nil, fmt.Errorf("missing 'rootPassword' parameter")
} }
editionPreset, ok := paramsMap["editionPreset"].(string) editionPreset, ok := paramsMap["editionPreset"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'editionPreset' parameter", nil) return nil, fmt.Errorf("missing 'editionPreset' parameter")
} }
settings := sqladmin.Settings{} settings := sqladmin.Settings{}
@@ -167,14 +165,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
settings.DataDiskSizeGb = 100 settings.DataDiskSizeGb = 100
settings.DataDiskType = "PD_SSD" settings.DataDiskType = "PD_SSD"
default: default:
return nil, util.NewAgentError(fmt.Sprintf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset), nil) return nil, fmt.Errorf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset)
} }
resp, err := source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken)) return source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package cloudsqlpgcreateinstances
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strings" "strings"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
sqladmin "google.golang.org/api/sqladmin/v1" sqladmin "google.golang.org/api/sqladmin/v1"
) )
@@ -123,33 +121,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'project' parameter", nil) return nil, fmt.Errorf("missing 'project' parameter")
} }
name, ok := paramsMap["name"].(string) name, ok := paramsMap["name"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'name' parameter", nil) return nil, fmt.Errorf("missing 'name' parameter")
} }
dbVersion, ok := paramsMap["databaseVersion"].(string) dbVersion, ok := paramsMap["databaseVersion"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'databaseVersion' parameter", nil) return nil, fmt.Errorf("missing 'databaseVersion' parameter")
} }
rootPassword, ok := paramsMap["rootPassword"].(string) rootPassword, ok := paramsMap["rootPassword"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'rootPassword' parameter", nil) return nil, fmt.Errorf("missing 'rootPassword' parameter")
} }
editionPreset, ok := paramsMap["editionPreset"].(string) editionPreset, ok := paramsMap["editionPreset"].(string)
if !ok { if !ok {
return nil, util.NewAgentError("missing 'editionPreset' parameter", nil) return nil, fmt.Errorf("missing 'editionPreset' parameter")
} }
settings := sqladmin.Settings{} settings := sqladmin.Settings{}
@@ -167,13 +165,9 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
settings.DataDiskSizeGb = 100 settings.DataDiskSizeGb = 100
settings.DataDiskType = "PD_SSD" settings.DataDiskType = "PD_SSD"
default: default:
return nil, util.NewAgentError(fmt.Sprintf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset), nil) return nil, fmt.Errorf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset)
} }
resp, err := source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken)) return source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package cloudsqlpgupgradeprecheck
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"time" "time"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
sqladmin "google.golang.org/api/sqladmin/v1" sqladmin "google.golang.org/api/sqladmin/v1"
) )
@@ -134,31 +132,31 @@ func (t Tool) ToConfig() tools.ToolConfig {
} }
// Invoke executes the tool's logic. // Invoke executes the tool's logic.
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
project, ok := paramsMap["project"].(string) project, ok := paramsMap["project"].(string)
if !ok || project == "" { if !ok || project == "" {
return nil, util.NewAgentError("missing or empty 'project' parameter", nil) return nil, fmt.Errorf("missing or empty 'project' parameter")
} }
instanceName, ok := paramsMap["instance"].(string) instanceName, ok := paramsMap["instance"].(string)
if !ok || instanceName == "" { if !ok || instanceName == "" {
return nil, util.NewAgentError("missing or empty 'instance' parameter", nil) return nil, fmt.Errorf("missing or empty 'instance' parameter")
} }
targetVersion, ok := paramsMap["targetDatabaseVersion"].(string) targetVersion, ok := paramsMap["targetDatabaseVersion"].(string)
if !ok || targetVersion == "" { if !ok || targetVersion == "" {
// This should not happen due to the default value // This should not happen due to the default value
return nil, util.NewAgentError("missing or empty 'targetDatabaseVersion' parameter", nil) return nil, fmt.Errorf("missing or empty 'targetDatabaseVersion' parameter")
} }
service, err := source.GetService(ctx, string(accessToken)) service, err := source.GetService(ctx, string(accessToken))
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to get HTTP client from source: %w", err)
} }
reqBody := &sqladmin.InstancesPreCheckMajorVersionUpgradeRequest{ reqBody := &sqladmin.InstancesPreCheckMajorVersionUpgradeRequest{
@@ -170,7 +168,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
call := service.Instances.PreCheckMajorVersionUpgrade(project, instanceName, reqBody).Context(ctx) call := service.Instances.PreCheckMajorVersionUpgrade(project, instanceName, reqBody).Context(ctx)
op, err := call.Do() op, err := call.Do()
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to start pre-check operation: %w", err)
} }
const pollTimeout = 20 * time.Second const pollTimeout = 20 * time.Second
@@ -179,7 +177,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
for time.Now().Before(cutoffTime) { for time.Now().Before(cutoffTime) {
currentOp, err := service.Operations.Get(project, op.Name).Context(ctx).Do() currentOp, err := service.Operations.Get(project, op.Name).Context(ctx).Do()
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, fmt.Errorf("failed to get operation status: %w", err)
} }
if currentOp.Status == "DONE" { if currentOp.Status == "DONE" {
@@ -188,7 +186,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if currentOp.Error.Errors[0].Code != "" { if currentOp.Error.Errors[0].Code != "" {
errMsg = fmt.Sprintf("%s (Code: %s)", errMsg, currentOp.Error.Errors[0].Code) errMsg = fmt.Sprintf("%s (Code: %s)", errMsg, currentOp.Error.Errors[0].Code)
} }
return nil, util.NewClientServerError(errMsg, http.StatusInternalServerError, fmt.Errorf("pre-check operation failed with error: %s", errMsg)) return nil, fmt.Errorf("%s", errMsg)
} }
var preCheckItems []*sqladmin.PreCheckResponse var preCheckItems []*sqladmin.PreCheckResponse
@@ -201,7 +199,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
select { select {
case <-ctx.Done(): case <-ctx.Done():
return nil, util.NewClientServerError("timed out waiting for operation", http.StatusRequestTimeout, ctx.Err()) return nil, ctx.Err()
case <-time.After(5 * time.Second): case <-time.After(5 * time.Second):
} }
} }

View File

@@ -17,14 +17,12 @@ package dataplexlookupentry
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
dataplexpb "cloud.google.com/go/dataplex/apiv1/dataplexpb" dataplexpb "cloud.google.com/go/dataplex/apiv1/dataplexpb"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -112,10 +110,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
@@ -124,14 +122,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
view, _ := paramsMap["view"].(int) view, _ := paramsMap["view"].(int)
aspectTypeSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["aspectTypes"].([]any), "string") aspectTypeSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["aspectTypes"].([]any), "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert aspectTypes to array of strings: %s", err), err) return nil, fmt.Errorf("can't convert aspectTypes to array of strings: %s", err)
} }
aspectTypes := aspectTypeSlice.([]string) aspectTypes := aspectTypeSlice.([]string)
resp, err := source.LookupEntry(ctx, name, view, aspectTypes, entry) return source.LookupEntry(ctx, name, view, aspectTypes, entry)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package dataplexsearchaspecttypes
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"cloud.google.com/go/dataplex/apiv1/dataplexpb" "cloud.google.com/go/dataplex/apiv1/dataplexpb"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -95,29 +93,16 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
query, ok := paramsMap["query"].(string) query, _ := paramsMap["query"].(string)
if !ok { pageSize, _ := paramsMap["pageSize"].(int)
return nil, util.NewAgentError(fmt.Sprintf("error casting 'query' parameter: %v", paramsMap["query"]), nil) orderBy, _ := paramsMap["orderBy"].(string)
} return source.SearchAspectTypes(ctx, query, pageSize, orderBy)
pageSize, ok := paramsMap["pageSize"].(int)
if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'pageSize' parameter: %v", paramsMap["pageSize"]), nil)
}
orderBy, ok := paramsMap["orderBy"].(string)
if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'orderBy' parameter: %v", paramsMap["orderBy"]), nil)
}
resp, err := source.SearchAspectTypes(ctx, query, pageSize, orderBy)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,14 +17,12 @@ package dataplexsearchentries
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"cloud.google.com/go/dataplex/apiv1/dataplexpb" "cloud.google.com/go/dataplex/apiv1/dataplexpb"
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -95,29 +93,16 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
query, ok := paramsMap["query"].(string) query, _ := paramsMap["query"].(string)
if !ok { pageSize, _ := paramsMap["pageSize"].(int)
return nil, util.NewAgentError(fmt.Sprintf("error casting 'query' parameter: %v", paramsMap["query"]), nil) orderBy, _ := paramsMap["orderBy"].(string)
} return source.SearchEntries(ctx, query, pageSize, orderBy)
pageSize, ok := paramsMap["pageSize"].(int)
if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'pageSize' parameter: %v", paramsMap["pageSize"]), nil)
}
orderBy, ok := paramsMap["orderBy"].(string)
if !ok {
return nil, util.NewAgentError(fmt.Sprintf("error casting 'orderBy' parameter: %v", paramsMap["orderBy"]), nil)
}
resp, err := source.SearchEntries(ctx, query, pageSize, orderBy)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,15 +17,13 @@ package firestoreadddocuments
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
firestoreapi "cloud.google.com/go/firestore" firestoreapi "cloud.google.com/go/firestore"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util" "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -130,32 +128,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
// Get collection path // Get collection path
collectionPath, ok := mapParams[collectionPathKey].(string) collectionPath, ok := mapParams[collectionPathKey].(string)
if !ok || collectionPath == "" { if !ok || collectionPath == "" {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter", collectionPathKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter", collectionPathKey)
} }
// Validate collection path // Validate collection path
if err := fsUtil.ValidateCollectionPath(collectionPath); err != nil { if err := util.ValidateCollectionPath(collectionPath); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("invalid collection path: %v", err), err) return nil, fmt.Errorf("invalid collection path: %w", err)
} }
// Get document data // Get document data
documentDataRaw, ok := mapParams[documentDataKey] documentDataRaw, ok := mapParams[documentDataKey]
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter", documentDataKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter", documentDataKey)
} }
// Convert the document data from JSON format to Firestore format // Convert the document data from JSON format to Firestore format
// The client is passed to handle referenceValue types // The client is passed to handle referenceValue types
documentData, err := fsUtil.JSONToFirestoreValue(documentDataRaw, source.FirestoreClient()) documentData, err := util.JSONToFirestoreValue(documentDataRaw, source.FirestoreClient())
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to convert document data: %v", err), err) return nil, fmt.Errorf("failed to convert document data: %w", err)
} }
// Get return document data flag // Get return document data flag
@@ -163,11 +161,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
if val, ok := mapParams[returnDocumentDataKey].(bool); ok { if val, ok := mapParams[returnDocumentDataKey].(bool); ok {
returnData = val returnData = val
} }
resp, err := source.AddDocuments(ctx, collectionPath, documentData, returnData) return source.AddDocuments(ctx, collectionPath, documentData, returnData)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,15 +17,13 @@ package firestoredeletedocuments
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
firestoreapi "cloud.google.com/go/firestore" firestoreapi "cloud.google.com/go/firestore"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util" "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -96,43 +94,39 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
documentPathsRaw, ok := mapParams[documentPathsKey].([]any) documentPathsRaw, ok := mapParams[documentPathsKey].([]any)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected an array", documentPathsKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected an array", documentPathsKey)
} }
if len(documentPathsRaw) == 0 { if len(documentPathsRaw) == 0 {
return nil, util.NewAgentError(fmt.Sprintf("'%s' parameter cannot be empty", documentPathsKey), nil) return nil, fmt.Errorf("'%s' parameter cannot be empty", documentPathsKey)
} }
// Use ConvertAnySliceToTyped to convert the slice // Use ConvertAnySliceToTyped to convert the slice
typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string") typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to convert document paths: %v", err), err) return nil, fmt.Errorf("failed to convert document paths: %w", err)
} }
documentPaths, ok := typedSlice.([]string) documentPaths, ok := typedSlice.([]string)
if !ok { if !ok {
return nil, util.NewAgentError("unexpected type conversion error for document paths", nil) return nil, fmt.Errorf("unexpected type conversion error for document paths")
} }
// Validate each document path // Validate each document path
for i, path := range documentPaths { for i, path := range documentPaths {
if err := fsUtil.ValidateDocumentPath(path); err != nil { if err := util.ValidateDocumentPath(path); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("invalid document path at index %d: %v", i, err), err) return nil, fmt.Errorf("invalid document path at index %d: %w", i, err)
} }
} }
resp, err := source.DeleteDocuments(ctx, documentPaths) return source.DeleteDocuments(ctx, documentPaths)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,15 +17,13 @@ package firestoregetdocuments
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
firestoreapi "cloud.google.com/go/firestore" firestoreapi "cloud.google.com/go/firestore"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util" "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -96,44 +94,40 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
documentPathsRaw, ok := mapParams[documentPathsKey].([]any) documentPathsRaw, ok := mapParams[documentPathsKey].([]any)
if !ok { if !ok {
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected an array", documentPathsKey), nil) return nil, fmt.Errorf("invalid or missing '%s' parameter; expected an array", documentPathsKey)
} }
if len(documentPathsRaw) == 0 { if len(documentPathsRaw) == 0 {
return nil, util.NewAgentError(fmt.Sprintf("'%s' parameter cannot be empty", documentPathsKey), nil) return nil, fmt.Errorf("'%s' parameter cannot be empty", documentPathsKey)
} }
// Use ConvertAnySliceToTyped to convert the slice // Use ConvertAnySliceToTyped to convert the slice
typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string") typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string")
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to convert document paths: %v", err), err) return nil, fmt.Errorf("failed to convert document paths: %w", err)
} }
documentPaths, ok := typedSlice.([]string) documentPaths, ok := typedSlice.([]string)
if !ok { if !ok {
return nil, util.NewAgentError("unexpected type conversion error for document paths", nil) return nil, fmt.Errorf("unexpected type conversion error for document paths")
} }
// Validate each document path // Validate each document path
for i, path := range documentPaths { for i, path := range documentPaths {
if err := fsUtil.ValidateDocumentPath(path); err != nil { if err := util.ValidateDocumentPath(path); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("invalid document path at index %d: %v", i, err), err) return nil, fmt.Errorf("invalid document path at index %d: %w", i, err)
} }
} }
resp, err := source.GetDocuments(ctx, documentPaths) return source.GetDocuments(ctx, documentPaths)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,13 +17,11 @@ package firestoregetrules
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"google.golang.org/api/firebaserules/v1" "google.golang.org/api/firebaserules/v1"
) )
@@ -94,16 +92,12 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
resp, err := source.GetRules(ctx) return source.GetRules(ctx)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -17,15 +17,13 @@ package firestorelistcollections
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
firestoreapi "cloud.google.com/go/firestore" firestoreapi "cloud.google.com/go/firestore"
yaml "github.com/goccy/go-yaml" yaml "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util" "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -97,10 +95,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
return t.Config return t.Config
} }
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
mapParams := params.AsMap() mapParams := params.AsMap()
@@ -109,15 +107,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
parentPath, _ := mapParams[parentPathKey].(string) parentPath, _ := mapParams[parentPathKey].(string)
if parentPath != "" { if parentPath != "" {
// Validate parent document path // Validate parent document path
if err := fsUtil.ValidateDocumentPath(parentPath); err != nil { if err := util.ValidateDocumentPath(parentPath); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("invalid parent document path: %v", err), err) return nil, fmt.Errorf("invalid parent document path: %w", err)
} }
} }
resp, err := source.ListCollections(ctx, parentPath) return source.ListCollections(ctx, parentPath)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) { func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {

View File

@@ -18,7 +18,6 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"strconv" "strconv"
"strings" "strings"
@@ -27,8 +26,7 @@ import (
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util" "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
"github.com/googleapis/genai-toolbox/internal/util"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
) )
@@ -160,16 +158,16 @@ var validOperators = map[string]bool{
} }
// Invoke executes the Firestore query based on the provided parameters // Invoke executes the Firestore query based on the provided parameters
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
if err != nil { if err != nil {
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) return nil, err
} }
paramsMap := params.AsMap() paramsMap := params.AsMap()
// Process collection path with template substitution // Process collection path with template substitution
collectionPath, err := parameters.PopulateTemplate("collectionPath", t.CollectionPath, paramsMap) collectionPath, err := parameters.PopulateTemplate("collectionPath", t.CollectionPath, paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to process collection path: %v", err), err) return nil, fmt.Errorf("failed to process collection path: %w", err)
} }
var filter firestoreapi.EntityFilter var filter firestoreapi.EntityFilter
@@ -178,13 +176,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Apply template substitution to filters // Apply template substitution to filters
filtersJSON, err := parameters.PopulateTemplateWithJSON("filters", t.Filters, paramsMap) filtersJSON, err := parameters.PopulateTemplateWithJSON("filters", t.Filters, paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to process filters template: %v", err), err) return nil, fmt.Errorf("failed to process filters template: %w", err)
} }
// Parse the simplified filter format // Parse the simplified filter format
var simplifiedFilter SimplifiedFilter var simplifiedFilter SimplifiedFilter
if err := json.Unmarshal([]byte(filtersJSON), &simplifiedFilter); err != nil { if err := json.Unmarshal([]byte(filtersJSON), &simplifiedFilter); err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to parse filters: %v", err), err) return nil, fmt.Errorf("failed to parse filters: %w", err)
} }
// Convert simplified filter to Firestore filter // Convert simplified filter to Firestore filter
@@ -193,17 +191,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Process and apply ordering // Process and apply ordering
orderBy, err := t.getOrderBy(paramsMap) orderBy, err := t.getOrderBy(paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to process order by: %v", err), err) return nil, err
} }
// Process select fields // Process select fields
selectFields, err := t.processSelectFields(paramsMap) selectFields, err := t.processSelectFields(paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to process select fields: %v", err), err) return nil, err
} }
// Process and apply limit // Process and apply limit
limit, err := t.getLimit(paramsMap) limit, err := t.getLimit(paramsMap)
if err != nil { if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("failed to process limit: %v", err), err) return nil, err
} }
// prevent panic when accessing orderBy incase it is nil // prevent panic when accessing orderBy incase it is nil
@@ -217,14 +215,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
// Build the query // Build the query
query, err := source.BuildQuery(collectionPath, filter, selectFields, orderByField, orderByDirection, limit, t.AnalyzeQuery) query, err := source.BuildQuery(collectionPath, filter, selectFields, orderByField, orderByDirection, limit, t.AnalyzeQuery)
if err != nil { if err != nil {
return nil, util.ProecessGcpError(err) return nil, err
} }
// Execute the query and return results // Execute the query and return results
resp, err := source.ExecuteQuery(ctx, query, t.AnalyzeQuery) return source.ExecuteQuery(ctx, query, t.AnalyzeQuery)
if err != nil {
return nil, util.ProecessGcpError(err)
}
return resp, nil
} }
// convertToFirestoreFilter converts simplified filter format to Firestore EntityFilter // convertToFirestoreFilter converts simplified filter format to Firestore EntityFilter
@@ -261,7 +255,7 @@ func (t Tool) convertToFirestoreFilter(source compatibleSource, filter Simplifie
if filter.Field != "" && filter.Op != "" && filter.Value != nil { if filter.Field != "" && filter.Op != "" && filter.Value != nil {
if validOperators[filter.Op] { if validOperators[filter.Op] {
// Convert the value using the Firestore native JSON converter // Convert the value using the Firestore native JSON converter
convertedValue, err := fsUtil.JSONToFirestoreValue(filter.Value, source.FirestoreClient()) convertedValue, err := util.JSONToFirestoreValue(filter.Value, source.FirestoreClient())
if err != nil { if err != nil {
// If conversion fails, use the original value // If conversion fails, use the original value
convertedValue = filter.Value convertedValue = filter.Value
@@ -373,7 +367,7 @@ func (t Tool) getLimit(params map[string]any) (int, error) {
if processedValue != "" { if processedValue != "" {
parsedLimit, err := strconv.Atoi(processedValue) parsedLimit, err := strconv.Atoi(processedValue)
if err != nil { if err != nil {
return 0, err return 0, fmt.Errorf("failed to parse limit value '%s': %w", processedValue, err)
} }
limit = parsedLimit limit = parsedLimit
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/goccy/go-yaml" "github.com/goccy/go-yaml"
"github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/embeddingmodels"
"github.com/googleapis/genai-toolbox/internal/util/parameters" "github.com/googleapis/genai-toolbox/internal/util/parameters"
"go.mongodb.org/mongo-driver/v2/mongo" "go.mongodb.org/mongo-driver/mongo"
"github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/sources"
"github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools"

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