Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions internal/prebuiltconfigs/tools/dataplex.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@ tools:
search_entries:
kind: dataplex-search-entries
source: dataplex-source
description: Use this tool to search for entries in Dataplex Catalog based on the provided search query.
description: Searches for data assets (eg. table/dataset/view) in Catalog based on the provided search query.
lookup_entry:
kind: dataplex-lookup-entry
source: dataplex-source
description: Use this tool to retrieve a specific entry from Dataplex Catalog.
description: Retrieves a specific metadata regarding a data asset (e.g. table/dataset/view) from Catalog
search_aspect_types:
kind: dataplex-search-aspect-types
source: dataplex-source
description: Use this tool to find aspect types relevant to the query.
description: Search aspect types relevant to the query.
lookup_context:
kind: dataplex-lookup-context
source: dataplex-source
description: Use this tool to retrieve rich metadata regarding one or more data assets along with their relationships.
description: Retrieves rich metadata regarding one or more data assets along with their relationships.

toolsets:
discovery:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"fmt"
"net/http"
"strings"

"cloud.google.com/go/dataplex/apiv1/dataplexpb"
"github.com/goccy/go-yaml"
Expand Down Expand Up @@ -65,9 +66,13 @@ func (cfg Config) ToolConfigType() string {
}

func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
name := parameters.NewStringParameter("name", "The project to which the request should be attributed in the following form: projects/{project}/locations/{location}.")
resources := parameters.NewArrayParameter("resources", "A list of up to 10 resources names for which metadata is needed.", parameters.NewStringParameter("resource", "Name of a resource in the following format: projects/{project}/locations/{location}/entryGroups/{group}/entries/{entry}."))
params := parameters.Parameters{name, resources}
resources := parameters.NewArrayParameter("resources",
"Required. A list of up to 10 resource names from same project and location.",
parameters.NewStringParameter("resource",
"Name of a resource in the following format: projects/{project_id_or_number}/locations/{location}/entryGroups/{group}/entries/{entry}."+
" Example for a BigQuery table: 'projects/{project_id_or_number}/locations/{location}/entryGroups/@bigquery/entries/bigquery.googleapis.com/projects/{project_id}/datasets/{dataset_id}/tables/{table_id}'."+
" This is the same value which is returned by the search_entries tool's response in the dataplexEntry.name field."))
params := parameters.Parameters{resources}

mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, params, nil)

Expand Down Expand Up @@ -102,12 +107,33 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
}

paramsMap := params.AsMap()
name, _ := paramsMap["name"].(string)
resourcesSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["resources"].([]any), "string")
if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert resources to array of strings: %s", err), err)
}
resources := resourcesSlice.([]string)

if len(resources) == 0 {
err := fmt.Errorf("resources cannot be empty")
return nil, util.NewAgentError(err.Error(), err)
}
var name string
for i, resource := range resources {
parts := strings.Split(resource, "/")
if len(parts) < 4 || parts[0] != "projects" || parts[2] != "locations" {
err := fmt.Errorf("invalid resource format at index %d, must be in the format of projects/{project_id_or_number}/locations/{location}/entryGroups/{group}/entries/{entry}", i)
return nil, util.NewAgentError(err.Error(), err)
}

currentName := strings.Join(parts[:4], "/")
if i == 0 {
name = currentName
} else if name != currentName {
err := fmt.Errorf("all resources must belong to the same project and location. Please make separate calls for each distinct project and location combination")
return nil, util.NewAgentError(err.Error(), err)
}
}

resp, err := source.LookupContext(ctx, name, resources)
if err != nil {
return nil, util.ProcessGcpError(err)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/testutils"
"github.com/googleapis/genai-toolbox/internal/tools/dataplex/dataplexlookupcontext"
"github.com/googleapis/genai-toolbox/internal/util/parameters"
)

