diff --git a/neo/assistant/api.go b/neo/assistant/api.go index b90d73a9..b64124ff 100644 --- a/neo/assistant/api.go +++ b/neo/assistant/api.go @@ -471,11 +471,13 @@ func (ast *Assistant) withOptions(options map[string]interface{}) map[string]int } } - // Add tools - if ast.Tools != nil && len(ast.Tools) > 0 { - options["tools"] = ast.Tools - if options["tool_choice"] == nil { - options["tool_choice"] = "auto" + // Add tool_calls + if ast.Tools != nil && ast.Tools.Tools != nil && len(ast.Tools.Tools) > 0 { + if settings, has := connectorSettings[ast.Connector]; has && settings.Tools { + options["tools"] = ast.Tools.Tools + if options["tool_choice"] == nil { + options["tool_choice"] = "auto" + } } } @@ -492,6 +494,22 @@ func (ast *Assistant) withPrompts(messages []chatMessage.Message) []chatMessage. messages = append(messages, *chatMessage.New().Map(map[string]interface{}{"role": prompt.Role, "content": prompt.Content, "name": name})) } } + + // Add tool_calls + if ast.Tools != nil && ast.Tools.Tools != nil && len(ast.Tools.Tools) > 0 { + if settings, has := connectorSettings[ast.Connector]; has && !settings.Tools { + if ast.Tools.Prompts != nil && len(ast.Tools.Prompts) > 0 { + for _, prompt := range ast.Tools.Prompts { + messages = append(messages, *chatMessage.New().Map(map[string]interface{}{ + "role": prompt.Role, + "content": prompt.Content, + "name": prompt.Name, + })) + } + } + } + } + return messages } diff --git a/neo/assistant/assistant.go b/neo/assistant/assistant.go index 75ac2db6..e320f91e 100644 --- a/neo/assistant/assistant.go +++ b/neo/assistant/assistant.go @@ -201,8 +201,16 @@ func (ast *Assistant) Clone() *Assistant { // Deep copy tools if ast.Tools != nil { - clone.Tools = make([]Tool, len(ast.Tools)) - copy(clone.Tools, ast.Tools) + clone.Tools = &ToolCalls{} + if ast.Tools.Tools != nil { + clone.Tools.Tools = make([]Tool, len(ast.Tools.Tools)) + copy(clone.Tools.Tools, ast.Tools.Tools) + } + + if ast.Tools.Prompts != nil { + clone.Tools.Prompts = make([]Prompt, len(ast.Tools.Prompts)) + copy(clone.Tools.Prompts, ast.Tools.Prompts) + } } // Deep copy flows @@ -242,13 +250,20 @@ func (ast *Assistant) Update(data map[string]interface{}) error { if v, has := data["tools"]; has { switch tools := v.(type) { case []Tool: + ast.Tools = &ToolCalls{ + Tools: tools, + Prompts: ast.Prompts, + } + + case *ToolCalls: ast.Tools = tools + default: raw, err := jsoniter.Marshal(tools) if err != nil { return err } - ast.Tools = []Tool{} + ast.Tools = &ToolCalls{} err = jsoniter.Unmarshal(raw, &ast.Tools) if err != nil { return err diff --git a/neo/assistant/load.go b/neo/assistant/load.go index d9f9aad4..9f162349 100644 --- a/neo/assistant/load.go +++ b/neo/assistant/load.go @@ -25,6 +25,7 @@ import ( var loaded = NewCache(200) // 200 is the default capacity var storage store.Store = nil var rag *RAG = nil +var connectorSettings map[string]ConnectorSetting = map[string]ConnectorSetting{} var vision *neovision.Vision = nil var defaultConnector string = "" // default connector @@ -124,6 +125,11 @@ func SetVision(v *neovision.Vision) { vision = v } +// SetConnectorSettings set the connector settings +func SetConnectorSettings(settings map[string]ConnectorSetting) { + connectorSettings = settings +} + // SetConnector set the connector func SetConnector(c string) { defaultConnector = c @@ -443,7 +449,13 @@ func loadMap(data map[string]interface{}) (*Assistant, error) { if tools, has := data["tools"]; has { switch vv := tools.(type) { case []Tool: - assistant.Tools = vv + assistant.Tools = &ToolCalls{ + Tools: vv, + Prompts: assistant.Prompts, + } + + case ToolCalls: + assistant.Tools = &vv default: raw, err := jsoniter.Marshal(tools) @@ -451,12 +463,12 @@ func loadMap(data map[string]interface{}) (*Assistant, error) { return nil, fmt.Errorf("tools format error %s", err.Error()) } - var tools []Tool + var tools ToolCalls err = jsoniter.Unmarshal(raw, &tools) if err != nil { return nil, fmt.Errorf("tools format error %s", err.Error()) } - assistant.Tools = tools + assistant.Tools = &tools } } @@ -605,7 +617,7 @@ func (ast *Assistant) initialize() error { return nil } -func loadTools(file string) ([]Tool, int64, error) { +func loadTools(file string) (*ToolCalls, int64, error) { app, err := fs.Get("app") if err != nil { @@ -623,14 +635,14 @@ func loadTools(file string) ([]Tool, int64, error) { } if len(content) == 0 { - return []Tool{}, ts.UnixNano(), nil + return &ToolCalls{Tools: []Tool{}, Prompts: []Prompt{}}, ts.UnixNano(), nil } - var tools []Tool - err = jsoniter.Unmarshal(content, &tools) + var tools ToolCalls + err = application.Parse(file, content, &tools) if err != nil { return nil, 0, err } - return tools, ts.UnixNano(), nil + return &tools, ts.UnixNano(), nil } diff --git a/neo/assistant/types.go b/neo/assistant/types.go index d4fa7fcc..712ccede 100644 --- a/neo/assistant/types.go +++ b/neo/assistant/types.go @@ -129,7 +129,7 @@ type Assistant struct { Automated bool `json:"automated,omitempty"` // Whether this assistant is automated Options map[string]interface{} `json:"options,omitempty"` // AI Options Prompts []Prompt `json:"prompts,omitempty"` // AI Prompts - Tools []Tool `json:"tools,omitempty"` // Assistant Tools + Tools *ToolCalls `json:"tools,omitempty"` // Assistant Tools Flows []map[string]interface{} `json:"flows,omitempty"` // Assistant Flows Placeholder *Placeholder `json:"placeholder,omitempty"` // Assistant Placeholder Script *v8.Script `json:"-" yaml:"-"` // Assistant Script @@ -137,9 +137,22 @@ type Assistant struct { UpdatedAt int64 `json:"updated_at"` // Last update timestamp openai *api.OpenAI // OpenAI API vision bool // Whether this assistant supports vision + toolCalls bool // Whether this assistant supports tool_calls initHook bool // Whether this assistant has an init hook } +// ToolCalls the tool calls +type ToolCalls struct { + Tools []Tool `json:"tools,omitempty"` + Prompts []Prompt `json:"prompts,omitempty"` +} + +// ConnectorSetting the connector setting +type ConnectorSetting struct { + Vision bool `json:"vision,omitempty" yaml:"vision,omitempty"` + Tools bool `json:"tools,omitempty" yaml:"tools,omitempty"` +} + // Placeholder the assistant placeholder type Placeholder struct { Title string `json:"title,omitempty"` diff --git a/neo/load.go b/neo/load.go index ae2e622d..9302352c 100644 --- a/neo/load.go +++ b/neo/load.go @@ -160,6 +160,10 @@ func initAssistant() error { assistant.SetVision(Neo.Vision) } + if Neo.Connectors != nil { + assistant.SetConnectorSettings(Neo.Connectors) + } + // Default Connector assistant.SetConnector(Neo.Connector) diff --git a/neo/types.go b/neo/types.go index 06e3ed22..6e6cb343 100644 --- a/neo/types.go +++ b/neo/types.go @@ -12,32 +12,26 @@ import ( // DSL AI assistant type DSL struct { - ID string `json:"-" yaml:"-"` - Name string `json:"name,omitempty" yaml:"name,omitempty"` - Use string `json:"use,omitempty" yaml:"use,omitempty"` // Which assistant to use default - Guard string `json:"guard,omitempty" yaml:"guard,omitempty"` - Connector string `json:"connector" yaml:"connector"` - StoreSetting store.Setting `json:"store" yaml:"store"` - RAGSetting rag.Setting `json:"rag" yaml:"rag"` - VisionSetting VisionSetting `json:"vision" yaml:"vision"` - Option map[string]interface{} `json:"option" yaml:"option"` - Prepare string `json:"prepare,omitempty" yaml:"prepare,omitempty"` - Create string `json:"create,omitempty" yaml:"create,omitempty"` - Write string `json:"write,omitempty" yaml:"write,omitempty"` - Prompts []assistant.Prompt `json:"prompts,omitempty" yaml:"prompts,omitempty"` - Allows []string `json:"allows,omitempty" yaml:"allows,omitempty"` - Assistant assistant.API `json:"-" yaml:"-"` // The default assistant - Store store.Store `json:"-" yaml:"-"` - RAG *rag.RAG `json:"-" yaml:"-"` - Vision *vision.Vision `json:"-" yaml:"-"` - GuardHandlers []gin.HandlerFunc `json:"-" yaml:"-"` - Connectors map[string]ConnectorSetting `json:"-" yaml:"-"` -} - -// ConnectorSetting the connector setting -type ConnectorSetting struct { - Vision bool `json:"vision,omitempty" yaml:"vision,omitempty"` - Tools bool `json:"tools,omitempty" yaml:"tools,omitempty"` + ID string `json:"-" yaml:"-"` + Name string `json:"name,omitempty" yaml:"name,omitempty"` + Use string `json:"use,omitempty" yaml:"use,omitempty"` // Which assistant to use default + Guard string `json:"guard,omitempty" yaml:"guard,omitempty"` + Connector string `json:"connector" yaml:"connector"` + StoreSetting store.Setting `json:"store" yaml:"store"` + RAGSetting rag.Setting `json:"rag" yaml:"rag"` + VisionSetting VisionSetting `json:"vision" yaml:"vision"` + Option map[string]interface{} `json:"option" yaml:"option"` + Prepare string `json:"prepare,omitempty" yaml:"prepare,omitempty"` + Create string `json:"create,omitempty" yaml:"create,omitempty"` + Write string `json:"write,omitempty" yaml:"write,omitempty"` + Prompts []assistant.Prompt `json:"prompts,omitempty" yaml:"prompts,omitempty"` + Allows []string `json:"allows,omitempty" yaml:"allows,omitempty"` + Connectors map[string]assistant.ConnectorSetting `json:"connectors,omitempty" yaml:"connectors,omitempty"` + Assistant assistant.API `json:"-" yaml:"-"` // The default assistant + Store store.Store `json:"-" yaml:"-"` + RAG *rag.RAG `json:"-" yaml:"-"` + Vision *vision.Vision `json:"-" yaml:"-"` + GuardHandlers []gin.HandlerFunc `json:"-" yaml:"-"` } // VisionSetting the vision setting