From d35a277967cc7284dcffd2076aef59d2e947ad73 Mon Sep 17 00:00:00 2001 From: zyqzyq Date: Thu, 14 May 2026 09:43:07 +0800 Subject: [PATCH] tool add show_on --- pkg/entities/plugin_entities/constant.go | 51 +++- .../plugin_entities/tool_declaration.go | 84 +++++- .../plugin_entities/tool_declaration_test.go | 282 ++++++++++++++++++ 3 files changed, 398 insertions(+), 19 deletions(-) diff --git a/pkg/entities/plugin_entities/constant.go b/pkg/entities/plugin_entities/constant.go index 2a44f0795..b6c5be7e2 100644 --- a/pkg/entities/plugin_entities/constant.go +++ b/pkg/entities/plugin_entities/constant.go @@ -1,5 +1,11 @@ package plugin_entities +import ( + "encoding/json" + + "gopkg.in/yaml.v3" +) + const ( SECRET_INPUT = "secret-input" TEXT_INPUT = "text-input" @@ -22,7 +28,46 @@ const ( ) type ParameterOption struct { - Value string `json:"value" yaml:"value" validate:"required"` - Label I18nObject `json:"label" yaml:"label" validate:"required"` - Icon string `json:"icon" yaml:"icon" validate:"omitempty"` + Value string `json:"value" yaml:"value" validate:"required"` + Label I18nObject `json:"label" yaml:"label" validate:"required"` + Icon string `json:"icon" yaml:"icon" validate:"omitempty"` + ShowOn []ToolParameterShowOnObject `json:"show_on" yaml:"show_on" validate:"omitempty,lte=16,dive"` +} + +func (p *ParameterOption) UnmarshalJSON(data []byte) error { + type Alias ParameterOption + aux := &struct { + *Alias + }{ + Alias: (*Alias)(p), + } + + if err := json.Unmarshal(data, aux); err != nil { + return err + } + + if p.ShowOn == nil { + p.ShowOn = []ToolParameterShowOnObject{} + } + + return nil +} + +func (p *ParameterOption) UnmarshalYAML(value *yaml.Node) error { + type Alias ParameterOption + aux := &struct { + *Alias `yaml:",inline"` + }{ + Alias: (*Alias)(p), + } + + if err := value.Decode(&aux); err != nil { + return err + } + + if p.ShowOn == nil { + p.ShowOn = []ToolParameterShowOnObject{} + } + + return nil } diff --git a/pkg/entities/plugin_entities/tool_declaration.go b/pkg/entities/plugin_entities/tool_declaration.go index 41891b369..19f4cf986 100644 --- a/pkg/entities/plugin_entities/tool_declaration.go +++ b/pkg/entities/plugin_entities/tool_declaration.go @@ -121,23 +121,75 @@ type ParameterTemplate struct { Enabled bool `json:"enabled" yaml:"enabled"` } +type ToolParameterShowOnObject struct { + Variable string `json:"variable" yaml:"variable" validate:"required,lt=256"` + Value string `json:"value" yaml:"value" validate:"required,lt=256"` +} + type ToolParameter struct { - Name string `json:"name" yaml:"name" validate:"required,gt=0,lt=1024"` - Label I18nObject `json:"label" yaml:"label" validate:"required"` - HumanDescription I18nObject `json:"human_description" yaml:"human_description" validate:"required"` - Type ToolParameterType `json:"type" yaml:"type" validate:"required,tool_parameter_type"` - Scope *string `json:"scope" yaml:"scope" validate:"omitempty,max=1024,is_scope"` - Form ToolParameterForm `json:"form" yaml:"form" validate:"required,tool_parameter_form"` - LLMDescription string `json:"llm_description" yaml:"llm_description" validate:"omitempty"` - Required bool `json:"required" yaml:"required"` - AutoGenerate *ParameterAutoGenerate `json:"auto_generate" yaml:"auto_generate" validate:"omitempty"` - Template *ParameterTemplate `json:"template" yaml:"template" validate:"omitempty"` - Default any `json:"default" yaml:"default" validate:"omitempty"` - Min *float64 `json:"min" yaml:"min" validate:"omitempty"` - Max *float64 `json:"max" yaml:"max" validate:"omitempty"` - Multiple bool `json:"multiple" yaml:"multiple" validate:"omitempty"` - Precision *int `json:"precision" yaml:"precision" validate:"omitempty"` - Options []ParameterOption `json:"options" yaml:"options" validate:"omitempty,dive"` + Name string `json:"name" yaml:"name" validate:"required,gt=0,lt=1024"` + Label I18nObject `json:"label" yaml:"label" validate:"required"` + HumanDescription I18nObject `json:"human_description" yaml:"human_description" validate:"required"` + Type ToolParameterType `json:"type" yaml:"type" validate:"required,tool_parameter_type"` + Scope *string `json:"scope" yaml:"scope" validate:"omitempty,max=1024,is_scope"` + Form ToolParameterForm `json:"form" yaml:"form" validate:"required,tool_parameter_form"` + LLMDescription string `json:"llm_description" yaml:"llm_description" validate:"omitempty"` + Required bool `json:"required" yaml:"required"` + AutoGenerate *ParameterAutoGenerate `json:"auto_generate" yaml:"auto_generate" validate:"omitempty"` + Template *ParameterTemplate `json:"template" yaml:"template" validate:"omitempty"` + Default any `json:"default" yaml:"default" validate:"omitempty"` + Min *float64 `json:"min" yaml:"min" validate:"omitempty"` + Max *float64 `json:"max" yaml:"max" validate:"omitempty"` + Multiple bool `json:"multiple" yaml:"multiple" validate:"omitempty"` + Precision *int `json:"precision" yaml:"precision" validate:"omitempty"` + Options []ParameterOption `json:"options" yaml:"options" validate:"omitempty,dive"` + ShowOn []ToolParameterShowOnObject `json:"show_on" yaml:"show_on" validate:"omitempty,lte=16,dive"` +} + +func (t *ToolParameter) UnmarshalJSON(data []byte) error { + type Alias ToolParameter + aux := &struct { + *Alias + }{ + Alias: (*Alias)(t), + } + + if err := json.Unmarshal(data, aux); err != nil { + return err + } + + if t.ShowOn == nil { + t.ShowOn = []ToolParameterShowOnObject{} + } + + if t.Options == nil { + t.Options = []ParameterOption{} + } + + return nil +} + +func (t *ToolParameter) UnmarshalYAML(value *yaml.Node) error { + type Alias ToolParameter + aux := &struct { + *Alias `yaml:",inline"` + }{ + Alias: (*Alias)(t), + } + + if err := value.Decode(&aux); err != nil { + return err + } + + if t.ShowOn == nil { + t.ShowOn = []ToolParameterShowOnObject{} + } + + if t.Options == nil { + t.Options = []ParameterOption{} + } + + return nil } type ToolDescription struct { diff --git a/pkg/entities/plugin_entities/tool_declaration_test.go b/pkg/entities/plugin_entities/tool_declaration_test.go index a80a989a9..2393d7204 100644 --- a/pkg/entities/plugin_entities/tool_declaration_test.go +++ b/pkg/entities/plugin_entities/tool_declaration_test.go @@ -1117,6 +1117,288 @@ func TestParameterScope_Validate(t *testing.T) { } } +func TestToolParameterShowOn_Validate(t *testing.T) { + const jsonData = ` +{ + "identity": { + "author": "author", + "name": "name", + "description": { + "en_US": "description" + }, + "icon": "icon", + "label": { + "en_US": "label" + }, + "tags": [] + }, + "credentials_schema": [], + "tools": [ + { + "identity": { + "author": "author", + "name": "tool", + "label": { + "en_US": "label" + } + }, + "description": { + "human": { + "en_US": "description" + }, + "llm": "description" + }, + "parameters": [ + { + "name": "mode", + "type": "select", + "label": { + "en_US": "Mode" + }, + "human_description": { + "en_US": "Select mode" + }, + "form": "form", + "required": true, + "options": [ + { + "value": "simple", + "label": { + "en_US": "Simple" + } + }, + { + "value": "advanced", + "label": { + "en_US": "Advanced" + } + } + ] + }, + { + "name": "advanced_param", + "type": "string", + "label": { + "en_US": "Advanced Param" + }, + "human_description": { + "en_US": "Advanced parameter" + }, + "form": "form", + "required": false, + "show_on": [ + { + "variable": "mode", + "value": "advanced" + } + ] + } + ] + } + ] +} +` + + const yamlData = `identity: + author: author + name: name + description: + en_US: description + icon: icon + label: + en_US: label + tags: [] +credentials_schema: [] +tools: + - identity: + author: author + name: tool + label: + en_US: label + description: + human: + en_US: description + llm: description + parameters: + - name: mode + type: select + label: + en_US: Mode + human_description: + en_US: Select mode + form: form + required: true + options: + - value: simple + label: + en_US: Simple + - value: advanced + label: + en_US: Advanced + - name: advanced_param + type: string + label: + en_US: Advanced Param + human_description: + en_US: Advanced parameter + form: form + required: false + show_on: + - variable: mode + value: advanced +` + + jsonDeclaration, jsonErr := UnmarshalToolProviderDeclaration([]byte(jsonData)) + if jsonErr != nil { + t.Errorf("UnmarshalToolProviderDeclaration() error for JSON = %v", jsonErr) + return + } + + if len(jsonDeclaration.Tools[0].Parameters) != 2 { + t.Errorf("Expected 2 parameters, got %d", len(jsonDeclaration.Tools[0].Parameters)) + return + } + + advancedParam := jsonDeclaration.Tools[0].Parameters[1] + if len(advancedParam.ShowOn) != 1 { + t.Errorf("Expected 1 show_on condition, got %d", len(advancedParam.ShowOn)) + return + } + + if advancedParam.ShowOn[0].Variable != "mode" || advancedParam.ShowOn[0].Value != "advanced" { + t.Errorf("Unexpected show_on values: variable=%s, value=%s", advancedParam.ShowOn[0].Variable, advancedParam.ShowOn[0].Value) + return + } + + modeParam := jsonDeclaration.Tools[0].Parameters[0] + if modeParam.ShowOn == nil { + t.Errorf("Expected ShowOn to be initialized to empty slice, got nil") + return + } + + yamlDeclaration, yamlErr := parser.UnmarshalYamlBytes[ToolProviderDeclaration]([]byte(yamlData)) + if yamlErr != nil { + t.Errorf("UnmarshalToolProviderDeclaration() error for YAML = %v", yamlErr) + return + } + + if len(yamlDeclaration.Tools[0].Parameters) != 2 { + t.Errorf("Expected 2 parameters, got %d", len(yamlDeclaration.Tools[0].Parameters)) + return + } + + yamlAdvancedParam := yamlDeclaration.Tools[0].Parameters[1] + if len(yamlAdvancedParam.ShowOn) != 1 { + t.Errorf("Expected 1 show_on condition, got %d", len(yamlAdvancedParam.ShowOn)) + return + } + + if yamlAdvancedParam.ShowOn[0].Variable != "mode" || yamlAdvancedParam.ShowOn[0].Value != "advanced" { + t.Errorf("Unexpected show_on values: variable=%s, value=%s", yamlAdvancedParam.ShowOn[0].Variable, yamlAdvancedParam.ShowOn[0].Value) + return + } +} + +func TestParameterOptionShowOn_Validate(t *testing.T) { + const jsonData = ` +{ + "identity": { + "author": "author", + "name": "name", + "description": { + "en_US": "description" + }, + "icon": "icon", + "label": { + "en_US": "label" + }, + "tags": [] + }, + "credentials_schema": [], + "tools": [ + { + "identity": { + "author": "author", + "name": "tool", + "label": { + "en_US": "label" + } + }, + "description": { + "human": { + "en_US": "description" + }, + "llm": "description" + }, + "parameters": [ + { + "name": "mode", + "type": "select", + "label": { + "en_US": "Mode" + }, + "human_description": { + "en_US": "Select mode" + }, + "form": "form", + "required": true, + "options": [ + { + "value": "simple", + "label": { + "en_US": "Simple" + } + }, + { + "value": "advanced", + "label": { + "en_US": "Advanced" + }, + "show_on": [ + { + "variable": "feature_flag", + "value": "true" + } + ] + } + ] + } + ] + } + ] +} +` + + declaration, err := UnmarshalToolProviderDeclaration([]byte(jsonData)) + if err != nil { + t.Errorf("UnmarshalToolProviderDeclaration() error = %v", err) + return + } + + modeParam := declaration.Tools[0].Parameters[0] + if len(modeParam.Options) != 2 { + t.Errorf("Expected 2 options, got %d", len(modeParam.Options)) + return + } + + advancedOption := modeParam.Options[1] + if len(advancedOption.ShowOn) != 1 { + t.Errorf("Expected 1 show_on condition on option, got %d", len(advancedOption.ShowOn)) + return + } + + if advancedOption.ShowOn[0].Variable != "feature_flag" || advancedOption.ShowOn[0].Value != "true" { + t.Errorf("Unexpected show_on values on option: variable=%s, value=%s", advancedOption.ShowOn[0].Variable, advancedOption.ShowOn[0].Value) + return + } + + simpleOption := modeParam.Options[0] + if simpleOption.ShowOn == nil { + t.Errorf("Expected ShowOn to be initialized to empty slice on option, got nil") + return + } +} + func TestToolName_Validate(t *testing.T) { data := parser.MarshalJsonBytes(ToolProviderIdentity{ Author: "author",