diff --git a/docs/en/resources/sources/spanner-admin.md b/docs/en/resources/sources/spanner-admin.md index 8926315d73..91aabf45dd 100644 --- a/docs/en/resources/sources/spanner-admin.md +++ b/docs/en/resources/sources/spanner-admin.md @@ -24,19 +24,20 @@ Authentication can be handled in two ways: ## Example ```yaml -sources: - my-spanner-admin: - kind: spanner-admin - - my-oauth-spanner-admin: - kind: spanner-admin - useClientOAuth: true +kind: sources +name: my-spanner-admin +type: spanner-admin +--- +kind: sources +name: my-oauth-spanner-admin +type: spanner-admin +useClientOAuth: true ``` ## Reference | **field** | **type** | **required** | **description** | | -------------- | :------: | :----------: | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| kind | string | true | Must be "spanner-admin". | +| type | string | true | Must be "spanner-admin". | | defaultProject | string | false | The Google Cloud project ID to use for Spanner infrastructure tools. | | useClientOAuth | boolean | false | If true, the source will use client-side OAuth for authorization. Otherwise, it will use Application Default Credentials. Defaults to `false`. | diff --git a/docs/en/resources/tools/spanneradmin/spanner-create-instance.md b/docs/en/resources/tools/spanneradmin/spanner-create-instance.md index 80ed99f785..5f98079980 100644 --- a/docs/en/resources/tools/spanneradmin/spanner-create-instance.md +++ b/docs/en/resources/tools/spanneradmin/spanner-create-instance.md @@ -18,15 +18,15 @@ Here is an example of how to configure the `spanner-create-instance` tool in your `tools.yaml` file: ```yaml -sources: - my-spanner-admin-source: - kind: spanner-admin - -tools: - create_my_spanner_instance: - kind: spanner-create-instance - source: my-spanner-admin-source - description: "Creates a Spanner instance." +kind: sources +name: my-spanner-admin-source +type: spanner-admin +--- +kind: tools +name: create_my_spanner_instance +type: spanner-create-instance +source: my-spanner-admin-source +description: "Creates a Spanner instance." ``` ## Parameters @@ -47,6 +47,6 @@ The `spanner-create-instance` tool has the following parameters: | **field** | **type** | **required** | **description** | | ----------- | :------: | :----------: | ------------------------------------------------------------ | -| kind | string | true | Must be `spanner-create-instance`. | +| type | string | true | Must be `spanner-create-instance`. | | source | string | true | The name of the `spanner-admin` source to use for this tool. | | description | string | false | A description of the tool that is passed to the agent. | diff --git a/internal/sources/spanneradmin/spanneradmin.go b/internal/sources/spanneradmin/spanneradmin.go index 3c89e8e62e..ac045e6455 100644 --- a/internal/sources/spanneradmin/spanneradmin.go +++ b/internal/sources/spanneradmin/spanneradmin.go @@ -27,14 +27,14 @@ import ( "google.golang.org/api/option" ) -const SourceKind string = "spanner-admin" +const SourceType string = "spanner-admin" // validate interface var _ sources.SourceConfig = Config{} func init() { - if !sources.Register(SourceKind, newConfig) { - panic(fmt.Sprintf("source kind %q already registered", SourceKind)) + if !sources.Register(SourceType, newConfig) { + panic(fmt.Sprintf("source type %q already registered", SourceType)) } } @@ -48,13 +48,13 @@ func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources type Config struct { Name string `yaml:"name" validate:"required"` - Kind string `yaml:"kind" validate:"required"` + Type string `yaml:"type" validate:"required"` DefaultProject string `yaml:"defaultProject"` UseClientOAuth bool `yaml:"useClientOAuth"` } -func (r Config) SourceConfigKind() string { - return SourceKind +func (r Config) SourceConfigType() string { + return SourceType } // Initialize initializes a Spanner Admin Source instance. @@ -87,8 +87,8 @@ type Source struct { Client *instance.InstanceAdminClient } -func (s *Source) SourceKind() string { - return SourceKind +func (s *Source) SourceType() string { + return SourceType } func (s *Source) ToConfig() sources.SourceConfig { diff --git a/internal/sources/spanneradmin/spanneradmin_test.go b/internal/sources/spanneradmin/spanneradmin_test.go index bdbf843c14..444f242527 100644 --- a/internal/sources/spanneradmin/spanneradmin_test.go +++ b/internal/sources/spanneradmin/spanneradmin_test.go @@ -15,9 +15,9 @@ package spanneradmin_test import ( + "context" "testing" - yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/sources" @@ -26,7 +26,6 @@ import ( ) func TestParseFromYamlSpannerAdmin(t *testing.T) { - t.Parallel() tcs := []struct { desc string in string @@ -35,14 +34,14 @@ func TestParseFromYamlSpannerAdmin(t *testing.T) { { desc: "basic example", in: ` - sources: - my-spanner-admin-instance: - kind: spanner-admin + kind: sources + name: my-spanner-admin-instance + type: spanner-admin `, want: map[string]sources.SourceConfig{ "my-spanner-admin-instance": spanneradmin.Config{ Name: "my-spanner-admin-instance", - Kind: spanneradmin.SourceKind, + Type: spanneradmin.SourceType, UseClientOAuth: false, }, }, @@ -50,34 +49,28 @@ func TestParseFromYamlSpannerAdmin(t *testing.T) { { desc: "use client auth example", in: ` - sources: - my-spanner-admin-instance: - kind: spanner-admin - useClientOAuth: true + kind: sources + name: my-spanner-admin-instance + type: spanner-admin + useClientOAuth: true `, want: map[string]sources.SourceConfig{ "my-spanner-admin-instance": spanneradmin.Config{ Name: "my-spanner-admin-instance", - Kind: spanneradmin.SourceKind, + Type: spanneradmin.SourceType, UseClientOAuth: true, }, }, }, } for _, tc := range tcs { - tc := tc t.Run(tc.desc, func(t *testing.T) { - t.Parallel() - got := struct { - Sources server.SourceConfigs `yaml:"sources"` - }{} - // Parse contents - err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got) + got, _, _, _, _, _, err := server.UnmarshalResourceConfig(context.Background(), testutils.FormatYaml(tc.in)) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } - if !cmp.Equal(tc.want, got.Sources) { - t.Fatalf("incorrect parse: want %v, got %v", tc.want, got.Sources) + if !cmp.Equal(tc.want, got) { + t.Fatalf("incorrect parse: want %v, got %v", tc.want, got) } }) } @@ -93,36 +86,30 @@ func TestFailParseFromYaml(t *testing.T) { { desc: "extra field", in: ` - sources: - my-spanner-admin-instance: - kind: spanner-admin - project: test-project + kind: sources + name: my-spanner-admin-instance + type: spanner-admin + project: test-project `, - err: `unable to parse source "my-spanner-admin-instance" as "spanner-admin": [2:1] unknown field "project" - 1 | kind: spanner-admin + err: `error unmarshaling sources: unable to parse source "my-spanner-admin-instance" as "spanner-admin": [2:1] unknown field "project" + 1 | name: my-spanner-admin-instance > 2 | project: test-project ^ -`, + 3 | type: spanner-admin`, }, { desc: "missing required field", in: ` - sources: - my-spanner-admin-instance: - useClientOAuth: true + kind: sources + name: my-spanner-admin-instance + useClientOAuth: true `, - err: "missing 'kind' field for source \"my-spanner-admin-instance\"", + err: "error unmarshaling sources: missing 'type' field or it is not a string", }, } for _, tc := range tcs { - tc := tc t.Run(tc.desc, func(t *testing.T) { - t.Parallel() - got := struct { - Sources server.SourceConfigs `yaml:"sources"` - }{} - // Parse contents - err := yaml.Unmarshal(testutils.FormatYaml(tc.in), &got) + _, _, _, _, _, _, err := server.UnmarshalResourceConfig(context.Background(), testutils.FormatYaml(tc.in)) if err == nil { t.Fatalf("expect parsing to fail") } diff --git a/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance.go b/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance.go index 68fea9b7ea..610f34d30e 100644 --- a/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance.go +++ b/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance.go @@ -27,11 +27,11 @@ import ( "github.com/googleapis/genai-toolbox/internal/util/parameters" ) -const kind string = "spanner-create-instance" +const resourceType string = "spanner-create-instance" func init() { - if !tools.Register(kind, newConfig) { - panic(fmt.Sprintf("tool kind %q already registered", kind)) + if !tools.Register(resourceType, newConfig) { + panic(fmt.Sprintf("tool type %q already registered", resourceType)) } } @@ -52,7 +52,7 @@ type compatibleSource interface { // Config defines the configuration for the create-instance tool. type Config struct { Name string `yaml:"name" validate:"required"` - Kind string `yaml:"kind" validate:"required"` + Type string `yaml:"type" validate:"required"` Description string `yaml:"description"` Source string `yaml:"source" validate:"required"` AuthRequired []string `yaml:"authRequired"` @@ -62,8 +62,8 @@ type Config struct { var _ tools.ToolConfig = Config{} // ToolConfigKind returns the kind of the tool. -func (cfg Config) ToolConfigKind() string { - return kind +func (cfg Config) ToolConfigType() string { + return resourceType } // Initialize initializes the tool from the configuration. @@ -74,7 +74,7 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) } s, ok := rawS.(compatibleSource) if !ok { - return nil, fmt.Errorf("invalid source for %q tool: source %q not compatible", kind, cfg.Source) + return nil, fmt.Errorf("invalid source for %q tool: source %q not compatible", resourceType, cfg.Source) } project := s.GetDefaultProject() @@ -139,7 +139,7 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para return nil, fmt.Errorf("one of nodeCount or processingUnits must be positive, and the other must be 0") } - source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Kind) + source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { return nil, err } @@ -221,7 +221,7 @@ func (t Tool) Authorized(verifiedAuthServices []string) bool { } func (t Tool) RequiresClientAuthorization(resourceMgr tools.SourceProvider) (bool, error) { - source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Kind) + source, err := tools.GetCompatibleSource[compatibleSource](resourceMgr, t.Source, t.Name, t.Type) if err != nil { return false, err } @@ -231,3 +231,7 @@ func (t Tool) RequiresClientAuthorization(resourceMgr tools.SourceProvider) (boo func (t Tool) GetAuthTokenHeaderName(resourceMgr tools.SourceProvider) (string, error) { return "Authorization", nil } + +func (t Tool) GetParameters() parameters.Parameters { + return t.AllParams +} diff --git a/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance_test.go b/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance_test.go index a302f27173..452759e0bb 100644 --- a/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance_test.go +++ b/internal/tools/spanneradmin/spannercreateinstance/spannercreateinstance_test.go @@ -18,7 +18,6 @@ import ( "context" "testing" - yaml "github.com/goccy/go-yaml" "github.com/google/go-cmp/cmp" "github.com/googleapis/genai-toolbox/internal/server" "github.com/googleapis/genai-toolbox/internal/testutils" @@ -39,16 +38,16 @@ func TestParseFromYaml(t *testing.T) { { desc: "basic example", in: ` - tools: - create-instance-tool: - kind: spanner-create-instance - description: a test description - source: a-source + kind: tools + name: create-instance-tool + type: spanner-create-instance + description: a test description + source: a-source `, want: server.ToolConfigs{ "create-instance-tool": spannercreateinstance.Config{ Name: "create-instance-tool", - Kind: "spanner-create-instance", + Type: "spanner-create-instance", Description: "a test description", Source: "a-source", AuthRequired: []string{}, @@ -58,15 +57,12 @@ func TestParseFromYaml(t *testing.T) { } for _, tc := range tcs { t.Run(tc.desc, func(t *testing.T) { - got := struct { - Tools server.ToolConfigs `yaml:"tools"` - }{} // Parse contents - err := yaml.UnmarshalContext(ctx, testutils.FormatYaml(tc.in), &got) + _, _, _, got, _, _, err := server.UnmarshalResourceConfig(ctx, testutils.FormatYaml(tc.in)) if err != nil { t.Fatalf("unable to unmarshal: %s", err) } - if diff := cmp.Diff(tc.want, got.Tools); diff != "" { + if diff := cmp.Diff(tc.want, got); diff != "" { t.Fatalf("incorrect parse: diff %v", diff) } }) diff --git a/tests/spanneradmin/spanneradmin_integration_test.go b/tests/spanneradmin/spanneradmin_integration_test.go index e76f945cb0..5236b29a68 100644 --- a/tests/spanneradmin/spanneradmin_integration_test.go +++ b/tests/spanneradmin/spanneradmin_integration_test.go @@ -44,7 +44,7 @@ func getSpannerAdminVars(t *testing.T) map[string]any { } return map[string]any{ - "kind": "spanner-admin", + "type": "spanner-admin", "defaultProject": SpannerProject, } } @@ -90,7 +90,7 @@ func TestSpannerAdminCreateInstance(t *testing.T) { }, "tools": map[string]any{ "create-instance-tool": map[string]any{ - "kind": "spanner-create-instance", + "type": "spanner-create-instance", "source": "my-spanner-admin", "description": "Creates a Spanner instance.", },