[add] Neo (100%)
This commit is contained in:
parent
0f70639292
commit
331a7defd8
4 changed files with 160 additions and 49 deletions
|
|
@ -65,7 +65,7 @@ func LoadSource(data []byte, file, id string) (*Command, error) {
|
|||
},
|
||||
Optional: Optional{
|
||||
Autopilot: false,
|
||||
Confirm: false,
|
||||
Confirm: "",
|
||||
MaxAttempts: 10,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,44 +5,128 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/google/uuid"
|
||||
jsoniter "github.com/json-iterator/go"
|
||||
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/neo/conversation"
|
||||
"github.com/yaoapp/yao/neo/message"
|
||||
"rogchap.com/v8go"
|
||||
)
|
||||
|
||||
// Run the command
|
||||
func (req *Request) Run(conversation conversation.Conversation, messages []map[string]interface{}, cb func(msg *message.JSON) int) (interface{}, error) {
|
||||
func (req *Request) Run(messages []map[string]interface{}, cb func(msg *message.JSON) int) error {
|
||||
|
||||
content, err := req.prepare(conversation, messages, cb)
|
||||
input, err := req.prepare(messages, cb)
|
||||
if err != nil {
|
||||
req.error(err, cb)
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(content))
|
||||
args, err := req.parseArgs(input, cb)
|
||||
if err != nil {
|
||||
cb(req.msg().Done())
|
||||
return nil
|
||||
}
|
||||
|
||||
if req.Command.Optional.Confirm != "" {
|
||||
req.confirm(args, cb)
|
||||
return nil
|
||||
}
|
||||
|
||||
utils.Dump(args)
|
||||
|
||||
// DONE
|
||||
cb(req.msg().Done())
|
||||
|
||||
// cb(req.msg().Text(fmt.Sprintf("- Command: %s\n", req.Command.Name)))
|
||||
// time.Sleep(200 * time.Millisecond)
|
||||
return nil
|
||||
}
|
||||
|
||||
// cb(req.msg().Text(fmt.Sprintf("- Session: %s\n", req.sid)))
|
||||
// time.Sleep(200 * time.Millisecond)
|
||||
// confirm the command
|
||||
func (req *Request) confirm(args []interface{}, cb func(msg *message.JSON) int) {
|
||||
|
||||
// cb(req.msg().Text(fmt.Sprintf("- Request: %s\n", req.sid)))
|
||||
// time.Sleep(200 * time.Millisecond)
|
||||
service := strings.Split(req.Command.Optional.Confirm, ".")
|
||||
if len(service) == 0 {
|
||||
service = []string{"neo", "Exec"}
|
||||
} else if len(service) == 1 {
|
||||
service = []string{"neo", service[0]}
|
||||
}
|
||||
|
||||
// cb(req.msg().Done())
|
||||
return nil, nil
|
||||
payload := map[string]interface{}{
|
||||
"method": service[1],
|
||||
"args": []interface{}{
|
||||
req.id,
|
||||
req.Command.Process,
|
||||
args,
|
||||
},
|
||||
}
|
||||
|
||||
msg := req.msg().
|
||||
Action("ExecCommand", fmt.Sprintf("Service.%s", service[0]), payload, "").
|
||||
Confirm().
|
||||
Done()
|
||||
|
||||
if req.Actions != nil && len(req.Actions) > 0 {
|
||||
for _, action := range req.Actions {
|
||||
msg.Action(action.Name, action.Type, action.Payload, action.Next)
|
||||
}
|
||||
}
|
||||
|
||||
cb(msg)
|
||||
}
|
||||
|
||||
// validate the command
|
||||
func (req *Request) parseArgs(input interface{}, cb func(msg *message.JSON) int) ([]interface{}, error) {
|
||||
args := []interface{}{}
|
||||
data := map[string]interface{}{}
|
||||
|
||||
switch v := input.(type) {
|
||||
case string:
|
||||
err := jsoniter.Unmarshal([]byte(v), &data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
|
||||
case []byte:
|
||||
err := jsoniter.Unmarshal(v, &data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break
|
||||
|
||||
case map[string]interface{}:
|
||||
data = v
|
||||
break
|
||||
|
||||
default:
|
||||
err := fmt.Errorf("\nInvalid input type: %T", v)
|
||||
req.error(err, cb)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// validate the args
|
||||
if req.Command.Args != nil && len(req.Command.Args) > 0 {
|
||||
for _, arg := range req.Command.Args {
|
||||
v, ok := data[arg.Name]
|
||||
if arg.Required && !ok {
|
||||
err := fmt.Errorf("\nMissing required argument: %s", arg.Name)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// @todo: validate the type
|
||||
args = append(args, v)
|
||||
}
|
||||
}
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// RunPrepare the command
|
||||
func (req *Request) prepare(conversation conversation.Conversation, messages []map[string]interface{}, cb func(msg *message.JSON) int) ([]byte, error) {
|
||||
func (req *Request) prepare(messages []map[string]interface{}, cb func(msg *message.JSON) int) (interface{}, error) {
|
||||
|
||||
// Before hook
|
||||
data, err := req.prepareBefore(messages, cb)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -67,7 +151,7 @@ func (req *Request) prepare(conversation conversation.Conversation, messages []m
|
|||
return nil, err
|
||||
}
|
||||
|
||||
chatMessages, err := req.messages(conversation, prompts, question)
|
||||
chatMessages, err := req.messages(prompts, question)
|
||||
if err != nil {
|
||||
req.error(err, cb)
|
||||
return nil, err
|
||||
|
|
@ -91,9 +175,17 @@ func (req *Request) prepare(conversation conversation.Conversation, messages []m
|
|||
req.error(fmt.Errorf(ex.Message), cb)
|
||||
return nil, fmt.Errorf("Chat error: %s", ex.Message)
|
||||
}
|
||||
defer req.saveHistory(conversation, content, chatMessages)
|
||||
defer req.saveHistory(content, chatMessages)
|
||||
|
||||
return content, nil
|
||||
// After hook
|
||||
args, err := req.prepareAfter(string(content), cb)
|
||||
if err != nil {
|
||||
log.Error("Prepare after error: %s", err.Error())
|
||||
fmt.Println(err)
|
||||
return content, nil
|
||||
}
|
||||
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// prepareBefore hook
|
||||
|
|
@ -112,11 +204,24 @@ func (req *Request) prepareBefore(messages []map[string]interface{}, cb func(msg
|
|||
return req.runScript(req.Prepare.Before, args, cb)
|
||||
}
|
||||
|
||||
// prepareAfter hook
|
||||
func (req *Request) prepareAfter(content string, cb func(msg *message.JSON) int) (interface{}, error) {
|
||||
|
||||
if req.Prepare.After == "" {
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// prepare the args
|
||||
args := []interface{}{content}
|
||||
|
||||
return req.runScript(req.Prepare.After, args, cb)
|
||||
}
|
||||
|
||||
// saveHistory save the history
|
||||
func (req *Request) saveHistory(conversation conversation.Conversation, content []byte, messages []map[string]interface{}) {
|
||||
func (req *Request) saveHistory(content []byte, messages []map[string]interface{}) {
|
||||
|
||||
if len(content) > 0 && req.sid != "" && len(messages) > 0 {
|
||||
err := conversation.SaveRequest(
|
||||
err := req.conversation.SaveRequest(
|
||||
req.sid,
|
||||
req.id,
|
||||
req.Command.ID,
|
||||
|
|
@ -151,7 +256,7 @@ func (req *Request) question(messages []map[string]interface{}) (string, error)
|
|||
return question, nil
|
||||
}
|
||||
|
||||
func (req *Request) messages(conversation conversation.Conversation, prompts []Prompt, question string) ([]map[string]interface{}, error) {
|
||||
func (req *Request) messages(prompts []Prompt, question string) ([]map[string]interface{}, error) {
|
||||
messages := []map[string]interface{}{}
|
||||
for _, prompt := range prompts {
|
||||
message := map[string]interface{}{"role": prompt.Role, "content": prompt.Content}
|
||||
|
|
@ -161,7 +266,7 @@ func (req *Request) messages(conversation conversation.Conversation, prompts []P
|
|||
messages = append(messages, message)
|
||||
}
|
||||
|
||||
history, err := conversation.GetRequest(req.sid, req.id)
|
||||
history, err := req.conversation.GetRequest(req.sid, req.id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -240,7 +345,7 @@ func (req *Request) msg() *message.JSON {
|
|||
}
|
||||
|
||||
// NewRequest create a new request
|
||||
func (cmd *Command) NewRequest(ctx Context) (*Request, error) {
|
||||
func (cmd *Command) NewRequest(ctx Context, conversation conversation.Conversation) (*Request, error) {
|
||||
|
||||
if DefaultStore == nil {
|
||||
return nil, fmt.Errorf("command store is not set")
|
||||
|
|
@ -257,10 +362,11 @@ func (cmd *Command) NewRequest(ctx Context) (*Request, error) {
|
|||
return nil, fmt.Errorf("request id is not match")
|
||||
}
|
||||
return &Request{
|
||||
Command: cmd,
|
||||
sid: ctx.Sid,
|
||||
id: id,
|
||||
ctx: ctx,
|
||||
Command: cmd,
|
||||
sid: ctx.Sid,
|
||||
id: id,
|
||||
ctx: ctx,
|
||||
conversation: conversation,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
@ -272,10 +378,11 @@ func (cmd *Command) NewRequest(ctx Context) (*Request, error) {
|
|||
}
|
||||
|
||||
return &Request{
|
||||
Command: cmd,
|
||||
sid: ctx.Sid,
|
||||
id: id,
|
||||
ctx: ctx,
|
||||
Command: cmd,
|
||||
sid: ctx.Sid,
|
||||
id: id,
|
||||
ctx: ctx,
|
||||
conversation: conversation,
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,29 +6,33 @@ import (
|
|||
"github.com/yaoapp/yao/aigc"
|
||||
"github.com/yaoapp/yao/neo/command/driver"
|
||||
"github.com/yaoapp/yao/neo/command/query"
|
||||
"github.com/yaoapp/yao/neo/conversation"
|
||||
"github.com/yaoapp/yao/neo/message"
|
||||
)
|
||||
|
||||
// Request the command request
|
||||
type Request struct {
|
||||
id string
|
||||
sid string
|
||||
ctx Context
|
||||
id string
|
||||
sid string
|
||||
ctx Context
|
||||
conversation conversation.Conversation
|
||||
*Command
|
||||
}
|
||||
|
||||
// Command the command struct
|
||||
type Command struct {
|
||||
ID string `json:"-" yaml:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Connector string `json:"connector"`
|
||||
Process string `json:"process"`
|
||||
Prepare Prepare `json:"prepare"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Optional Optional `json:"optional,omitempty"`
|
||||
Args []Arg `json:"args,omitempty"`
|
||||
Stack string `json:"stack,omitempty"` // query stack
|
||||
Path string `json:"path,omitempty"` // query path
|
||||
AI aigc.AI `json:"-" yaml:"-"`
|
||||
ID string `json:"-" yaml:"-"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Connector string `json:"connector"`
|
||||
Process string `json:"process"`
|
||||
Prepare Prepare `json:"prepare"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Optional Optional `json:"optional,omitempty"`
|
||||
Args []Arg `json:"args,omitempty"`
|
||||
Actions []message.Action `json:"actions,omitempty"`
|
||||
Stack string `json:"stack,omitempty"` // query stack
|
||||
Path string `json:"path,omitempty"` // query path
|
||||
AI aigc.AI `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// Arg the argument
|
||||
|
|
@ -57,9 +61,9 @@ type Prompt struct {
|
|||
|
||||
// Optional optional
|
||||
type Optional struct {
|
||||
Autopilot bool `json:"autopilot,omitempty"`
|
||||
Confirm bool `json:"confirm,omitempty"`
|
||||
MaxAttempts int `json:"maxAttempts,omitempty"` // default 10
|
||||
Autopilot bool `json:"autopilot,omitempty"`
|
||||
Confirm string `json:"confirm,omitempty"`
|
||||
MaxAttempts int `json:"maxAttempts,omitempty"` // default 10
|
||||
}
|
||||
|
||||
// Context the context
|
||||
|
|
|
|||
|
|
@ -145,13 +145,13 @@ func (neo *DSL) Answer(ctx command.Context, question string, answer Answer) erro
|
|||
// execute the command
|
||||
if isCommand {
|
||||
|
||||
req, err := cmd.NewRequest(ctx)
|
||||
req, err := cmd.NewRequest(ctx, neo.Conversation)
|
||||
if err != nil {
|
||||
chanError <- err
|
||||
return
|
||||
}
|
||||
|
||||
_, err = req.Run(neo.Conversation, messages, func(msg *message.JSON) int {
|
||||
err = req.Run(messages, func(msg *message.JSON) int {
|
||||
chanStream <- msg
|
||||
return 1
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue