From 9208b2b237f54dd145f38a9f219e10bc72a66c4f Mon Sep 17 00:00:00 2001 From: duwenxin Date: Tue, 3 Feb 2026 01:15:21 -0500 Subject: [PATCH] add gcp tools refactor --- .../bigqueryanalyzecontribution.go | 45 +++++++++------- .../bigqueryconversationalanalytics.go | 19 +++---- .../bigqueryforecast/bigqueryforecast.go | 51 ++++++++++--------- .../bigquerysearchcatalog.go | 23 +++++---- internal/tools/cloudgda/cloudgda.go | 20 +++++--- .../cloudhealthcarefhirfetchpage.go | 19 +++++-- .../cloudhealthcarefhirpatienteverything.go | 26 ++++++---- .../cloudhealthcarefhirpatientsearch.go | 24 +++++---- .../cloudhealthcaregetdataset.go | 14 +++-- .../cloudhealthcaregetdicomstore.go | 16 ++++-- .../cloudhealthcaregetdicomstoremetrics.go | 16 ++++-- .../cloudhealthcaregetfhirresource.go | 20 +++++--- .../cloudhealthcaregetfhirstore.go | 16 ++++-- .../cloudhealthcaregetfhirstoremetrics.go | 16 ++++-- .../cloudhealthcarelistdicomstores.go | 14 +++-- .../cloudhealthcarelistfhirstores.go | 14 +++-- ...healthcareretrieverendereddicominstance.go | 24 +++++---- .../cloudhealthcaresearchdicominstances.go | 22 +++++--- .../cloudhealthcaresearchdicomseries.go | 20 +++++--- .../cloudhealthcaresearchdicomstudies.go | 18 ++++--- .../cloudloggingadminlistlognames.go | 16 ++++-- .../cloudloggingadminlistresourcetypes.go | 14 +++-- .../cloudloggingadminquerylogs.go | 22 +++++--- .../tools/cloudmonitoring/cloudmonitoring.go | 15 ++++-- .../cloudsqlcloneinstance.go | 18 ++++--- .../cloudsqlcreatebackup.go | 16 ++++-- .../cloudsqlcreatedatabase.go | 18 ++++--- .../cloudsqlgetinstances.go | 16 ++++-- .../cloudsqllistdatabases.go | 16 ++++-- .../cloudsqllistinstances.go | 14 +++-- .../cloudsqlrestorebackup.go | 18 ++++--- .../cloudsqlwaitforoperation.go | 18 ++++--- 32 files changed, 412 insertions(+), 226 deletions(-) diff --git a/internal/tools/bigquery/bigqueryanalyzecontribution/bigqueryanalyzecontribution.go b/internal/tools/bigquery/bigqueryanalyzecontribution/bigqueryanalyzecontribution.go index e9758ba7a9..b6394ebcf7 100644 --- a/internal/tools/bigquery/bigqueryanalyzecontribution/bigqueryanalyzecontribution.go +++ b/internal/tools/bigquery/bigqueryanalyzecontribution/bigqueryanalyzecontribution.go @@ -17,6 +17,7 @@ package bigqueryanalyzecontribution import ( "context" "fmt" + "net/http" "strings" bigqueryapi "cloud.google.com/go/bigquery" @@ -27,6 +28,7 @@ import ( bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery" "github.com/googleapis/genai-toolbox/internal/tools" 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" bigqueryrestapi "google.golang.org/api/bigquery/v2" ) @@ -154,21 +156,21 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke runs the contribution analysis. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() inputData, ok := paramsMap["input_data"].(string) if !ok { - return nil, fmt.Errorf("unable to cast input_data parameter %s", paramsMap["input_data"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast input_data parameter %s", paramsMap["input_data"]), nil) } bqClient, restService, err := source.RetrieveClientAndService(accessToken) if err != nil { - return nil, err + return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) } modelID := fmt.Sprintf("contribution_analysis_model_%s", strings.ReplaceAll(uuid.New().String(), "-", "")) @@ -186,7 +188,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } options = append(options, fmt.Sprintf("DIMENSION_ID_COLS = [%s]", strings.Join(strCols, ", "))) } else { - return nil, fmt.Errorf("unable to cast dimension_id_cols parameter %s", paramsMap["dimension_id_cols"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast dimension_id_cols parameter %s", paramsMap["dimension_id_cols"]), nil) } } if val, ok := paramsMap["top_k_insights_by_apriori_support"]; ok { @@ -195,7 +197,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if val, ok := paramsMap["pruning_method"].(string); ok { upperVal := strings.ToUpper(val) if upperVal != "NO_PRUNING" && upperVal != "PRUNE_REDUNDANT_INSIGHTS" { - return nil, fmt.Errorf("invalid pruning_method: %s", val) + return nil, util.NewAgentError(fmt.Sprintf("invalid pruning_method: %s", val), nil) } options = append(options, fmt.Sprintf("PRUNING_METHOD = '%s'", upperVal)) } @@ -207,7 +209,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var connProps []*bigqueryapi.ConnectionProperty session, err := source.BigQuerySession()(ctx) if err != nil { - return nil, fmt.Errorf("failed to get BigQuery session: %w", err) + return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) } if session != nil { connProps = []*bigqueryapi.ConnectionProperty{ @@ -216,22 +218,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) if err != nil { - return nil, fmt.Errorf("query validation failed: %w", err) + return nil, util.ProecessGcpError(err) } statementType := dryRunJob.Statistics.Query.StatementType if statementType != "SELECT" { - 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) + 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) } queryStats := dryRunJob.Statistics.Query if queryStats != nil { for _, tableRef := range queryStats.ReferencedTables { if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) { - return nil, fmt.Errorf("query in input_data accesses dataset '%s.%s', which is not in the allowed list", 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) } } } else { - return nil, fmt.Errorf("could not analyze query in input_data to validate against allowed datasets") + return nil, util.NewAgentError("could not analyze query in input_data to validate against allowed datasets", nil) } } inputDataSource = fmt.Sprintf("(%s)", inputData) @@ -245,10 +247,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para case 2: // dataset.table projectID, datasetID = source.BigQueryClient().Project(), parts[0] default: - return nil, fmt.Errorf("invalid table ID format for 'input_data': %q. Expected 'dataset.table' or 'project.dataset.table'", inputData) + return nil, util.NewAgentError(fmt.Sprintf("invalid table ID format for 'input_data': %q. Expected 'dataset.table' or 'project.dataset.table'", inputData), nil) } if !source.IsDatasetAllowed(projectID, datasetID) { - return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, inputData) + return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, inputData), nil) } } inputDataSource = fmt.Sprintf("SELECT * FROM `%s`", inputData) @@ -268,7 +270,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para // Otherwise, a new session will be created by the first query. session, err := source.BigQuerySession()(ctx) if err != nil { - return nil, fmt.Errorf("failed to get BigQuery session: %w", err) + return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) } if session != nil { @@ -281,15 +283,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } createModelJob, err := createModelQuery.Run(ctx) if err != nil { - return nil, fmt.Errorf("failed to start create model job: %w", err) + return nil, util.ProecessGcpError(err) } status, err := createModelJob.Wait(ctx) if err != nil { - return nil, fmt.Errorf("failed to wait for create model job: %w", err) + return nil, util.ProecessGcpError(err) } if err := status.Err(); err != nil { - return nil, fmt.Errorf("create model job failed: %w", err) + return nil, util.ProecessGcpError(err) } // Determine the session ID to use for subsequent queries. @@ -300,12 +302,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } else if status.Statistics != nil && status.Statistics.SessionInfo != nil { sessionID = status.Statistics.SessionInfo.SessionID } else { - return nil, fmt.Errorf("failed to get or create a BigQuery session ID") + return nil, util.NewClientServerError("failed to get or create a BigQuery session ID", http.StatusInternalServerError, nil) } getInsightsSQL := fmt.Sprintf("SELECT * FROM ML.GET_INSIGHTS(MODEL %s)", modelID) 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) { diff --git a/internal/tools/bigquery/bigqueryconversationalanalytics/bigqueryconversationalanalytics.go b/internal/tools/bigquery/bigqueryconversationalanalytics/bigqueryconversationalanalytics.go index 6f822e241e..196a08b51d 100644 --- a/internal/tools/bigquery/bigqueryconversationalanalytics/bigqueryconversationalanalytics.go +++ b/internal/tools/bigquery/bigqueryconversationalanalytics/bigqueryconversationalanalytics.go @@ -172,10 +172,10 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } var tokenStr string @@ -188,22 +188,22 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } else { // Get a token source for the Gemini Data Analytics API. tokenSource, err := source.BigQueryTokenSourceWithScope(ctx, nil) if err != nil { - return nil, fmt.Errorf("failed to get token source: %w", err) + return nil, util.NewClientServerError("failed to get token source", http.StatusInternalServerError, err) } // Use cloud-platform token source for Gemini Data Analytics API if tokenSource == nil { - return nil, fmt.Errorf("cloud-platform token source is missing") + return nil, util.NewClientServerError("cloud-platform token source is missing", http.StatusInternalServerError, nil) } token, err := tokenSource.Token() if err != nil { - return nil, fmt.Errorf("failed to get token from cloud-platform token source: %w", err) + return nil, util.NewClientServerError("failed to get token from cloud-platform token source", http.StatusInternalServerError, err) } tokenStr = token.AccessToken } @@ -218,14 +218,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var tableRefs []BQTableReference if tableRefsJSON != "" { if err := json.Unmarshal([]byte(tableRefsJSON), &tableRefs); err != nil { - return nil, fmt.Errorf("failed to parse 'table_references' JSON string: %w", err) + return nil, util.NewAgentError("failed to parse 'table_references' JSON string", err) } } if len(source.BigQueryAllowedDatasets()) > 0 { for _, tableRef := range tableRefs { if !source.IsDatasetAllowed(tableRef.ProjectID, tableRef.DatasetID) { - return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", tableRef.ProjectID, tableRef.DatasetID, tableRef.TableID) + return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", tableRef.ProjectID, tableRef.DatasetID, tableRef.TableID), nil) } } } @@ -258,7 +258,8 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para // Call the streaming API response, err := getStream(caURL, payload, headers, source.GetMaxQueryResultRows()) if err != nil { - return nil, fmt.Errorf("failed to get response from conversational analytics API: %w", err) + // getStream wraps network errors or non-200 responses + return nil, util.NewClientServerError("failed to get response from conversational analytics API", http.StatusInternalServerError, err) } return response, nil diff --git a/internal/tools/bigquery/bigqueryforecast/bigqueryforecast.go b/internal/tools/bigquery/bigqueryforecast/bigqueryforecast.go index 72f244bd96..9758ea397d 100644 --- a/internal/tools/bigquery/bigqueryforecast/bigqueryforecast.go +++ b/internal/tools/bigquery/bigqueryforecast/bigqueryforecast.go @@ -17,6 +17,7 @@ package bigqueryforecast import ( "context" "fmt" + "net/http" "strings" bigqueryapi "cloud.google.com/go/bigquery" @@ -133,34 +134,34 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() historyData, ok := paramsMap["history_data"].(string) if !ok { - return nil, fmt.Errorf("unable to cast history_data parameter %v", paramsMap["history_data"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast history_data parameter %v", paramsMap["history_data"]), nil) } timestampCol, ok := paramsMap["timestamp_col"].(string) if !ok { - return nil, fmt.Errorf("unable to cast timestamp_col parameter %v", paramsMap["timestamp_col"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast timestamp_col parameter %v", paramsMap["timestamp_col"]), nil) } dataCol, ok := paramsMap["data_col"].(string) if !ok { - return nil, fmt.Errorf("unable to cast data_col parameter %v", paramsMap["data_col"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast data_col parameter %v", paramsMap["data_col"]), nil) } idColsRaw, ok := paramsMap["id_cols"].([]any) if !ok { - return nil, fmt.Errorf("unable to cast id_cols parameter %v", paramsMap["id_cols"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast id_cols parameter %v", paramsMap["id_cols"]), nil) } var idCols []string for _, v := range idColsRaw { s, ok := v.(string) if !ok { - return nil, fmt.Errorf("id_cols contains non-string value: %v", v) + return nil, util.NewAgentError(fmt.Sprintf("id_cols contains non-string value: %v", v), nil) } idCols = append(idCols, s) } @@ -169,13 +170,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if h, ok := paramsMap["horizon"].(float64); ok { horizon = int(h) } else { - return nil, fmt.Errorf("unable to cast horizon parameter %v", paramsMap["horizon"]) + return nil, util.NewAgentError(fmt.Sprintf("unable to cast horizon parameter %v", paramsMap["horizon"]), nil) } } bqClient, restService, err := source.RetrieveClientAndService(accessToken) if err != nil { - return nil, err + return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err) } var historyDataSource string @@ -185,7 +186,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var connProps []*bigqueryapi.ConnectionProperty session, err := source.BigQuerySession()(ctx) if err != nil { - return nil, fmt.Errorf("failed to get BigQuery session: %w", err) + return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) } if session != nil { connProps = []*bigqueryapi.ConnectionProperty{ @@ -194,22 +195,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) if err != nil { - return nil, fmt.Errorf("query validation failed: %w", err) + return nil, util.ProecessGcpError(err) } statementType := dryRunJob.Statistics.Query.StatementType if statementType != "SELECT" { - 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) + 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) } queryStats := dryRunJob.Statistics.Query if queryStats != nil { for _, tableRef := range queryStats.ReferencedTables { if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) { - return nil, fmt.Errorf("query in history_data accesses dataset '%s.%s', which is not in the allowed list", 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) } } } else { - return nil, fmt.Errorf("could not analyze query in history_data to validate against allowed datasets") + return nil, util.NewAgentError("could not analyze query in history_data to validate against allowed datasets", nil) } } historyDataSource = fmt.Sprintf("(%s)", historyData) @@ -226,11 +227,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para projectID = source.BigQueryClient().Project() datasetID = parts[0] default: - return nil, fmt.Errorf("invalid table ID format for 'history_data': %q. Expected 'dataset.table' or 'project.dataset.table'", historyData) + return nil, util.NewAgentError(fmt.Sprintf("invalid table ID format for 'history_data': %q. Expected 'dataset.table' or 'project.dataset.table'", historyData), nil) } if !source.IsDatasetAllowed(projectID, datasetID) { - return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, historyData) + return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, historyData), nil) } } historyDataSource = fmt.Sprintf("TABLE `%s`", historyData) @@ -243,15 +244,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } sql := fmt.Sprintf(`SELECT * FROM AI.FORECAST( - %s, - data_col => '%s', - timestamp_col => '%s', - horizon => %d%s)`, + %s, + data_col => '%s', + timestamp_col => '%s', + horizon => %d%s)`, historyDataSource, dataCol, timestampCol, horizon, idColsArg) session, err := source.BigQuerySession()(ctx) if err != nil { - return nil, fmt.Errorf("failed to get BigQuery session: %w", err) + return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err) } var connProps []*bigqueryapi.ConnectionProperty if session != nil { @@ -264,11 +265,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para // Log the query executed for debugging. logger, err := util.LoggerFromContext(ctx) if err != nil { - return nil, fmt.Errorf("error getting logger: %s", err) + return nil, util.NewClientServerError("error getting logger", http.StatusInternalServerError, err) } logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql)) - return source.RunSQL(ctx, bqClient, sql, "SELECT", nil, connProps) + resp, err := 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) { diff --git a/internal/tools/bigquery/bigquerysearchcatalog/bigquerysearchcatalog.go b/internal/tools/bigquery/bigquerysearchcatalog/bigquerysearchcatalog.go index 323dbbebb1..2752108fb2 100644 --- a/internal/tools/bigquery/bigquerysearchcatalog/bigquerysearchcatalog.go +++ b/internal/tools/bigquery/bigquerysearchcatalog/bigquerysearchcatalog.go @@ -17,6 +17,7 @@ package bigquerysearchcatalog import ( "context" "fmt" + "net/http" "strings" dataplexapi "cloud.google.com/go/dataplex/apiv1" @@ -26,6 +27,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/iterator" ) @@ -186,28 +188,31 @@ func ExtractType(resourceString string) string { return typeMap[resourceString[lastIndex+1:]] } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() pageSize := int32(paramsMap["pageSize"].(int)) prompt, _ := paramsMap["prompt"].(string) + projectIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["projectIds"].([]any), "string") if err != nil { - return nil, fmt.Errorf("can't convert projectIds to array of strings: %s", err) + return nil, util.NewAgentError(fmt.Sprintf("can't convert projectIds to array of strings: %s", err), err) } projectIds := projectIdSlice.([]string) + datasetIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["datasetIds"].([]any), "string") if err != nil { - return nil, fmt.Errorf("can't convert datasetIds to array of strings: %s", err) + return nil, util.NewAgentError(fmt.Sprintf("can't convert datasetIds to array of strings: %s", err), err) } datasetIds := datasetIdSlice.([]string) + typesSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["types"].([]any), "string") if err != nil { - return nil, fmt.Errorf("can't convert types to array of strings: %s", err) + return nil, util.NewAgentError(fmt.Sprintf("can't convert types to array of strings: %s", err), err) } types := typesSlice.([]string) @@ -223,17 +228,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if source.UseClientAuthorization() { tokenStr, err := accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } catalogClient, err = dataplexClientCreator(tokenStr) if err != nil { - return nil, fmt.Errorf("error creating client from OAuth access token: %w", err) + return nil, util.NewClientServerError("error creating client from OAuth access token", http.StatusInternalServerError, err) } } it := catalogClient.SearchEntries(ctx, req) if it == nil { - return nil, fmt.Errorf("failed to create search entries iterator for project %q", source.BigQueryProject()) + return nil, util.NewClientServerError(fmt.Sprintf("failed to create search entries iterator for project %q", source.BigQueryProject()), http.StatusInternalServerError, nil) } var results []Response @@ -243,7 +248,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para break } if err != nil { - break + return nil, util.ProecessGcpError(err) } entrySource := entry.DataplexEntry.GetEntrySource() resp := Response{ diff --git a/internal/tools/cloudgda/cloudgda.go b/internal/tools/cloudgda/cloudgda.go index a650c8e4a1..0e117822a6 100644 --- a/internal/tools/cloudgda/cloudgda.go +++ b/internal/tools/cloudgda/cloudgda.go @@ -18,11 +18,13 @@ import ( "context" "encoding/json" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -119,17 +121,16 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -// Invoke executes the tool logic -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() query, ok := paramsMap["query"].(string) if !ok { - return nil, fmt.Errorf("query parameter not found or not a string") + return nil, util.NewAgentError("query parameter not found or not a string", nil) } // Parse the access token if provided @@ -138,7 +139,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var err error tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } @@ -154,9 +155,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para bodyBytes, err := json.Marshal(payload) if err != nil { - return nil, fmt.Errorf("failed to marshal request payload: %w", err) + return nil, util.NewClientServerError("failed to marshal request payload", http.StatusInternalServerError, 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcarefhirfetchpage/cloudhealthcarefhirfetchpage.go b/internal/tools/cloudhealthcare/cloudhealthcarefhirfetchpage/cloudhealthcarefhirfetchpage.go index 104bf53a73..a33779b68c 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcarefhirfetchpage/cloudhealthcarefhirfetchpage.go +++ b/internal/tools/cloudhealthcare/cloudhealthcarefhirfetchpage/cloudhealthcarefhirfetchpage.go @@ -17,11 +17,13 @@ package fhirfetchpage import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -93,24 +95,31 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } url, ok := params.AsMap()[pageURLKey].(string) if !ok { - return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", pageURLKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", pageURLKey), nil) } + var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcarefhirpatienteverything/cloudhealthcarefhirpatienteverything.go b/internal/tools/cloudhealthcare/cloudhealthcarefhirpatienteverything/cloudhealthcarefhirpatienteverything.go index 40c479cbfd..64892b9a08 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcarefhirpatienteverything/cloudhealthcarefhirpatienteverything.go +++ b/internal/tools/cloudhealthcare/cloudhealthcarefhirpatienteverything/cloudhealthcarefhirpatienteverything.go @@ -17,6 +17,7 @@ package fhirpatienteverything import ( "context" "fmt" + "net/http" "strings" "github.com/goccy/go-yaml" @@ -24,6 +25,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/googleapi" ) @@ -116,26 +118,27 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) if err != nil { - return nil, err + // ValidateAndFetchStoreID usually returns input validation errors + return nil, util.NewAgentError("failed to validate store ID", err) } patientID, ok := params.AsMap()[patientIDKey].(string) if !ok { - return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", patientIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", patientIDKey), nil) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } @@ -143,11 +146,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if val, ok := params.AsMap()[typeFilterKey]; ok { types, ok := val.([]any) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string array", typeFilterKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string array", typeFilterKey), nil) } typeFilterSlice, err := parameters.ConvertAnySliceToTyped(types, "string") if err != nil { - return nil, fmt.Errorf("can't convert '%s' to array of strings: %s", typeFilterKey, err) + return nil, util.NewAgentError(fmt.Sprintf("can't convert '%s' to array of strings: %s", typeFilterKey, err), err) } if len(typeFilterSlice.([]string)) != 0 { opts = append(opts, googleapi.QueryParameter("_type", strings.Join(typeFilterSlice.([]string), ","))) @@ -156,13 +159,18 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if since, ok := params.AsMap()[sinceFilterKey]; ok { sinceStr, ok := since.(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", sinceFilterKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", sinceFilterKey), nil) } if 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcarefhirpatientsearch/cloudhealthcarefhirpatientsearch.go b/internal/tools/cloudhealthcare/cloudhealthcarefhirpatientsearch/cloudhealthcarefhirpatientsearch.go index 08283c8b88..622399bccf 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcarefhirpatientsearch/cloudhealthcarefhirpatientsearch.go +++ b/internal/tools/cloudhealthcare/cloudhealthcarefhirpatientsearch/cloudhealthcarefhirpatientsearch.go @@ -17,6 +17,7 @@ package fhirpatientsearch import ( "context" "fmt" + "net/http" "strings" "github.com/goccy/go-yaml" @@ -24,6 +25,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/googleapi" ) @@ -150,22 +152,22 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } @@ -179,14 +181,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var ok bool summary, ok = v.(bool) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a boolean", summaryKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a boolean", summaryKey), nil) } continue } val, ok := v.(string) if !ok { - return nil, fmt.Errorf("invalid parameter '%s'; expected a string", k) + return nil, util.NewAgentError(fmt.Sprintf("invalid parameter '%s'; expected a string", k), nil) } if val == "" { continue @@ -205,7 +207,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } parts := strings.Split(val, "/") if len(parts) != 2 { - return nil, fmt.Errorf("invalid '%s' format; expected YYYY-MM-DD/YYYY-MM-DD", k) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' format; expected YYYY-MM-DD/YYYY-MM-DD", k), nil) } var values []string if parts[0] != "" { @@ -229,13 +231,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para case familyNameKey: opts = append(opts, googleapi.QueryParameter("family", val)) default: - return nil, fmt.Errorf("unexpected parameter key %q", k) + return nil, util.NewAgentError(fmt.Sprintf("unexpected parameter key %q", k), nil) } } if summary { opts = append(opts, googleapi.QueryParameter("_summary", "text")) } - return source.FHIRPatientSearch(storeID, tokenStr, opts) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaregetdataset/cloudhealthcaregetdataset.go b/internal/tools/cloudhealthcare/cloudhealthcaregetdataset/cloudhealthcaregetdataset.go index 23b34a489c..02399fe98a 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaregetdataset/cloudhealthcaregetdataset.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaregetdataset/cloudhealthcaregetdataset.go @@ -17,11 +17,13 @@ package gethealthcaredataset import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -90,19 +92,23 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.GetDataset(tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstore/cloudhealthcaregetdicomstore.go b/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstore/cloudhealthcaregetdicomstore.go index f3015ea801..6c7a8ae885 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstore/cloudhealthcaregetdicomstore.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstore/cloudhealthcaregetdicomstore.go @@ -17,12 +17,14 @@ package getdicomstore import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -107,23 +109,27 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.GetDICOMStore(storeID, tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstoremetrics/cloudhealthcaregetdicomstoremetrics.go b/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstoremetrics/cloudhealthcaregetdicomstoremetrics.go index 1a3c23b7be..467145bbd8 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstoremetrics/cloudhealthcaregetdicomstoremetrics.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaregetdicomstoremetrics/cloudhealthcaregetdicomstoremetrics.go @@ -17,12 +17,14 @@ package getdicomstoremetrics import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -107,23 +109,27 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.GetDICOMStoreMetrics(storeID, tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaregetfhirresource/cloudhealthcaregetfhirresource.go b/internal/tools/cloudhealthcare/cloudhealthcaregetfhirresource/cloudhealthcaregetfhirresource.go index 2d1d316489..cd0cbd1adc 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaregetfhirresource/cloudhealthcaregetfhirresource.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaregetfhirresource/cloudhealthcaregetfhirresource.go @@ -17,12 +17,14 @@ package getfhirresource import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -112,32 +114,36 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } resType, ok := params.AsMap()[typeKey].(string) if !ok { - return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", typeKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", typeKey), nil) } resID, ok := params.AsMap()[idKey].(string) if !ok { - return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", idKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", idKey), nil) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.GetFHIRResource(storeID, resType, resID, tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstore/cloudhealthcaregetfhirstore.go b/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstore/cloudhealthcaregetfhirstore.go index 633df3b9dc..38cf0b8487 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstore/cloudhealthcaregetfhirstore.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstore/cloudhealthcaregetfhirstore.go @@ -17,12 +17,14 @@ package getfhirstore import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -107,23 +109,27 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.GetFHIRStore(storeID, tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstoremetrics/cloudhealthcaregetfhirstoremetrics.go b/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstoremetrics/cloudhealthcaregetfhirstoremetrics.go index 39088122ba..d7baef08f7 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstoremetrics/cloudhealthcaregetfhirstoremetrics.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaregetfhirstoremetrics/cloudhealthcaregetfhirstoremetrics.go @@ -17,12 +17,14 @@ package getfhirstoremetrics import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -107,23 +109,27 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.GetFHIRStoreMetrics(storeID, tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcarelistdicomstores/cloudhealthcarelistdicomstores.go b/internal/tools/cloudhealthcare/cloudhealthcarelistdicomstores/cloudhealthcarelistdicomstores.go index 612a455b39..d13cb04f89 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcarelistdicomstores/cloudhealthcarelistdicomstores.go +++ b/internal/tools/cloudhealthcare/cloudhealthcarelistdicomstores/cloudhealthcarelistdicomstores.go @@ -17,11 +17,13 @@ package listdicomstores import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -90,19 +92,23 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.ListDICOMStores(tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcarelistfhirstores/cloudhealthcarelistfhirstores.go b/internal/tools/cloudhealthcare/cloudhealthcarelistfhirstores/cloudhealthcarelistfhirstores.go index bb1e182416..53581d65b4 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcarelistfhirstores/cloudhealthcarelistfhirstores.go +++ b/internal/tools/cloudhealthcare/cloudhealthcarelistfhirstores/cloudhealthcarelistfhirstores.go @@ -17,11 +17,13 @@ package listfhirstores import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/healthcare/v1" ) @@ -90,19 +92,23 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } - return source.ListFHIRStores(tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcareretrieverendereddicominstance/cloudhealthcareretrieverendereddicominstance.go b/internal/tools/cloudhealthcare/cloudhealthcareretrieverendereddicominstance/cloudhealthcareretrieverendereddicominstance.go index c3379142ce..f6708abe38 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcareretrieverendereddicominstance/cloudhealthcareretrieverendereddicominstance.go +++ b/internal/tools/cloudhealthcare/cloudhealthcareretrieverendereddicominstance/cloudhealthcareretrieverendereddicominstance.go @@ -17,12 +17,14 @@ package retrieverendereddicominstance import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -117,40 +119,44 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } study, ok := params.AsMap()[studyInstanceUIDKey].(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil) } series, ok := params.AsMap()[seriesInstanceUIDKey].(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey), nil) } sop, ok := params.AsMap()[sopInstanceUIDKey].(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", sopInstanceUIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", sopInstanceUIDKey), nil) } frame, ok := params.AsMap()[frameNumberKey].(int) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected an integer", frameNumberKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected an integer", frameNumberKey), nil) } - return source.RetrieveRenderedDICOMInstance(storeID, study, series, sop, frame, tokenStr) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaresearchdicominstances/cloudhealthcaresearchdicominstances.go b/internal/tools/cloudhealthcare/cloudhealthcaresearchdicominstances/cloudhealthcaresearchdicominstances.go index 1de1f0b12f..2f17bfdc44 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaresearchdicominstances/cloudhealthcaresearchdicominstances.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaresearchdicominstances/cloudhealthcaresearchdicominstances.go @@ -17,6 +17,7 @@ package searchdicominstances import ( "context" "fmt" + "net/http" "strings" "github.com/goccy/go-yaml" @@ -24,6 +25,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/googleapi" ) @@ -131,33 +133,33 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } opts, err := common.ParseDICOMSearchParameters(params, []string{sopInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey}) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to parse DICOM search parameters", err) } paramsMap := params.AsMap() dicomWebPath := "instances" if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok { id, ok := studyInstanceUID.(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil) } if id != "" { dicomWebPath = fmt.Sprintf("studies/%s/instances", id) @@ -166,7 +168,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if seriesInstanceUID, ok := paramsMap[seriesInstanceUIDKey]; ok { id, ok := seriesInstanceUID.(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey), nil) } if id != "" { if dicomWebPath != "instances" { @@ -176,7 +178,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } } } - return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomseries/cloudhealthcaresearchdicomseries.go b/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomseries/cloudhealthcaresearchdicomseries.go index dac124e1ee..6ca6133b6b 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomseries/cloudhealthcaresearchdicomseries.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomseries/cloudhealthcaresearchdicomseries.go @@ -17,12 +17,14 @@ package searchdicomseries import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/googleapi" ) @@ -128,40 +130,44 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } opts, err := common.ParseDICOMSearchParameters(params, []string{seriesInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey}) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to parse DICOM search parameters", err) } paramsMap := params.AsMap() dicomWebPath := "series" if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok { id, ok := studyInstanceUID.(string) if !ok { - return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey) + return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil) } if id != "" { dicomWebPath = fmt.Sprintf("studies/%s/series", id) } } - return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts) + resp, err := 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) { diff --git a/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomstudies/cloudhealthcaresearchdicomstudies.go b/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomstudies/cloudhealthcaresearchdicomstudies.go index 7d51b22d83..0144867d54 100644 --- a/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomstudies/cloudhealthcaresearchdicomstudies.go +++ b/internal/tools/cloudhealthcare/cloudhealthcaresearchdicomstudies/cloudhealthcaresearchdicomstudies.go @@ -17,12 +17,14 @@ package searchdicomstudies import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" "github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/googleapi" ) @@ -124,28 +126,32 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores()) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to validate store ID", err) } var tokenStr string if source.UseClientAuthorization() { tokenStr, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("error parsing access token: %w", err) + return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err) } } opts, err := common.ParseDICOMSearchParameters(params, []string{studyInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey}) if err != nil { - return nil, err + return nil, util.NewAgentError("failed to parse DICOM search parameters", err) } dicomWebPath := "studies" - return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts) + resp, err := 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) { diff --git a/internal/tools/cloudloggingadmin/cloudloggingadminlistlognames/cloudloggingadminlistlognames.go b/internal/tools/cloudloggingadmin/cloudloggingadminlistlognames/cloudloggingadminlistlognames.go index 063fbba334..b82cf32cd9 100644 --- a/internal/tools/cloudloggingadmin/cloudloggingadminlistlognames/cloudloggingadminlistlognames.go +++ b/internal/tools/cloudloggingadmin/cloudloggingadminlistlognames/cloudloggingadminlistlognames.go @@ -16,11 +16,13 @@ package cloudloggingadminlistlognames import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -89,10 +91,10 @@ type Tool struct { Parameters parameters.Parameters `yaml:"parameters"` } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } limit := defaultLimit @@ -100,18 +102,22 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if val, ok := paramsMap["limit"].(int); ok && val > 0 { limit = val } else if ok && val < 0 { - return nil, fmt.Errorf("limit must be greater than or equal to 1") + return nil, util.NewAgentError("limit must be greater than or equal to 1", nil) } tokenString := "" if source.UseClientAuthorization() { tokenString, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("failed to parse access token: %w", err) + return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err) } } - return source.ListLogNames(ctx, limit, tokenString) + resp, err := 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) { diff --git a/internal/tools/cloudloggingadmin/cloudloggingadminlistresourcetypes/cloudloggingadminlistresourcetypes.go b/internal/tools/cloudloggingadmin/cloudloggingadminlistresourcetypes/cloudloggingadminlistresourcetypes.go index 1326bf037c..016658e6e6 100644 --- a/internal/tools/cloudloggingadmin/cloudloggingadminlistresourcetypes/cloudloggingadminlistresourcetypes.go +++ b/internal/tools/cloudloggingadmin/cloudloggingadminlistresourcetypes/cloudloggingadminlistresourcetypes.go @@ -16,11 +16,13 @@ package cloudloggingadminlistresourcetypes import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -84,21 +86,25 @@ type Tool struct { mcpManifest tools.McpManifest } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } tokenString := "" if source.UseClientAuthorization() { tokenString, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("failed to parse access token: %w", err) + return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err) } } - return source.ListResourceTypes(ctx, tokenString) + resp, err := 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) { diff --git a/internal/tools/cloudloggingadmin/cloudloggingadminquerylogs/cloudloggingadminquerylogs.go b/internal/tools/cloudloggingadmin/cloudloggingadminquerylogs/cloudloggingadminquerylogs.go index ab62ef3510..051aa418b6 100644 --- a/internal/tools/cloudloggingadmin/cloudloggingadminquerylogs/cloudloggingadminquerylogs.go +++ b/internal/tools/cloudloggingadmin/cloudloggingadminquerylogs/cloudloggingadminquerylogs.go @@ -16,6 +16,7 @@ package cloudloggingadminquerylogs import ( "context" "fmt" + "net/http" "time" "github.com/goccy/go-yaml" @@ -23,6 +24,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/sources" cla "github.com/googleapis/genai-toolbox/internal/sources/cloudloggingadmin" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -104,10 +106,10 @@ type Tool struct { mcpManifest tools.McpManifest } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } // Parse parameters @@ -119,7 +121,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if val, ok := paramsMap["limit"].(int); ok && val > 0 { limit = val } else if ok && val < 0 { - return nil, fmt.Errorf("limit must be greater than or equal to 1") + return nil, util.NewAgentError("limit must be greater than or equal to 1", nil) } // Check for verbosity of output @@ -129,7 +131,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var filter string if f, ok := paramsMap["filter"].(string); ok { if len(f) == 0 { - return nil, fmt.Errorf("filter cannot be empty if provided") + return nil, util.NewAgentError("filter cannot be empty if provided", nil) } filter = f } @@ -138,7 +140,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var startTime string if val, ok := paramsMap["startTime"].(string); ok && val != "" { if _, err := time.Parse(time.RFC3339, val); err != nil { - return nil, fmt.Errorf("startTime must be in RFC3339 format (e.g., 2025-12-09T00:00:00Z): %w", err) + return nil, util.NewAgentError(fmt.Sprintf("startTime must be in RFC3339 format (e.g., 2025-12-09T00:00:00Z): %v", err), err) } startTime = val } else { @@ -149,7 +151,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para var endTime string if val, ok := paramsMap["endTime"].(string); ok && val != "" { if _, err := time.Parse(time.RFC3339, val); err != nil { - return nil, fmt.Errorf("endTime must be in RFC3339 format (e.g., 2025-12-09T23:59:59Z): %w", err) + return nil, util.NewAgentError(fmt.Sprintf("endTime must be in RFC3339 format (e.g., 2025-12-09T23:59:59Z): %v", err), err) } endTime = val } @@ -158,7 +160,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para if source.UseClientAuthorization() { tokenString, err = accessToken.ParseBearerToken() if err != nil { - return nil, fmt.Errorf("failed to parse access token: %w", err) + return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err) } } @@ -171,7 +173,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para Limit: limit, } - return source.QueryLogs(ctx, queryParams, tokenString) + resp, err := 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) { diff --git a/internal/tools/cloudmonitoring/cloudmonitoring.go b/internal/tools/cloudmonitoring/cloudmonitoring.go index 3d28b61f68..34203798df 100644 --- a/internal/tools/cloudmonitoring/cloudmonitoring.go +++ b/internal/tools/cloudmonitoring/cloudmonitoring.go @@ -23,6 +23,7 @@ import ( "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -93,22 +94,26 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() projectID, ok := paramsMap["projectId"].(string) if !ok { - return nil, fmt.Errorf("projectId parameter not found or not a string") + return nil, util.NewAgentError("projectId parameter not found or not a string", nil) } query, ok := paramsMap["query"].(string) if !ok { - return nil, fmt.Errorf("query parameter not found or not a string") + return nil, util.NewAgentError("query parameter not found or not a string", nil) } - return source.RunQuery(projectID, query) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqlcloneinstance/cloudsqlcloneinstance.go b/internal/tools/cloudsql/cloudsqlcloneinstance/cloudsqlcloneinstance.go index 03e5a75390..4e9817281d 100644 --- a/internal/tools/cloudsql/cloudsqlcloneinstance/cloudsqlcloneinstance.go +++ b/internal/tools/cloudsql/cloudsqlcloneinstance/cloudsqlcloneinstance.go @@ -17,11 +17,13 @@ package cloudsqlcloneinstance import ( "context" "fmt" + "net/http" yaml "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" sqladmin "google.golang.org/api/sqladmin/v1" ) @@ -124,31 +126,35 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke executes the tool's logic. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() project, ok := paramsMap["project"].(string) if !ok { - return nil, fmt.Errorf("error casting 'project' parameter: %v", paramsMap["project"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %v", paramsMap["project"]), nil) } sourceInstanceName, ok := paramsMap["sourceInstanceName"].(string) if !ok { - return nil, fmt.Errorf("error casting 'sourceInstanceName' parameter: %v", paramsMap["sourceInstanceName"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'sourceInstanceName' parameter: %v", paramsMap["sourceInstanceName"]), nil) } destinationInstanceName, ok := paramsMap["destinationInstanceName"].(string) if !ok { - return nil, fmt.Errorf("error casting 'destinationInstanceName' parameter: %v", paramsMap["destinationInstanceName"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'destinationInstanceName' parameter: %v", paramsMap["destinationInstanceName"]), nil) } pointInTime, _ := paramsMap["pointInTime"].(string) preferredZone, _ := paramsMap["preferredZone"].(string) preferredSecondaryZone, _ := paramsMap["preferredSecondaryZone"].(string) - return source.CloneInstance(ctx, project, sourceInstanceName, destinationInstanceName, pointInTime, preferredZone, preferredSecondaryZone, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqlcreatebackup/cloudsqlcreatebackup.go b/internal/tools/cloudsql/cloudsqlcreatebackup/cloudsqlcreatebackup.go index e5b5b6c3b9..fbb70c1115 100644 --- a/internal/tools/cloudsql/cloudsqlcreatebackup/cloudsqlcreatebackup.go +++ b/internal/tools/cloudsql/cloudsqlcreatebackup/cloudsqlcreatebackup.go @@ -17,11 +17,13 @@ package cloudsqlcreatebackup import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/sqladmin/v1" ) @@ -120,26 +122,30 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() project, ok := paramsMap["project"].(string) if !ok { - return nil, fmt.Errorf("error casting 'project' parameter: %v", paramsMap["project"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %v", paramsMap["project"]), nil) } instance, ok := paramsMap["instance"].(string) if !ok { - return nil, fmt.Errorf("error casting 'instance' parameter: %v", paramsMap["instance"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'instance' parameter: %v", paramsMap["instance"]), nil) } location, _ := paramsMap["location"].(string) description, _ := paramsMap["backup_description"].(string) - return source.InsertBackupRun(ctx, project, instance, location, description, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqlcreatedatabase/cloudsqlcreatedatabase.go b/internal/tools/cloudsql/cloudsqlcreatedatabase/cloudsqlcreatedatabase.go index 3b1573c70c..beeda446d8 100644 --- a/internal/tools/cloudsql/cloudsqlcreatedatabase/cloudsqlcreatedatabase.go +++ b/internal/tools/cloudsql/cloudsqlcreatedatabase/cloudsqlcreatedatabase.go @@ -17,11 +17,13 @@ package cloudsqlcreatedatabase import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -117,27 +119,31 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke executes the tool's logic. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() project, ok := paramsMap["project"].(string) if !ok { - return nil, fmt.Errorf("missing 'project' parameter") + return nil, util.NewAgentError("missing 'project' parameter", nil) } instance, ok := paramsMap["instance"].(string) if !ok { - return nil, fmt.Errorf("missing 'instance' parameter") + return nil, util.NewAgentError("missing 'instance' parameter", nil) } name, ok := paramsMap["name"].(string) if !ok { - return nil, fmt.Errorf("missing 'name' parameter") + return nil, util.NewAgentError("missing 'name' parameter", nil) } - return source.CreateDatabase(ctx, name, project, instance, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqlgetinstances/cloudsqlgetinstances.go b/internal/tools/cloudsql/cloudsqlgetinstances/cloudsqlgetinstances.go index d65aa749be..cadcf12d38 100644 --- a/internal/tools/cloudsql/cloudsqlgetinstances/cloudsqlgetinstances.go +++ b/internal/tools/cloudsql/cloudsqlgetinstances/cloudsqlgetinstances.go @@ -17,11 +17,13 @@ package cloudsqlgetinstances import ( "context" "fmt" + "net/http" yaml "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -117,23 +119,27 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke executes the tool's logic. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() projectId, ok := paramsMap["projectId"].(string) if !ok { - return nil, fmt.Errorf("missing 'projectId' parameter") + return nil, util.NewAgentError("missing 'projectId' parameter", nil) } instanceId, ok := paramsMap["instanceId"].(string) if !ok { - return nil, fmt.Errorf("missing 'instanceId' parameter") + return nil, util.NewAgentError("missing 'instanceId' parameter", nil) } - return source.GetInstance(ctx, projectId, instanceId, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqllistdatabases/cloudsqllistdatabases.go b/internal/tools/cloudsql/cloudsqllistdatabases/cloudsqllistdatabases.go index f185862622..da74402c0f 100644 --- a/internal/tools/cloudsql/cloudsqllistdatabases/cloudsqllistdatabases.go +++ b/internal/tools/cloudsql/cloudsqllistdatabases/cloudsqllistdatabases.go @@ -17,11 +17,13 @@ package cloudsqllistdatabases import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -116,23 +118,27 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke executes the tool's logic. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() project, ok := paramsMap["project"].(string) if !ok { - return nil, fmt.Errorf("missing 'project' parameter") + return nil, util.NewAgentError("missing 'project' parameter", nil) } instance, ok := paramsMap["instance"].(string) if !ok { - return nil, fmt.Errorf("missing 'instance' parameter") + return nil, util.NewAgentError("missing 'instance' parameter", nil) } - return source.ListDatabase(ctx, project, instance, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqllistinstances/cloudsqllistinstances.go b/internal/tools/cloudsql/cloudsqllistinstances/cloudsqllistinstances.go index 8a032b73e9..e6d82a25c8 100644 --- a/internal/tools/cloudsql/cloudsqllistinstances/cloudsqllistinstances.go +++ b/internal/tools/cloudsql/cloudsqllistinstances/cloudsqllistinstances.go @@ -17,11 +17,13 @@ package cloudsqllistinstances import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" ) @@ -115,19 +117,23 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke executes the tool's logic. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() project, ok := paramsMap["project"].(string) if !ok { - return nil, fmt.Errorf("missing 'project' parameter") + return nil, util.NewAgentError("missing 'project' parameter", nil) } - return source.ListInstance(ctx, project, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqlrestorebackup/cloudsqlrestorebackup.go b/internal/tools/cloudsql/cloudsqlrestorebackup/cloudsqlrestorebackup.go index 84ae63b3f9..50df9a735a 100644 --- a/internal/tools/cloudsql/cloudsqlrestorebackup/cloudsqlrestorebackup.go +++ b/internal/tools/cloudsql/cloudsqlrestorebackup/cloudsqlrestorebackup.go @@ -17,11 +17,13 @@ package cloudsqlrestorebackup import ( "context" "fmt" + "net/http" "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/sqladmin/v1" ) @@ -120,29 +122,33 @@ func (t Tool) ToConfig() tools.ToolConfig { return t.Config } -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() targetProject, ok := paramsMap["target_project"].(string) if !ok { - return nil, fmt.Errorf("error casting 'target_project' parameter: %v", paramsMap["target_project"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'target_project' parameter: %v", paramsMap["target_project"]), nil) } targetInstance, ok := paramsMap["target_instance"].(string) if !ok { - return nil, fmt.Errorf("error casting 'target_instance' parameter: %v", paramsMap["target_instance"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'target_instance' parameter: %v", paramsMap["target_instance"]), nil) } backupID, ok := paramsMap["backup_id"].(string) if !ok { - return nil, fmt.Errorf("error casting 'backup_id' parameter: %v", paramsMap["backup_id"]) + return nil, util.NewAgentError(fmt.Sprintf("error casting 'backup_id' parameter: %v", paramsMap["backup_id"]), nil) } sourceProject, _ := paramsMap["source_project"].(string) sourceInstance, _ := paramsMap["source_instance"].(string) - return source.RestoreBackup(ctx, targetProject, targetInstance, sourceProject, sourceInstance, backupID, string(accessToken)) + resp, err := 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) { diff --git a/internal/tools/cloudsql/cloudsqlwaitforoperation/cloudsqlwaitforoperation.go b/internal/tools/cloudsql/cloudsqlwaitforoperation/cloudsqlwaitforoperation.go index e6d40885bf..85588c57fa 100644 --- a/internal/tools/cloudsql/cloudsqlwaitforoperation/cloudsqlwaitforoperation.go +++ b/internal/tools/cloudsql/cloudsqlwaitforoperation/cloudsqlwaitforoperation.go @@ -17,12 +17,14 @@ package cloudsqlwaitforoperation import ( "context" "fmt" + "net/http" "time" yaml "github.com/goccy/go-yaml" "github.com/googleapis/genai-toolbox/internal/embeddingmodels" "github.com/googleapis/genai-toolbox/internal/sources" "github.com/googleapis/genai-toolbox/internal/tools" + "github.com/googleapis/genai-toolbox/internal/util" "github.com/googleapis/genai-toolbox/internal/util/parameters" "google.golang.org/api/sqladmin/v1" ) @@ -210,21 +212,21 @@ func (t Tool) ToConfig() tools.ToolConfig { } // Invoke executes the tool's logic. -func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) { +func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) { source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { - return nil, err + return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err) } paramsMap := params.AsMap() project, ok := paramsMap["project"].(string) if !ok { - return nil, fmt.Errorf("missing 'project' parameter") + return nil, util.NewAgentError("missing 'project' parameter", nil) } operationID, ok := paramsMap["operation"].(string) if !ok { - return nil, fmt.Errorf("missing 'operation' parameter") + return nil, util.NewAgentError("missing 'operation' parameter", nil) } ctx, cancel := context.WithTimeout(ctx, 30*time.Minute) @@ -232,7 +234,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para service, err := source.GetService(ctx, string(accessToken)) if err != nil { - return nil, err + return nil, util.ProecessGcpError(err) } delay := t.Delay @@ -244,13 +246,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para for retries < maxRetries { select { case <-ctx.Done(): - return nil, fmt.Errorf("timed out waiting for operation: %w", ctx.Err()) + return nil, util.NewClientServerError("timed out waiting for operation", http.StatusRequestTimeout, ctx.Err()) default: } op, err := source.GetWaitForOperations(ctx, service, project, operationID, cloudSQLConnectionMessageTemplate, delay) if err != nil { - return nil, err + return nil, util.ProecessGcpError(err) } else if op != nil { return op, nil } @@ -262,7 +264,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para } retries++ } - return nil, fmt.Errorf("exceeded max retries waiting for operation") + return nil, util.NewClientServerError("exceeded max retries waiting for operation", http.StatusGatewayTimeout, fmt.Errorf("exceeded max retries")) } func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {