From 4bb5fca43029244742484f9bd776fb8e913dc80b Mon Sep 17 00:00:00 2001 From: Max Date: Fri, 12 May 2023 13:20:09 +0800 Subject: [PATCH] [add] Neo enter command mode by typing the /name --- neo/command/command.go | 34 ++++++++++++++++++++++++++++-- neo/command/driver/memory.go | 13 ++++++------ neo/command/driver/types.go | 1 + neo/command/request.go | 40 +++++++++++++++++++++++++++++++++++- neo/command/types.go | 7 ++++--- neo/neo.go | 6 +++--- neo/types.go | 1 + 7 files changed, 87 insertions(+), 15 deletions(-) diff --git a/neo/command/command.go b/neo/command/command.go index 1b503aef..efd695a2 100644 --- a/neo/command/command.go +++ b/neo/command/command.go @@ -2,6 +2,8 @@ package command import ( "fmt" + "regexp" + "strings" "github.com/yaoapp/gou/connector" "github.com/yaoapp/yao/aigc" @@ -12,6 +14,8 @@ import ( // DefaultStore the default store driver var DefaultStore Store +var recmd, _ = regexp.Compile(`^\/([a-zA-Z]+) +`) +var reCmdOnly, _ = regexp.Compile(`^\/([a-zA-Z]+)$`) // SetStore the driver interface func SetStore(store Store) { @@ -31,6 +35,21 @@ func Match(sid string, query query.Param, input string) (string, error) { return cid, nil } + // Match the command use the command ID + match := reCmdOnly.FindSubmatch([]byte(strings.TrimSpace(input))) + if match == nil { + match = recmd.FindSubmatch([]byte(strings.TrimSpace(input))) + } + if match != nil { + key := fmt.Sprintf("[Index]%s", match[1]) + fmt.Println("Match Index:", key) + + if cmd, ok := DefaultStore.Get(key); ok { + fmt.Println("Match Command:", cmd.ID) + return cmd.ID, nil + } + } + return DefaultStore.Match(query, input) } @@ -60,13 +79,24 @@ func (cmd *Command) save() error { }) } - return DefaultStore.Set(cmd.ID, driver.Command{ + data := driver.Command{ ID: cmd.ID, + Use: cmd.Use, Description: cmd.Description, Args: args, Stack: cmd.Stack, Path: cmd.Path, - }) + } + + if cmd.Use != "" { + key := fmt.Sprintf("[Index]%s", cmd.Use) + err := DefaultStore.Set(key, data) + if err != nil { + return err + } + } + + return DefaultStore.Set(cmd.ID, data) } // NewAI create a new AI diff --git a/neo/command/driver/memory.go b/neo/command/driver/memory.go index fc251ade..0cf16800 100644 --- a/neo/command/driver/memory.go +++ b/neo/command/driver/memory.go @@ -60,6 +60,7 @@ func (driver *Memory) Match(query query.Param, content string) (string, error) { has = true bytes, err := jsoniter.Marshal(map[string]interface{}{ "id": cmd.ID, + "use": cmd.Use, "name": cmd.Name, "description": cmd.Description, "args": cmd.Args, @@ -118,19 +119,19 @@ func (driver *Memory) Match(query query.Param, content string) (string, error) { } // Set Set the command data -func (driver *Memory) Set(id string, cmd Command) error { - commands.Store(id, cmd) +func (driver *Memory) Set(key string, cmd Command) error { + commands.Store(key, cmd) return nil } // Del delete the command data -func (driver *Memory) Del(id string) { - commands.Delete(id) +func (driver *Memory) Del(key string) { + commands.Delete(key) } // Get the command data -func (driver *Memory) Get(id string) (Command, bool) { - v, ok := commands.Load(id) +func (driver *Memory) Get(key string) (Command, bool) { + v, ok := commands.Load(key) if !ok { return Command{}, false } diff --git a/neo/command/driver/types.go b/neo/command/driver/types.go index b0c19feb..282dd496 100644 --- a/neo/command/driver/types.go +++ b/neo/command/driver/types.go @@ -10,6 +10,7 @@ type Request struct { // Command the command struct type Command struct { ID string `json:"-" yaml:"-"` + Use string `json:"use,omitempty"` Name string `json:"name,omitempty"` Description string `json:"description,omitempty"` Args []map[string]interface{} `json:"args,omitempty"` diff --git a/neo/command/request.go b/neo/command/request.go index a2b1303b..4451e863 100644 --- a/neo/command/request.go +++ b/neo/command/request.go @@ -10,6 +10,8 @@ import ( v8 "github.com/yaoapp/gou/runtime/v8" "github.com/yaoapp/kun/log" "github.com/yaoapp/kun/maps" + "github.com/yaoapp/kun/utils" + "github.com/yaoapp/yao/config" "github.com/yaoapp/yao/neo/conversation" "github.com/yaoapp/yao/neo/message" "rogchap.com/v8go" @@ -18,18 +20,46 @@ import ( // Run the command func (req *Request) Run(messages []map[string]interface{}, cb func(msg *message.JSON) int) error { + // Enter the command mode + if input, ok := messages[len(messages)-1]["content"].(string); ok { + match := reCmdOnly.FindSubmatch([]byte(strings.TrimSpace(input))) + if match != nil { + fmt.Printf("Match Command: %s | %s\n", match[1], input) + cb(req.msg().Text("Enter the command Mode")) + cb(req.msg().Done()) + return nil + } + } + + if config.Conf.Mode == "development" { + utils.Dump("----Request Run ----") + fmt.Printf("Command Request: %s %s\n", req.Command.ID, req.sid) + fmt.Printf("Command Process: %s\n", req.Command.Process) + fmt.Printf("Command Prepare Before: %s\n", req.Command.Prepare.Before) + fmt.Printf("Command Prepare Before: %s\n", req.Command.Prepare.After) + } + input, err := req.prepare(messages, cb) if err != nil { req.error(err, cb) return err } + if config.Conf.Mode == "development" { + utils.Dump("----Input After Prepare ----", input) + } + args, err := req.parseArgs(input, cb) if err != nil { + cb(req.msg().Text("\n\n" + err.Error())) cb(req.msg().Done()) return nil } + if config.Conf.Mode == "development" { + utils.Dump("---- Command Args ----", args) + } + // Send the command to the service if req.Command.Optional.Confirm != "" { req.confirm(args, cb) @@ -167,6 +197,10 @@ func (req *Request) parseArgs(input interface{}, cb func(msg *message.JSON) int) // RunPrepare the command func (req *Request) prepare(messages []map[string]interface{}, cb func(msg *message.JSON) int) (interface{}, error) { + if config.Conf.Mode == "development" { + utils.Dump("----Messages Before Prepare ----", messages) + } + // Before hook data, err := req.prepareBefore(messages, cb) if err != nil { @@ -198,6 +232,10 @@ func (req *Request) prepare(messages []map[string]interface{}, cb func(msg *mess return nil, err } + if config.Conf.Mode == "development" { + utils.Dump("----Command Prompts ----", chatMessages) + } + // chat with AI content := []byte{} _, ex := req.AI.ChatCompletionsWith(req.ctx, chatMessages, req.Prepare.Option, func(data []byte) int { @@ -281,7 +319,7 @@ func (req *Request) saveHistory(content []byte, messages []map[string]interface{ func (req *Request) error(err error, cb func(msg *message.JSON) int) { cb(req.msg().Text(err.Error())) cb(message.New().Done()) - req.Done() + // req.Done() } func (req *Request) question(messages []map[string]interface{}) (string, error) { diff --git a/neo/command/types.go b/neo/command/types.go index 0703ca68..e14dc08e 100644 --- a/neo/command/types.go +++ b/neo/command/types.go @@ -23,6 +23,7 @@ type Request struct { type Command struct { ID string `json:"-" yaml:"-"` Name string `json:"name,omitempty"` + Use string `json:"use,omitempty"` Connector string `json:"connector"` Process string `json:"process"` Prepare Prepare `json:"prepare"` @@ -77,9 +78,9 @@ type Context struct { // Store the command driver type Store interface { Match(query query.Param, content string) (string, error) - Set(id string, cmd driver.Command) error - Get(id string) (driver.Command, bool) - Del(id string) + Set(key string, cmd driver.Command) error + Get(key string) (driver.Command, bool) + Del(key string) SetRequest(sid, id, cid string) error GetRequest(sid string) (string, string, bool) DelRequest(sid string) diff --git a/neo/neo.go b/neo/neo.go index 2ddac88f..fbe4d13d 100644 --- a/neo/neo.go +++ b/neo/neo.go @@ -251,9 +251,9 @@ func (neo *DSL) matchCommand(ctx command.Context, messages []map[string]interfac return nil, false } - name, err := command.Match(ctx.Sid, query.Param{Stack: ctx.Stack, Path: ctx.Path}, input) - if err == nil && name != "" { - cmd, isCommand := command.Commands[name] + id, err := command.Match(ctx.Sid, query.Param{Stack: ctx.Stack, Path: ctx.Path}, input) + if err == nil && id != "" { + cmd, isCommand := command.Commands[id] return cmd, isCommand } diff --git a/neo/types.go b/neo/types.go index 084030f7..a0dfe9f7 100644 --- a/neo/types.go +++ b/neo/types.go @@ -11,6 +11,7 @@ import ( type DSL struct { ID string `json:"-" yaml:"-"` Name string `json:"name,omitempty"` + Use string `json:"use,omitempty"` Guard string `json:"guard,omitempty"` Connector string `json:"connector"` ConversationSetting conversation.Setting `json:"conversation" yaml:"conversation"`