func TestParseFromYamlDataplexLookupContext(t *testing.T) {
Expand Down Expand Up @@ -53,40 +52,6 @@ func TestParseFromYamlDataplexLookupContext(t *testing.T) {
},
},
},
{
desc: "advanced example",
in: `
kind: tool
name: example_tool
type: dataplex-lookup-context
source: my-instance
description: some description
parameters:
- name: name
type: string
description: some name description
- name: resources
type: array
description: some resources description
items:
name: resource
type: string
description: some resource description
`,
want: server.ToolConfigs{
"example_tool": dataplexlookupcontext.Config{
Name: "example_tool",
Type: "dataplex-lookup-context",
Source: "my-instance",
Description: "some description",
AuthRequired: []string{},
Parameters: []parameters.Parameter{
parameters.NewStringParameter("name", "some name description"),
parameters.NewArrayParameter("resources", "some resources description", parameters.NewStringParameter("resource", "some resource description")),
},
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (
"context"
"fmt"
"net/http"
"strings"

dataplexpb "cloud.google.com/go/dataplex/apiv1/dataplexpb"
"github.com/goccy/go-yaml"
Expand Down Expand Up @@ -70,7 +71,7 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)

**Type:** Integer

**Description:** Specifies the parts of the entry and its aspects to return.
**Description:** Optional. Specifies the parts of the entry and its aspects to return.

**Possible Values:**

Expand All @@ -80,11 +81,10 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
* 4 (ALL): Return the entry and both required and optional aspects (at most 100 aspects)
`

name := parameters.NewStringParameter("name", "The project to which the request should be attributed in the following form: projects/{project}/locations/{location}.")
view := parameters.NewIntParameterWithDefault("view", 2, viewDesc)
aspectTypes := parameters.NewArrayParameterWithDefault("aspectTypes", []any{}, "Limits the aspects returned to the provided aspect types. It only works when used together with CUSTOM view.", parameters.NewStringParameter("aspectType", "The types of aspects to be included in the response in the format `projects/{project}/locations/{location}/aspectTypes/{aspectType}`."))
entry := parameters.NewStringParameter("entry", "The resource name of the Entry in the following form: projects/{project}/locations/{location}/entryGroups/{entryGroup}/entries/{entry}.")
params := parameters.Parameters{name, view, aspectTypes, entry}
aspectTypes := parameters.NewArrayParameterWithDefault("aspectTypes", []any{}, "Optional. Limits the aspects returned to the provided aspect types. It only works when used together with CUSTOM view.", parameters.NewStringParameter("aspectType", "The types of aspects to be included in the response in the format `projects/{project}/locations/{location}/aspectTypes/{aspectType}`."))
entry := parameters.NewStringParameter("entry", "Required. The resource name of the Entry in the following form: projects/{project}/locations/{location}/entryGroups/{entryGroup}/entries/{entry}.")
params := parameters.Parameters{entry, view, aspectTypes}

mcpManifest := tools.GetMcpManifest(cfg.Name, cfg.Description, cfg.AuthRequired, params, nil)

Expand Down Expand Up @@ -119,13 +119,18 @@ func (t Tool) Invoke(ctx context.Context, resourceMgr tools.SourceProvider, para
}

paramsMap := params.AsMap()
name, _ := paramsMap["name"].(string)
entry, _ := paramsMap["entry"].(string)
view, _ := paramsMap["view"].(int)
aspectTypeSlice, err := parameters.ConvertAnySliceToTyped(paramsMap["aspectTypes"].([]any), "string")
if err != nil {
return nil, util.NewAgentError(fmt.Sprintf("can't convert aspectTypes to array of strings: %s", err), err)
}
parts := strings.Split(entry, "/")
if len(parts) < 4 || parts[0] != "projects" || parts[2] != "locations" {
err = fmt.Errorf("invalid entry format: must be in the form projects/{project}/locations/{location}/entryGroups/{entryGroup}/entries/{entry}")
return nil, util.NewAgentError(err.Error(), err)
}
name := strings.Join(parts[:4], "/")
aspectTypes := aspectTypeSlice.([]string)
resp, err := source.LookupEntry(ctx, name, view, aspectTypes, entry)
if err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"github.com/googleapis/genai-toolbox/internal/server"
"github.com/googleapis/genai-toolbox/internal/testutils"
"github.com/googleapis/genai-toolbox/internal/tools/dataplex/dataplexlookupentry"
"github.com/googleapis/genai-toolbox/internal/util/parameters"
)

func TestParseFromYamlDataplexLookupEntry(t *testing.T) {
Expand Down Expand Up @@ -53,49 +52,6 @@ func TestParseFromYamlDataplexLookupEntry(t *testing.T) {
},
},
},
{
desc: "advanced example",
in: `
kind: tool
name: example_tool
type: dataplex-lookup-entry
source: my-instance
description: some description
parameters:
- name: name
type: string
description: some name description
- name: view
type: string
description: some view description
- name: aspectTypes
type: array
description: some aspect types description
default: []
items:
name: aspectType
type: string
description: some aspect type description
- name: entry
type: string
description: some entry description
`,
want: server.ToolConfigs{
"example_tool": dataplexlookupentry.Config{
Name: "example_tool",
Type: "dataplex-lookup-entry",
Source: "my-instance",
Description: "some description",
AuthRequired: []string{},
Parameters: []parameters.Parameter{
parameters.NewStringParameter("name", "some name description"),
parameters.NewStringParameter("view", "some view description"),
parameters.NewArrayParameterWithDefault("aspectTypes", []any{}, "some aspect types description", parameters.NewStringParameter("aspectType", "some aspect type description")),
parameters.NewStringParameter("entry", "some entry description"),
},
},
},
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,12 @@ func (cfg Config) ToolConfigType() string {
}

func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error) {
query := parameters.NewStringParameter("query", "The query against which entries in scope should be matched.")
query := parameters.NewStringParameter("query",
"A query string for searching entries, following Dataplex search syntax. "+
"Supports logical operators (AND, OR, NOT) and grouping. "+
"For example, to find a table that might have been renamed, you could use 'type:table (name:books OR fiction)'. "+
"This can be more efficient than multiple separate calls."+
"Warning: Performing broad searches without specific filters (e.g., type:table) can be slow and consume significant resources. When performing exploratory searches, always use the pageSize parameter to limit the number of results returned.")
scope := parameters.NewStringParameterWithDefault("scope", "", "A scope limits the search space to a particular project or organization. It must be in the format: organizations/<org_id> or projects/<project_id> or projects/<project_number>.")
pageSize := parameters.NewIntParameterWithDefault("pageSize", 5, "Number of results in the search page.")
orderBy := parameters.NewStringParameterWithDefault("orderBy", "relevance", "Specifies the ordering of results. Supported values are: relevance, last_modified_timestamp, last_modified_timestamp asc")
Expand Down
Loading
Loading