From 8e3a1fcbe57eff6a3a61b741112ba0dcd00c8116 Mon Sep 17 00:00:00 2001 From: mudler Date: Mon, 1 Apr 2024 22:50:11 +0200 Subject: [PATCH] return statesg --- agent/actions.go | 13 ++++++++++++- agent/agent.go | 2 +- agent/agent_test.go | 19 ++++++++++++++----- agent/jobs.go | 42 +++++++++++++++++++++++------------------- 4 files changed, 50 insertions(+), 26 deletions(-) diff --git a/agent/actions.go b/agent/actions.go index e08c706..6770505 100644 --- a/agent/actions.go +++ b/agent/actions.go @@ -11,6 +11,17 @@ import ( "github.com/sashabaranov/go-openai" ) +type ActionState struct { + ActionCurrentState + Result string +} + +type ActionCurrentState struct { + Action Action + Params action.ActionParams + Reasoning string +} + // Actions is something the agent can do type Action interface { Run(action.ActionParams) (string, error) @@ -135,7 +146,7 @@ func (a *Agent) pickAction(ctx context.Context, templ string, messages []openai. return nil, "", err } - err = hudTmpl.Execute(prompt, a.prepareHUD()) + err = hudTmpl.Execute(hud, a.prepareHUD()) if err != nil { return nil, "", err } diff --git a/agent/agent.go b/agent/agent.go index ff01696..df2fd10 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -63,7 +63,7 @@ func New(opts ...Option) (*Agent, error) { // Ask is a pre-emptive, blocking call that returns the response as soon as it's ready. // It discards any other computation. -func (a *Agent) Ask(opts ...JobOption) []string { +func (a *Agent) Ask(opts ...JobOption) []ActionState { //a.StopAction() j := NewJob(opts...) // fmt.Println("Job created", text) diff --git a/agent/agent_test.go b/agent/agent_test.go index aa5af1e..312f305 100644 --- a/agent/agent_test.go +++ b/agent/agent_test.go @@ -62,13 +62,18 @@ var _ = Describe("Agent test", func() { go agent.Run() defer agent.Stop() res := agent.Ask( - WithReasoningCallback(func(a Action, ap action.ActionParams, s string) { - fmt.Println("Reasoning", s) + WithReasoningCallback(func(state ActionCurrentState) bool { + fmt.Println("Reasoning", state) + return true }), WithText("can you get the weather in boston, and afterward of Milano, Italy?"), ) - Expect(res).To(ContainElement(testActionResult), fmt.Sprint(res)) - Expect(res).To(ContainElement(testActionResult2), fmt.Sprint(res)) + reasons := []string{} + for _, r := range res { + reasons = append(reasons, r.Result) + } + Expect(reasons).To(ContainElement(testActionResult), fmt.Sprint(res)) + Expect(reasons).To(ContainElement(testActionResult2), fmt.Sprint(res)) }) It("pick the correct action", func() { agent, err := New( @@ -83,7 +88,11 @@ var _ = Describe("Agent test", func() { res := agent.Ask( WithText("can you get the weather in boston?"), ) - Expect(res).To(ContainElement(testActionResult), fmt.Sprint(res)) + reasons := []string{} + for _, r := range res { + reasons = append(reasons, r.Result) + } + Expect(reasons).To(ContainElement(testActionResult), fmt.Sprint(res)) }) }) }) diff --git a/agent/jobs.go b/agent/jobs.go index 5f463de..53b1a96 100644 --- a/agent/jobs.go +++ b/agent/jobs.go @@ -17,28 +17,28 @@ type Job struct { Text string Image string // base64 encoded image Result *JobResult - reasoningCallback func(Action, action.ActionParams, string) - resultCallback func(Action, action.ActionParams, string, string) + reasoningCallback func(ActionCurrentState) bool + resultCallback func(ActionState) } // JobResult is the result of a job type JobResult struct { sync.Mutex // The result of a job - Data []string + State []ActionState Error error ready chan bool } type JobOption func(*Job) -func WithReasoningCallback(f func(Action, action.ActionParams, string)) JobOption { +func WithReasoningCallback(f func(ActionCurrentState) bool) JobOption { return func(r *Job) { r.reasoningCallback = f } } -func WithResultCallback(f func(Action, action.ActionParams, string, string)) JobOption { +func WithResultCallback(f func(ActionState)) JobOption { return func(r *Job) { r.resultCallback = f } @@ -52,18 +52,18 @@ func NewJobResult() *JobResult { return r } -func (j *Job) Callback(a Action, p action.ActionParams, s string) { +func (j *Job) Callback(stateResult ActionCurrentState) bool { if j.reasoningCallback == nil { - return + return true } - j.reasoningCallback(a, p, s) + return j.reasoningCallback(stateResult) } -func (j *Job) CallbackWithResult(a Action, p action.ActionParams, s, r string) { +func (j *Job) CallbackWithResult(stateResult ActionState) { if j.resultCallback == nil { return } - j.resultCallback(a, p, s, r) + j.resultCallback(stateResult) } func WithImage(image string) JobOption { @@ -93,11 +93,11 @@ func NewJob(opts ...JobOption) *Job { } // SetResult sets the result of a job -func (j *JobResult) SetResult(text string) { +func (j *JobResult) SetResult(text ActionState) { j.Lock() defer j.Unlock() - j.Data = append(j.Data, text) + j.State = append(j.State, text) } // SetResult sets the result of a job @@ -110,11 +110,11 @@ func (j *JobResult) Finish(e error) { } // WaitResult waits for the result of a job -func (j *JobResult) WaitResult() []string { +func (j *JobResult) WaitResult() []ActionState { <-j.ready j.Lock() defer j.Unlock() - return j.Data + return j.State } const pickActionTemplate = `You can take any of the following tools: @@ -185,8 +185,7 @@ func (a *Agent) consumeJob(job *Job) { } if chosenAction == nil || chosenAction.Definition().Name.Is(action.ReplyActionName) { - fmt.Println("No action to do, just reply") - job.Result.SetResult(reasoning) + job.Result.SetResult(ActionState{ActionCurrentState{nil, nil, "No action to do, just reply"}, ""}) return } @@ -196,7 +195,11 @@ func (a *Agent) consumeJob(job *Job) { return } - job.Callback(chosenAction, params.actionParams, reasoning) + if !job.Callback(ActionCurrentState{chosenAction, params.actionParams, reasoning}) { + fmt.Println("Stop from callback") + job.Result.SetResult(ActionState{ActionCurrentState{chosenAction, params.actionParams, reasoning}, "stopped by callback"}) + return + } if params.actionParams == nil { fmt.Println("no parameters") @@ -216,8 +219,9 @@ func (a *Agent) consumeJob(job *Job) { } } fmt.Printf("Action run result: %v\n", result) - job.Result.SetResult(result) - job.CallbackWithResult(chosenAction, params.actionParams, reasoning, result) + stateResult := ActionState{ActionCurrentState{chosenAction, params.actionParams, reasoning}, result} + job.Result.SetResult(stateResult) + job.CallbackWithResult(stateResult) // calling the function messages = append(messages, openai.ChatCompletionMessage{