mirror of
https://github.com/googleapis/genai-toolbox.git
synced 2026-02-03 11:45:10 -05:00
Compare commits
1 Commits
refactor-t
...
skillgen
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e388a80b40 |
@@ -35,6 +35,7 @@ import (
|
|||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/auth"
|
"github.com/googleapis/genai-toolbox/internal/auth"
|
||||||
"github.com/googleapis/genai-toolbox/internal/cli/invoke"
|
"github.com/googleapis/genai-toolbox/internal/cli/invoke"
|
||||||
|
"github.com/googleapis/genai-toolbox/internal/cli/skills"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/log"
|
"github.com/googleapis/genai-toolbox/internal/log"
|
||||||
"github.com/googleapis/genai-toolbox/internal/prebuiltconfigs"
|
"github.com/googleapis/genai-toolbox/internal/prebuiltconfigs"
|
||||||
@@ -401,6 +402,8 @@ func NewCommand(opts ...Option) *Command {
|
|||||||
|
|
||||||
// Register subcommands for tool invocation
|
// Register subcommands for tool invocation
|
||||||
baseCmd.AddCommand(invoke.NewCommand(cmd))
|
baseCmd.AddCommand(invoke.NewCommand(cmd))
|
||||||
|
// Register subcommands for skill generation
|
||||||
|
baseCmd.AddCommand(skills.NewCommand(cmd))
|
||||||
|
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|||||||
179
cmd/skill_generate_test.go
Normal file
179
cmd/skill_generate_test.go
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
// Copyright 2026 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGenerateSkill(t *testing.T) {
|
||||||
|
// Create a temporary directory for tests
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputDir := filepath.Join(tmpDir, "skills")
|
||||||
|
|
||||||
|
// Create a tools.yaml file with a sqlite tool
|
||||||
|
toolsFileContent := `
|
||||||
|
sources:
|
||||||
|
my-sqlite:
|
||||||
|
kind: sqlite
|
||||||
|
database: test.db
|
||||||
|
tools:
|
||||||
|
hello-sqlite:
|
||||||
|
kind: sqlite-sql
|
||||||
|
source: my-sqlite
|
||||||
|
description: "hello tool"
|
||||||
|
statement: "SELECT 'hello' as greeting"
|
||||||
|
`
|
||||||
|
|
||||||
|
toolsFilePath := filepath.Join(tmpDir, "tools.yaml")
|
||||||
|
if err := os.WriteFile(toolsFilePath, []byte(toolsFileContent), 0644); err != nil {
|
||||||
|
t.Fatalf("failed to write tools file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"skills-generate",
|
||||||
|
"--tools-file", toolsFilePath,
|
||||||
|
"--output-dir", outputDir,
|
||||||
|
"--name", "hello-sqlite",
|
||||||
|
"--description", "hello tool",
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
_, got, err := invokeCommandWithContext(ctx, args)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("command failed: %v\nOutput: %s", err, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify generated directory structure
|
||||||
|
skillPath := filepath.Join(outputDir, "hello-sqlite")
|
||||||
|
if _, err := os.Stat(skillPath); os.IsNotExist(err) {
|
||||||
|
t.Fatalf("skill directory not created: %s", skillPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check SKILL.md
|
||||||
|
skillMarkdown := filepath.Join(skillPath, "SKILL.md")
|
||||||
|
content, err := os.ReadFile(skillMarkdown)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read SKILL.md: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedFrontmatter := `---
|
||||||
|
name: hello-sqlite
|
||||||
|
description: hello tool
|
||||||
|
---`
|
||||||
|
if !strings.HasPrefix(string(content), expectedFrontmatter) {
|
||||||
|
t.Errorf("SKILL.md does not have expected frontmatter format.\nExpected prefix:\n%s\nGot:\n%s", expectedFrontmatter, string(content))
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(content), "## Usage") {
|
||||||
|
t.Errorf("SKILL.md does not contain '## Usage' section")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(content), "## Scripts") {
|
||||||
|
t.Errorf("SKILL.md does not contain '## Scripts' section")
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(string(content), "### hello-sqlite") {
|
||||||
|
t.Errorf("SKILL.md does not contain '### hello-sqlite' tool header")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check script file
|
||||||
|
scriptFilename := "hello-sqlite.js"
|
||||||
|
scriptPath := filepath.Join(skillPath, "scripts", scriptFilename)
|
||||||
|
if _, err := os.Stat(scriptPath); os.IsNotExist(err) {
|
||||||
|
t.Fatalf("script file not created: %s", scriptPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptContent, err := os.ReadFile(scriptPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read script file: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(scriptContent), "hello-sqlite") {
|
||||||
|
t.Errorf("script file does not contain expected tool name")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check assets
|
||||||
|
assetPath := filepath.Join(skillPath, "assets", "hello-sqlite.yaml")
|
||||||
|
if _, err := os.Stat(assetPath); os.IsNotExist(err) {
|
||||||
|
t.Fatalf("asset file not created: %s", assetPath)
|
||||||
|
}
|
||||||
|
assetContent, err := os.ReadFile(assetPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to read asset file: %v", err)
|
||||||
|
}
|
||||||
|
if !strings.Contains(string(assetContent), "hello-sqlite") {
|
||||||
|
t.Errorf("asset file does not contain expected tool name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateSkill_NoConfig(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
outputDir := filepath.Join(tmpDir, "skills")
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"skills-generate",
|
||||||
|
"--output-dir", outputDir,
|
||||||
|
"--name", "test",
|
||||||
|
"--description", "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err := invokeCommandWithContext(context.Background(), args)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected command to fail when no configuration is provided and tools.yaml is missing")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not have created the directory if no config was processed
|
||||||
|
if _, err := os.Stat(outputDir); !os.IsNotExist(err) {
|
||||||
|
t.Errorf("output directory should not have been created")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateSkill_MissingArguments(t *testing.T) {
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
toolsFilePath := filepath.Join(tmpDir, "tools.yaml")
|
||||||
|
if err := os.WriteFile(toolsFilePath, []byte("tools: {}"), 0644); err != nil {
|
||||||
|
t.Fatalf("failed to write tools file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "missing name",
|
||||||
|
args: []string{"skills-generate", "--tools-file", toolsFilePath, "--description", "test"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "missing description",
|
||||||
|
args: []string{"skills-generate", "--tools-file", toolsFilePath, "--name", "test"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_, got, err := invokeCommandWithContext(context.Background(), tt.args)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected command to fail due to missing arguments, but it succeeded\nOutput: %s", got)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
|
|||||||
|
|
||||||
In the Antigravity MCP Store, click the "Install" button.
|
In the Antigravity MCP Store, click the "Install" button.
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt alloydb-postgres-admin```.
|
|
||||||
|
|
||||||
You'll now be able to see all enabled tools in the "Tools" tab.
|
You'll now be able to see all enabled tools in the "Tools" tab.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
|
|||||||
@@ -27,13 +27,6 @@ For AlloyDB infrastructure management, search the MCP store for the AlloyDB for
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt alloydb-postgres```.
|
|
||||||
|
|
||||||
2. Add the required inputs for your [cluster](https://docs.cloud.google.com/alloydb/docs/cluster-list) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs for your [cluster](https://docs.cloud.google.com/alloydb/docs/cluster-list) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,6 @@ An editor configured to use the BigQuery MCP server can use its AI capabilities
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt bigquery```.
|
|
||||||
|
|
||||||
2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
|
|||||||
|
|
||||||
In the Antigravity MCP Store, click the "Install" button.
|
In the Antigravity MCP Store, click the "Install" button.
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mssql-admin```.
|
|
||||||
|
|
||||||
You'll now be able to see all enabled tools in the "Tools" tab.
|
You'll now be able to see all enabled tools in the "Tools" tab.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
|
|||||||
@@ -24,13 +24,6 @@ For Cloud SQL infrastructure management, search the MCP store for the Cloud SQL
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mssql```.
|
|
||||||
|
|
||||||
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/sqlserver/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/sqlserver/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
|
|||||||
|
|
||||||
In the Antigravity MCP Store, click the "Install" button.
|
In the Antigravity MCP Store, click the "Install" button.
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mysql-admin```.
|
|
||||||
|
|
||||||
You'll now be able to see all enabled tools in the "Tools" tab.
|
You'll now be able to see all enabled tools in the "Tools" tab.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
|
|||||||
@@ -26,13 +26,6 @@ For Cloud SQL infrastructure management, search the MCP store for the Cloud SQL
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-mysql```.
|
|
||||||
|
|
||||||
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/mysql/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/mysql/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -23,14 +23,6 @@ To connect to the database to explore and query data, search the MCP store for t
|
|||||||
|
|
||||||
In the Antigravity MCP Store, click the "Install" button.
|
In the Antigravity MCP Store, click the "Install" button.
|
||||||
|
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-postgres-admin```.
|
|
||||||
|
|
||||||
You'll now be able to see all enabled tools in the "Tools" tab.
|
You'll now be able to see all enabled tools in the "Tools" tab.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
|
|||||||
@@ -26,13 +26,6 @@ For Cloud SQL infrastructure management, search the MCP store for the Cloud SQL
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt cloud-sql-postgres```.
|
|
||||||
|
|
||||||
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/postgres/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs for your [instance](https://cloud.google.com/sql/docs/postgres/instance-info) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -20,13 +20,6 @@ An editor configured to use the Dataplex MCP server can use its AI capabilities
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt dataplex```.
|
|
||||||
|
|
||||||
2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,6 @@ An editor configured to use the Looker MCP server can use its AI capabilities to
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt looker```.
|
|
||||||
|
|
||||||
2. Add the required inputs for your [instance](https://docs.cloud.google.com/looker/docs/set-up-and-administer-looker) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs for your [instance](https://docs.cloud.google.com/looker/docs/set-up-and-administer-looker) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -21,13 +21,6 @@ An editor configured to use the Cloud Spanner MCP server can use its AI capabili
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the "Install" button.
|
1. In the Antigravity MCP Store, click the "Install" button.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest --prebuilt spanner```.
|
|
||||||
|
|
||||||
2. Add the required inputs for your [instance](https://docs.cloud.google.com/spanner/docs/instances) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
2. Add the required inputs for your [instance](https://docs.cloud.google.com/spanner/docs/instances) in the configuration pop-up, then click "Save". You can update this configuration at any time in the "Configure" tab.
|
||||||
|
|
||||||
|
|||||||
@@ -12,17 +12,10 @@ The MCP Toolbox for Databases Server gives AI-powered development tools the abil
|
|||||||
## Install & Configuration
|
## Install & Configuration
|
||||||
|
|
||||||
1. In the Antigravity MCP Store, click the **Install** button. A configuration window will appear.
|
1. In the Antigravity MCP Store, click the **Install** button. A configuration window will appear.
|
||||||
> [!NOTE]
|
|
||||||
> On first use, the installation process automatically downloads and uses
|
|
||||||
> [MCP Toolbox](https://www.npmjs.com/package/@toolbox-sdk/server)
|
|
||||||
> `>=0.26.0`. To update MCP Toolbox, use:
|
|
||||||
> ```npm i -g @toolbox-sdk/server@latest```
|
|
||||||
> To always run the latest version, update the MCP server configuration to use:
|
|
||||||
> ```npx -y @toolbox-sdk/server@latest```.
|
|
||||||
|
|
||||||
3. Create your [`tools.yaml` configuration file](https://googleapis.github.io/genai-toolbox/getting-started/configure/).
|
2. Create your [`tools.yaml` configuration file](https://googleapis.github.io/genai-toolbox/getting-started/configure/).
|
||||||
|
|
||||||
4. In the configuration window, enter the full absolute path to your `tools.yaml` file and click **Save**.
|
3. In the configuration window, enter the full absolute path to your `tools.yaml` file and click **Save**.
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> If you encounter issues with Windows Defender blocking the execution, you may need to configure an allowlist. See [Configure exclusions for Microsoft Defender Antivirus](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/configure-exclusions-microsoft-defender-antivirus?view=o365-worldwide) for more details.
|
> If you encounter issues with Windows Defender blocking the execution, you may need to configure an allowlist. See [Configure exclusions for Microsoft Defender Antivirus](https://learn.microsoft.com/en-us/microsoft-365/security/defender-endpoint/configure-exclusions-microsoft-defender-antivirus?view=o365-worldwide) for more details.
|
||||||
|
|||||||
109
docs/en/how-to/generate_skill.md
Normal file
109
docs/en/how-to/generate_skill.md
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
---
|
||||||
|
title: "Generate Agent Skills"
|
||||||
|
type: docs
|
||||||
|
weight: 10
|
||||||
|
description: >
|
||||||
|
How to generate agent skills from a toolset.
|
||||||
|
---
|
||||||
|
|
||||||
|
The `skills-generate` command allows you to convert a **toolset** into an **Agent Skill**. A toolset is a collection of tools, and the generated skill will contain metadata and execution scripts for all tools within that toolset, complying with the [Agent Skill specification](https://agentskills.io/specification).
|
||||||
|
|
||||||
|
## Before you begin
|
||||||
|
|
||||||
|
1. Make sure you have the `toolbox` executable in your PATH.
|
||||||
|
2. Make sure you have [Node.js](https://nodejs.org/) installed on your system.
|
||||||
|
|
||||||
|
## Generating a Skill from a Toolset
|
||||||
|
|
||||||
|
A skill package consists of a `SKILL.md` file (with required YAML frontmatter) and a set of Node.js scripts. Each tool defined in your toolset maps to a corresponding script in the generated skill.
|
||||||
|
|
||||||
|
### Command Signature
|
||||||
|
|
||||||
|
The `skills-generate` command follows this signature:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox [--tools-file <path> | --prebuilt <name>] skills-generate \
|
||||||
|
--name <skill-name> \
|
||||||
|
--toolset <toolset-name> \
|
||||||
|
--description <description> \
|
||||||
|
--output-dir <output-directory>
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** The `<skill-name>` must follow the Agent Skill naming convention: it must contain only lowercase alphanumeric characters and hyphens, cannot start or end with a hyphen, and cannot contain consecutive hyphens (e.g., `my-skill`, `data-processing`).
|
||||||
|
|
||||||
|
### Example: Custom Tools File
|
||||||
|
|
||||||
|
1. Create a `tools.yaml` file with a toolset and some tools:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
tools:
|
||||||
|
tool_a:
|
||||||
|
description: "First tool"
|
||||||
|
run:
|
||||||
|
command: "echo 'Tool A'"
|
||||||
|
tool_b:
|
||||||
|
description: "Second tool"
|
||||||
|
run:
|
||||||
|
command: "echo 'Tool B'"
|
||||||
|
toolsets:
|
||||||
|
my_toolset:
|
||||||
|
tools:
|
||||||
|
- tool_a
|
||||||
|
- tool_b
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Generate the skill:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox --tools-file tools.yaml skills-generate \
|
||||||
|
--name "my-skill" \
|
||||||
|
--toolset "my_toolset" \
|
||||||
|
--description "A skill containing multiple tools" \
|
||||||
|
--output-dir "generated-skills"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. The generated skill directory structure:
|
||||||
|
|
||||||
|
```text
|
||||||
|
generated-skills/
|
||||||
|
└── my-skill/
|
||||||
|
├── SKILL.md
|
||||||
|
├── assets/
|
||||||
|
│ ├── tool_a.yaml
|
||||||
|
│ └── tool_b.yaml
|
||||||
|
└── scripts/
|
||||||
|
├── tool_a.js
|
||||||
|
└── tool_b.js
|
||||||
|
```
|
||||||
|
|
||||||
|
In this example, the skill contains two Node.js scripts (`tool_a.js` and `tool_b.js`), each mapping to a tool in the original toolset.
|
||||||
|
|
||||||
|
### Example: Prebuilt Configuration
|
||||||
|
|
||||||
|
You can also generate skills from prebuilt toolsets:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox --prebuilt alloydb-postgres-admin skills-generate \
|
||||||
|
--name "alloydb-postgres-admin" \
|
||||||
|
--description "skill for performing administrative operations on alloydb"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Output Directory
|
||||||
|
|
||||||
|
By default, skills are generated in the `skills` directory. You can specify a different output directory using the `--output-dir` flag.
|
||||||
|
|
||||||
|
## Shared Node.js Scripts
|
||||||
|
|
||||||
|
The `skills-generate` command generates shared Node.js scripts (`.js`) that work across different platforms (Linux, macOS, Windows). This ensures that the generated skills are portable.
|
||||||
|
|
||||||
|
## Installing the Generated Skill in Gemini CLI
|
||||||
|
|
||||||
|
Once you have generated a skill, you can install it into the Gemini CLI using the `gemini skills install` command.
|
||||||
|
|
||||||
|
### Installation Command
|
||||||
|
|
||||||
|
Provide the path to the directory containing the generated skill:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gemini skills install /path/to/generated-skills/my-skill
|
||||||
|
```
|
||||||
@@ -32,7 +32,8 @@ description: >
|
|||||||
|
|
||||||
## Sub Commands
|
## Sub Commands
|
||||||
|
|
||||||
### `invoke`
|
<details>
|
||||||
|
<summary><code>invoke</code></summary>
|
||||||
|
|
||||||
Executes a tool directly with the provided parameters. This is useful for testing tool configurations and parameters without needing a full client setup.
|
Executes a tool directly with the provided parameters. This is useful for testing tool configurations and parameters without needing a full client setup.
|
||||||
|
|
||||||
@@ -45,6 +46,30 @@ toolbox invoke <tool-name> [params]
|
|||||||
- `<tool-name>`: The name of the tool to execute (as defined in your configuration).
|
- `<tool-name>`: The name of the tool to execute (as defined in your configuration).
|
||||||
- `[params]`: (Optional) A JSON string containing the parameters for the tool.
|
- `[params]`: (Optional) A JSON string containing the parameters for the tool.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><code>skills-generate</code></summary>
|
||||||
|
|
||||||
|
Generates a skill package from a specified toolset. Each tool in the toolset will have a corresponding Node.js execution script in the generated skill.
|
||||||
|
|
||||||
|
**Syntax:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
toolbox [--tools-file <path> | --prebuilt <name>] skills-generate --name <name> --description <description> --toolset <toolset> --output-dir <output>
|
||||||
|
```
|
||||||
|
|
||||||
|
**Flags:**
|
||||||
|
|
||||||
|
- `--name`: Name of the generated skill.
|
||||||
|
- `--description`: Description of the generated skill.
|
||||||
|
- `--toolset`: (Optional) Name of the toolset to convert into a skill. If not provided, all tools will be included.
|
||||||
|
- `--output-dir`: (Optional) Directory to output generated skills (default: "skills").
|
||||||
|
|
||||||
|
For more detailed instructions, see [Generate Agent Skills](../how-to/generate_skill.md).
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Transport Configuration
|
### Transport Configuration
|
||||||
|
|||||||
@@ -414,10 +414,10 @@ See [Usage Examples](../reference/cli.md#examples).
|
|||||||
entries.
|
entries.
|
||||||
* **Dataplex Editor** (`roles/dataplex.editor`) to modify entries.
|
* **Dataplex Editor** (`roles/dataplex.editor`) to modify entries.
|
||||||
* **Tools:**
|
* **Tools:**
|
||||||
* `search_entries`: Searches for entries in Dataplex Catalog.
|
* `dataplex_search_entries`: Searches for entries in Dataplex Catalog.
|
||||||
* `lookup_entry`: Retrieves a specific entry from Dataplex
|
* `dataplex_lookup_entry`: Retrieves a specific entry from Dataplex
|
||||||
Catalog.
|
Catalog.
|
||||||
* `search_aspect_types`: Finds aspect types relevant to the
|
* `dataplex_search_aspect_types`: Finds aspect types relevant to the
|
||||||
query.
|
query.
|
||||||
|
|
||||||
## Firestore
|
## Firestore
|
||||||
|
|||||||
299
internal/cli/skills/command.go
Normal file
299
internal/cli/skills/command.go
Normal file
@@ -0,0 +1,299 @@
|
|||||||
|
// Copyright 2026 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package skills
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/googleapis/genai-toolbox/internal/log"
|
||||||
|
"github.com/googleapis/genai-toolbox/internal/server"
|
||||||
|
"github.com/googleapis/genai-toolbox/internal/server/resources"
|
||||||
|
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RootCommand defines the interface for required by skills-generate subcommand.
|
||||||
|
// This allows subcommands to access shared resources and functionality without
|
||||||
|
// direct coupling to the root command's implementation.
|
||||||
|
type RootCommand interface {
|
||||||
|
// Config returns a copy of the current server configuration.
|
||||||
|
Config() server.ServerConfig
|
||||||
|
|
||||||
|
// LoadConfig loads and merges the configuration from files, folders, and prebuilts.
|
||||||
|
LoadConfig(ctx context.Context) error
|
||||||
|
|
||||||
|
// Setup initializes the runtime environment, including logging and telemetry.
|
||||||
|
// It returns the updated context and a shutdown function to be called when finished.
|
||||||
|
Setup(ctx context.Context) (context.Context, func(context.Context) error, error)
|
||||||
|
|
||||||
|
// Logger returns the logger instance.
|
||||||
|
Logger() log.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Command is the command for generating skills.
|
||||||
|
type Command struct {
|
||||||
|
*cobra.Command
|
||||||
|
rootCmd RootCommand
|
||||||
|
name string
|
||||||
|
description string
|
||||||
|
toolset string
|
||||||
|
outputDir string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parameter represents a parameter of a tool.
|
||||||
|
type Parameter struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Default interface{} `json:"default"`
|
||||||
|
Required bool `json:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tool represents a tool.
|
||||||
|
type Tool struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Description string `json:"description"`
|
||||||
|
Parameters []Parameter `json:"parameters"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config represents the structure of the tools.yaml file.
|
||||||
|
type Config struct {
|
||||||
|
Sources map[string]interface{} `yaml:"sources,omitempty"`
|
||||||
|
Tools map[string]map[string]interface{} `yaml:"tools"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// serverConfig holds the configuration used to start the toolbox server.
|
||||||
|
type serverConfig struct {
|
||||||
|
prebuiltConfigs []string
|
||||||
|
toolsFile string
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCommand creates a new Command.
|
||||||
|
func NewCommand(rootCmd RootCommand) *cobra.Command {
|
||||||
|
cmd := &Command{
|
||||||
|
rootCmd: rootCmd,
|
||||||
|
}
|
||||||
|
cmd.Command = &cobra.Command{
|
||||||
|
Use: "skills-generate",
|
||||||
|
Short: "Generate skills from tool configurations",
|
||||||
|
RunE: func(c *cobra.Command, args []string) error {
|
||||||
|
return cmd.run(c)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd.Flags().StringVar(&cmd.name, "name", "", "Name of the generated skill.")
|
||||||
|
cmd.Flags().StringVar(&cmd.description, "description", "", "Description of the generated skill")
|
||||||
|
cmd.Flags().StringVar(&cmd.toolset, "toolset", "", "Name of the toolset (and generated skill folder). If provided, only tools in this toolset are generated.")
|
||||||
|
cmd.Flags().StringVar(&cmd.outputDir, "output-dir", "skills", "Directory to output generated skills")
|
||||||
|
|
||||||
|
cmd.MarkFlagRequired("name")
|
||||||
|
cmd.MarkFlagRequired("description")
|
||||||
|
return cmd.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) run(cmd *cobra.Command) error {
|
||||||
|
ctx, cancel := context.WithCancel(cmd.Context())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
ctx, shutdown, err := c.rootCmd.Setup(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer func() {
|
||||||
|
_ = shutdown(ctx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
logger := c.rootCmd.Logger()
|
||||||
|
|
||||||
|
toolsFile, err := cmd.Flags().GetString("tools-file")
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Errorf("error getting tools-file flag: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
prebuiltConfigs, err := cmd.Flags().GetStringSlice("prebuilt")
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Errorf("error getting prebuilt flag: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and merge tool configurations
|
||||||
|
if err := c.rootCmd.LoadConfig(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(prebuiltConfigs) == 0 && toolsFile == "" {
|
||||||
|
logger.InfoContext(ctx, "No configurations found to process. Use --tools-file or --prebuilt.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if err := os.MkdirAll(c.outputDir, 0755); err != nil {
|
||||||
|
errMsg := fmt.Errorf("error creating output directory: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.InfoContext(ctx, fmt.Sprintf("Generating skill '%s'...", c.name))
|
||||||
|
|
||||||
|
config := serverConfig{
|
||||||
|
prebuiltConfigs: prebuiltConfigs,
|
||||||
|
toolsFile: toolsFile,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize toolbox and collect tools
|
||||||
|
allTools, err := c.collectTools(ctx)
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Errorf("error collecting tools: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(allTools) == 0 {
|
||||||
|
logger.InfoContext(ctx, "No tools found to generate.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the combined skill
|
||||||
|
skillPath := filepath.Join(c.outputDir, c.name)
|
||||||
|
if err := os.MkdirAll(skillPath, 0755); err != nil {
|
||||||
|
errMsg := fmt.Errorf("error creating skill directory: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate assets directory if needed
|
||||||
|
assetsPath := filepath.Join(skillPath, "assets")
|
||||||
|
if toolsFile != "" {
|
||||||
|
if err := os.MkdirAll(assetsPath, 0755); err != nil {
|
||||||
|
errMsg := fmt.Errorf("error creating assets dir: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate scripts
|
||||||
|
scriptsPath := filepath.Join(skillPath, "scripts")
|
||||||
|
if err := os.MkdirAll(scriptsPath, 0755); err != nil {
|
||||||
|
errMsg := fmt.Errorf("error creating scripts dir: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tool := range allTools {
|
||||||
|
specificToolsFileName := ""
|
||||||
|
if toolsFile != "" {
|
||||||
|
minimizedContent, err := generateFilteredConfig(toolsFile, tool.Name)
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, fmt.Sprintf("Error generating filtered config for %s: %v", tool.Name, err))
|
||||||
|
}
|
||||||
|
|
||||||
|
if minimizedContent != nil {
|
||||||
|
specificToolsFileName = fmt.Sprintf("%s.yaml", tool.Name)
|
||||||
|
destPath := filepath.Join(assetsPath, specificToolsFileName)
|
||||||
|
if err := os.WriteFile(destPath, minimizedContent, 0644); err != nil {
|
||||||
|
logger.ErrorContext(ctx, fmt.Sprintf("Error writing filtered config for %s: %v", tool.Name, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scriptContent, err := generateScriptContent(tool.Name, config, specificToolsFileName)
|
||||||
|
if err != nil {
|
||||||
|
logger.ErrorContext(ctx, fmt.Sprintf("Error generating script content for %s: %v", tool.Name, err))
|
||||||
|
} else {
|
||||||
|
scriptFilename := filepath.Join(scriptsPath, fmt.Sprintf("%s.js", tool.Name))
|
||||||
|
if err := os.WriteFile(scriptFilename, []byte(scriptContent), 0755); err != nil {
|
||||||
|
logger.ErrorContext(ctx, fmt.Sprintf("Error writing script %s: %v", scriptFilename, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate SKILL.md
|
||||||
|
skillContent, err := generateSkillMarkdown(c.name, c.description, allTools)
|
||||||
|
if err != nil {
|
||||||
|
errMsg := fmt.Errorf("error generating SKILL.md content: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
skillMdPath := filepath.Join(skillPath, "SKILL.md")
|
||||||
|
if err := os.WriteFile(skillMdPath, []byte(skillContent), 0644); err != nil {
|
||||||
|
errMsg := fmt.Errorf("error writing SKILL.md: %w", err)
|
||||||
|
logger.ErrorContext(ctx, errMsg.Error())
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.InfoContext(ctx, fmt.Sprintf("Successfully generated skill '%s' with %d tools.", c.name, len(allTools)))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Command) collectTools(ctx context.Context) (map[string]Tool, error) {
|
||||||
|
// Initialize Resources
|
||||||
|
sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, toolsetsMap, promptsMap, promptsetsMap, err := server.InitializeConfigs(ctx, c.rootCmd.Config())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to initialize resources: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
resourceMgr := resources.NewResourceManager(sourcesMap, authServicesMap, embeddingModelsMap, toolsMap, toolsetsMap, promptsMap, promptsetsMap)
|
||||||
|
|
||||||
|
result := make(map[string]Tool)
|
||||||
|
|
||||||
|
var toolsToProcess []string
|
||||||
|
|
||||||
|
if c.toolset != "" {
|
||||||
|
ts, ok := resourceMgr.GetToolset(c.toolset)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("toolset %q not found", c.toolset)
|
||||||
|
}
|
||||||
|
toolsToProcess = ts.ToolNames
|
||||||
|
} else {
|
||||||
|
// All tools
|
||||||
|
for name := range toolsMap {
|
||||||
|
toolsToProcess = append(toolsToProcess, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, toolName := range toolsToProcess {
|
||||||
|
t, ok := resourceMgr.GetTool(toolName)
|
||||||
|
if !ok {
|
||||||
|
// Should happen only if toolset refers to non-existent tool, but good to check
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
params := []Parameter{}
|
||||||
|
for _, p := range t.GetParameters() {
|
||||||
|
manifest := p.Manifest()
|
||||||
|
params = append(params, Parameter{
|
||||||
|
Name: p.GetName(),
|
||||||
|
Description: manifest.Description, // Use description from manifest
|
||||||
|
Type: p.GetType(),
|
||||||
|
Default: p.GetDefault(),
|
||||||
|
Required: p.GetRequired(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest := t.Manifest()
|
||||||
|
result[toolName] = Tool{
|
||||||
|
Name: toolName,
|
||||||
|
Description: manifest.Description,
|
||||||
|
Parameters: params,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
253
internal/cli/skills/generator.go
Normal file
253
internal/cli/skills/generator.go
Normal file
@@ -0,0 +1,253 @@
|
|||||||
|
// Copyright 2026 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package skills
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
)
|
||||||
|
|
||||||
|
const skillTemplate = `---
|
||||||
|
name: {{.SkillName}}
|
||||||
|
description: {{.SkillDescription}}
|
||||||
|
---
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
All scripts can be executed using Node.js. Replace ` + "`" + `<param_name>` + "`" + ` and ` + "`" + `<param_value>` + "`" + ` with actual values.
|
||||||
|
|
||||||
|
**Bash:**
|
||||||
|
` + "`" + `node scripts/<script_name>.js '{"<param_name>": "<param_value>"}'` + "`" + `
|
||||||
|
|
||||||
|
**PowerShell:**
|
||||||
|
` + "`" + `node scripts/<script_name>.js '{\"<param_name>\": \"<param_value>\"}'` + "`" + `
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
{{range .Tools}}
|
||||||
|
### {{.Name}}
|
||||||
|
|
||||||
|
{{.Description}}
|
||||||
|
|
||||||
|
{{.ParametersSchema}}
|
||||||
|
|
||||||
|
---
|
||||||
|
{{end}}
|
||||||
|
`
|
||||||
|
|
||||||
|
type toolTemplateData struct {
|
||||||
|
Name string
|
||||||
|
Description string
|
||||||
|
ParametersSchema string
|
||||||
|
}
|
||||||
|
|
||||||
|
type skillTemplateData struct {
|
||||||
|
SkillName string
|
||||||
|
SkillDescription string
|
||||||
|
Tools []toolTemplateData
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateSkillMarkdown(skillName, skillDescription string, toolsMap map[string]Tool) (string, error) {
|
||||||
|
var toolsData []toolTemplateData
|
||||||
|
|
||||||
|
// Order tools based on name
|
||||||
|
var tools []Tool
|
||||||
|
for _, tool := range toolsMap {
|
||||||
|
tools = append(tools, tool)
|
||||||
|
}
|
||||||
|
sort.Slice(tools, func(i, j int) bool {
|
||||||
|
return tools[i].Name < tools[j].Name
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, tool := range tools {
|
||||||
|
parametersSchema, err := formatParameters(tool.Parameters)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
toolsData = append(toolsData, toolTemplateData{
|
||||||
|
Name: tool.Name,
|
||||||
|
Description: tool.Description,
|
||||||
|
ParametersSchema: parametersSchema,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
data := skillTemplateData{
|
||||||
|
SkillName: skillName,
|
||||||
|
SkillDescription: skillDescription,
|
||||||
|
Tools: toolsData,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("markdown").Parse(skillTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error parsing markdown template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf strings.Builder
|
||||||
|
if err := tmpl.Execute(&buf, data); err != nil {
|
||||||
|
return "", fmt.Errorf("error executing markdown template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const nodeScriptTemplate = `#!/usr/bin/env node
|
||||||
|
|
||||||
|
const { spawn } = require('child_process');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const toolName = "{{.Name}}";
|
||||||
|
const prebuiltNames = {{.PrebuiltNamesJSON}};
|
||||||
|
const toolsFileName = "{{.ToolsFileName}}";
|
||||||
|
|
||||||
|
let configArgs = [];
|
||||||
|
if (prebuiltNames.length > 0) {
|
||||||
|
prebuiltNames.forEach(name => {
|
||||||
|
configArgs.push("--prebuilt", name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toolsFileName) {
|
||||||
|
configArgs.push("--tools-file", path.join(__dirname, "..", "assets", toolsFileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
const toolboxArgs = [...configArgs, "invoke", toolName, ...args];
|
||||||
|
|
||||||
|
const command = process.platform === 'win32' ? 'toolbox.exe' : 'toolbox';
|
||||||
|
|
||||||
|
const child = spawn(command, toolboxArgs, { stdio: 'inherit' });
|
||||||
|
|
||||||
|
child.on('close', (code) => {
|
||||||
|
process.exit(code);
|
||||||
|
});
|
||||||
|
|
||||||
|
child.on('error', (err) => {
|
||||||
|
console.error("Error executing toolbox:", err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
`
|
||||||
|
|
||||||
|
type scriptData struct {
|
||||||
|
Name string
|
||||||
|
PrebuiltNamesJSON string
|
||||||
|
ToolsFileName string
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateScriptContent(name string, config serverConfig, toolsFileName string) (string, error) {
|
||||||
|
prebuiltJSON, err := json.Marshal(config.prebuiltConfigs)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error marshaling prebuilt configs: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data := scriptData{
|
||||||
|
Name: name,
|
||||||
|
PrebuiltNamesJSON: string(prebuiltJSON),
|
||||||
|
ToolsFileName: toolsFileName,
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("script").Parse(nodeScriptTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error parsing script template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf strings.Builder
|
||||||
|
if err := tmpl.Execute(&buf, data); err != nil {
|
||||||
|
return "", fmt.Errorf("error executing script template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatParameters(params []Parameter) (string, error) {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
properties := make(map[string]interface{})
|
||||||
|
var required []string
|
||||||
|
|
||||||
|
for _, p := range params {
|
||||||
|
paramMap := map[string]interface{}{
|
||||||
|
"type": p.Type,
|
||||||
|
"description": p.Description,
|
||||||
|
}
|
||||||
|
if p.Default != nil {
|
||||||
|
paramMap["default"] = p.Default
|
||||||
|
}
|
||||||
|
properties[p.Name] = paramMap
|
||||||
|
if p.Required {
|
||||||
|
required = append(required, p.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
schema := map[string]interface{}{
|
||||||
|
"type": "object",
|
||||||
|
"properties": properties,
|
||||||
|
}
|
||||||
|
if len(required) > 0 {
|
||||||
|
schema["required"] = required
|
||||||
|
}
|
||||||
|
|
||||||
|
schemaJSON, err := json.MarshalIndent(schema, "", " ")
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("error generating parameters schema: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("## Parameters\n\n```json\n%s\n```", string(schemaJSON)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateFilteredConfig(toolsFile, toolName string) ([]byte, error) {
|
||||||
|
data, err := os.ReadFile(toolsFile)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error reading %s: %w", toolsFile, err)
|
||||||
|
}
|
||||||
|
var cfg Config
|
||||||
|
if err := yaml.Unmarshal(data, &cfg); err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing YAML from %s: %w", toolsFile, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, ok := cfg.Tools[toolName]; !ok {
|
||||||
|
return nil, nil // Tool not found in this file
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredCfg := Config{
|
||||||
|
Tools: map[string]map[string]interface{}{
|
||||||
|
toolName: cfg.Tools[toolName],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add relevant source if exists
|
||||||
|
if src, ok := cfg.Tools[toolName]["source"].(string); ok && src != "" {
|
||||||
|
if sourceData, exists := cfg.Sources[src]; exists {
|
||||||
|
if filteredCfg.Sources == nil {
|
||||||
|
filteredCfg.Sources = make(map[string]interface{})
|
||||||
|
}
|
||||||
|
filteredCfg.Sources[src] = sourceData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
filteredData, err := yaml.Marshal(filteredCfg)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error marshaling filtered tools for %s: %w", toolName, err)
|
||||||
|
}
|
||||||
|
return filteredData, nil
|
||||||
|
}
|
||||||
306
internal/cli/skills/generator_test.go
Normal file
306
internal/cli/skills/generator_test.go
Normal file
@@ -0,0 +1,306 @@
|
|||||||
|
// Copyright 2026 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package skills
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
"github.com/google/go-cmp/cmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFormatParameters(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
params []Parameter
|
||||||
|
wantContains []string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "empty parameters",
|
||||||
|
params: []Parameter{},
|
||||||
|
wantContains: []string{""},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "single required string parameter",
|
||||||
|
params: []Parameter{
|
||||||
|
{
|
||||||
|
Name: "param1",
|
||||||
|
Description: "A test parameter",
|
||||||
|
Type: "string",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantContains: []string{
|
||||||
|
"## Parameters",
|
||||||
|
"```json",
|
||||||
|
`"type": "object"`,
|
||||||
|
`"properties": {`,
|
||||||
|
`"param1": {`,
|
||||||
|
`"type": "string"`,
|
||||||
|
`"description": "A test parameter"`,
|
||||||
|
`"required": [`,
|
||||||
|
`"param1"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "mixed parameters with defaults",
|
||||||
|
params: []Parameter{
|
||||||
|
{
|
||||||
|
Name: "param1",
|
||||||
|
Description: "Param 1",
|
||||||
|
Type: "string",
|
||||||
|
Required: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "param2",
|
||||||
|
Description: "Param 2",
|
||||||
|
Type: "integer",
|
||||||
|
Default: 42,
|
||||||
|
Required: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantContains: []string{
|
||||||
|
`"param1": {`,
|
||||||
|
`"param2": {`,
|
||||||
|
`"default": 42`,
|
||||||
|
`"required": [`,
|
||||||
|
`"param1"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := formatParameters(tt.params)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("formatParameters() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tt.wantErr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(tt.params) == 0 {
|
||||||
|
if got != "" {
|
||||||
|
t.Errorf("formatParameters() = %v, want empty string", got)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, want := range tt.wantContains {
|
||||||
|
if !strings.Contains(got, want) {
|
||||||
|
t.Errorf("formatParameters() result missing expected string: %s\nGot:\n%s", want, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateSkillMarkdown(t *testing.T) {
|
||||||
|
tools := map[string]Tool{
|
||||||
|
"tool1": {
|
||||||
|
Name: "tool1",
|
||||||
|
Description: "First tool",
|
||||||
|
Parameters: []Parameter{
|
||||||
|
{Name: "p1", Type: "string", Description: "d1", Required: true},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
got, err := generateSkillMarkdown("MySkill", "My Description", tools)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("generateSkillMarkdown() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedSubstrings := []string{
|
||||||
|
"name: MySkill",
|
||||||
|
"description: My Description",
|
||||||
|
"## Usage",
|
||||||
|
"All scripts can be executed using Node.js",
|
||||||
|
"**Bash:**",
|
||||||
|
"`node scripts/<script_name>.js '{\"<param_name>\": \"<param_value>\"}'`",
|
||||||
|
"**PowerShell:**",
|
||||||
|
"`node scripts/<script_name>.js '{\\\"<param_name>\\\": \\\"<param_value>\\\"}'`",
|
||||||
|
"## Scripts",
|
||||||
|
"### tool1",
|
||||||
|
"First tool",
|
||||||
|
"## Parameters",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range expectedSubstrings {
|
||||||
|
if !strings.Contains(got, s) {
|
||||||
|
t.Errorf("generateSkillMarkdown() missing substring %q", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateShellScriptContent(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
toolName string
|
||||||
|
config serverConfig
|
||||||
|
toolsFileName string
|
||||||
|
wantContains []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "basic script",
|
||||||
|
toolName: "test-tool",
|
||||||
|
config: serverConfig{
|
||||||
|
prebuiltConfigs: []string{},
|
||||||
|
},
|
||||||
|
toolsFileName: "",
|
||||||
|
wantContains: []string{
|
||||||
|
`const toolName = "test-tool";`,
|
||||||
|
`const prebuiltNames = [];`,
|
||||||
|
`const toolsFileName = "";`,
|
||||||
|
`const toolboxArgs = [...configArgs, "invoke", toolName, ...args];`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "script with prebuilts and tools file",
|
||||||
|
toolName: "complex-tool",
|
||||||
|
config: serverConfig{
|
||||||
|
prebuiltConfigs: []string{"pre1", "pre2"},
|
||||||
|
},
|
||||||
|
toolsFileName: "tools.yaml",
|
||||||
|
wantContains: []string{
|
||||||
|
`const toolName = "complex-tool";`,
|
||||||
|
`const prebuiltNames = ["pre1","pre2"];`,
|
||||||
|
`const toolsFileName = "tools.yaml";`,
|
||||||
|
`configArgs.push("--prebuilt", name);`,
|
||||||
|
`configArgs.push("--tools-file", path.join(__dirname, "..", "assets", toolsFileName));`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := generateScriptContent(tt.toolName, tt.config, tt.toolsFileName)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("generateShellScriptContent() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range tt.wantContains {
|
||||||
|
if !strings.Contains(got, s) {
|
||||||
|
t.Errorf("generateShellScriptContent() missing substring %q\nGot:\n%s", s, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGenerateFilteredConfig(t *testing.T) {
|
||||||
|
// Setup temporary directory and file
|
||||||
|
tmpDir := t.TempDir()
|
||||||
|
toolsFile := filepath.Join(tmpDir, "tools.yaml")
|
||||||
|
|
||||||
|
configContent := `
|
||||||
|
sources:
|
||||||
|
src1:
|
||||||
|
type: "postgres"
|
||||||
|
connection_string: "conn1"
|
||||||
|
src2:
|
||||||
|
type: "mysql"
|
||||||
|
connection_string: "conn2"
|
||||||
|
tools:
|
||||||
|
tool1:
|
||||||
|
source: "src1"
|
||||||
|
query: "SELECT 1"
|
||||||
|
tool2:
|
||||||
|
source: "src2"
|
||||||
|
query: "SELECT 2"
|
||||||
|
tool3:
|
||||||
|
type: "http" # No source
|
||||||
|
`
|
||||||
|
if err := os.WriteFile(toolsFile, []byte(configContent), 0644); err != nil {
|
||||||
|
t.Fatalf("Failed to create temp tools file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
toolName string
|
||||||
|
wantCfg Config
|
||||||
|
wantErr bool
|
||||||
|
wantNil bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "tool with source",
|
||||||
|
toolName: "tool1",
|
||||||
|
wantCfg: Config{
|
||||||
|
Sources: map[string]interface{}{
|
||||||
|
"src1": map[string]interface{}{
|
||||||
|
"type": "postgres",
|
||||||
|
"connection_string": "conn1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Tools: map[string]map[string]interface{}{
|
||||||
|
"tool1": {
|
||||||
|
"source": "src1",
|
||||||
|
"query": "SELECT 1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "tool without source",
|
||||||
|
toolName: "tool3",
|
||||||
|
wantCfg: Config{
|
||||||
|
Tools: map[string]map[string]interface{}{
|
||||||
|
"tool3": {
|
||||||
|
"type": "http",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "non-existent tool",
|
||||||
|
toolName: "missing-tool",
|
||||||
|
wantNil: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
gotBytes, err := generateFilteredConfig(toolsFile, tt.toolName)
|
||||||
|
if (err != nil) != tt.wantErr {
|
||||||
|
t.Errorf("generateFilteredConfig() error = %v, wantErr %v", err, tt.wantErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if tt.wantErr {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.wantNil {
|
||||||
|
if gotBytes != nil {
|
||||||
|
t.Errorf("generateFilteredConfig() expected nil, got %s", string(gotBytes))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var gotCfg Config
|
||||||
|
if err := yaml.Unmarshal(gotBytes, &gotCfg); err != nil {
|
||||||
|
t.Errorf("Failed to unmarshal result: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if diff := cmp.Diff(tt.wantCfg, gotCfg); diff != "" {
|
||||||
|
t.Errorf("generateFilteredConfig() mismatch (-want +got):\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/go-chi/chi/v5/middleware"
|
"github.com/go-chi/chi/v5/middleware"
|
||||||
@@ -234,10 +235,8 @@ func toolInvokeHandler(s *Server, w http.ResponseWriter, r *http.Request) {
|
|||||||
params, err := parameters.ParseParams(tool.GetParameters(), data, claimsFromAuth)
|
params, err := parameters.ParseParams(tool.GetParameters(), data, claimsFromAuth)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If auth error, return 401
|
// If auth error, return 401
|
||||||
errMsg := fmt.Sprintf("error parsing authenticated parameters from ID token: %w", err)
|
if errors.Is(err, util.ErrUnauthorized) {
|
||||||
var clientServerErr *util.ClientServerError
|
s.logger.DebugContext(ctx, fmt.Sprintf("error parsing authenticated parameters from ID token: %s", err))
|
||||||
if errors.As(err, &clientServerErr) && clientServerErr.Code == http.StatusUnauthorized {
|
|
||||||
s.logger.DebugContext(ctx, errMsg)
|
|
||||||
_ = render.Render(w, r, newErrResponse(err, http.StatusUnauthorized))
|
_ = render.Render(w, r, newErrResponse(err, http.StatusUnauthorized))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -260,49 +259,34 @@ func toolInvokeHandler(s *Server, w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// Determine what error to return to the users.
|
// Determine what error to return to the users.
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tbErr util.ToolboxError
|
errStr := err.Error()
|
||||||
|
var statusCode int
|
||||||
|
|
||||||
if errors.As(err, &tbErr) {
|
// Upstream API auth error propagation
|
||||||
switch tbErr.Category() {
|
switch {
|
||||||
case util.CategoryAgent:
|
case strings.Contains(errStr, "Error 401"):
|
||||||
// Agent Errors -> 200 OK
|
statusCode = http.StatusUnauthorized
|
||||||
s.logger.DebugContext(ctx, fmt.Sprintf("Tool invocation agent error: %v", err))
|
case strings.Contains(errStr, "Error 403"):
|
||||||
_ = render.Render(w, r, newErrResponse(err, http.StatusOK))
|
statusCode = http.StatusForbidden
|
||||||
return
|
}
|
||||||
|
|
||||||
case util.CategoryServer:
|
if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden {
|
||||||
// Server Errors -> Check the specific code inside
|
if clientAuth {
|
||||||
var clientServerErr *util.ClientServerError
|
// Propagate the original 401/403 error.
|
||||||
statusCode := http.StatusInternalServerError // Default to 500
|
s.logger.DebugContext(ctx, fmt.Sprintf("error invoking tool. Client credentials lack authorization to the source: %v", err))
|
||||||
|
|
||||||
if errors.As(err, &clientServerErr) {
|
|
||||||
if clientServerErr.Code != 0 {
|
|
||||||
statusCode = clientServerErr.Code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Process auth error
|
|
||||||
if statusCode == http.StatusUnauthorized || statusCode == http.StatusForbidden {
|
|
||||||
if clientAuth {
|
|
||||||
// Token error, pass through 401/403
|
|
||||||
s.logger.DebugContext(ctx, fmt.Sprintf("Client credentials lack authorization: %v", err))
|
|
||||||
_ = render.Render(w, r, newErrResponse(err, statusCode))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// ADC/Config error, return 500
|
|
||||||
statusCode = http.StatusInternalServerError
|
|
||||||
}
|
|
||||||
|
|
||||||
s.logger.ErrorContext(ctx, fmt.Sprintf("Tool invocation server error: %v", err))
|
|
||||||
_ = render.Render(w, r, newErrResponse(err, statusCode))
|
_ = render.Render(w, r, newErrResponse(err, statusCode))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
// ADC lacking permission or credentials configuration error.
|
||||||
// Unknown error -> 500
|
internalErr := fmt.Errorf("unexpected auth error occured during Tool invocation: %w", err)
|
||||||
s.logger.ErrorContext(ctx, fmt.Sprintf("Tool invocation unknown error: %v", err))
|
s.logger.ErrorContext(ctx, internalErr.Error())
|
||||||
_ = render.Render(w, r, newErrResponse(err, http.StatusInternalServerError))
|
_ = render.Render(w, r, newErrResponse(internalErr, http.StatusInternalServerError))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
err = fmt.Errorf("error while invoking tool: %w", err)
|
||||||
|
s.logger.DebugContext(ctx, err.Error())
|
||||||
|
_ = render.Render(w, r, newErrResponse(err, http.StatusBadRequest))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
resMarshal, err := json.Marshal(res)
|
resMarshal, err := json.Marshal(res)
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/server/resources"
|
"github.com/googleapis/genai-toolbox/internal/server/resources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/telemetry"
|
"github.com/googleapis/genai-toolbox/internal/telemetry"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -52,7 +51,7 @@ type MockTool struct {
|
|||||||
requiresClientAuthrorization bool
|
requiresClientAuthrorization bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t MockTool) Invoke(context.Context, tools.SourceProvider, parameters.ParamValues, tools.AccessToken) (any, util.ToolboxError) {
|
func (t MockTool) Invoke(context.Context, tools.SourceProvider, parameters.ParamValues, tools.AccessToken) (any, error) {
|
||||||
mock := []any{t.Name}
|
mock := []any{t.Name}
|
||||||
return mock, nil
|
return mock, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -443,17 +444,15 @@ func httpHandler(s *Server, w http.ResponseWriter, r *http.Request) {
|
|||||||
code := rpcResponse.Error.Code
|
code := rpcResponse.Error.Code
|
||||||
switch code {
|
switch code {
|
||||||
case jsonrpc.INTERNAL_ERROR:
|
case jsonrpc.INTERNAL_ERROR:
|
||||||
// Map Internal RPC Error (-32603) to HTTP 500
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
case jsonrpc.INVALID_REQUEST:
|
case jsonrpc.INVALID_REQUEST:
|
||||||
var clientServerErr *util.ClientServerError
|
errStr := err.Error()
|
||||||
if errors.As(err, &clientServerErr) {
|
if errors.Is(err, util.ErrUnauthorized) {
|
||||||
switch clientServerErr.Code {
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
case http.StatusUnauthorized:
|
} else if strings.Contains(errStr, "Error 401") {
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
case http.StatusForbidden:
|
} else if strings.Contains(errStr, "Error 403") {
|
||||||
w.WriteHeader(http.StatusForbidden)
|
w.WriteHeader(http.StatusForbidden)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/prompts"
|
"github.com/googleapis/genai-toolbox/internal/prompts"
|
||||||
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
||||||
@@ -123,11 +124,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
}
|
}
|
||||||
if clientAuth {
|
if clientAuth {
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.NewClientServerError(
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
|
||||||
"missing access token in the 'Authorization' header",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,11 +172,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// Check if any of the specified auth services is verified
|
// Check if any of the specified auth services is verified
|
||||||
isAuthorized := tool.Authorized(verifiedAuthServices)
|
isAuthorized := tool.Authorized(verifiedAuthServices)
|
||||||
if !isAuthorized {
|
if !isAuthorized {
|
||||||
err = util.NewClientServerError(
|
err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
|
||||||
"unauthorized Tool call: Please make sure you specify correct auth headers",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
logger.DebugContext(ctx, "tool invocation authorized")
|
logger.DebugContext(ctx, "tool invocation authorized")
|
||||||
@@ -201,44 +194,30 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// run tool invocation and generate response.
|
// run tool invocation and generate response.
|
||||||
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tbErr util.ToolboxError
|
errStr := err.Error()
|
||||||
|
// Missing authService tokens.
|
||||||
if errors.As(err, &tbErr) {
|
if errors.Is(err, util.ErrUnauthorized) {
|
||||||
switch tbErr.Category() {
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
case util.CategoryAgent:
|
}
|
||||||
// MCP - Tool execution error
|
// Upstream auth error
|
||||||
// Return SUCCESS but with IsError: true
|
if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
|
||||||
text := TextContent{
|
if clientAuth {
|
||||||
Type: "text",
|
// Error with client credentials should pass down to the client
|
||||||
Text: err.Error(),
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
|
||||||
return jsonrpc.JSONRPCResponse{
|
|
||||||
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
|
||||||
Id: id,
|
|
||||||
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
case util.CategoryServer:
|
|
||||||
// MCP Spec - Protocol error
|
|
||||||
// Return JSON-RPC ERROR
|
|
||||||
var clientServerErr *util.ClientServerError
|
|
||||||
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
|
|
||||||
|
|
||||||
if errors.As(err, &clientServerErr) {
|
|
||||||
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
|
|
||||||
if clientAuth {
|
|
||||||
rpcCode = jsonrpc.INVALID_REQUEST
|
|
||||||
} else {
|
|
||||||
rpcCode = jsonrpc.INTERNAL_ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
|
|
||||||
}
|
}
|
||||||
} else {
|
// Auth error with ADC should raise internal 500 error
|
||||||
// Unknown error -> 500
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
text := TextContent{
|
||||||
|
Type: "text",
|
||||||
|
Text: err.Error(),
|
||||||
|
}
|
||||||
|
return jsonrpc.JSONRPCResponse{
|
||||||
|
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
||||||
|
Id: id,
|
||||||
|
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
content := make([]TextContent, 0)
|
content := make([]TextContent, 0)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/prompts"
|
"github.com/googleapis/genai-toolbox/internal/prompts"
|
||||||
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
||||||
@@ -123,11 +124,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
}
|
}
|
||||||
if clientAuth {
|
if clientAuth {
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.NewClientServerError(
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
|
||||||
"missing access token in the 'Authorization' header",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,11 +172,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// Check if any of the specified auth services is verified
|
// Check if any of the specified auth services is verified
|
||||||
isAuthorized := tool.Authorized(verifiedAuthServices)
|
isAuthorized := tool.Authorized(verifiedAuthServices)
|
||||||
if !isAuthorized {
|
if !isAuthorized {
|
||||||
err = util.NewClientServerError(
|
err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
|
||||||
"unauthorized Tool call: Please make sure you specify correct auth headers",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
logger.DebugContext(ctx, "tool invocation authorized")
|
logger.DebugContext(ctx, "tool invocation authorized")
|
||||||
@@ -201,45 +194,31 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// run tool invocation and generate response.
|
// run tool invocation and generate response.
|
||||||
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tbErr util.ToolboxError
|
errStr := err.Error()
|
||||||
|
// Missing authService tokens.
|
||||||
if errors.As(err, &tbErr) {
|
if errors.Is(err, util.ErrUnauthorized) {
|
||||||
switch tbErr.Category() {
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
case util.CategoryAgent:
|
}
|
||||||
// MCP - Tool execution error
|
// Upstream auth error
|
||||||
// Return SUCCESS but with IsError: true
|
if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
|
||||||
text := TextContent{
|
if clientAuth {
|
||||||
Type: "text",
|
// Error with client credentials should pass down to the client
|
||||||
Text: err.Error(),
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
|
||||||
return jsonrpc.JSONRPCResponse{
|
|
||||||
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
|
||||||
Id: id,
|
|
||||||
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
case util.CategoryServer:
|
|
||||||
// MCP Spec - Protocol error
|
|
||||||
// Return JSON-RPC ERROR
|
|
||||||
var clientServerErr *util.ClientServerError
|
|
||||||
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
|
|
||||||
|
|
||||||
if errors.As(err, &clientServerErr) {
|
|
||||||
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
|
|
||||||
if clientAuth {
|
|
||||||
rpcCode = jsonrpc.INVALID_REQUEST
|
|
||||||
} else {
|
|
||||||
rpcCode = jsonrpc.INTERNAL_ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
|
|
||||||
}
|
}
|
||||||
} else {
|
// Auth error with ADC should raise internal 500 error
|
||||||
// Unknown error -> 500
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
|
text := TextContent{
|
||||||
|
Type: "text",
|
||||||
|
Text: err.Error(),
|
||||||
|
}
|
||||||
|
return jsonrpc.JSONRPCResponse{
|
||||||
|
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
||||||
|
Id: id,
|
||||||
|
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
content := make([]TextContent, 0)
|
content := make([]TextContent, 0)
|
||||||
|
|
||||||
sliceRes, ok := results.([]any)
|
sliceRes, ok := results.([]any)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/prompts"
|
"github.com/googleapis/genai-toolbox/internal/prompts"
|
||||||
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
||||||
@@ -116,12 +117,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
}
|
}
|
||||||
if clientAuth {
|
if clientAuth {
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
errMsg := "missing access token in the 'Authorization' header"
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, errMsg, nil), util.NewClientServerError(
|
|
||||||
errMsg,
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,11 +165,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// Check if any of the specified auth services is verified
|
// Check if any of the specified auth services is verified
|
||||||
isAuthorized := tool.Authorized(verifiedAuthServices)
|
isAuthorized := tool.Authorized(verifiedAuthServices)
|
||||||
if !isAuthorized {
|
if !isAuthorized {
|
||||||
err = util.NewClientServerError(
|
err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
|
||||||
"unauthorized Tool call: Please make sure you specify correct auth headers",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
logger.DebugContext(ctx, "tool invocation authorized")
|
logger.DebugContext(ctx, "tool invocation authorized")
|
||||||
@@ -195,44 +187,29 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// run tool invocation and generate response.
|
// run tool invocation and generate response.
|
||||||
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tbErr util.ToolboxError
|
errStr := err.Error()
|
||||||
|
// Missing authService tokens.
|
||||||
if errors.As(err, &tbErr) {
|
if errors.Is(err, util.ErrUnauthorized) {
|
||||||
switch tbErr.Category() {
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
case util.CategoryAgent:
|
}
|
||||||
// MCP - Tool execution error
|
// Upstream auth error
|
||||||
// Return SUCCESS but with IsError: true
|
if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
|
||||||
text := TextContent{
|
if clientAuth {
|
||||||
Type: "text",
|
// Error with client credentials should pass down to the client
|
||||||
Text: err.Error(),
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
|
||||||
return jsonrpc.JSONRPCResponse{
|
|
||||||
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
|
||||||
Id: id,
|
|
||||||
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
case util.CategoryServer:
|
|
||||||
// MCP Spec - Protocol error
|
|
||||||
// Return JSON-RPC ERROR
|
|
||||||
var clientServerErr *util.ClientServerError
|
|
||||||
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
|
|
||||||
|
|
||||||
if errors.As(err, &clientServerErr) {
|
|
||||||
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
|
|
||||||
if clientAuth {
|
|
||||||
rpcCode = jsonrpc.INVALID_REQUEST
|
|
||||||
} else {
|
|
||||||
rpcCode = jsonrpc.INTERNAL_ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
|
|
||||||
}
|
}
|
||||||
} else {
|
// Auth error with ADC should raise internal 500 error
|
||||||
// Unknown error -> 500
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
|
text := TextContent{
|
||||||
|
Type: "text",
|
||||||
|
Text: err.Error(),
|
||||||
|
}
|
||||||
|
return jsonrpc.JSONRPCResponse{
|
||||||
|
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
||||||
|
Id: id,
|
||||||
|
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
content := make([]TextContent, 0)
|
content := make([]TextContent, 0)
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/prompts"
|
"github.com/googleapis/genai-toolbox/internal/prompts"
|
||||||
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
"github.com/googleapis/genai-toolbox/internal/server/mcp/jsonrpc"
|
||||||
@@ -116,11 +117,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
}
|
}
|
||||||
if clientAuth {
|
if clientAuth {
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.NewClientServerError(
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, "missing access token in the 'Authorization' header", nil), util.ErrUnauthorized
|
||||||
"missing access token in the 'Authorization' header",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,11 +165,7 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// Check if any of the specified auth services is verified
|
// Check if any of the specified auth services is verified
|
||||||
isAuthorized := tool.Authorized(verifiedAuthServices)
|
isAuthorized := tool.Authorized(verifiedAuthServices)
|
||||||
if !isAuthorized {
|
if !isAuthorized {
|
||||||
err = util.NewClientServerError(
|
err = fmt.Errorf("unauthorized Tool call: Please make sure your specify correct auth headers: %w", util.ErrUnauthorized)
|
||||||
"unauthorized Tool call: Please make sure you specify correct auth headers",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
nil,
|
|
||||||
)
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
logger.DebugContext(ctx, "tool invocation authorized")
|
logger.DebugContext(ctx, "tool invocation authorized")
|
||||||
@@ -194,44 +187,29 @@ func toolsCallHandler(ctx context.Context, id jsonrpc.RequestId, resourceMgr *re
|
|||||||
// run tool invocation and generate response.
|
// run tool invocation and generate response.
|
||||||
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
results, err := tool.Invoke(ctx, resourceMgr, params, accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var tbErr util.ToolboxError
|
errStr := err.Error()
|
||||||
|
// Missing authService tokens.
|
||||||
if errors.As(err, &tbErr) {
|
if errors.Is(err, util.ErrUnauthorized) {
|
||||||
switch tbErr.Category() {
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
case util.CategoryAgent:
|
}
|
||||||
// MCP - Tool execution error
|
// Upstream auth error
|
||||||
// Return SUCCESS but with IsError: true
|
if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "Error 403") {
|
||||||
text := TextContent{
|
if clientAuth {
|
||||||
Type: "text",
|
// Error with client credentials should pass down to the client
|
||||||
Text: err.Error(),
|
return jsonrpc.NewError(id, jsonrpc.INVALID_REQUEST, err.Error(), nil), err
|
||||||
}
|
|
||||||
return jsonrpc.JSONRPCResponse{
|
|
||||||
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
|
||||||
Id: id,
|
|
||||||
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
case util.CategoryServer:
|
|
||||||
// MCP Spec - Protocol error
|
|
||||||
// Return JSON-RPC ERROR
|
|
||||||
var clientServerErr *util.ClientServerError
|
|
||||||
rpcCode := jsonrpc.INTERNAL_ERROR // Default to Internal Error (-32603)
|
|
||||||
|
|
||||||
if errors.As(err, &clientServerErr) {
|
|
||||||
if clientServerErr.Code == http.StatusUnauthorized || clientServerErr.Code == http.StatusForbidden {
|
|
||||||
if clientAuth {
|
|
||||||
rpcCode = jsonrpc.INVALID_REQUEST
|
|
||||||
} else {
|
|
||||||
rpcCode = jsonrpc.INTERNAL_ERROR
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jsonrpc.NewError(id, rpcCode, err.Error(), nil), err
|
|
||||||
}
|
}
|
||||||
} else {
|
// Auth error with ADC should raise internal 500 error
|
||||||
// Unknown error -> 500
|
|
||||||
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
return jsonrpc.NewError(id, jsonrpc.INTERNAL_ERROR, err.Error(), nil), err
|
||||||
}
|
}
|
||||||
|
text := TextContent{
|
||||||
|
Type: "text",
|
||||||
|
Text: err.Error(),
|
||||||
|
}
|
||||||
|
return jsonrpc.JSONRPCResponse{
|
||||||
|
Jsonrpc: jsonrpc.JSONRPC_VERSION,
|
||||||
|
Id: id,
|
||||||
|
Result: CallToolResult{Content: []TextContent{text}, IsError: true},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
content := make([]TextContent, 0)
|
content := make([]TextContent, 0)
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,49 +122,44 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok || project == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterID, ok := paramsMap["cluster"].(string)
|
clusterID, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || clusterID == "" {
|
if !ok || clusterID == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'cluster' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
password, ok := paramsMap["password"].(string)
|
password, ok := paramsMap["password"].(string)
|
||||||
if !ok || password == "" {
|
if !ok || password == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'password' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'password' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
network, ok := paramsMap["network"].(string)
|
network, ok := paramsMap["network"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'network' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'network' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
user, ok := paramsMap["user"].(string)
|
user, ok := paramsMap["user"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'user' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'user' parameter; expected a string")
|
||||||
}
|
|
||||||
resp, err := source.CreateCluster(ctx, project, location, network, user, password, clusterID, string(accessToken))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return resp, nil
|
return source.CreateCluster(ctx, project, location, network, user, password, clusterID, string(accessToken))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -124,36 +123,36 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok || project == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok || location == "" {
|
if !ok || location == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'location' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || cluster == "" {
|
if !ok || cluster == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'cluster' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceID, ok := paramsMap["instance"].(string)
|
instanceID, ok := paramsMap["instance"].(string)
|
||||||
if !ok || instanceID == "" {
|
if !ok || instanceID == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'instance' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'instance' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
instanceType, ok := paramsMap["instanceType"].(string)
|
instanceType, ok := paramsMap["instanceType"].(string)
|
||||||
if !ok || (instanceType != "READ_POOL" && instanceType != "PRIMARY") {
|
if !ok || (instanceType != "READ_POOL" && instanceType != "PRIMARY") {
|
||||||
return nil, util.NewAgentError("invalid 'instanceType' parameter; expected 'PRIMARY' or 'READ_POOL'", nil)
|
return nil, fmt.Errorf("invalid 'instanceType' parameter; expected 'PRIMARY' or 'READ_POOL'")
|
||||||
}
|
}
|
||||||
|
|
||||||
displayName, _ := paramsMap["displayName"].(string)
|
displayName, _ := paramsMap["displayName"].(string)
|
||||||
@@ -162,15 +161,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if instanceType == "READ_POOL" {
|
if instanceType == "READ_POOL" {
|
||||||
nodeCount, ok = paramsMap["nodeCount"].(int)
|
nodeCount, ok = paramsMap["nodeCount"].(int)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'nodeCount' parameter; expected an integer for READ_POOL", nil)
|
return nil, fmt.Errorf("invalid 'nodeCount' parameter; expected an integer for READ_POOL")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.CreateInstance(ctx, project, location, cluster, instanceID, instanceType, displayName, nodeCount, string(accessToken))
|
return source.CreateInstance(ctx, project, location, cluster, instanceID, instanceType, displayName, nodeCount, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -123,43 +122,43 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok || project == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok || location == "" {
|
if !ok || location == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing'location' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing'location' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || cluster == "" {
|
if !ok || cluster == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'cluster' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
userID, ok := paramsMap["user"].(string)
|
userID, ok := paramsMap["user"].(string)
|
||||||
if !ok || userID == "" {
|
if !ok || userID == "" {
|
||||||
return nil, util.NewAgentError("invalid or missing 'user' parameter; expected a non-empty string", nil)
|
return nil, fmt.Errorf("invalid or missing 'user' parameter; expected a non-empty string")
|
||||||
}
|
}
|
||||||
|
|
||||||
userType, ok := paramsMap["userType"].(string)
|
userType, ok := paramsMap["userType"].(string)
|
||||||
if !ok || (userType != "ALLOYDB_BUILT_IN" && userType != "ALLOYDB_IAM_USER") {
|
if !ok || (userType != "ALLOYDB_BUILT_IN" && userType != "ALLOYDB_IAM_USER") {
|
||||||
return nil, util.NewAgentError("invalid or missing 'userType' parameter; expected 'ALLOYDB_BUILT_IN' or 'ALLOYDB_IAM_USER'", nil)
|
return nil, fmt.Errorf("invalid or missing 'userType' parameter; expected 'ALLOYDB_BUILT_IN' or 'ALLOYDB_IAM_USER'")
|
||||||
}
|
}
|
||||||
var password string
|
var password string
|
||||||
|
|
||||||
if userType == "ALLOYDB_BUILT_IN" {
|
if userType == "ALLOYDB_BUILT_IN" {
|
||||||
password, ok = paramsMap["password"].(string)
|
password, ok = paramsMap["password"].(string)
|
||||||
if !ok || password == "" {
|
if !ok || password == "" {
|
||||||
return nil, util.NewAgentError("password is required when userType is ALLOYDB_BUILT_IN", nil)
|
return nil, fmt.Errorf("password is required when userType is ALLOYDB_BUILT_IN")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,11 +170,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.CreateUser(ctx, userType, password, roles, string(accessToken), project, location, cluster, userID)
|
return source.CreateUser(ctx, userType, password, roles, string(accessToken), project, location, cluster, userID)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,32 +120,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok || location == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || cluster == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.GetCluster(ctx, project, location, cluster, string(accessToken))
|
return source.GetCluster(ctx, project, location, cluster, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,36 +120,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok || location == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || cluster == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
|
||||||
}
|
}
|
||||||
instance, ok := paramsMap["instance"].(string)
|
instance, ok := paramsMap["instance"].(string)
|
||||||
if !ok || instance == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'instance' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'instance' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.GetInstance(ctx, project, location, cluster, instance, string(accessToken))
|
return source.GetInstance(ctx, project, location, cluster, instance, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,36 +120,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok || location == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || cluster == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
|
||||||
}
|
}
|
||||||
user, ok := paramsMap["user"].(string)
|
user, ok := paramsMap["user"].(string)
|
||||||
if !ok || user == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'user' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'user' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.GetUsers(ctx, project, location, cluster, user, string(accessToken))
|
return source.GetUsers(ctx, project, location, cluster, user, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,28 +118,24 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.ListCluster(ctx, project, location, string(accessToken))
|
return source.ListCluster(ctx, project, location, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -120,32 +119,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid 'cluster' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.ListInstance(ctx, project, location, cluster, string(accessToken))
|
return source.ListInstance(ctx, project, location, cluster, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -120,32 +119,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'project' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid or missing 'project' parameter; expected a string")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok || location == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'location' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'location' parameter; expected a string")
|
||||||
}
|
}
|
||||||
cluster, ok := paramsMap["cluster"].(string)
|
cluster, ok := paramsMap["cluster"].(string)
|
||||||
if !ok || cluster == "" {
|
if !ok {
|
||||||
return nil, util.NewAgentError("invalid or missing 'cluster' parameter; expected a string", nil)
|
return nil, fmt.Errorf("invalid 'cluster' parameter; expected a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.ListUsers(ctx, project, location, cluster, string(accessToken))
|
return source.ListUsers(ctx, project, location, cluster, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -24,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -214,25 +213,25 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", 500, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
location, ok := paramsMap["location"].(string)
|
location, ok := paramsMap["location"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'location' parameter", nil)
|
return nil, fmt.Errorf("missing 'location' parameter")
|
||||||
}
|
}
|
||||||
operation, ok := paramsMap["operation"].(string)
|
operation, ok := paramsMap["operation"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'operation' parameter", nil)
|
return nil, fmt.Errorf("missing 'operation' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
|
ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
|
||||||
@@ -247,15 +246,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
for retries < maxRetries {
|
for retries < maxRetries {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, util.NewAgentError("timed out waiting for operation %s", ctx.Err())
|
return nil, fmt.Errorf("timed out waiting for operation: %w", ctx.Err())
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
op, err := source.GetOperations(ctx, project, location, operation, alloyDBConnectionMessageTemplate, delay, string(accessToken))
|
op, err := source.GetOperations(ctx, project, location, operation, alloyDBConnectionMessageTemplate, delay, string(accessToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, err
|
||||||
}
|
} else if op != nil {
|
||||||
if op != nil {
|
|
||||||
return op, nil
|
return op, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +264,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
retries++
|
retries++
|
||||||
}
|
}
|
||||||
return nil, util.NewAgentError("exceeded max retries waiting for operation", nil)
|
return nil, fmt.Errorf("exceeded max retries waiting for operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package alloydbainl
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"github.com/jackc/pgx/v5/pgxpool"
|
"github.com/jackc/pgx/v5/pgxpool"
|
||||||
)
|
)
|
||||||
@@ -129,10 +127,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
sliceParams := params.AsSlice()
|
sliceParams := params.AsSlice()
|
||||||
@@ -145,7 +143,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
resp, err := source.RunSQL(ctx, t.Statement, allParamValues)
|
resp, err := source.RunSQL(ctx, t.Statement, allParamValues)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError(fmt.Sprintf("error running SQL query: %v. Query: %v , Values: %v. Toolbox v0.19.0+ is only compatible with AlloyDB AI NL v1.0.3+. Please ensure that you are using the latest AlloyDB AI NL extension", err, t.Statement, allParamValues), http.StatusBadRequest, err)
|
return nil, fmt.Errorf("%w. Query: %v , Values: %v. Toolbox v0.19.0+ is only compatible with AlloyDB AI NL v1.0.3+. Please ensure that you are using the latest AlloyDB AI NL extension", err, t.Statement, allParamValues)
|
||||||
}
|
}
|
||||||
return resp, nil
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigqueryanalyzecontribution
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
@@ -28,7 +27,6 @@ import (
|
|||||||
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
||||||
)
|
)
|
||||||
@@ -156,21 +154,21 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke runs the contribution analysis.
|
// Invoke runs the contribution analysis.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
inputData, ok := paramsMap["input_data"].(string)
|
inputData, ok := paramsMap["input_data"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast input_data parameter %s", paramsMap["input_data"]), nil)
|
return nil, fmt.Errorf("unable to cast input_data parameter %s", paramsMap["input_data"])
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
modelID := fmt.Sprintf("contribution_analysis_model_%s", strings.ReplaceAll(uuid.New().String(), "-", ""))
|
modelID := fmt.Sprintf("contribution_analysis_model_%s", strings.ReplaceAll(uuid.New().String(), "-", ""))
|
||||||
@@ -188,7 +186,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
options = append(options, fmt.Sprintf("DIMENSION_ID_COLS = [%s]", strings.Join(strCols, ", ")))
|
options = append(options, fmt.Sprintf("DIMENSION_ID_COLS = [%s]", strings.Join(strCols, ", ")))
|
||||||
} else {
|
} else {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast dimension_id_cols parameter %s", paramsMap["dimension_id_cols"]), nil)
|
return nil, fmt.Errorf("unable to cast dimension_id_cols parameter %s", paramsMap["dimension_id_cols"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if val, ok := paramsMap["top_k_insights_by_apriori_support"]; ok {
|
if val, ok := paramsMap["top_k_insights_by_apriori_support"]; ok {
|
||||||
@@ -197,7 +195,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if val, ok := paramsMap["pruning_method"].(string); ok {
|
if val, ok := paramsMap["pruning_method"].(string); ok {
|
||||||
upperVal := strings.ToUpper(val)
|
upperVal := strings.ToUpper(val)
|
||||||
if upperVal != "NO_PRUNING" && upperVal != "PRUNE_REDUNDANT_INSIGHTS" {
|
if upperVal != "NO_PRUNING" && upperVal != "PRUNE_REDUNDANT_INSIGHTS" {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid pruning_method: %s", val), nil)
|
return nil, fmt.Errorf("invalid pruning_method: %s", val)
|
||||||
}
|
}
|
||||||
options = append(options, fmt.Sprintf("PRUNING_METHOD = '%s'", upperVal))
|
options = append(options, fmt.Sprintf("PRUNING_METHOD = '%s'", upperVal))
|
||||||
}
|
}
|
||||||
@@ -209,7 +207,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var connProps []*bigqueryapi.ConnectionProperty
|
var connProps []*bigqueryapi.ConnectionProperty
|
||||||
session, err := source.BigQuerySession()(ctx)
|
session, err := source.BigQuerySession()(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
|
||||||
}
|
}
|
||||||
if session != nil {
|
if session != nil {
|
||||||
connProps = []*bigqueryapi.ConnectionProperty{
|
connProps = []*bigqueryapi.ConnectionProperty{
|
||||||
@@ -218,22 +216,22 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, inputData, nil, connProps)
|
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, inputData, nil, connProps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("query validation failed: %w", err)
|
||||||
}
|
}
|
||||||
statementType := dryRunJob.Statistics.Query.StatementType
|
statementType := dryRunJob.Statistics.Query.StatementType
|
||||||
if statementType != "SELECT" {
|
if statementType != "SELECT" {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("the 'input_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType), nil)
|
return nil, fmt.Errorf("the 'input_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType)
|
||||||
}
|
}
|
||||||
|
|
||||||
queryStats := dryRunJob.Statistics.Query
|
queryStats := dryRunJob.Statistics.Query
|
||||||
if queryStats != nil {
|
if queryStats != nil {
|
||||||
for _, tableRef := range queryStats.ReferencedTables {
|
for _, tableRef := range queryStats.ReferencedTables {
|
||||||
if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) {
|
if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("query in input_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId), nil)
|
return nil, fmt.Errorf("query in input_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, util.NewAgentError("could not analyze query in input_data to validate against allowed datasets", nil)
|
return nil, fmt.Errorf("could not analyze query in input_data to validate against allowed datasets")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inputDataSource = fmt.Sprintf("(%s)", inputData)
|
inputDataSource = fmt.Sprintf("(%s)", inputData)
|
||||||
@@ -247,10 +245,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
case 2: // dataset.table
|
case 2: // dataset.table
|
||||||
projectID, datasetID = source.BigQueryClient().Project(), parts[0]
|
projectID, datasetID = source.BigQueryClient().Project(), parts[0]
|
||||||
default:
|
default:
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid table ID format for 'input_data': %q. Expected 'dataset.table' or 'project.dataset.table'", inputData), nil)
|
return nil, fmt.Errorf("invalid table ID format for 'input_data': %q. Expected 'dataset.table' or 'project.dataset.table'", inputData)
|
||||||
}
|
}
|
||||||
if !source.IsDatasetAllowed(projectID, datasetID) {
|
if !source.IsDatasetAllowed(projectID, datasetID) {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, inputData), nil)
|
return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, inputData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inputDataSource = fmt.Sprintf("SELECT * FROM `%s`", inputData)
|
inputDataSource = fmt.Sprintf("SELECT * FROM `%s`", inputData)
|
||||||
@@ -270,7 +268,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Otherwise, a new session will be created by the first query.
|
// Otherwise, a new session will be created by the first query.
|
||||||
session, err := source.BigQuerySession()(ctx)
|
session, err := source.BigQuerySession()(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if session != nil {
|
if session != nil {
|
||||||
@@ -283,15 +281,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
createModelJob, err := createModelQuery.Run(ctx)
|
createModelJob, err := createModelQuery.Run(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to start create model job: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
status, err := createModelJob.Wait(ctx)
|
status, err := createModelJob.Wait(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to wait for create model job: %w", err)
|
||||||
}
|
}
|
||||||
if err := status.Err(); err != nil {
|
if err := status.Err(); err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("create model job failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the session ID to use for subsequent queries.
|
// Determine the session ID to use for subsequent queries.
|
||||||
@@ -302,17 +300,12 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
} else if status.Statistics != nil && status.Statistics.SessionInfo != nil {
|
} else if status.Statistics != nil && status.Statistics.SessionInfo != nil {
|
||||||
sessionID = status.Statistics.SessionInfo.SessionID
|
sessionID = status.Statistics.SessionInfo.SessionID
|
||||||
} else {
|
} else {
|
||||||
return nil, util.NewClientServerError("failed to get or create a BigQuery session ID", http.StatusInternalServerError, nil)
|
return nil, fmt.Errorf("failed to get or create a BigQuery session ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
getInsightsSQL := fmt.Sprintf("SELECT * FROM ML.GET_INSIGHTS(MODEL %s)", modelID)
|
getInsightsSQL := fmt.Sprintf("SELECT * FROM ML.GET_INSIGHTS(MODEL %s)", modelID)
|
||||||
connProps := []*bigqueryapi.ConnectionProperty{{Key: "session_id", Value: sessionID}}
|
connProps := []*bigqueryapi.ConnectionProperty{{Key: "session_id", Value: sessionID}}
|
||||||
|
return source.RunSQL(ctx, bqClient, getInsightsSQL, "SELECT", nil, connProps)
|
||||||
resp, err := source.RunSQL(ctx, bqClient, getInsightsSQL, "SELECT", nil, connProps)
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -172,10 +172,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
@@ -184,26 +184,26 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
// Use client-side access token
|
// Use client-side access token
|
||||||
if accessToken == "" {
|
if accessToken == "" {
|
||||||
return nil, util.NewClientServerError("tool is configured for client OAuth but no token was provided in the request header", http.StatusUnauthorized, nil)
|
return nil, fmt.Errorf("tool is configured for client OAuth but no token was provided in the request header: %w", util.ErrUnauthorized)
|
||||||
}
|
}
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Get a token source for the Gemini Data Analytics API.
|
// Get a token source for the Gemini Data Analytics API.
|
||||||
tokenSource, err := source.BigQueryTokenSourceWithScope(ctx, nil)
|
tokenSource, err := source.BigQueryTokenSourceWithScope(ctx, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get token source", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get token source: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use cloud-platform token source for Gemini Data Analytics API
|
// Use cloud-platform token source for Gemini Data Analytics API
|
||||||
if tokenSource == nil {
|
if tokenSource == nil {
|
||||||
return nil, util.NewClientServerError("cloud-platform token source is missing", http.StatusInternalServerError, nil)
|
return nil, fmt.Errorf("cloud-platform token source is missing")
|
||||||
}
|
}
|
||||||
token, err := tokenSource.Token()
|
token, err := tokenSource.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get token from cloud-platform token source", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get token from cloud-platform token source: %w", err)
|
||||||
}
|
}
|
||||||
tokenStr = token.AccessToken
|
tokenStr = token.AccessToken
|
||||||
}
|
}
|
||||||
@@ -218,14 +218,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var tableRefs []BQTableReference
|
var tableRefs []BQTableReference
|
||||||
if tableRefsJSON != "" {
|
if tableRefsJSON != "" {
|
||||||
if err := json.Unmarshal([]byte(tableRefsJSON), &tableRefs); err != nil {
|
if err := json.Unmarshal([]byte(tableRefsJSON), &tableRefs); err != nil {
|
||||||
return nil, util.NewAgentError("failed to parse 'table_references' JSON string", err)
|
return nil, fmt.Errorf("failed to parse 'table_references' JSON string: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(source.BigQueryAllowedDatasets()) > 0 {
|
if len(source.BigQueryAllowedDatasets()) > 0 {
|
||||||
for _, tableRef := range tableRefs {
|
for _, tableRef := range tableRefs {
|
||||||
if !source.IsDatasetAllowed(tableRef.ProjectID, tableRef.DatasetID) {
|
if !source.IsDatasetAllowed(tableRef.ProjectID, tableRef.DatasetID) {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", tableRef.ProjectID, tableRef.DatasetID, tableRef.TableID), nil)
|
return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", tableRef.ProjectID, tableRef.DatasetID, tableRef.TableID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,8 +258,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Call the streaming API
|
// Call the streaming API
|
||||||
response, err := getStream(caURL, payload, headers, source.GetMaxQueryResultRows())
|
response, err := getStream(caURL, payload, headers, source.GetMaxQueryResultRows())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// getStream wraps network errors or non-200 responses
|
return nil, fmt.Errorf("failed to get response from conversational analytics API: %w", err)
|
||||||
return nil, util.NewClientServerError("failed to get response from conversational analytics API", http.StatusInternalServerError, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response, nil
|
return response, nil
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
@@ -153,25 +152,25 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
sql, ok := paramsMap["sql"].(string)
|
sql, ok := paramsMap["sql"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast sql parameter %s", paramsMap["sql"]), nil)
|
return nil, fmt.Errorf("unable to cast sql parameter %s", paramsMap["sql"])
|
||||||
}
|
}
|
||||||
dryRun, ok := paramsMap["dry_run"].(bool)
|
dryRun, ok := paramsMap["dry_run"].(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast dry_run parameter %s", paramsMap["dry_run"]), nil)
|
return nil, fmt.Errorf("unable to cast dry_run parameter %s", paramsMap["dry_run"])
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var connProps []*bigqueryapi.ConnectionProperty
|
var connProps []*bigqueryapi.ConnectionProperty
|
||||||
@@ -179,7 +178,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if source.BigQueryWriteMode() == bigqueryds.WriteModeProtected {
|
if source.BigQueryWriteMode() == bigqueryds.WriteModeProtected {
|
||||||
session, err = source.BigQuerySession()(ctx)
|
session, err = source.BigQuerySession()(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get BigQuery session for protected mode", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get BigQuery session for protected mode: %w", err)
|
||||||
}
|
}
|
||||||
connProps = []*bigqueryapi.ConnectionProperty{
|
connProps = []*bigqueryapi.ConnectionProperty{
|
||||||
{Key: "session_id", Value: session.ID},
|
{Key: "session_id", Value: session.ID},
|
||||||
@@ -188,7 +187,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, sql, nil, connProps)
|
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, sql, nil, connProps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("query validation failed", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("query validation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
statementType := dryRunJob.Statistics.Query.StatementType
|
statementType := dryRunJob.Statistics.Query.StatementType
|
||||||
@@ -196,13 +195,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
switch source.BigQueryWriteMode() {
|
switch source.BigQueryWriteMode() {
|
||||||
case bigqueryds.WriteModeBlocked:
|
case bigqueryds.WriteModeBlocked:
|
||||||
if statementType != "SELECT" {
|
if statementType != "SELECT" {
|
||||||
return nil, util.NewAgentError("write mode is 'blocked', only SELECT statements are allowed", nil)
|
return nil, fmt.Errorf("write mode is 'blocked', only SELECT statements are allowed")
|
||||||
}
|
}
|
||||||
case bigqueryds.WriteModeProtected:
|
case bigqueryds.WriteModeProtected:
|
||||||
if dryRunJob.Configuration != nil && dryRunJob.Configuration.Query != nil {
|
if dryRunJob.Configuration != nil && dryRunJob.Configuration.Query != nil {
|
||||||
if dest := dryRunJob.Configuration.Query.DestinationTable; dest != nil && dest.DatasetId != session.DatasetID {
|
if dest := dryRunJob.Configuration.Query.DestinationTable; dest != nil && dest.DatasetId != session.DatasetID {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("protected write mode only supports SELECT statements, or write operations in the anonymous "+
|
return nil, fmt.Errorf("protected write mode only supports SELECT statements, or write operations in the anonymous "+
|
||||||
"dataset of a BigQuery session, but destination was %q", dest.DatasetId), nil)
|
"dataset of a BigQuery session, but destination was %q", dest.DatasetId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -210,11 +209,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if len(source.BigQueryAllowedDatasets()) > 0 {
|
if len(source.BigQueryAllowedDatasets()) > 0 {
|
||||||
switch statementType {
|
switch statementType {
|
||||||
case "CREATE_SCHEMA", "DROP_SCHEMA", "ALTER_SCHEMA":
|
case "CREATE_SCHEMA", "DROP_SCHEMA", "ALTER_SCHEMA":
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("dataset-level operations like '%s' are not allowed when dataset restrictions are in place", statementType), nil)
|
return nil, fmt.Errorf("dataset-level operations like '%s' are not allowed when dataset restrictions are in place", statementType)
|
||||||
case "CREATE_FUNCTION", "CREATE_TABLE_FUNCTION", "CREATE_PROCEDURE":
|
case "CREATE_FUNCTION", "CREATE_TABLE_FUNCTION", "CREATE_PROCEDURE":
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("creating stored routines ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType), nil)
|
return nil, fmt.Errorf("creating stored routines ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType)
|
||||||
case "CALL":
|
case "CALL":
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("calling stored procedures ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType), nil)
|
return nil, fmt.Errorf("calling stored procedures ('%s') is not allowed when dataset restrictions are in place, as their contents cannot be safely analyzed", statementType)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use a map to avoid duplicate table names.
|
// Use a map to avoid duplicate table names.
|
||||||
@@ -245,7 +244,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
parsedTables, parseErr := bqutil.TableParser(sql, source.BigQueryClient().Project())
|
parsedTables, parseErr := bqutil.TableParser(sql, source.BigQueryClient().Project())
|
||||||
if parseErr != nil {
|
if parseErr != nil {
|
||||||
// If parsing fails (e.g., EXECUTE IMMEDIATE), we cannot guarantee safety, so we must fail.
|
// If parsing fails (e.g., EXECUTE IMMEDIATE), we cannot guarantee safety, so we must fail.
|
||||||
return nil, util.NewAgentError("could not parse tables from query to validate against allowed datasets", parseErr)
|
return nil, fmt.Errorf("could not parse tables from query to validate against allowed datasets: %w", parseErr)
|
||||||
}
|
}
|
||||||
tableNames = parsedTables
|
tableNames = parsedTables
|
||||||
}
|
}
|
||||||
@@ -255,7 +254,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if len(parts) == 3 {
|
if len(parts) == 3 {
|
||||||
projectID, datasetID := parts[0], parts[1]
|
projectID, datasetID := parts[0], parts[1]
|
||||||
if !source.IsDatasetAllowed(projectID, datasetID) {
|
if !source.IsDatasetAllowed(projectID, datasetID) {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("query accesses dataset '%s.%s', which is not in the allowed list", projectID, datasetID), nil)
|
return nil, fmt.Errorf("query accesses dataset '%s.%s', which is not in the allowed list", projectID, datasetID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,7 +264,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if dryRunJob != nil {
|
if dryRunJob != nil {
|
||||||
jobJSON, err := json.MarshalIndent(dryRunJob, "", " ")
|
jobJSON, err := json.MarshalIndent(dryRunJob, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to marshal dry run job to JSON", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to marshal dry run job to JSON: %w", err)
|
||||||
}
|
}
|
||||||
return string(jobJSON), nil
|
return string(jobJSON), nil
|
||||||
}
|
}
|
||||||
@@ -276,14 +275,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Log the query executed for debugging.
|
// Log the query executed for debugging.
|
||||||
logger, err := util.LoggerFromContext(ctx)
|
logger, err := util.LoggerFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error getting logger", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("error getting logger: %s", err)
|
||||||
}
|
}
|
||||||
logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql))
|
logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql))
|
||||||
resp, err := source.RunSQL(ctx, bqClient, sql, statementType, nil, connProps)
|
return source.RunSQL(ctx, bqClient, sql, statementType, nil, connProps)
|
||||||
if err != nil {
|
|
||||||
return nil, util.NewClientServerError("error running sql", http.StatusInternalServerError, err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigqueryforecast
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
@@ -134,34 +133,34 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
historyData, ok := paramsMap["history_data"].(string)
|
historyData, ok := paramsMap["history_data"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast history_data parameter %v", paramsMap["history_data"]), nil)
|
return nil, fmt.Errorf("unable to cast history_data parameter %v", paramsMap["history_data"])
|
||||||
}
|
}
|
||||||
timestampCol, ok := paramsMap["timestamp_col"].(string)
|
timestampCol, ok := paramsMap["timestamp_col"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast timestamp_col parameter %v", paramsMap["timestamp_col"]), nil)
|
return nil, fmt.Errorf("unable to cast timestamp_col parameter %v", paramsMap["timestamp_col"])
|
||||||
}
|
}
|
||||||
dataCol, ok := paramsMap["data_col"].(string)
|
dataCol, ok := paramsMap["data_col"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast data_col parameter %v", paramsMap["data_col"]), nil)
|
return nil, fmt.Errorf("unable to cast data_col parameter %v", paramsMap["data_col"])
|
||||||
}
|
}
|
||||||
idColsRaw, ok := paramsMap["id_cols"].([]any)
|
idColsRaw, ok := paramsMap["id_cols"].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast id_cols parameter %v", paramsMap["id_cols"]), nil)
|
return nil, fmt.Errorf("unable to cast id_cols parameter %v", paramsMap["id_cols"])
|
||||||
}
|
}
|
||||||
var idCols []string
|
var idCols []string
|
||||||
for _, v := range idColsRaw {
|
for _, v := range idColsRaw {
|
||||||
s, ok := v.(string)
|
s, ok := v.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("id_cols contains non-string value: %v", v), nil)
|
return nil, fmt.Errorf("id_cols contains non-string value: %v", v)
|
||||||
}
|
}
|
||||||
idCols = append(idCols, s)
|
idCols = append(idCols, s)
|
||||||
}
|
}
|
||||||
@@ -170,13 +169,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if h, ok := paramsMap["horizon"].(float64); ok {
|
if h, ok := paramsMap["horizon"].(float64); ok {
|
||||||
horizon = int(h)
|
horizon = int(h)
|
||||||
} else {
|
} else {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to cast horizon parameter %v", paramsMap["horizon"]), nil)
|
return nil, fmt.Errorf("unable to cast horizon parameter %v", paramsMap["horizon"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var historyDataSource string
|
var historyDataSource string
|
||||||
@@ -186,7 +185,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var connProps []*bigqueryapi.ConnectionProperty
|
var connProps []*bigqueryapi.ConnectionProperty
|
||||||
session, err := source.BigQuerySession()(ctx)
|
session, err := source.BigQuerySession()(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
|
||||||
}
|
}
|
||||||
if session != nil {
|
if session != nil {
|
||||||
connProps = []*bigqueryapi.ConnectionProperty{
|
connProps = []*bigqueryapi.ConnectionProperty{
|
||||||
@@ -195,22 +194,22 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, historyData, nil, connProps)
|
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, source.BigQueryClient().Project(), source.BigQueryClient().Location, historyData, nil, connProps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("query validation failed: %w", err)
|
||||||
}
|
}
|
||||||
statementType := dryRunJob.Statistics.Query.StatementType
|
statementType := dryRunJob.Statistics.Query.StatementType
|
||||||
if statementType != "SELECT" {
|
if statementType != "SELECT" {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("the 'history_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType), nil)
|
return nil, fmt.Errorf("the 'history_data' parameter only supports a table ID or a SELECT query. The provided query has statement type '%s'", statementType)
|
||||||
}
|
}
|
||||||
|
|
||||||
queryStats := dryRunJob.Statistics.Query
|
queryStats := dryRunJob.Statistics.Query
|
||||||
if queryStats != nil {
|
if queryStats != nil {
|
||||||
for _, tableRef := range queryStats.ReferencedTables {
|
for _, tableRef := range queryStats.ReferencedTables {
|
||||||
if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) {
|
if !source.IsDatasetAllowed(tableRef.ProjectId, tableRef.DatasetId) {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("query in history_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId), nil)
|
return nil, fmt.Errorf("query in history_data accesses dataset '%s.%s', which is not in the allowed list", tableRef.ProjectId, tableRef.DatasetId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return nil, util.NewAgentError("could not analyze query in history_data to validate against allowed datasets", nil)
|
return nil, fmt.Errorf("could not analyze query in history_data to validate against allowed datasets")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyDataSource = fmt.Sprintf("(%s)", historyData)
|
historyDataSource = fmt.Sprintf("(%s)", historyData)
|
||||||
@@ -227,11 +226,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
projectID = source.BigQueryClient().Project()
|
projectID = source.BigQueryClient().Project()
|
||||||
datasetID = parts[0]
|
datasetID = parts[0]
|
||||||
default:
|
default:
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid table ID format for 'history_data': %q. Expected 'dataset.table' or 'project.dataset.table'", historyData), nil)
|
return nil, fmt.Errorf("invalid table ID format for 'history_data': %q. Expected 'dataset.table' or 'project.dataset.table'", historyData)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !source.IsDatasetAllowed(projectID, datasetID) {
|
if !source.IsDatasetAllowed(projectID, datasetID) {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, historyData), nil)
|
return nil, fmt.Errorf("access to dataset '%s.%s' (from table '%s') is not allowed", projectID, datasetID, historyData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
historyDataSource = fmt.Sprintf("TABLE `%s`", historyData)
|
historyDataSource = fmt.Sprintf("TABLE `%s`", historyData)
|
||||||
@@ -244,15 +243,15 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
sql := fmt.Sprintf(`SELECT *
|
sql := fmt.Sprintf(`SELECT *
|
||||||
FROM AI.FORECAST(
|
FROM AI.FORECAST(
|
||||||
%s,
|
%s,
|
||||||
data_col => '%s',
|
data_col => '%s',
|
||||||
timestamp_col => '%s',
|
timestamp_col => '%s',
|
||||||
horizon => %d%s)`,
|
horizon => %d%s)`,
|
||||||
historyDataSource, dataCol, timestampCol, horizon, idColsArg)
|
historyDataSource, dataCol, timestampCol, horizon, idColsArg)
|
||||||
|
|
||||||
session, err := source.BigQuerySession()(ctx)
|
session, err := source.BigQuerySession()(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
|
||||||
}
|
}
|
||||||
var connProps []*bigqueryapi.ConnectionProperty
|
var connProps []*bigqueryapi.ConnectionProperty
|
||||||
if session != nil {
|
if session != nil {
|
||||||
@@ -265,15 +264,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Log the query executed for debugging.
|
// Log the query executed for debugging.
|
||||||
logger, err := util.LoggerFromContext(ctx)
|
logger, err := util.LoggerFromContext(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error getting logger", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("error getting logger: %s", err)
|
||||||
}
|
}
|
||||||
logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql))
|
logger.DebugContext(ctx, fmt.Sprintf("executing `%s` tool query: %s", resourceType, sql))
|
||||||
|
|
||||||
resp, err := source.RunSQL(ctx, bqClient, sql, "SELECT", nil, connProps)
|
return source.RunSQL(ctx, bqClient, sql, "SELECT", nil, connProps)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigquerygetdatasetinfo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
||||||
)
|
)
|
||||||
@@ -122,38 +120,38 @@ type Tool struct {
|
|||||||
func (t Tool) ToConfig() tools.ToolConfig {
|
func (t Tool) ToConfig() tools.ToolConfig {
|
||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
|
||||||
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
projectId, ok := mapParams[projectKey].(string)
|
projectId, ok := mapParams[projectKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
// Updated: Use fmt.Sprintf for formatting, pass nil as cause
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
datasetId, ok := mapParams[datasetKey].(string)
|
datasetId, ok := mapParams[datasetKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", datasetKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", datasetKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !source.IsDatasetAllowed(projectId, datasetId) {
|
if !source.IsDatasetAllowed(projectId, datasetId) {
|
||||||
return nil, util.NewClientServerError(fmt.Sprintf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId), http.StatusInternalServerError, nil)
|
return nil, fmt.Errorf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId)
|
||||||
}
|
}
|
||||||
|
|
||||||
dsHandle := bqClient.DatasetInProject(projectId, datasetId)
|
dsHandle := bqClient.DatasetInProject(projectId, datasetId)
|
||||||
|
|
||||||
metadata, err := dsHandle.Metadata(ctx)
|
metadata, err := dsHandle.Metadata(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to get metadata for dataset %s (in project %s): %w", datasetId, projectId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata, nil
|
return metadata, nil
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigquerygettableinfo
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
||||||
)
|
)
|
||||||
@@ -127,35 +125,35 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
projectId, ok := mapParams[projectKey].(string)
|
projectId, ok := mapParams[projectKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
datasetId, ok := mapParams[datasetKey].(string)
|
datasetId, ok := mapParams[datasetKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", datasetKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", datasetKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
tableId, ok := mapParams[tableKey].(string)
|
tableId, ok := mapParams[tableKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", tableKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", tableKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !source.IsDatasetAllowed(projectId, datasetId) {
|
if !source.IsDatasetAllowed(projectId, datasetId) {
|
||||||
return nil, util.NewClientServerError(fmt.Sprintf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId), http.StatusInternalServerError, nil)
|
return nil, fmt.Errorf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId)
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dsHandle := bqClient.DatasetInProject(projectId, datasetId)
|
dsHandle := bqClient.DatasetInProject(projectId, datasetId)
|
||||||
@@ -163,7 +161,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
metadata, err := tableHandle.Metadata(ctx)
|
metadata, err := tableHandle.Metadata(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to get metadata for table %s.%s.%s: %w", projectId, datasetId, tableId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadata, nil
|
return metadata, nil
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package bigquerylistdatasetids
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
||||||
"google.golang.org/api/iterator"
|
"google.golang.org/api/iterator"
|
||||||
@@ -122,10 +120,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(source.BigQueryAllowedDatasets()) > 0 {
|
if len(source.BigQueryAllowedDatasets()) > 0 {
|
||||||
@@ -134,12 +132,12 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
projectId, ok := mapParams[projectKey].(string)
|
projectId, ok := mapParams[projectKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
datasetIterator := bqClient.Datasets(ctx)
|
datasetIterator := bqClient.Datasets(ctx)
|
||||||
datasetIterator.ProjectID = projectId
|
datasetIterator.ProjectID = projectId
|
||||||
@@ -151,7 +149,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("unable to iterate through datasets: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove leading and trailing quotes
|
// Remove leading and trailing quotes
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigquerylisttableids
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
bigqueryapi "cloud.google.com/go/bigquery"
|
bigqueryapi "cloud.google.com/go/bigquery"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
||||||
"google.golang.org/api/iterator"
|
"google.golang.org/api/iterator"
|
||||||
@@ -125,30 +123,31 @@ type Tool struct {
|
|||||||
func (t Tool) ToConfig() tools.ToolConfig {
|
func (t Tool) ToConfig() tools.ToolConfig {
|
||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
|
||||||
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
projectId, ok := mapParams[projectKey].(string)
|
projectId, ok := mapParams[projectKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", projectKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", projectKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
datasetId, ok := mapParams[datasetKey].(string)
|
datasetId, ok := mapParams[datasetKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", datasetKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", datasetKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !source.IsDatasetAllowed(projectId, datasetId) {
|
if !source.IsDatasetAllowed(projectId, datasetId) {
|
||||||
return nil, util.NewClientServerError(fmt.Sprintf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId), http.StatusInternalServerError, nil)
|
return nil, fmt.Errorf("access denied to dataset '%s' because it is not in the configured list of allowed datasets for project '%s'", datasetId, projectId)
|
||||||
}
|
}
|
||||||
|
|
||||||
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
bqClient, _, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dsHandle := bqClient.DatasetInProject(projectId, datasetId)
|
dsHandle := bqClient.DatasetInProject(projectId, datasetId)
|
||||||
@@ -161,7 +160,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to iterate through tables in dataset %s.%s: %w", projectId, datasetId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove leading and trailing quotes
|
// Remove leading and trailing quotes
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigquerysearchcatalog
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
dataplexapi "cloud.google.com/go/dataplex/apiv1"
|
dataplexapi "cloud.google.com/go/dataplex/apiv1"
|
||||||
@@ -27,7 +26,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/iterator"
|
"google.golang.org/api/iterator"
|
||||||
)
|
)
|
||||||
@@ -188,31 +186,28 @@ func ExtractType(resourceString string) string {
|
|||||||
return typeMap[resourceString[lastIndex+1:]]
|
return typeMap[resourceString[lastIndex+1:]]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
pageSize := int32(paramsMap["pageSize"].(int))
|
pageSize := int32(paramsMap["pageSize"].(int))
|
||||||
prompt, _ := paramsMap["prompt"].(string)
|
prompt, _ := paramsMap["prompt"].(string)
|
||||||
|
|
||||||
projectIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["projectIds"].([]any), "string")
|
projectIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["projectIds"].([]any), "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("can't convert projectIds to array of strings: %s", err), err)
|
return nil, fmt.Errorf("can't convert projectIds to array of strings: %s", err)
|
||||||
}
|
}
|
||||||
projectIds := projectIdSlice.([]string)
|
projectIds := projectIdSlice.([]string)
|
||||||
|
|
||||||
datasetIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["datasetIds"].([]any), "string")
|
datasetIdSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["datasetIds"].([]any), "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("can't convert datasetIds to array of strings: %s", err), err)
|
return nil, fmt.Errorf("can't convert datasetIds to array of strings: %s", err)
|
||||||
}
|
}
|
||||||
datasetIds := datasetIdSlice.([]string)
|
datasetIds := datasetIdSlice.([]string)
|
||||||
|
|
||||||
typesSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["types"].([]any), "string")
|
typesSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["types"].([]any), "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("can't convert types to array of strings: %s", err), err)
|
return nil, fmt.Errorf("can't convert types to array of strings: %s", err)
|
||||||
}
|
}
|
||||||
types := typesSlice.([]string)
|
types := typesSlice.([]string)
|
||||||
|
|
||||||
@@ -228,17 +223,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err := accessToken.ParseBearerToken()
|
tokenStr, err := accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
catalogClient, err = dataplexClientCreator(tokenStr)
|
catalogClient, err = dataplexClientCreator(tokenStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error creating client from OAuth access token", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("error creating client from OAuth access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
it := catalogClient.SearchEntries(ctx, req)
|
it := catalogClient.SearchEntries(ctx, req)
|
||||||
if it == nil {
|
if it == nil {
|
||||||
return nil, util.NewClientServerError(fmt.Sprintf("failed to create search entries iterator for project %q", source.BigQueryProject()), http.StatusInternalServerError, nil)
|
return nil, fmt.Errorf("failed to create search entries iterator for project %q", source.BigQueryProject())
|
||||||
}
|
}
|
||||||
|
|
||||||
var results []Response
|
var results []Response
|
||||||
@@ -248,7 +243,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
break
|
||||||
}
|
}
|
||||||
entrySource := entry.DataplexEntry.GetEntrySource()
|
entrySource := entry.DataplexEntry.GetEntrySource()
|
||||||
resp := Response{
|
resp := Response{
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package bigquerysql
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -28,7 +27,6 @@ import (
|
|||||||
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
bigqueryds "github.com/googleapis/genai-toolbox/internal/sources/bigquery"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
bqutil "github.com/googleapis/genai-toolbox/internal/tools/bigquery/bigquerycommon"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
bigqueryrestapi "google.golang.org/api/bigquery/v2"
|
||||||
)
|
)
|
||||||
@@ -105,10 +103,11 @@ type Tool struct {
|
|||||||
func (t Tool) ToConfig() tools.ToolConfig {
|
func (t Tool) ToConfig() tools.ToolConfig {
|
||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
|
||||||
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
highLevelParams := make([]bigqueryapi.QueryParameter, 0, len(t.Parameters))
|
highLevelParams := make([]bigqueryapi.QueryParameter, 0, len(t.Parameters))
|
||||||
@@ -117,7 +116,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
|
newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("unable to extract template params", err)
|
return nil, fmt.Errorf("unable to extract template params %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, p := range t.Parameters {
|
for _, p := range t.Parameters {
|
||||||
@@ -128,13 +127,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if arrayParam, ok := p.(*parameters.ArrayParameter); ok {
|
if arrayParam, ok := p.(*parameters.ArrayParameter); ok {
|
||||||
arrayParamValue, ok := value.([]any)
|
arrayParamValue, ok := value.([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to convert parameter `%s` to []any", name), nil)
|
return nil, fmt.Errorf("unable to convert parameter `%s` to []any", name)
|
||||||
}
|
}
|
||||||
itemType := arrayParam.GetItems().GetType()
|
itemType := arrayParam.GetItems().GetType()
|
||||||
var err error
|
var err error
|
||||||
value, err = parameters.ConvertAnySliceToTyped(arrayParamValue, itemType)
|
value, err = parameters.ConvertAnySliceToTyped(arrayParamValue, itemType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unable to convert parameter `%s` from []any to typed slice", name), err)
|
return nil, fmt.Errorf("unable to convert parameter `%s` from []any to typed slice: %w", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,7 +161,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
lowLevelParam.ParameterType.Type = "ARRAY"
|
lowLevelParam.ParameterType.Type = "ARRAY"
|
||||||
itemType, err := bqutil.BQTypeStringFromToolType(arrayParam.GetItems().GetType())
|
itemType, err := bqutil.BQTypeStringFromToolType(arrayParam.GetItems().GetType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("unable to get BigQuery type from tool parameter type", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
lowLevelParam.ParameterType.ArrayType = &bigqueryrestapi.QueryParameterType{Type: itemType}
|
lowLevelParam.ParameterType.ArrayType = &bigqueryrestapi.QueryParameterType{Type: itemType}
|
||||||
|
|
||||||
@@ -179,7 +178,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Handle scalar types based on their defined type.
|
// Handle scalar types based on their defined type.
|
||||||
bqType, err := bqutil.BQTypeStringFromToolType(p.GetType())
|
bqType, err := bqutil.BQTypeStringFromToolType(p.GetType())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("unable to get BigQuery type from tool parameter type", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
lowLevelParam.ParameterType.Type = bqType
|
lowLevelParam.ParameterType.Type = bqType
|
||||||
lowLevelParam.ParameterValue.Value = fmt.Sprintf("%v", value)
|
lowLevelParam.ParameterValue.Value = fmt.Sprintf("%v", value)
|
||||||
@@ -191,7 +190,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if source.BigQuerySession() != nil {
|
if source.BigQuerySession() != nil {
|
||||||
session, err := source.BigQuerySession()(ctx)
|
session, err := source.BigQuerySession()(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to get BigQuery session", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to get BigQuery session: %w", err)
|
||||||
}
|
}
|
||||||
if session != nil {
|
if session != nil {
|
||||||
// Add session ID to the connection properties for subsequent calls.
|
// Add session ID to the connection properties for subsequent calls.
|
||||||
@@ -201,20 +200,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
bqClient, restService, err := source.RetrieveClientAndService(accessToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to retrieve BigQuery client", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, newStatement, lowLevelParams, connProps)
|
dryRunJob, err := bqutil.DryRunQuery(ctx, restService, bqClient.Project(), bqClient.Location, newStatement, lowLevelParams, connProps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("query validation failed: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
statementType := dryRunJob.Statistics.Query.StatementType
|
statementType := dryRunJob.Statistics.Query.StatementType
|
||||||
resp, err := source.RunSQL(ctx, bqClient, newStatement, statementType, highLevelParams, connProps)
|
|
||||||
if err != nil {
|
return source.RunSQL(ctx, bqClient, newStatement, statementType, highLevelParams, connProps)
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package bigtable
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"cloud.google.com/go/bigtable"
|
"cloud.google.com/go/bigtable"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -98,28 +96,24 @@ type Tool struct {
|
|||||||
func (t Tool) ToConfig() tools.ToolConfig {
|
func (t Tool) ToConfig() tools.ToolConfig {
|
||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
|
||||||
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
|
newStatement, err := parameters.ResolveTemplateParams(t.TemplateParameters, t.Statement, paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("unable to extract template params", err)
|
return nil, fmt.Errorf("unable to extract template params %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
newParams, err := parameters.GetParams(t.Parameters, paramsMap)
|
newParams, err := parameters.GetParams(t.Parameters, paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("unable to extract standard params", err)
|
return nil, fmt.Errorf("unable to extract standard params %w", err)
|
||||||
}
|
}
|
||||||
|
return source.RunSQL(ctx, newStatement, t.Parameters, newParams)
|
||||||
resp, err := source.RunSQL(ctx, newStatement, t.Parameters, newParams)
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -18,13 +18,11 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,16 +119,17 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
// Invoke executes the tool logic
|
||||||
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
query, ok := paramsMap["query"].(string)
|
query, ok := paramsMap["query"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("query parameter not found or not a string", nil)
|
return nil, fmt.Errorf("query parameter not found or not a string")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the access token if provided
|
// Parse the access token if provided
|
||||||
@@ -139,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var err error
|
var err error
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,14 +154,9 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
bodyBytes, err := json.Marshal(payload)
|
bodyBytes, err := json.Marshal(payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to marshal request payload", http.StatusInternalServerError, err)
|
return nil, fmt.Errorf("failed to marshal request payload: %w", err)
|
||||||
}
|
}
|
||||||
|
return source.RunQuery(ctx, tokenStr, bodyBytes)
|
||||||
resp, err := source.RunQuery(ctx, tokenStr, bodyBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package fhirfetchpage
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -95,31 +93,24 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
url, ok := params.AsMap()[pageURLKey].(string)
|
url, ok := params.AsMap()[pageURLKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", pageURLKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", pageURLKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return source.FHIRFetchPage(ctx, url, tokenStr)
|
||||||
resp, err := source.FHIRFetchPage(ctx, url, tokenStr)
|
|
||||||
if err != nil {
|
|
||||||
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package fhirpatienteverything
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
@@ -118,27 +116,26 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// ValidateAndFetchStoreID usually returns input validation errors
|
return nil, err
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
|
||||||
}
|
}
|
||||||
patientID, ok := params.AsMap()[patientIDKey].(string)
|
patientID, ok := params.AsMap()[patientIDKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", patientIDKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", patientIDKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,11 +143,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if val, ok := params.AsMap()[typeFilterKey]; ok {
|
if val, ok := params.AsMap()[typeFilterKey]; ok {
|
||||||
types, ok := val.([]any)
|
types, ok := val.([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string array", typeFilterKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string array", typeFilterKey)
|
||||||
}
|
}
|
||||||
typeFilterSlice, err := parameters.ConvertAnySliceToTyped(types, "string")
|
typeFilterSlice, err := parameters.ConvertAnySliceToTyped(types, "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("can't convert '%s' to array of strings: %s", typeFilterKey, err), err)
|
return nil, fmt.Errorf("can't convert '%s' to array of strings: %s", typeFilterKey, err)
|
||||||
}
|
}
|
||||||
if len(typeFilterSlice.([]string)) != 0 {
|
if len(typeFilterSlice.([]string)) != 0 {
|
||||||
opts = append(opts, googleapi.QueryParameter("_type", strings.Join(typeFilterSlice.([]string), ",")))
|
opts = append(opts, googleapi.QueryParameter("_type", strings.Join(typeFilterSlice.([]string), ",")))
|
||||||
@@ -159,18 +156,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if since, ok := params.AsMap()[sinceFilterKey]; ok {
|
if since, ok := params.AsMap()[sinceFilterKey]; ok {
|
||||||
sinceStr, ok := since.(string)
|
sinceStr, ok := since.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", sinceFilterKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", sinceFilterKey)
|
||||||
}
|
}
|
||||||
if sinceStr != "" {
|
if sinceStr != "" {
|
||||||
opts = append(opts, googleapi.QueryParameter("_since", sinceStr))
|
opts = append(opts, googleapi.QueryParameter("_since", sinceStr))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return source.FHIRPatientEverything(storeID, patientID, tokenStr, opts)
|
||||||
resp, err := source.FHIRPatientEverything(storeID, patientID, tokenStr, opts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package fhirpatientsearch
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
@@ -152,22 +150,22 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,14 +179,14 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var ok bool
|
var ok bool
|
||||||
summary, ok = v.(bool)
|
summary, ok = v.(bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a boolean", summaryKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a boolean", summaryKey)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
val, ok := v.(string)
|
val, ok := v.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid parameter '%s'; expected a string", k), nil)
|
return nil, fmt.Errorf("invalid parameter '%s'; expected a string", k)
|
||||||
}
|
}
|
||||||
if val == "" {
|
if val == "" {
|
||||||
continue
|
continue
|
||||||
@@ -207,7 +205,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
parts := strings.Split(val, "/")
|
parts := strings.Split(val, "/")
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' format; expected YYYY-MM-DD/YYYY-MM-DD", k), nil)
|
return nil, fmt.Errorf("invalid '%s' format; expected YYYY-MM-DD/YYYY-MM-DD", k)
|
||||||
}
|
}
|
||||||
var values []string
|
var values []string
|
||||||
if parts[0] != "" {
|
if parts[0] != "" {
|
||||||
@@ -231,17 +229,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
case familyNameKey:
|
case familyNameKey:
|
||||||
opts = append(opts, googleapi.QueryParameter("family", val))
|
opts = append(opts, googleapi.QueryParameter("family", val))
|
||||||
default:
|
default:
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("unexpected parameter key %q", k), nil)
|
return nil, fmt.Errorf("unexpected parameter key %q", k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if summary {
|
if summary {
|
||||||
opts = append(opts, googleapi.QueryParameter("_summary", "text"))
|
opts = append(opts, googleapi.QueryParameter("_summary", "text"))
|
||||||
}
|
}
|
||||||
resp, err := source.FHIRPatientSearch(storeID, tokenStr, opts)
|
return source.FHIRPatientSearch(storeID, tokenStr, opts)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package gethealthcaredataset
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -92,23 +90,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetDataset(tokenStr)
|
return source.GetDataset(tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package getdicomstore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetDICOMStore(storeID, tokenStr)
|
return source.GetDICOMStore(storeID, tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package getdicomstoremetrics
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetDICOMStoreMetrics(storeID, tokenStr)
|
return source.GetDICOMStoreMetrics(storeID, tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package getfhirresource
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -114,36 +112,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
resType, ok := params.AsMap()[typeKey].(string)
|
resType, ok := params.AsMap()[typeKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", typeKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", typeKey)
|
||||||
}
|
}
|
||||||
resID, ok := params.AsMap()[idKey].(string)
|
resID, ok := params.AsMap()[idKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected a string", idKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected a string", idKey)
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetFHIRResource(storeID, resType, resID, tokenStr)
|
return source.GetFHIRResource(storeID, resType, resID, tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package getfhirstore
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetFHIRStore(storeID, tokenStr)
|
return source.GetFHIRStore(storeID, tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package getfhirstoremetrics
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -109,27 +107,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedFHIRStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetFHIRStoreMetrics(storeID, tokenStr)
|
return source.GetFHIRStoreMetrics(storeID, tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package listdicomstores
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -92,23 +90,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.ListDICOMStores(tokenStr)
|
return source.ListDICOMStores(tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package listfhirstores
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/healthcare/v1"
|
"google.golang.org/api/healthcare/v1"
|
||||||
)
|
)
|
||||||
@@ -92,23 +90,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.ListFHIRStores(tokenStr)
|
return source.ListFHIRStores(tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package retrieverendereddicominstance
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,44 +117,40 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
study, ok := params.AsMap()[studyInstanceUIDKey].(string)
|
study, ok := params.AsMap()[studyInstanceUIDKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey)
|
||||||
}
|
}
|
||||||
series, ok := params.AsMap()[seriesInstanceUIDKey].(string)
|
series, ok := params.AsMap()[seriesInstanceUIDKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey)
|
||||||
}
|
}
|
||||||
sop, ok := params.AsMap()[sopInstanceUIDKey].(string)
|
sop, ok := params.AsMap()[sopInstanceUIDKey].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", sopInstanceUIDKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", sopInstanceUIDKey)
|
||||||
}
|
}
|
||||||
frame, ok := params.AsMap()[frameNumberKey].(int)
|
frame, ok := params.AsMap()[frameNumberKey].(int)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected an integer", frameNumberKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected an integer", frameNumberKey)
|
||||||
}
|
}
|
||||||
resp, err := source.RetrieveRenderedDICOMInstance(storeID, study, series, sop, frame, tokenStr)
|
return source.RetrieveRenderedDICOMInstance(storeID, study, series, sop, frame, tokenStr)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package searchdicominstances
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
@@ -25,7 +24,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
@@ -133,33 +131,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opts, err := common.ParseDICOMSearchParameters(params, []string{sopInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey})
|
opts, err := common.ParseDICOMSearchParameters(params, []string{sopInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to parse DICOM search parameters", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
dicomWebPath := "instances"
|
dicomWebPath := "instances"
|
||||||
if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok {
|
if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok {
|
||||||
id, ok := studyInstanceUID.(string)
|
id, ok := studyInstanceUID.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey)
|
||||||
}
|
}
|
||||||
if id != "" {
|
if id != "" {
|
||||||
dicomWebPath = fmt.Sprintf("studies/%s/instances", id)
|
dicomWebPath = fmt.Sprintf("studies/%s/instances", id)
|
||||||
@@ -168,7 +166,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if seriesInstanceUID, ok := paramsMap[seriesInstanceUIDKey]; ok {
|
if seriesInstanceUID, ok := paramsMap[seriesInstanceUIDKey]; ok {
|
||||||
id, ok := seriesInstanceUID.(string)
|
id, ok := seriesInstanceUID.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", seriesInstanceUIDKey)
|
||||||
}
|
}
|
||||||
if id != "" {
|
if id != "" {
|
||||||
if dicomWebPath != "instances" {
|
if dicomWebPath != "instances" {
|
||||||
@@ -178,11 +176,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
|
return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package searchdicomseries
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
@@ -130,44 +128,40 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opts, err := common.ParseDICOMSearchParameters(params, []string{seriesInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey})
|
opts, err := common.ParseDICOMSearchParameters(params, []string{seriesInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey, modalityKey})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to parse DICOM search parameters", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
dicomWebPath := "series"
|
dicomWebPath := "series"
|
||||||
if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok {
|
if studyInstanceUID, ok := paramsMap[studyInstanceUIDKey]; ok {
|
||||||
id, ok := studyInstanceUID.(string)
|
id, ok := studyInstanceUID.(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid '%s' parameter; expected a string", studyInstanceUIDKey), nil)
|
return nil, fmt.Errorf("invalid '%s' parameter; expected a string", studyInstanceUIDKey)
|
||||||
}
|
}
|
||||||
if id != "" {
|
if id != "" {
|
||||||
dicomWebPath = fmt.Sprintf("studies/%s/series", id)
|
dicomWebPath = fmt.Sprintf("studies/%s/series", id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
|
return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package searchdicomstudies
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
"github.com/googleapis/genai-toolbox/internal/tools/cloudhealthcare/common"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/googleapi"
|
"google.golang.org/api/googleapi"
|
||||||
)
|
)
|
||||||
@@ -126,32 +124,28 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
storeID, err := common.ValidateAndFetchStoreID(params, source.AllowedDICOMStores())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to validate store ID", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
var tokenStr string
|
var tokenStr string
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenStr, err = accessToken.ParseBearerToken()
|
tokenStr, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("error parsing access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("error parsing access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
opts, err := common.ParseDICOMSearchParameters(params, []string{studyInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey})
|
opts, err := common.ParseDICOMSearchParameters(params, []string{studyInstanceUIDKey, patientNameKey, patientIDKey, accessionNumberKey, referringPhysicianNameKey, studyDateKey})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError("failed to parse DICOM search parameters", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
dicomWebPath := "studies"
|
dicomWebPath := "studies"
|
||||||
resp, err := source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
|
return source.SearchDICOM(t.Type, storeID, dicomWebPath, tokenStr, opts)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ package cloudloggingadminlistlognames
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -91,10 +89,10 @@ type Tool struct {
|
|||||||
Parameters parameters.Parameters `yaml:"parameters"`
|
Parameters parameters.Parameters `yaml:"parameters"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
limit := defaultLimit
|
limit := defaultLimit
|
||||||
@@ -102,22 +100,18 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if val, ok := paramsMap["limit"].(int); ok && val > 0 {
|
if val, ok := paramsMap["limit"].(int); ok && val > 0 {
|
||||||
limit = val
|
limit = val
|
||||||
} else if ok && val < 0 {
|
} else if ok && val < 0 {
|
||||||
return nil, util.NewAgentError("limit must be greater than or equal to 1", nil)
|
return nil, fmt.Errorf("limit must be greater than or equal to 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenString := ""
|
tokenString := ""
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenString, err = accessToken.ParseBearerToken()
|
tokenString, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("failed to parse access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.ListLogNames(ctx, limit, tokenString)
|
return source.ListLogNames(ctx, limit, tokenString)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {
|
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -16,13 +16,11 @@ package cloudloggingadminlistresourcetypes
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -86,25 +84,21 @@ type Tool struct {
|
|||||||
mcpManifest tools.McpManifest
|
mcpManifest tools.McpManifest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tokenString := ""
|
tokenString := ""
|
||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenString, err = accessToken.ParseBearerToken()
|
tokenString, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("failed to parse access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.ListResourceTypes(ctx, tokenString)
|
return source.ListResourceTypes(ctx, tokenString)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {
|
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -16,7 +16,6 @@ package cloudloggingadminquerylogs
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
@@ -24,7 +23,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
cla "github.com/googleapis/genai-toolbox/internal/sources/cloudloggingadmin"
|
cla "github.com/googleapis/genai-toolbox/internal/sources/cloudloggingadmin"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -106,10 +104,10 @@ type Tool struct {
|
|||||||
mcpManifest tools.McpManifest
|
mcpManifest tools.McpManifest
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parameters
|
// Parse parameters
|
||||||
@@ -121,7 +119,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if val, ok := paramsMap["limit"].(int); ok && val > 0 {
|
if val, ok := paramsMap["limit"].(int); ok && val > 0 {
|
||||||
limit = val
|
limit = val
|
||||||
} else if ok && val < 0 {
|
} else if ok && val < 0 {
|
||||||
return nil, util.NewAgentError("limit must be greater than or equal to 1", nil)
|
return nil, fmt.Errorf("limit must be greater than or equal to 1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for verbosity of output
|
// Check for verbosity of output
|
||||||
@@ -131,7 +129,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var filter string
|
var filter string
|
||||||
if f, ok := paramsMap["filter"].(string); ok {
|
if f, ok := paramsMap["filter"].(string); ok {
|
||||||
if len(f) == 0 {
|
if len(f) == 0 {
|
||||||
return nil, util.NewAgentError("filter cannot be empty if provided", nil)
|
return nil, fmt.Errorf("filter cannot be empty if provided")
|
||||||
}
|
}
|
||||||
filter = f
|
filter = f
|
||||||
}
|
}
|
||||||
@@ -140,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var startTime string
|
var startTime string
|
||||||
if val, ok := paramsMap["startTime"].(string); ok && val != "" {
|
if val, ok := paramsMap["startTime"].(string); ok && val != "" {
|
||||||
if _, err := time.Parse(time.RFC3339, val); err != nil {
|
if _, err := time.Parse(time.RFC3339, val); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("startTime must be in RFC3339 format (e.g., 2025-12-09T00:00:00Z): %v", err), err)
|
return nil, fmt.Errorf("startTime must be in RFC3339 format (e.g., 2025-12-09T00:00:00Z): %w", err)
|
||||||
}
|
}
|
||||||
startTime = val
|
startTime = val
|
||||||
} else {
|
} else {
|
||||||
@@ -151,7 +149,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
var endTime string
|
var endTime string
|
||||||
if val, ok := paramsMap["endTime"].(string); ok && val != "" {
|
if val, ok := paramsMap["endTime"].(string); ok && val != "" {
|
||||||
if _, err := time.Parse(time.RFC3339, val); err != nil {
|
if _, err := time.Parse(time.RFC3339, val); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("endTime must be in RFC3339 format (e.g., 2025-12-09T23:59:59Z): %v", err), err)
|
return nil, fmt.Errorf("endTime must be in RFC3339 format (e.g., 2025-12-09T23:59:59Z): %w", err)
|
||||||
}
|
}
|
||||||
endTime = val
|
endTime = val
|
||||||
}
|
}
|
||||||
@@ -160,7 +158,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if source.UseClientAuthorization() {
|
if source.UseClientAuthorization() {
|
||||||
tokenString, err = accessToken.ParseBearerToken()
|
tokenString, err = accessToken.ParseBearerToken()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("failed to parse access token", http.StatusUnauthorized, err)
|
return nil, fmt.Errorf("failed to parse access token: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,11 +171,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
Limit: limit,
|
Limit: limit,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.QueryLogs(ctx, queryParams, tokenString)
|
return source.QueryLogs(ctx, queryParams, tokenString)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {
|
func (t Tool) ParseParams(data map[string]any, claimsMap map[string]map[string]any) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -94,26 +93,22 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
projectID, ok := paramsMap["projectId"].(string)
|
projectID, ok := paramsMap["projectId"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("projectId parameter not found or not a string", nil)
|
return nil, fmt.Errorf("projectId parameter not found or not a string")
|
||||||
}
|
}
|
||||||
query, ok := paramsMap["query"].(string)
|
query, ok := paramsMap["query"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("query parameter not found or not a string", nil)
|
return nil, fmt.Errorf("query parameter not found or not a string")
|
||||||
}
|
}
|
||||||
resp, err := source.RunQuery(projectID, query)
|
return source.RunQuery(projectID, query)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqlcloneinstance
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
sqladmin "google.golang.org/api/sqladmin/v1"
|
sqladmin "google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -126,35 +124,31 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %v", paramsMap["project"]), nil)
|
return nil, fmt.Errorf("error casting 'project' parameter: %v", paramsMap["project"])
|
||||||
}
|
}
|
||||||
sourceInstanceName, ok := paramsMap["sourceInstanceName"].(string)
|
sourceInstanceName, ok := paramsMap["sourceInstanceName"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'sourceInstanceName' parameter: %v", paramsMap["sourceInstanceName"]), nil)
|
return nil, fmt.Errorf("error casting 'sourceInstanceName' parameter: %v", paramsMap["sourceInstanceName"])
|
||||||
}
|
}
|
||||||
destinationInstanceName, ok := paramsMap["destinationInstanceName"].(string)
|
destinationInstanceName, ok := paramsMap["destinationInstanceName"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'destinationInstanceName' parameter: %v", paramsMap["destinationInstanceName"]), nil)
|
return nil, fmt.Errorf("error casting 'destinationInstanceName' parameter: %v", paramsMap["destinationInstanceName"])
|
||||||
}
|
}
|
||||||
|
|
||||||
pointInTime, _ := paramsMap["pointInTime"].(string)
|
pointInTime, _ := paramsMap["pointInTime"].(string)
|
||||||
preferredZone, _ := paramsMap["preferredZone"].(string)
|
preferredZone, _ := paramsMap["preferredZone"].(string)
|
||||||
preferredSecondaryZone, _ := paramsMap["preferredSecondaryZone"].(string)
|
preferredSecondaryZone, _ := paramsMap["preferredSecondaryZone"].(string)
|
||||||
|
|
||||||
resp, err := source.CloneInstance(ctx, project, sourceInstanceName, destinationInstanceName, pointInTime, preferredZone, preferredSecondaryZone, string(accessToken))
|
return source.CloneInstance(ctx, project, sourceInstanceName, destinationInstanceName, pointInTime, preferredZone, preferredSecondaryZone, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqlcreatebackup
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/sqladmin/v1"
|
"google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -122,30 +120,26 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %v", paramsMap["project"]), nil)
|
return nil, fmt.Errorf("error casting 'project' parameter: %v", paramsMap["project"])
|
||||||
}
|
}
|
||||||
instance, ok := paramsMap["instance"].(string)
|
instance, ok := paramsMap["instance"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'instance' parameter: %v", paramsMap["instance"]), nil)
|
return nil, fmt.Errorf("error casting 'instance' parameter: %v", paramsMap["instance"])
|
||||||
}
|
}
|
||||||
|
|
||||||
location, _ := paramsMap["location"].(string)
|
location, _ := paramsMap["location"].(string)
|
||||||
description, _ := paramsMap["backup_description"].(string)
|
description, _ := paramsMap["backup_description"].(string)
|
||||||
|
|
||||||
resp, err := source.InsertBackupRun(ctx, project, instance, location, description, string(accessToken))
|
return source.InsertBackupRun(ctx, project, instance, location, description, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqlcreatedatabase
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,31 +117,27 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
instance, ok := paramsMap["instance"].(string)
|
instance, ok := paramsMap["instance"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'instance' parameter", nil)
|
return nil, fmt.Errorf("missing 'instance' parameter")
|
||||||
}
|
}
|
||||||
name, ok := paramsMap["name"].(string)
|
name, ok := paramsMap["name"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'name' parameter", nil)
|
return nil, fmt.Errorf("missing 'name' parameter")
|
||||||
}
|
}
|
||||||
resp, err := source.CreateDatabase(ctx, name, project, instance, string(accessToken))
|
return source.CreateDatabase(ctx, name, project, instance, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqlcreateusers
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -121,34 +119,30 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
instance, ok := paramsMap["instance"].(string)
|
instance, ok := paramsMap["instance"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'instance' parameter", nil)
|
return nil, fmt.Errorf("missing 'instance' parameter")
|
||||||
}
|
}
|
||||||
name, ok := paramsMap["name"].(string)
|
name, ok := paramsMap["name"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'name' parameter", nil)
|
return nil, fmt.Errorf("missing 'name' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
iamUser, _ := paramsMap["iamUser"].(bool)
|
iamUser, _ := paramsMap["iamUser"].(bool)
|
||||||
password, _ := paramsMap["password"].(string)
|
password, _ := paramsMap["password"].(string)
|
||||||
resp, err := source.CreateUsers(ctx, project, instance, name, password, iamUser, string(accessToken))
|
return source.CreateUsers(ctx, project, instance, name, password, iamUser, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqlgetinstances
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -119,27 +117,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
projectId, ok := paramsMap["projectId"].(string)
|
projectId, ok := paramsMap["projectId"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'projectId' parameter", nil)
|
return nil, fmt.Errorf("missing 'projectId' parameter")
|
||||||
}
|
}
|
||||||
instanceId, ok := paramsMap["instanceId"].(string)
|
instanceId, ok := paramsMap["instanceId"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'instanceId' parameter", nil)
|
return nil, fmt.Errorf("missing 'instanceId' parameter")
|
||||||
}
|
}
|
||||||
resp, err := source.GetInstance(ctx, projectId, instanceId, string(accessToken))
|
return source.GetInstance(ctx, projectId, instanceId, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqllistdatabases
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -118,27 +116,23 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
instance, ok := paramsMap["instance"].(string)
|
instance, ok := paramsMap["instance"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'instance' parameter", nil)
|
return nil, fmt.Errorf("missing 'instance' parameter")
|
||||||
}
|
}
|
||||||
resp, err := source.ListDatabase(ctx, project, instance, string(accessToken))
|
return source.ListDatabase(ctx, project, instance, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqllistinstances
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -117,23 +115,19 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
resp, err := source.ListInstance(ctx, project, string(accessToken))
|
return source.ListInstance(ctx, project, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package cloudsqlrestorebackup
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/sqladmin/v1"
|
"google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -122,33 +120,29 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
targetProject, ok := paramsMap["target_project"].(string)
|
targetProject, ok := paramsMap["target_project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'target_project' parameter: %v", paramsMap["target_project"]), nil)
|
return nil, fmt.Errorf("error casting 'target_project' parameter: %v", paramsMap["target_project"])
|
||||||
}
|
}
|
||||||
targetInstance, ok := paramsMap["target_instance"].(string)
|
targetInstance, ok := paramsMap["target_instance"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'target_instance' parameter: %v", paramsMap["target_instance"]), nil)
|
return nil, fmt.Errorf("error casting 'target_instance' parameter: %v", paramsMap["target_instance"])
|
||||||
}
|
}
|
||||||
backupID, ok := paramsMap["backup_id"].(string)
|
backupID, ok := paramsMap["backup_id"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'backup_id' parameter: %v", paramsMap["backup_id"]), nil)
|
return nil, fmt.Errorf("error casting 'backup_id' parameter: %v", paramsMap["backup_id"])
|
||||||
}
|
}
|
||||||
sourceProject, _ := paramsMap["source_project"].(string)
|
sourceProject, _ := paramsMap["source_project"].(string)
|
||||||
sourceInstance, _ := paramsMap["source_instance"].(string)
|
sourceInstance, _ := paramsMap["source_instance"].(string)
|
||||||
|
|
||||||
resp, err := source.RestoreBackup(ctx, targetProject, targetInstance, sourceProject, sourceInstance, backupID, string(accessToken))
|
return source.RestoreBackup(ctx, targetProject, targetInstance, sourceProject, sourceInstance, backupID, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package cloudsqlwaitforoperation
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/sqladmin/v1"
|
"google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -212,21 +210,21 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
operationID, ok := paramsMap["operation"].(string)
|
operationID, ok := paramsMap["operation"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'operation' parameter", nil)
|
return nil, fmt.Errorf("missing 'operation' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
|
ctx, cancel := context.WithTimeout(ctx, 30*time.Minute)
|
||||||
@@ -234,7 +232,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
service, err := source.GetService(ctx, string(accessToken))
|
service, err := source.GetService(ctx, string(accessToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
delay := t.Delay
|
delay := t.Delay
|
||||||
@@ -246,13 +244,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
for retries < maxRetries {
|
for retries < maxRetries {
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, util.NewClientServerError("timed out waiting for operation", http.StatusRequestTimeout, ctx.Err())
|
return nil, fmt.Errorf("timed out waiting for operation: %w", ctx.Err())
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
op, err := source.GetWaitForOperations(ctx, service, project, operationID, cloudSQLConnectionMessageTemplate, delay)
|
op, err := source.GetWaitForOperations(ctx, service, project, operationID, cloudSQLConnectionMessageTemplate, delay)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, err
|
||||||
} else if op != nil {
|
} else if op != nil {
|
||||||
return op, nil
|
return op, nil
|
||||||
}
|
}
|
||||||
@@ -264,7 +262,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
}
|
}
|
||||||
retries++
|
retries++
|
||||||
}
|
}
|
||||||
return nil, util.NewClientServerError("exceeded max retries waiting for operation", http.StatusGatewayTimeout, fmt.Errorf("exceeded max retries"))
|
return nil, fmt.Errorf("exceeded max retries waiting for operation")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package cloudsqlmssqlcreateinstance
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/sqladmin/v1"
|
"google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -123,33 +121,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'project' parameter: %s", paramsMap["project"]), nil)
|
return nil, fmt.Errorf("error casting 'project' parameter: %s", paramsMap["project"])
|
||||||
}
|
}
|
||||||
name, ok := paramsMap["name"].(string)
|
name, ok := paramsMap["name"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'name' parameter: %s", paramsMap["name"]), nil)
|
return nil, fmt.Errorf("error casting 'name' parameter: %s", paramsMap["name"])
|
||||||
}
|
}
|
||||||
dbVersion, ok := paramsMap["databaseVersion"].(string)
|
dbVersion, ok := paramsMap["databaseVersion"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'databaseVersion' parameter: %s", paramsMap["databaseVersion"]), nil)
|
return nil, fmt.Errorf("error casting 'databaseVersion' parameter: %s", paramsMap["databaseVersion"])
|
||||||
}
|
}
|
||||||
rootPassword, ok := paramsMap["rootPassword"].(string)
|
rootPassword, ok := paramsMap["rootPassword"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'rootPassword' parameter: %s", paramsMap["rootPassword"]), nil)
|
return nil, fmt.Errorf("error casting 'rootPassword' parameter: %s", paramsMap["rootPassword"])
|
||||||
}
|
}
|
||||||
editionPreset, ok := paramsMap["editionPreset"].(string)
|
editionPreset, ok := paramsMap["editionPreset"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'editionPreset' parameter: %s", paramsMap["editionPreset"]), nil)
|
return nil, fmt.Errorf("error casting 'editionPreset' parameter: %s", paramsMap["editionPreset"])
|
||||||
}
|
}
|
||||||
settings := sqladmin.Settings{}
|
settings := sqladmin.Settings{}
|
||||||
switch strings.ToLower(editionPreset) {
|
switch strings.ToLower(editionPreset) {
|
||||||
@@ -166,13 +164,9 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
settings.DataDiskSizeGb = 100
|
settings.DataDiskSizeGb = 100
|
||||||
settings.DataDiskType = "PD_SSD"
|
settings.DataDiskType = "PD_SSD"
|
||||||
default:
|
default:
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset), nil)
|
return nil, fmt.Errorf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset)
|
||||||
}
|
}
|
||||||
resp, err := source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
|
return source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package cloudsqlmysqlcreateinstance
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
sqladmin "google.golang.org/api/sqladmin/v1"
|
sqladmin "google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -123,33 +121,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
name, ok := paramsMap["name"].(string)
|
name, ok := paramsMap["name"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'name' parameter", nil)
|
return nil, fmt.Errorf("missing 'name' parameter")
|
||||||
}
|
}
|
||||||
dbVersion, ok := paramsMap["databaseVersion"].(string)
|
dbVersion, ok := paramsMap["databaseVersion"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'databaseVersion' parameter", nil)
|
return nil, fmt.Errorf("missing 'databaseVersion' parameter")
|
||||||
}
|
}
|
||||||
rootPassword, ok := paramsMap["rootPassword"].(string)
|
rootPassword, ok := paramsMap["rootPassword"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'rootPassword' parameter", nil)
|
return nil, fmt.Errorf("missing 'rootPassword' parameter")
|
||||||
}
|
}
|
||||||
editionPreset, ok := paramsMap["editionPreset"].(string)
|
editionPreset, ok := paramsMap["editionPreset"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'editionPreset' parameter", nil)
|
return nil, fmt.Errorf("missing 'editionPreset' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := sqladmin.Settings{}
|
settings := sqladmin.Settings{}
|
||||||
@@ -167,14 +165,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
settings.DataDiskSizeGb = 100
|
settings.DataDiskSizeGb = 100
|
||||||
settings.DataDiskType = "PD_SSD"
|
settings.DataDiskType = "PD_SSD"
|
||||||
default:
|
default:
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset), nil)
|
return nil, fmt.Errorf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset)
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
|
return source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package cloudsqlpgcreateinstances
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
sqladmin "google.golang.org/api/sqladmin/v1"
|
sqladmin "google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -123,33 +121,33 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'project' parameter", nil)
|
return nil, fmt.Errorf("missing 'project' parameter")
|
||||||
}
|
}
|
||||||
name, ok := paramsMap["name"].(string)
|
name, ok := paramsMap["name"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'name' parameter", nil)
|
return nil, fmt.Errorf("missing 'name' parameter")
|
||||||
}
|
}
|
||||||
dbVersion, ok := paramsMap["databaseVersion"].(string)
|
dbVersion, ok := paramsMap["databaseVersion"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'databaseVersion' parameter", nil)
|
return nil, fmt.Errorf("missing 'databaseVersion' parameter")
|
||||||
}
|
}
|
||||||
rootPassword, ok := paramsMap["rootPassword"].(string)
|
rootPassword, ok := paramsMap["rootPassword"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'rootPassword' parameter", nil)
|
return nil, fmt.Errorf("missing 'rootPassword' parameter")
|
||||||
}
|
}
|
||||||
editionPreset, ok := paramsMap["editionPreset"].(string)
|
editionPreset, ok := paramsMap["editionPreset"].(string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("missing 'editionPreset' parameter", nil)
|
return nil, fmt.Errorf("missing 'editionPreset' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
settings := sqladmin.Settings{}
|
settings := sqladmin.Settings{}
|
||||||
@@ -167,13 +165,9 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
settings.DataDiskSizeGb = 100
|
settings.DataDiskSizeGb = 100
|
||||||
settings.DataDiskType = "PD_SSD"
|
settings.DataDiskType = "PD_SSD"
|
||||||
default:
|
default:
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset), nil)
|
return nil, fmt.Errorf("invalid 'editionPreset': %q. Must be either 'Production' or 'Development'", editionPreset)
|
||||||
}
|
}
|
||||||
resp, err := source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
|
return source.CreateInstance(ctx, project, name, dbVersion, rootPassword, settings, string(accessToken))
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package cloudsqlpgupgradeprecheck
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
sqladmin "google.golang.org/api/sqladmin/v1"
|
sqladmin "google.golang.org/api/sqladmin/v1"
|
||||||
)
|
)
|
||||||
@@ -134,31 +132,31 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the tool's logic.
|
// Invoke executes the tool's logic.
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
|
|
||||||
project, ok := paramsMap["project"].(string)
|
project, ok := paramsMap["project"].(string)
|
||||||
if !ok || project == "" {
|
if !ok || project == "" {
|
||||||
return nil, util.NewAgentError("missing or empty 'project' parameter", nil)
|
return nil, fmt.Errorf("missing or empty 'project' parameter")
|
||||||
}
|
}
|
||||||
instanceName, ok := paramsMap["instance"].(string)
|
instanceName, ok := paramsMap["instance"].(string)
|
||||||
if !ok || instanceName == "" {
|
if !ok || instanceName == "" {
|
||||||
return nil, util.NewAgentError("missing or empty 'instance' parameter", nil)
|
return nil, fmt.Errorf("missing or empty 'instance' parameter")
|
||||||
}
|
}
|
||||||
targetVersion, ok := paramsMap["targetDatabaseVersion"].(string)
|
targetVersion, ok := paramsMap["targetDatabaseVersion"].(string)
|
||||||
if !ok || targetVersion == "" {
|
if !ok || targetVersion == "" {
|
||||||
// This should not happen due to the default value
|
// This should not happen due to the default value
|
||||||
return nil, util.NewAgentError("missing or empty 'targetDatabaseVersion' parameter", nil)
|
return nil, fmt.Errorf("missing or empty 'targetDatabaseVersion' parameter")
|
||||||
}
|
}
|
||||||
|
|
||||||
service, err := source.GetService(ctx, string(accessToken))
|
service, err := source.GetService(ctx, string(accessToken))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to get HTTP client from source: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
reqBody := &sqladmin.InstancesPreCheckMajorVersionUpgradeRequest{
|
reqBody := &sqladmin.InstancesPreCheckMajorVersionUpgradeRequest{
|
||||||
@@ -170,7 +168,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
call := service.Instances.PreCheckMajorVersionUpgrade(project, instanceName, reqBody).Context(ctx)
|
call := service.Instances.PreCheckMajorVersionUpgrade(project, instanceName, reqBody).Context(ctx)
|
||||||
op, err := call.Do()
|
op, err := call.Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to start pre-check operation: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
const pollTimeout = 20 * time.Second
|
const pollTimeout = 20 * time.Second
|
||||||
@@ -179,7 +177,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
for time.Now().Before(cutoffTime) {
|
for time.Now().Before(cutoffTime) {
|
||||||
currentOp, err := service.Operations.Get(project, op.Name).Context(ctx).Do()
|
currentOp, err := service.Operations.Get(project, op.Name).Context(ctx).Do()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, fmt.Errorf("failed to get operation status: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if currentOp.Status == "DONE" {
|
if currentOp.Status == "DONE" {
|
||||||
@@ -188,7 +186,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if currentOp.Error.Errors[0].Code != "" {
|
if currentOp.Error.Errors[0].Code != "" {
|
||||||
errMsg = fmt.Sprintf("%s (Code: %s)", errMsg, currentOp.Error.Errors[0].Code)
|
errMsg = fmt.Sprintf("%s (Code: %s)", errMsg, currentOp.Error.Errors[0].Code)
|
||||||
}
|
}
|
||||||
return nil, util.NewClientServerError(errMsg, http.StatusInternalServerError, fmt.Errorf("pre-check operation failed with error: %s", errMsg))
|
return nil, fmt.Errorf("%s", errMsg)
|
||||||
}
|
}
|
||||||
|
|
||||||
var preCheckItems []*sqladmin.PreCheckResponse
|
var preCheckItems []*sqladmin.PreCheckResponse
|
||||||
@@ -201,7 +199,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
|
|
||||||
select {
|
select {
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return nil, util.NewClientServerError("timed out waiting for operation", http.StatusRequestTimeout, ctx.Err())
|
return nil, ctx.Err()
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package dataplexlookupentry
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
dataplexpb "cloud.google.com/go/dataplex/apiv1/dataplexpb"
|
dataplexpb "cloud.google.com/go/dataplex/apiv1/dataplexpb"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -112,10 +110,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
@@ -124,14 +122,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
view, _ := paramsMap["view"].(int)
|
view, _ := paramsMap["view"].(int)
|
||||||
aspectTypeSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["aspectTypes"].([]any), "string")
|
aspectTypeSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["aspectTypes"].([]any), "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("can't convert aspectTypes to array of strings: %s", err), err)
|
return nil, fmt.Errorf("can't convert aspectTypes to array of strings: %s", err)
|
||||||
}
|
}
|
||||||
aspectTypes := aspectTypeSlice.([]string)
|
aspectTypes := aspectTypeSlice.([]string)
|
||||||
resp, err := source.LookupEntry(ctx, name, view, aspectTypes, entry)
|
return source.LookupEntry(ctx, name, view, aspectTypes, entry)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package dataplexsearchaspecttypes
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"cloud.google.com/go/dataplex/apiv1/dataplexpb"
|
"cloud.google.com/go/dataplex/apiv1/dataplexpb"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -95,29 +93,16 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
query, ok := paramsMap["query"].(string)
|
query, _ := paramsMap["query"].(string)
|
||||||
if !ok {
|
pageSize, _ := paramsMap["pageSize"].(int)
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'query' parameter: %v", paramsMap["query"]), nil)
|
orderBy, _ := paramsMap["orderBy"].(string)
|
||||||
}
|
return source.SearchAspectTypes(ctx, query, pageSize, orderBy)
|
||||||
pageSize, ok := paramsMap["pageSize"].(int)
|
|
||||||
if !ok {
|
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'pageSize' parameter: %v", paramsMap["pageSize"]), nil)
|
|
||||||
}
|
|
||||||
orderBy, ok := paramsMap["orderBy"].(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'orderBy' parameter: %v", paramsMap["orderBy"]), nil)
|
|
||||||
}
|
|
||||||
resp, err := source.SearchAspectTypes(ctx, query, pageSize, orderBy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,14 +17,12 @@ package dataplexsearchentries
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"cloud.google.com/go/dataplex/apiv1/dataplexpb"
|
"cloud.google.com/go/dataplex/apiv1/dataplexpb"
|
||||||
"github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -95,29 +93,16 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
query, ok := paramsMap["query"].(string)
|
query, _ := paramsMap["query"].(string)
|
||||||
if !ok {
|
pageSize, _ := paramsMap["pageSize"].(int)
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'query' parameter: %v", paramsMap["query"]), nil)
|
orderBy, _ := paramsMap["orderBy"].(string)
|
||||||
}
|
return source.SearchEntries(ctx, query, pageSize, orderBy)
|
||||||
pageSize, ok := paramsMap["pageSize"].(int)
|
|
||||||
if !ok {
|
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'pageSize' parameter: %v", paramsMap["pageSize"]), nil)
|
|
||||||
}
|
|
||||||
orderBy, ok := paramsMap["orderBy"].(string)
|
|
||||||
if !ok {
|
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("error casting 'orderBy' parameter: %v", paramsMap["orderBy"]), nil)
|
|
||||||
}
|
|
||||||
resp, err := source.SearchEntries(ctx, query, pageSize, orderBy)
|
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ package firestoreadddocuments
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
firestoreapi "cloud.google.com/go/firestore"
|
firestoreapi "cloud.google.com/go/firestore"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
"github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -130,32 +128,32 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
// Get collection path
|
// Get collection path
|
||||||
collectionPath, ok := mapParams[collectionPathKey].(string)
|
collectionPath, ok := mapParams[collectionPathKey].(string)
|
||||||
if !ok || collectionPath == "" {
|
if !ok || collectionPath == "" {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter", collectionPathKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter", collectionPathKey)
|
||||||
}
|
}
|
||||||
// Validate collection path
|
// Validate collection path
|
||||||
if err := fsUtil.ValidateCollectionPath(collectionPath); err != nil {
|
if err := util.ValidateCollectionPath(collectionPath); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid collection path: %v", err), err)
|
return nil, fmt.Errorf("invalid collection path: %w", err)
|
||||||
}
|
}
|
||||||
// Get document data
|
// Get document data
|
||||||
documentDataRaw, ok := mapParams[documentDataKey]
|
documentDataRaw, ok := mapParams[documentDataKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter", documentDataKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter", documentDataKey)
|
||||||
}
|
}
|
||||||
// Convert the document data from JSON format to Firestore format
|
// Convert the document data from JSON format to Firestore format
|
||||||
// The client is passed to handle referenceValue types
|
// The client is passed to handle referenceValue types
|
||||||
documentData, err := fsUtil.JSONToFirestoreValue(documentDataRaw, source.FirestoreClient())
|
documentData, err := util.JSONToFirestoreValue(documentDataRaw, source.FirestoreClient())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to convert document data: %v", err), err)
|
return nil, fmt.Errorf("failed to convert document data: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get return document data flag
|
// Get return document data flag
|
||||||
@@ -163,11 +161,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
if val, ok := mapParams[returnDocumentDataKey].(bool); ok {
|
if val, ok := mapParams[returnDocumentDataKey].(bool); ok {
|
||||||
returnData = val
|
returnData = val
|
||||||
}
|
}
|
||||||
resp, err := source.AddDocuments(ctx, collectionPath, documentData, returnData)
|
return source.AddDocuments(ctx, collectionPath, documentData, returnData)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ package firestoredeletedocuments
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
firestoreapi "cloud.google.com/go/firestore"
|
firestoreapi "cloud.google.com/go/firestore"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
"github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,43 +94,39 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
documentPathsRaw, ok := mapParams[documentPathsKey].([]any)
|
documentPathsRaw, ok := mapParams[documentPathsKey].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected an array", documentPathsKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected an array", documentPathsKey)
|
||||||
}
|
}
|
||||||
if len(documentPathsRaw) == 0 {
|
if len(documentPathsRaw) == 0 {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("'%s' parameter cannot be empty", documentPathsKey), nil)
|
return nil, fmt.Errorf("'%s' parameter cannot be empty", documentPathsKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use ConvertAnySliceToTyped to convert the slice
|
// Use ConvertAnySliceToTyped to convert the slice
|
||||||
typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string")
|
typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to convert document paths: %v", err), err)
|
return nil, fmt.Errorf("failed to convert document paths: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
documentPaths, ok := typedSlice.([]string)
|
documentPaths, ok := typedSlice.([]string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("unexpected type conversion error for document paths", nil)
|
return nil, fmt.Errorf("unexpected type conversion error for document paths")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate each document path
|
// Validate each document path
|
||||||
for i, path := range documentPaths {
|
for i, path := range documentPaths {
|
||||||
if err := fsUtil.ValidateDocumentPath(path); err != nil {
|
if err := util.ValidateDocumentPath(path); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid document path at index %d: %v", i, err), err)
|
return nil, fmt.Errorf("invalid document path at index %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.DeleteDocuments(ctx, documentPaths)
|
return source.DeleteDocuments(ctx, documentPaths)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ package firestoregetdocuments
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
firestoreapi "cloud.google.com/go/firestore"
|
firestoreapi "cloud.google.com/go/firestore"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
"github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -96,44 +94,40 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
documentPathsRaw, ok := mapParams[documentPathsKey].([]any)
|
documentPathsRaw, ok := mapParams[documentPathsKey].([]any)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid or missing '%s' parameter; expected an array", documentPathsKey), nil)
|
return nil, fmt.Errorf("invalid or missing '%s' parameter; expected an array", documentPathsKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(documentPathsRaw) == 0 {
|
if len(documentPathsRaw) == 0 {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("'%s' parameter cannot be empty", documentPathsKey), nil)
|
return nil, fmt.Errorf("'%s' parameter cannot be empty", documentPathsKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use ConvertAnySliceToTyped to convert the slice
|
// Use ConvertAnySliceToTyped to convert the slice
|
||||||
typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string")
|
typedSlice, err := parameters.ConvertAnySliceToTyped(documentPathsRaw, "string")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to convert document paths: %v", err), err)
|
return nil, fmt.Errorf("failed to convert document paths: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
documentPaths, ok := typedSlice.([]string)
|
documentPaths, ok := typedSlice.([]string)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, util.NewAgentError("unexpected type conversion error for document paths", nil)
|
return nil, fmt.Errorf("unexpected type conversion error for document paths")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate each document path
|
// Validate each document path
|
||||||
for i, path := range documentPaths {
|
for i, path := range documentPaths {
|
||||||
if err := fsUtil.ValidateDocumentPath(path); err != nil {
|
if err := util.ValidateDocumentPath(path); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid document path at index %d: %v", i, err), err)
|
return nil, fmt.Errorf("invalid document path at index %d: %w", i, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.GetDocuments(ctx, documentPaths)
|
return source.GetDocuments(ctx, documentPaths)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,13 +17,11 @@ package firestoregetrules
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
"google.golang.org/api/firebaserules/v1"
|
"google.golang.org/api/firebaserules/v1"
|
||||||
)
|
)
|
||||||
@@ -94,16 +92,12 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
resp, err := source.GetRules(ctx)
|
return source.GetRules(ctx)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -17,15 +17,13 @@ package firestorelistcollections
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
|
|
||||||
firestoreapi "cloud.google.com/go/firestore"
|
firestoreapi "cloud.google.com/go/firestore"
|
||||||
yaml "github.com/goccy/go-yaml"
|
yaml "github.com/goccy/go-yaml"
|
||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
"github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -97,10 +95,10 @@ func (t Tool) ToConfig() tools.ToolConfig {
|
|||||||
return t.Config
|
return t.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
mapParams := params.AsMap()
|
mapParams := params.AsMap()
|
||||||
@@ -109,15 +107,11 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
parentPath, _ := mapParams[parentPathKey].(string)
|
parentPath, _ := mapParams[parentPathKey].(string)
|
||||||
if parentPath != "" {
|
if parentPath != "" {
|
||||||
// Validate parent document path
|
// Validate parent document path
|
||||||
if err := fsUtil.ValidateDocumentPath(parentPath); err != nil {
|
if err := util.ValidateDocumentPath(parentPath); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("invalid parent document path: %v", err), err)
|
return nil, fmt.Errorf("invalid parent document path: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resp, err := source.ListCollections(ctx, parentPath)
|
return source.ListCollections(ctx, parentPath)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
func (t Tool) EmbedParams(ctx context.Context, paramValues parameters.ParamValues, embeddingModelsMap map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error) {
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -27,8 +26,7 @@ import (
|
|||||||
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
"github.com/googleapis/genai-toolbox/internal/embeddingmodels"
|
||||||
"github.com/googleapis/genai-toolbox/internal/sources"
|
"github.com/googleapis/genai-toolbox/internal/sources"
|
||||||
"github.com/googleapis/genai-toolbox/internal/tools"
|
"github.com/googleapis/genai-toolbox/internal/tools"
|
||||||
fsUtil "github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
"github.com/googleapis/genai-toolbox/internal/tools/firestore/util"
|
||||||
"github.com/googleapis/genai-toolbox/internal/util"
|
|
||||||
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
"github.com/googleapis/genai-toolbox/internal/util/parameters"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -160,16 +158,16 @@ var validOperators = map[string]bool{
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Invoke executes the Firestore query based on the provided parameters
|
// Invoke executes the Firestore query based on the provided parameters
|
||||||
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, util.ToolboxError) {
|
func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, params parameters.ParamValues, accessToken tools.AccessToken) (any, error) {
|
||||||
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewClientServerError("source used is not compatible with the tool", http.StatusInternalServerError, err)
|
return nil, err
|
||||||
}
|
}
|
||||||
paramsMap := params.AsMap()
|
paramsMap := params.AsMap()
|
||||||
// Process collection path with template substitution
|
// Process collection path with template substitution
|
||||||
collectionPath, err := parameters.PopulateTemplate("collectionPath", t.CollectionPath, paramsMap)
|
collectionPath, err := parameters.PopulateTemplate("collectionPath", t.CollectionPath, paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to process collection path: %v", err), err)
|
return nil, fmt.Errorf("failed to process collection path: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter firestoreapi.EntityFilter
|
var filter firestoreapi.EntityFilter
|
||||||
@@ -178,13 +176,13 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Apply template substitution to filters
|
// Apply template substitution to filters
|
||||||
filtersJSON, err := parameters.PopulateTemplateWithJSON("filters", t.Filters, paramsMap)
|
filtersJSON, err := parameters.PopulateTemplateWithJSON("filters", t.Filters, paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to process filters template: %v", err), err)
|
return nil, fmt.Errorf("failed to process filters template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the simplified filter format
|
// Parse the simplified filter format
|
||||||
var simplifiedFilter SimplifiedFilter
|
var simplifiedFilter SimplifiedFilter
|
||||||
if err := json.Unmarshal([]byte(filtersJSON), &simplifiedFilter); err != nil {
|
if err := json.Unmarshal([]byte(filtersJSON), &simplifiedFilter); err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to parse filters: %v", err), err)
|
return nil, fmt.Errorf("failed to parse filters: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert simplified filter to Firestore filter
|
// Convert simplified filter to Firestore filter
|
||||||
@@ -193,17 +191,17 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Process and apply ordering
|
// Process and apply ordering
|
||||||
orderBy, err := t.getOrderBy(paramsMap)
|
orderBy, err := t.getOrderBy(paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to process order by: %v", err), err)
|
return nil, err
|
||||||
}
|
}
|
||||||
// Process select fields
|
// Process select fields
|
||||||
selectFields, err := t.processSelectFields(paramsMap)
|
selectFields, err := t.processSelectFields(paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to process select fields: %v", err), err)
|
return nil, err
|
||||||
}
|
}
|
||||||
// Process and apply limit
|
// Process and apply limit
|
||||||
limit, err := t.getLimit(paramsMap)
|
limit, err := t.getLimit(paramsMap)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.NewAgentError(fmt.Sprintf("failed to process limit: %v", err), err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent panic when accessing orderBy incase it is nil
|
// prevent panic when accessing orderBy incase it is nil
|
||||||
@@ -217,14 +215,10 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
|
|||||||
// Build the query
|
// Build the query
|
||||||
query, err := source.BuildQuery(collectionPath, filter, selectFields, orderByField, orderByDirection, limit, t.AnalyzeQuery)
|
query, err := source.BuildQuery(collectionPath, filter, selectFields, orderByField, orderByDirection, limit, t.AnalyzeQuery)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, util.ProecessGcpError(err)
|
return nil, err
|
||||||
}
|
}
|
||||||
// Execute the query and return results
|
// Execute the query and return results
|
||||||
resp, err := source.ExecuteQuery(ctx, query, t.AnalyzeQuery)
|
return source.ExecuteQuery(ctx, query, t.AnalyzeQuery)
|
||||||
if err != nil {
|
|
||||||
return nil, util.ProecessGcpError(err)
|
|
||||||
}
|
|
||||||
return resp, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// convertToFirestoreFilter converts simplified filter format to Firestore EntityFilter
|
// convertToFirestoreFilter converts simplified filter format to Firestore EntityFilter
|
||||||
@@ -261,7 +255,7 @@ func (t Tool) convertToFirestoreFilter(source compatibleSource, filter Simplifie
|
|||||||
if filter.Field != "" && filter.Op != "" && filter.Value != nil {
|
if filter.Field != "" && filter.Op != "" && filter.Value != nil {
|
||||||
if validOperators[filter.Op] {
|
if validOperators[filter.Op] {
|
||||||
// Convert the value using the Firestore native JSON converter
|
// Convert the value using the Firestore native JSON converter
|
||||||
convertedValue, err := fsUtil.JSONToFirestoreValue(filter.Value, source.FirestoreClient())
|
convertedValue, err := util.JSONToFirestoreValue(filter.Value, source.FirestoreClient())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If conversion fails, use the original value
|
// If conversion fails, use the original value
|
||||||
convertedValue = filter.Value
|
convertedValue = filter.Value
|
||||||
@@ -373,7 +367,7 @@ func (t Tool) getLimit(params map[string]any) (int, error) {
|
|||||||
if processedValue != "" {
|
if processedValue != "" {
|
||||||
parsedLimit, err := strconv.Atoi(processedValue)
|
parsedLimit, err := strconv.Atoi(processedValue)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, fmt.Errorf("failed to parse limit value '%s': %w", processedValue, err)
|
||||||
}
|
}
|
||||||
limit = parsedLimit
|
limit = parsedLimit
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ package tools
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -81,13 +80,13 @@ type AccessToken string
|
|||||||
func (token AccessToken) ParseBearerToken() (string, error) {
|
func (token AccessToken) ParseBearerToken() (string, error) {
|
||||||
headerParts := strings.Split(string(token), " ")
|
headerParts := strings.Split(string(token), " ")
|
||||||
if len(headerParts) != 2 || strings.ToLower(headerParts[0]) != "bearer" {
|
if len(headerParts) != 2 || strings.ToLower(headerParts[0]) != "bearer" {
|
||||||
return "", util.NewClientServerError("authorization header must be in the format 'Bearer <token>'", http.StatusUnauthorized, nil)
|
return "", fmt.Errorf("authorization header must be in the format 'Bearer <token>': %w", util.ErrUnauthorized)
|
||||||
}
|
}
|
||||||
return headerParts[1], nil
|
return headerParts[1], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tool interface {
|
type Tool interface {
|
||||||
Invoke(context.Context, SourceProvider, parameters.ParamValues, AccessToken) (any, util.ToolboxError)
|
Invoke(context.Context, SourceProvider, parameters.ParamValues, AccessToken) (any, error)
|
||||||
EmbedParams(context.Context, parameters.ParamValues, map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error)
|
EmbedParams(context.Context, parameters.ParamValues, map[string]embeddingmodels.EmbeddingModel) (parameters.ParamValues, error)
|
||||||
Manifest() Manifest
|
Manifest() Manifest
|
||||||
McpManifest() McpManifest
|
McpManifest() McpManifest
|
||||||
|
|||||||
@@ -1,122 +0,0 @@
|
|||||||
// Copyright 2026 Google LLC
|
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
// you may not use this file except in compliance with the License.
|
|
||||||
// You may obtain a copy of the License at
|
|
||||||
//
|
|
||||||
// http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
//
|
|
||||||
// Unless required by applicable law or agreed to in writing, software
|
|
||||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
// See the License for the specific language governing permissions and
|
|
||||||
// limitations under the License.
|
|
||||||
package util
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"google.golang.org/api/googleapi"
|
|
||||||
)
|
|
||||||
|
|
||||||
type ErrorCategory string
|
|
||||||
|
|
||||||
const (
|
|
||||||
CategoryAgent ErrorCategory = "AGENT_ERROR"
|
|
||||||
CategoryServer ErrorCategory = "SERVER_ERROR"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ToolboxError is the interface all custom errors must satisfy
|
|
||||||
type ToolboxError interface {
|
|
||||||
error
|
|
||||||
Category() ErrorCategory
|
|
||||||
}
|
|
||||||
|
|
||||||
// Agent Errors return 200 to the sender
|
|
||||||
type AgentError struct {
|
|
||||||
Msg string
|
|
||||||
Cause error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *AgentError) Error() string { return e.Msg }
|
|
||||||
|
|
||||||
func (e *AgentError) Category() ErrorCategory { return CategoryAgent }
|
|
||||||
|
|
||||||
func (e *AgentError) Unwrap() error { return e.Cause }
|
|
||||||
|
|
||||||
func NewAgentError(msg string, cause error) *AgentError {
|
|
||||||
return &AgentError{Msg: msg, Cause: cause}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientServerError returns 4XX/5XX error code
|
|
||||||
type ClientServerError struct {
|
|
||||||
Msg string
|
|
||||||
Code int
|
|
||||||
Cause error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (e *ClientServerError) Error() string { return fmt.Sprintf("%s: %v", e.Msg, e.Cause) }
|
|
||||||
|
|
||||||
func (e *ClientServerError) Category() ErrorCategory { return CategoryServer }
|
|
||||||
|
|
||||||
func (e *ClientServerError) Unwrap() error { return e.Cause }
|
|
||||||
|
|
||||||
func NewClientServerError(msg string, code int, cause error) *ClientServerError {
|
|
||||||
return &ClientServerError{Msg: msg, Code: code, Cause: cause}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProecessGcpError catches auth related errors and return 401/403 error codes
|
|
||||||
// Returns AgentError for all other errors
|
|
||||||
func ProecessGcpError(err error) ToolboxError {
|
|
||||||
var gErr *googleapi.Error
|
|
||||||
if errors.As(err, &gErr) {
|
|
||||||
if gErr.Code == 401 {
|
|
||||||
return NewClientServerError(
|
|
||||||
"failed to access GCP resource",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if gErr.Code == 403 {
|
|
||||||
return NewClientServerError(
|
|
||||||
"failed to access GCP resource",
|
|
||||||
http.StatusForbidden,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NewAgentError("error processing GCP request", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ProcessGeneralError handles generic errors by inspecting the error string
|
|
||||||
// for common status code patterns.
|
|
||||||
func ProcessGeneralError(err error) ToolboxError {
|
|
||||||
if err == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
errStr := err.Error()
|
|
||||||
|
|
||||||
// Check for Unauthorized
|
|
||||||
if strings.Contains(errStr, "Error 401") || strings.Contains(errStr, "status 401") {
|
|
||||||
return NewClientServerError(
|
|
||||||
"failed to access resource",
|
|
||||||
http.StatusUnauthorized,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for Forbidden
|
|
||||||
if strings.Contains(errStr, "Error 403") || strings.Contains(errStr, "status 403") {
|
|
||||||
return NewClientServerError(
|
|
||||||
"failed to access resource",
|
|
||||||
http.StatusForbidden,
|
|
||||||
err,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to AgentError for logical failures (task execution failed)
|
|
||||||
return NewAgentError("error processing request", err)
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"slices"
|
"slices"
|
||||||
@@ -119,7 +118,7 @@ func parseFromAuthService(paramAuthServices []ParamAuthService, claimsMap map[st
|
|||||||
}
|
}
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
return nil, util.NewClientServerError("missing or invalid authentication header", http.StatusUnauthorized, nil)
|
return nil, fmt.Errorf("missing or invalid authentication header: %w", util.ErrUnauthorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckParamRequired checks if a parameter is required based on the required and default field.
|
// CheckParamRequired checks if a parameter is required based on the required and default field.
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -187,3 +188,5 @@ func InstrumentationFromContext(ctx context.Context) (*telemetry.Instrumentation
|
|||||||
}
|
}
|
||||||
return nil, fmt.Errorf("unable to retrieve instrumentation")
|
return nil, fmt.Errorf("unable to retrieve instrumentation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var ErrUnauthorized = errors.New("unauthorized")
|
||||||
|
|||||||
Reference in New Issue
Block a user