feat(tools/looker): Control over whether hidden objects are surfaced (#1222)

The following config is added to the looker source:

* show_hidden_models
* show_hidden_explores
* show_hidden_fields

## Description
---
> Should include a concise description of the changes (bug or feature),
it's
> impact, along with a summary of the solution

## PR Checklist
---
> Thank you for opening a Pull Request! Before submitting your PR, there
are a
> few things you can do to make sure it goes smoothly:
- [ x] Make sure you reviewed

[CONTRIBUTING.md](https://github.com/googleapis/genai-toolbox/blob/main/CONTRIBUTING.md)
- [ x] Make sure to open an issue as a

[bug/issue](https://github.com/googleapis/langchain-google-alloydb-pg-python/issues/new/choose)
before writing your code! That way we can discuss the change, evaluate
  designs, and agree on the general idea
- [ x] Ensure the tests and linter pass
- [ x] Code coverage does not decrease (if any source code was changed)
- [ x] Appropriate docs were updated (if necessary)
- [ x] Make sure to add `!` if this involve a breaking change

🛠️ Fixes #1214
This commit is contained in:
Dr. Strangelove
2025-08-26 18:39:44 -04:00
committed by GitHub
parent 650e2e26f5
commit bc91559cc4
12 changed files with 146 additions and 103 deletions

View File

@@ -56,11 +56,14 @@ instead of hardcoding your secrets into the configuration file.
## Reference
| **field** | **type** | **required** | **description** |
| ------------- | :------: | :----------: | ----------------------------------------------------------------------------------------- |
| kind | string | true | Must be "looker". |
| base_url | string | true | The URL of your Looker server with no trailing /). |
| client_id | string | true | The client id assigned by Looker. |
| client_secret | string | true | The client secret assigned by Looker. |
| verify_ssl | string | true | Whether to check the ssl certificate of the server. |
| timeout | string | false | Maximum time to wait for query execution (e.g. "30s", "2m"). By default, 120s is applied. |
| **field** | **type** | **required** | **description** |
| -------------------- | :------: | :----------: | ----------------------------------------------------------------------------------------- |
| kind | string | true | Must be "looker". |
| base_url | string | true | The URL of your Looker server with no trailing /). |
| client_id | string | true | The client id assigned by Looker. |
| client_secret | string | true | The client secret assigned by Looker. |
| verify_ssl | string | true | Whether to check the ssl certificate of the server. |
| timeout | string | false | Maximum time to wait for query execution (e.g. "30s", "2m"). By default, 120s is applied. |
| show_hidden_models | string | false | Show or hide hidden models. (default: true) |
| show_hidden_explores | string | false | Show or hide hidden explores. (default: true) |
| show_hidden_fields | string | false | Show or hide hidden fields. (default: true) |

View File

@@ -4,8 +4,11 @@ sources:
base_url: ${LOOKER_BASE_URL}
client_id: ${LOOKER_CLIENT_ID}
client_secret: ${LOOKER_CLIENT_SECRET}
verify_ssl: ${LOOKER_VERIFY_SSL}
verify_ssl: ${LOOKER_VERIFY_SSL:true}
timeout: 600s
show_hidden_models: ${LOOKER_SHOW_HIDDEN_MODELS:true}
show_hidden_explores: ${LOOKER_SHOW_HIDDEN_EXPLORES:true}
show_hidden_fields: ${LOOKER_SHOW_HIDDEN_FIELDS:true}
tools:
get_models:

View File

@@ -39,7 +39,14 @@ func init() {
}
func newConfig(ctx context.Context, name string, decoder *yaml.Decoder) (sources.SourceConfig, error) {
actual := Config{Name: name, SslVerification: "true", Timeout: "600s"} // Default Ssl,timeout
actual := Config{
Name: name,
SslVerification: true,
Timeout: "600s",
ShowHiddenModels: true,
ShowHiddenExplores: true,
ShowHiddenFields: true,
} // Default Ssl,timeout, ShowHidden
if err := decoder.DecodeContext(ctx, &actual); err != nil {
return nil, err
}
@@ -47,13 +54,16 @@ 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"`
BaseURL string `yaml:"base_url" validate:"required"`
ClientId string `yaml:"client_id" validate:"required"`
ClientSecret string `yaml:"client_secret" validate:"required"`
SslVerification string `yaml:"verify_ssl"`
Timeout string `yaml:"timeout"`
Name string `yaml:"name" validate:"required"`
Kind string `yaml:"kind" validate:"required"`
BaseURL string `yaml:"base_url" validate:"required"`
ClientId string `yaml:"client_id" validate:"required"`
ClientSecret string `yaml:"client_secret" validate:"required"`
SslVerification bool `yaml:"verify_ssl"`
Timeout string `yaml:"timeout"`
ShowHiddenModels bool `yaml:"show_hidden_models"`
ShowHiddenExplores bool `yaml:"show_hidden_explores"`
ShowHiddenFields bool `yaml:"show_hidden_fields"`
}
func (r Config) SourceConfigKind() string {
@@ -77,14 +87,14 @@ func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.So
return nil, fmt.Errorf("unable to parse Timeout string as time.Duration: %s", err)
}
if r.SslVerification != "true" {
if !r.SslVerification {
logger.WarnContext(ctx, "Insecure HTTP is enabled for Looker source %s. TLS certificate verification is skipped.\n", r.Name)
}
cfg := rtl.ApiSettings{
AgentTag: userAgent,
BaseUrl: r.BaseURL,
ApiVersion: "4.0",
VerifySsl: (r.SslVerification == "true"),
VerifySsl: r.SslVerification,
Timeout: int32(duration.Seconds()),
ClientId: r.ClientId,
ClientSecret: r.ClientSecret,
@@ -98,11 +108,14 @@ func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.So
logger.DebugContext(ctx, fmt.Sprintf("logged in as user %v %v.\n", *me.FirstName, *me.LastName))
s := &Source{
Name: r.Name,
Kind: SourceKind,
Timeout: r.Timeout,
Client: sdk,
ApiSettings: &cfg,
Name: r.Name,
Kind: SourceKind,
Timeout: r.Timeout,
Client: sdk,
ApiSettings: &cfg,
ShowHiddenModels: r.ShowHiddenModels,
ShowHiddenExplores: r.ShowHiddenExplores,
ShowHiddenFields: r.ShowHiddenFields,
}
return s, nil
@@ -111,11 +124,14 @@ func (r Config) Initialize(ctx context.Context, tracer trace.Tracer) (sources.So
var _ sources.Source = &Source{}
type Source struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Timeout string `yaml:"timeout"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Timeout string `yaml:"timeout"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
ShowHiddenModels bool `yaml:"show_hidden_models"`
ShowHiddenExplores bool `yaml:"show_hidden_explores"`
ShowHiddenFields bool `yaml:"show_hidden_fields"`
}
func (s *Source) SourceKind() string {

View File

@@ -43,13 +43,16 @@ func TestParseFromYamlLooker(t *testing.T) {
`,
want: map[string]sources.SourceConfig{
"my-looker-instance": looker.Config{
Name: "my-looker-instance",
Kind: looker.SourceKind,
BaseURL: "http://example.looker.com/",
ClientId: "jasdl;k;tjl",
ClientSecret: "sdakl;jgflkasdfkfg",
Timeout: "600s",
SslVerification: "true",
Name: "my-looker-instance",
Kind: looker.SourceKind,
BaseURL: "http://example.looker.com/",
ClientId: "jasdl;k;tjl",
ClientSecret: "sdakl;jgflkasdfkfg",
Timeout: "600s",
SslVerification: true,
ShowHiddenModels: true,
ShowHiddenExplores: true,
ShowHiddenFields: true,
},
},
},

View File

@@ -25,14 +25,14 @@ import (
)
const (
DimensionsFields = "fields(dimensions(name,type,label,label_short,description,synonyms,tags))"
FiltersFields = "fields(filters(name,type,label,label_short,description,synonyms,tags))"
MeasuresFields = "fields(measures(name,type,label,label_short,description,synonyms,tags))"
ParametersFields = "fields(parameters(name,type,label,label_short,description,synonyms,tags))"
DimensionsFields = "fields(dimensions(name,type,label,label_short,description,synonyms,tags,hidden))"
FiltersFields = "fields(filters(name,type,label,label_short,description,synonyms,tags,hidden))"
MeasuresFields = "fields(measures(name,type,label,label_short,description,synonyms,tags,hidden))"
ParametersFields = "fields(parameters(name,type,label,label_short,description,synonyms,tags,hidden))"
)
// ExtractLookerFieldProperties extracts common properties from Looker field objects.
func ExtractLookerFieldProperties(ctx context.Context, fields *[]v4.LookmlModelExploreField) ([]any, error) {
func ExtractLookerFieldProperties(ctx context.Context, fields *[]v4.LookmlModelExploreField, showHiddenFields bool) ([]any, error) {
data := make([]any, 0)
// Handle nil fields pointer
@@ -52,6 +52,9 @@ func ExtractLookerFieldProperties(ctx context.Context, fields *[]v4.LookmlModelE
if v.Name != nil && strings.HasSuffix(*v.Name, "_raw") {
continue
}
if !showHiddenFields && v.Hidden != nil && *v.Hidden {
continue
}
vMap := make(map[string]any)
if v.Name != nil {
vMap["name"] = *v.Name

View File

@@ -132,7 +132,7 @@ func TestExtractLookerFieldProperties(t *testing.T) {
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
got, err := lookercommon.ExtractLookerFieldProperties(ctx, &tc.fields)
got, err := lookercommon.ExtractLookerFieldProperties(ctx, &tc.fields, true)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
@@ -150,7 +150,7 @@ func TestExtractLookerFieldPropertiesWithNilFields(t *testing.T) {
t.Fatalf("unexpected error: %s", err)
}
got, err := lookercommon.ExtractLookerFieldProperties(ctx, nil)
got, err := lookercommon.ExtractLookerFieldProperties(ctx, nil, true)
if err != nil {
t.Fatalf("unexpected error: %v", err)
}

View File

@@ -93,7 +93,8 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
Parameters: parameters.Manifest(),
AuthRequired: cfg.AuthRequired,
},
mcpManifest: mcpManifest,
mcpManifest: mcpManifest,
ShowHiddenFields: s.ShowHiddenFields,
}, nil
}
@@ -101,14 +102,15 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
ShowHiddenFields bool
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
@@ -136,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
return nil, fmt.Errorf("error processing get_dimensions response: %w", err)
}
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Dimensions)
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Dimensions, t.ShowHiddenFields)
if err != nil {
return nil, fmt.Errorf("error extracting get_dimensions response: %w", err)
}

View File

@@ -93,7 +93,8 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
Parameters: parameters.Manifest(),
AuthRequired: cfg.AuthRequired,
},
mcpManifest: mcpManifest,
mcpManifest: mcpManifest,
ShowHiddenExplores: s.ShowHiddenExplores,
}, nil
}
@@ -101,14 +102,15 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
ShowHiddenExplores bool
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
@@ -122,7 +124,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
return nil, fmt.Errorf("'model' must be a string, got %T", mapParams["model"])
}
resp, err := t.Client.LookmlModel(model, "explores(name,label,group_label)", t.ApiSettings)
resp, err := t.Client.LookmlModel(model, "explores(name,description,label,group_label,hidden)", t.ApiSettings)
if err != nil {
return nil, fmt.Errorf("error making get_explores request: %s", err)
}
@@ -130,6 +132,9 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
var data []any
for _, v := range *resp.Explores {
logger.DebugContext(ctx, "Got response element of %v\n", v)
if !t.ShowHiddenExplores && v.Hidden != nil && *v.Hidden {
continue
}
vMap := make(map[string]any)
if v.Name != nil {
vMap["name"] = *v.Name

View File

@@ -93,7 +93,8 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
Parameters: parameters.Manifest(),
AuthRequired: cfg.AuthRequired,
},
mcpManifest: mcpManifest,
mcpManifest: mcpManifest,
ShowHiddenFields: s.ShowHiddenFields,
}, nil
}
@@ -101,14 +102,15 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
ShowHiddenFields bool
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
@@ -136,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
return nil, fmt.Errorf("error processing get_filters response: %w", err)
}
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Filters)
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Filters, t.ShowHiddenFields)
if err != nil {
return nil, fmt.Errorf("error extracting get_filters response: %w", err)
}

View File

@@ -93,7 +93,8 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
Parameters: parameters.Manifest(),
AuthRequired: cfg.AuthRequired,
},
mcpManifest: mcpManifest,
mcpManifest: mcpManifest,
ShowHiddenFields: s.ShowHiddenFields,
}, nil
}
@@ -101,14 +102,15 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
ShowHiddenFields bool
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
@@ -136,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
return nil, fmt.Errorf("error processing get_measures response: %w", err)
}
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Measures)
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Measures, t.ShowHiddenFields)
if err != nil {
return nil, fmt.Errorf("error extracting get_measures response: %w", err)
}

View File

@@ -92,7 +92,8 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
Parameters: parameters.Manifest(),
AuthRequired: cfg.AuthRequired,
},
mcpManifest: mcpManifest,
mcpManifest: mcpManifest,
ShowHiddenModels: s.ShowHiddenModels,
}, nil
}
@@ -100,14 +101,15 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
ShowHiddenModels bool
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
@@ -117,7 +119,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
}
excludeEmpty := false
excludeHidden := false
excludeHidden := !t.ShowHiddenModels
includeInternal := true
req := v4.RequestAllLookmlModels{

View File

@@ -93,7 +93,8 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
Parameters: parameters.Manifest(),
AuthRequired: cfg.AuthRequired,
},
mcpManifest: mcpManifest,
mcpManifest: mcpManifest,
ShowHiddenFields: s.ShowHiddenFields,
}, nil
}
@@ -101,14 +102,15 @@ func (cfg Config) Initialize(srcs map[string]sources.Source) (tools.Tool, error)
var _ tools.Tool = Tool{}
type Tool struct {
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
Name string `yaml:"name"`
Kind string `yaml:"kind"`
Client *v4.LookerSDK
ApiSettings *rtl.ApiSettings
AuthRequired []string `yaml:"authRequired"`
Parameters tools.Parameters `yaml:"parameters"`
manifest tools.Manifest
mcpManifest tools.McpManifest
ShowHiddenFields bool
}
func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken tools.AccessToken) (any, error) {
@@ -136,7 +138,7 @@ func (t Tool) Invoke(ctx context.Context, params tools.ParamValues, accessToken
return nil, fmt.Errorf("error processing get_parameters response: %w", err)
}
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Parameters)
data, err := lookercommon.ExtractLookerFieldProperties(ctx, resp.Fields.Parameters, t.ShowHiddenFields)
if err != nil {
return nil, fmt.Errorf("error extracting get_parameters response: %w", err)
}