Merge pull request #921 from trheyi/main
Refactor: Remove deprecated retry logic from objectCall, use the retr…
This commit is contained in:
commit
8551bdfdf6
1 changed files with 142 additions and 143 deletions
|
|
@ -3,18 +3,13 @@ package assistant
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/fatih/color"
|
"github.com/fatih/color"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"github.com/yaoapp/gou/runtime/v8/bridge"
|
"github.com/yaoapp/gou/runtime/v8/bridge"
|
||||||
"github.com/yaoapp/kun/exception"
|
|
||||||
"github.com/yaoapp/kun/log"
|
"github.com/yaoapp/kun/log"
|
||||||
chatctx "github.com/yaoapp/yao/neo/context"
|
chatctx "github.com/yaoapp/yao/neo/context"
|
||||||
chatMessage "github.com/yaoapp/yao/neo/message"
|
chatMessage "github.com/yaoapp/yao/neo/message"
|
||||||
sui "github.com/yaoapp/yao/sui/core"
|
|
||||||
"rogchap.com/v8go"
|
"rogchap.com/v8go"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -185,12 +180,12 @@ func (obj *objectCall) run(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
||||||
|
|
||||||
// Options
|
// Options
|
||||||
options := OptionsCall{
|
options := OptionsCall{
|
||||||
Retry: OptionsCallRetry{
|
// Retry: OptionsCallRetry{
|
||||||
Times: 3,
|
// Times: 3,
|
||||||
Delay: 200,
|
// Delay: 200,
|
||||||
DelayMax: 1000,
|
// DelayMax: 1000,
|
||||||
Prompt: "{{ input }}\n**Answer is not correct, please try again.**\nError:\n{{ error }} \nAssistant's last answer:\n{{ output }}",
|
// Prompt: "{{ input }}\n**Answer is not correct, please try again.**\nError:\n{{ error }} \nAssistant's last answer:\n{{ output }}",
|
||||||
},
|
// },
|
||||||
Silent: true,
|
Silent: true,
|
||||||
Options: map[string]interface{}{}, // LLM API options
|
Options: map[string]interface{}{}, // LLM API options
|
||||||
}
|
}
|
||||||
|
|
@ -267,11 +262,12 @@ func (obj *objectCall) run(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
||||||
// Execute the assistant
|
// Execute the assistant
|
||||||
result, err := newAst.Execute(global.GinContext, chatCtx, input, options.Options, cb) // Execute the assistant
|
result, err := newAst.Execute(global.GinContext, chatCtx, input, options.Options, cb) // Execute the assistant
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result, err = obj.retry(jsArgs, err, input, output, info, options)
|
// result, err = obj.retry(jsArgs, err, input, output, info, options)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
|
// return bridge.JsException(info.Context(), err.Error())
|
||||||
|
// }
|
||||||
return bridge.JsException(info.Context(), err.Error())
|
return bridge.JsException(info.Context(), err.Error())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Copy props
|
// Copy props
|
||||||
for name, value := range goCallProps {
|
for name, value := range goCallProps {
|
||||||
|
|
@ -281,11 +277,12 @@ func (obj *objectCall) run(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
||||||
// Trigger the done event
|
// Trigger the done event
|
||||||
doneResult, err := obj.trigger(info, "done", jsArgs...)
|
doneResult, err := obj.trigger(info, "done", jsArgs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
result, err = obj.retry(jsArgs, err, input, output, info, options)
|
// result, err = obj.retry(jsArgs, err, input, output, info, options)
|
||||||
if err != nil {
|
// if err != nil {
|
||||||
|
// return bridge.JsException(info.Context(), err.Error())
|
||||||
|
// }
|
||||||
return bridge.JsException(info.Context(), err.Error())
|
return bridge.JsException(info.Context(), err.Error())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Return the done result
|
// Return the done result
|
||||||
if doneResult != nil && !doneResult.IsUndefined() {
|
if doneResult != nil && !doneResult.IsUndefined() {
|
||||||
|
|
@ -308,154 +305,156 @@ func (obj *objectCall) run(info *v8go.FunctionCallbackInfo) *v8go.Value {
|
||||||
return jsResult
|
return jsResult
|
||||||
}
|
}
|
||||||
|
|
||||||
func (obj *objectCall) retry(jsArgs []v8go.Valuer, err error, input interface{}, output []chatMessage.Message, info *v8go.FunctionCallbackInfo, options OptionsCall) (*v8go.Value, error) {
|
// Deprecated this function is not used anymore
|
||||||
|
// Use the hook retry instead
|
||||||
|
// func (obj *objectCall) retry(jsArgs []v8go.Valuer, err error, input interface{}, output []chatMessage.Message, info *v8go.FunctionCallbackInfo, options OptionsCall) (*v8go.Value, error) {
|
||||||
|
|
||||||
// Retry times, if not set, return the error
|
// // Retry times, if not set, return the error
|
||||||
if options.Retry.Times <= 0 {
|
// if options.Retry.Times <= 0 {
|
||||||
return nil, err
|
// return nil, err
|
||||||
}
|
// }
|
||||||
|
|
||||||
this := info.This()
|
// this := info.This()
|
||||||
errmsg := exception.Trim(err)
|
// errmsg := exception.Trim(err)
|
||||||
|
|
||||||
// Get current retry times
|
// // Get current retry times
|
||||||
jsTimes, retryErr := this.Get("retry_times")
|
// jsTimes, retryErr := this.Get("retry_times")
|
||||||
if retryErr != nil {
|
// if retryErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to get the retry times: %s", errmsg, retryErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to get the retry times: %s", errmsg, retryErr.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
times := int(jsTimes.Int32())
|
// times := int(jsTimes.Int32())
|
||||||
if times > options.Retry.Times {
|
// if times > options.Retry.Times {
|
||||||
return nil, fmt.Errorf("%s occurred, max retry times reached", errmsg)
|
// return nil, fmt.Errorf("%s occurred, max retry times reached", errmsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Update the retry times
|
// // Update the retry times
|
||||||
times = times + 1
|
// times = times + 1
|
||||||
this.Set("retry_times", int32(times))
|
// this.Set("retry_times", int32(times))
|
||||||
|
|
||||||
// Message content
|
// // Message content
|
||||||
content := ""
|
// content := ""
|
||||||
for _, msg := range output {
|
// for _, msg := range output {
|
||||||
if msg.Type == "text" && msg.IsDelta {
|
// if msg.Type == "text" && msg.IsDelta {
|
||||||
content += msg.Text
|
// content += msg.Text
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Delay
|
// // Delay
|
||||||
delay := options.Retry.Delay * int(times)
|
// delay := options.Retry.Delay * int(times)
|
||||||
if delay > options.Retry.DelayMax {
|
// if delay > options.Retry.DelayMax {
|
||||||
delay = options.Retry.DelayMax
|
// delay = options.Retry.DelayMax
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Wait for the delay
|
// // Wait for the delay
|
||||||
if delay > 0 {
|
// if delay > 0 {
|
||||||
time.Sleep(time.Duration(delay) * time.Millisecond)
|
// time.Sleep(time.Duration(delay) * time.Millisecond)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Format the input
|
// // Format the input
|
||||||
var lastUserMessage *chatMessage.Message = nil
|
// var lastUserMessage *chatMessage.Message = nil
|
||||||
var inputMessages []*chatMessage.Message = nil
|
// var inputMessages []*chatMessage.Message = nil
|
||||||
var lastUserMessageIndex int = 0
|
// var lastUserMessageIndex int = 0
|
||||||
switch v := input.(type) {
|
// switch v := input.(type) {
|
||||||
case string:
|
// case string:
|
||||||
lastUserMessage = &chatMessage.Message{Type: "text", Text: v, Role: "user"}
|
// lastUserMessage = &chatMessage.Message{Type: "text", Text: v, Role: "user"}
|
||||||
inputMessages = []*chatMessage.Message{lastUserMessage}
|
// inputMessages = []*chatMessage.Message{lastUserMessage}
|
||||||
|
|
||||||
case []interface{}:
|
// case []interface{}:
|
||||||
// Get the last user message
|
// // Get the last user message
|
||||||
raw, parseErr := jsoniter.Marshal(v)
|
// raw, parseErr := jsoniter.Marshal(v)
|
||||||
if parseErr != nil {
|
// if parseErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to marshal the input: %s", errmsg, parseErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to marshal the input: %s", errmsg, parseErr.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
parseErr = jsoniter.Unmarshal(raw, &inputMessages)
|
// parseErr = jsoniter.Unmarshal(raw, &inputMessages)
|
||||||
if parseErr != nil {
|
// if parseErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to unmarshal the input: %s", errmsg, parseErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to unmarshal the input: %s", errmsg, parseErr.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get the last user message
|
// // Get the last user message
|
||||||
for i := len(inputMessages) - 1; i >= 0; i-- {
|
// for i := len(inputMessages) - 1; i >= 0; i-- {
|
||||||
if inputMessages[i].Type == "text" && inputMessages[i].Role == "user" {
|
// if inputMessages[i].Type == "text" && inputMessages[i].Role == "user" {
|
||||||
lastUserMessage = inputMessages[i]
|
// lastUserMessage = inputMessages[i]
|
||||||
lastUserMessageIndex = i
|
// lastUserMessageIndex = i
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
case *chatMessage.Message:
|
// case *chatMessage.Message:
|
||||||
lastUserMessage = v
|
// lastUserMessage = v
|
||||||
inputMessages = []*chatMessage.Message{lastUserMessage}
|
// inputMessages = []*chatMessage.Message{lastUserMessage}
|
||||||
|
|
||||||
case map[string]interface{}:
|
// case map[string]interface{}:
|
||||||
text, ok := v["text"].(string)
|
// text, ok := v["text"].(string)
|
||||||
if !ok {
|
// if !ok {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to get the text", errmsg)
|
// return nil, fmt.Errorf("%s occurred but failed to get the text", errmsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v["role"] != "user" {
|
// if v["role"] != "user" {
|
||||||
return nil, fmt.Errorf("%s occurred but the role is not user", errmsg)
|
// return nil, fmt.Errorf("%s occurred but the role is not user", errmsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
lastUserMessage = &chatMessage.Message{Type: "text", Text: text, Role: "user"}
|
// lastUserMessage = &chatMessage.Message{Type: "text", Text: text, Role: "user"}
|
||||||
inputMessages = []*chatMessage.Message{lastUserMessage}
|
// inputMessages = []*chatMessage.Message{lastUserMessage}
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Get the prompt from the options
|
// // Get the prompt from the options
|
||||||
promptTmpl := options.Retry.Prompt
|
// promptTmpl := options.Retry.Prompt
|
||||||
data := sui.Data{
|
// data := sui.Data{
|
||||||
"error": errmsg,
|
// "error": errmsg,
|
||||||
"output": strings.TrimSpace(content),
|
// "output": strings.TrimSpace(content),
|
||||||
"input": lastUserMessage.Text,
|
// "input": lastUserMessage.Text,
|
||||||
}
|
// }
|
||||||
prompt, _ := data.Replace(promptTmpl)
|
// prompt, _ := data.Replace(promptTmpl)
|
||||||
|
|
||||||
// Custom retry prompt by hooking the retry event
|
// // Custom retry prompt by hooking the retry event
|
||||||
if this.Has("on_retry") {
|
// if this.Has("on_retry") {
|
||||||
info.Context().Global().Set("error", errmsg) // Set error
|
// info.Context().Global().Set("error", errmsg) // Set error
|
||||||
jsDelay, _ := bridge.JsValue(info.Context(), delay)
|
// jsDelay, _ := bridge.JsValue(info.Context(), delay)
|
||||||
jsPrompt, _ := bridge.JsValue(info.Context(), prompt)
|
// jsPrompt, _ := bridge.JsValue(info.Context(), prompt)
|
||||||
newPrompt, retryErr := obj.trigger(info, "retry", jsTimes, jsDelay, jsPrompt)
|
// newPrompt, retryErr := obj.trigger(info, "retry", jsTimes, jsDelay, jsPrompt)
|
||||||
if retryErr != nil {
|
// if retryErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to trigger the retry event: %s", errmsg, retryErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to trigger the retry event: %s", errmsg, retryErr.Error())
|
||||||
}
|
// }
|
||||||
// Update the prompt
|
// // Update the prompt
|
||||||
if newPrompt.IsString() {
|
// if newPrompt.IsString() {
|
||||||
prompt = newPrompt.String()
|
// prompt = newPrompt.String()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Generate the new input with the prompt
|
// // Generate the new input with the prompt
|
||||||
// Update the input
|
// // Update the input
|
||||||
inputMessages[lastUserMessageIndex].Text = prompt
|
// inputMessages[lastUserMessageIndex].Text = prompt
|
||||||
jsInput, inputErr := bridge.JsValue(info.Context(), inputMessages)
|
// jsInput, inputErr := bridge.JsValue(info.Context(), inputMessages)
|
||||||
if inputErr != nil {
|
// if inputErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to update the input: %s", errmsg, inputErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to update the input: %s", errmsg, inputErr.Error())
|
||||||
}
|
// }
|
||||||
// Update the input
|
// // Update the input
|
||||||
this.Set("retry_input", jsInput)
|
// this.Set("retry_input", jsInput)
|
||||||
|
|
||||||
// Call the run function
|
// // Call the run function
|
||||||
run, funcErr := this.Get("Run")
|
// run, funcErr := this.Get("Run")
|
||||||
if funcErr != nil {
|
// if funcErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to get the run function: %s", errmsg, funcErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to get the run function: %s", errmsg, funcErr.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
if !run.IsFunction() {
|
// if !run.IsFunction() {
|
||||||
return nil, fmt.Errorf("%s occurred but the run function is not a function", errmsg)
|
// return nil, fmt.Errorf("%s occurred but the run function is not a function", errmsg)
|
||||||
}
|
// }
|
||||||
|
|
||||||
fn, fnErr := run.AsFunction()
|
// fn, fnErr := run.AsFunction()
|
||||||
if fnErr != nil {
|
// if fnErr != nil {
|
||||||
return nil, fmt.Errorf("%s occurred but failed to get the run function: %s", errmsg, fnErr.Error())
|
// return nil, fmt.Errorf("%s occurred but failed to get the run function: %s", errmsg, fnErr.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
result, resErr := fn.Call(this, jsArgs...)
|
// result, resErr := fn.Call(this, jsArgs...)
|
||||||
if resErr != nil {
|
// if resErr != nil {
|
||||||
return nil, fmt.Errorf("%s (%d)", exception.Trim(resErr), times-1)
|
// return nil, fmt.Errorf("%s (%d)", exception.Trim(resErr), times-1)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return result, nil
|
// return result, nil
|
||||||
}
|
// }
|
||||||
|
|
||||||
func (obj *objectCall) triggerAnonymous(chatCtx chatctx.Context, global *GlobalVariables, goCallProps map[string]interface{}, source string, bindArgs []interface{}, fnArgs ...interface{}) error {
|
func (obj *objectCall) triggerAnonymous(chatCtx chatctx.Context, global *GlobalVariables, goCallProps map[string]interface{}, source string, bindArgs []interface{}, fnArgs ...interface{}) error {
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue