restructured answers a bit
This commit is contained in:
@@ -6,6 +6,8 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"gitea.stevedudenhoeffer.com/steve/answer/pkg/toolbox"
|
||||
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
|
||||
cache2 "gitea.stevedudenhoeffer.com/steve/answer/pkg/cache"
|
||||
@@ -60,7 +62,7 @@ var (
|
||||
)
|
||||
|
||||
func ask(ctx *Context, q Question) (Answers, error) {
|
||||
var tb = ToolBox{}
|
||||
var tb = toolbox.ToolBox{}
|
||||
|
||||
if ctx.Agent.RemainingSearches.Load() > 0 {
|
||||
tb.Register(SearchTool)
|
||||
@@ -71,11 +73,11 @@ func ask(ctx *Context, q Question) (Answers, error) {
|
||||
return tb.Run(ctx, q)
|
||||
}
|
||||
|
||||
var SummarizeAnswers = FromFunction(
|
||||
var SummarizeAnswers = toolbox.FromFunction(
|
||||
func(ctx *Context, args struct {
|
||||
Summary string `description:"the summary of the answers"`
|
||||
}) (FuncResponse, error) {
|
||||
return FuncResponse{Result: args.Summary}, nil
|
||||
}) (toolbox.FuncResponse, error) {
|
||||
return toolbox.FuncResponse{Result: args.Summary}, nil
|
||||
}).
|
||||
WithName("summarize_answers").
|
||||
WithDescription(`You are given previously figured out answers and they are in the format of: [ { "answer": "the answer", "source": "the source of the answer" }, { "answer": "answer 2", "source": "the source for answer2" } ]. You need to summarize the answers into a single string. Be sure to make the summary clear and concise, but include the sources at some point.`)
|
||||
@@ -92,7 +94,7 @@ func (a *Agent) Ask(ctx context.Context, q Question) (string, error) {
|
||||
return "", err
|
||||
}
|
||||
|
||||
tb := ToolBox{}
|
||||
tb := toolbox.ToolBox{}
|
||||
|
||||
tb.Register(SummarizeAnswers)
|
||||
|
||||
|
@@ -1,10 +1,12 @@
|
||||
package agent
|
||||
|
||||
var AnswerTool = FromFunction(
|
||||
import "gitea.stevedudenhoeffer.com/steve/answer/pkg/toolbox"
|
||||
|
||||
var AnswerTool = toolbox.FromFunction(
|
||||
func(ctx *Context, args struct {
|
||||
Answer string `description:"the answer to the question"`
|
||||
}) (FuncResponse, error) {
|
||||
return FuncResponse{Result: args.Answer}, nil
|
||||
}) (toolbox.FuncResponse, error) {
|
||||
return toolbox.FuncResponse{Result: args.Answer}, nil
|
||||
}).
|
||||
WithName("answer").
|
||||
WithDescription("Answer the question")
|
||||
|
@@ -3,12 +3,14 @@ package agent
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"gitea.stevedudenhoeffer.com/steve/answer/pkg/toolbox"
|
||||
)
|
||||
|
||||
var AskTool = FromFunction(
|
||||
var AskTool = toolbox.FromFunction(
|
||||
func(ctx *Context, args struct {
|
||||
Question string `description:"the question to answer"`
|
||||
}) (FuncResponse, error) {
|
||||
}) (toolbox.FuncResponse, error) {
|
||||
var q Question
|
||||
|
||||
q.Question = args.Question
|
||||
@@ -17,15 +19,15 @@ var AskTool = FromFunction(
|
||||
answers, err := ask(ctx, q)
|
||||
|
||||
if err != nil {
|
||||
return FuncResponse{}, err
|
||||
return toolbox.FuncResponse{}, err
|
||||
}
|
||||
|
||||
tb := ToolBox{}
|
||||
tb := toolbox.ToolBox{}
|
||||
tb.Register(SummarizeAnswers)
|
||||
|
||||
b, err := json.Marshal(answers.Answers)
|
||||
if err != nil {
|
||||
return FuncResponse{}, fmt.Errorf("failed to marshal answers: %w", err)
|
||||
return toolbox.FuncResponse{}, fmt.Errorf("failed to marshal answers: %w", err)
|
||||
}
|
||||
|
||||
q = Question{Question: string(b)}
|
||||
@@ -33,14 +35,14 @@ var AskTool = FromFunction(
|
||||
answers, err = tb.Run(ctx, q)
|
||||
|
||||
if err != nil {
|
||||
return FuncResponse{}, fmt.Errorf("failed to summarize answers: %w", err)
|
||||
return toolbox.FuncResponse{}, fmt.Errorf("failed to summarize answers: %w", err)
|
||||
}
|
||||
|
||||
if len(answers.Answers) == 0 {
|
||||
return FuncResponse{}, fmt.Errorf("no response from model")
|
||||
return toolbox.FuncResponse{}, fmt.Errorf("no response from model")
|
||||
}
|
||||
|
||||
return FuncResponse{Result: answers.Answers[0].Answer}, nil
|
||||
return toolbox.FuncResponse{Result: answers.Answers[0].Answer}, nil
|
||||
}).
|
||||
WithName("ask").
|
||||
WithDescription("Ask the agent a question, this is useful for splitting a question into multiple parts")
|
||||
|
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"gitea.stevedudenhoeffer.com/steve/answer/pkg/toolbox"
|
||||
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
)
|
||||
|
||||
@@ -35,7 +37,7 @@ func (c *Context) WithMessages(m ...llms.MessageContent) *Context {
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Context) WithToolResults(r ...ToolResult) *Context {
|
||||
func (c *Context) WithToolResults(r ...toolbox.ToolResult) *Context {
|
||||
msg := llms.MessageContent{
|
||||
Role: llms.ChatMessageTypeTool,
|
||||
}
|
||||
|
@@ -1,11 +1,13 @@
|
||||
package agent
|
||||
|
||||
var SearchTool = FromFunction(
|
||||
import "gitea.stevedudenhoeffer.com/steve/answer/pkg/toolbox"
|
||||
|
||||
var SearchTool = toolbox.FromFunction(
|
||||
func(ctx *Context, args struct {
|
||||
SearchFor string `description:"what to search for"`
|
||||
Question string `description:"the question to answer with the search results"`
|
||||
}) (FuncResponse, error) {
|
||||
return FuncResponse{}, nil
|
||||
}) (toolbox.FuncResponse, error) {
|
||||
return toolbox.FuncResponse{}, nil
|
||||
}).
|
||||
WithName("search").
|
||||
WithDescription("Search the web and read a few articles to find the answer to the question")
|
||||
|
@@ -4,13 +4,15 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"gitea.stevedudenhoeffer.com/steve/answer/pkg/toolbox"
|
||||
|
||||
"github.com/Edw590/go-wolfram"
|
||||
)
|
||||
|
||||
var WolframTool = FromFunction(
|
||||
var WolframTool = toolbox.FromFunction(
|
||||
func(ctx *Context, args struct {
|
||||
Query string `description:"what to ask wolfram alpha"`
|
||||
}) (FuncResponse, error) {
|
||||
}) (toolbox.FuncResponse, error) {
|
||||
var cl = wolfram.Client{
|
||||
AppID: os.Getenv("WOLFRAM_APPID"),
|
||||
}
|
||||
@@ -19,10 +21,10 @@ var WolframTool = FromFunction(
|
||||
|
||||
a, err := cl.GetShortAnswerQuery(args.Query, unit, 10)
|
||||
if err != nil {
|
||||
return FuncResponse{}, fmt.Errorf("failed to get short answer from wolfram: %w", err)
|
||||
return toolbox.FuncResponse{}, fmt.Errorf("failed to get short answer from wolfram: %w", err)
|
||||
}
|
||||
|
||||
return FuncResponse{Result: a, Source: "Wolfram|Alpha"}, nil
|
||||
return toolbox.FuncResponse{Result: a, Source: "Wolfram|Alpha"}, nil
|
||||
}).
|
||||
WithName("wolfram").
|
||||
WithDescription("ask wolfram alpha for the answer")
|
||||
|
17
pkg/toolbox/context.go
Normal file
17
pkg/toolbox/context.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
)
|
||||
|
||||
type Context interface {
|
||||
context.Context
|
||||
|
||||
WithCancel() (Context, func())
|
||||
WithTimeout(time.Duration) (Context, func())
|
||||
WithMessages([]llms.MessageContent) Context
|
||||
GetMessages() []llms.MessageContent
|
||||
}
|
@@ -1,6 +1,7 @@
|
||||
package agent
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -190,14 +191,14 @@ func analyzeFuncFromReflect(fn reflect.Value) (function, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func analyzeFunction[T any](fn func(*Context, T) (FuncResponse, error)) (function, error) {
|
||||
func analyzeFunction[T any, AgentContext any](fn func(AgentContext, T) (FuncResponse, error)) (function, error) {
|
||||
return analyzeFuncFromReflect(reflect.ValueOf(fn))
|
||||
}
|
||||
|
||||
// Execute will execute the given function with the given context and arguments.
|
||||
// Returns the result of the execution and an error if the operation fails.
|
||||
// The arguments must be a JSON-encoded string that represents the struct to be passed to the function.
|
||||
func (f function) Execute(ctx *Context, args string) (FuncResponse, error) {
|
||||
func (f function) Execute(ctx context.Context, args string) (FuncResponse, error) {
|
||||
var m = map[string]any{}
|
||||
|
||||
err := json.Unmarshal([]byte(args), &m)
|
@@ -1,6 +1,7 @@
|
||||
package agent
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
|
||||
"github.com/tmc/langchaingo/llms"
|
||||
@@ -36,11 +37,11 @@ func (t *Tool) Definition() *llms.FunctionDefinition {
|
||||
// Execute executes the tool with the given context and arguments.
|
||||
// Returns the result of the execution and an error if the operation fails.
|
||||
// The arguments must be a JSON-encoded string that represents the struct to be passed to the function.
|
||||
func (t *Tool) Execute(ctx *Context, args string) (FuncResponse, error) {
|
||||
func (t *Tool) Execute(ctx context.Context, args string) (FuncResponse, error) {
|
||||
return t.Function.Execute(ctx, args)
|
||||
}
|
||||
|
||||
func FromFunction[T any](fn func(*Context, T) (FuncResponse, error)) *Tool {
|
||||
func FromFunction[T any, AgentContext any](fn func(AgentContext, T) (FuncResponse, error)) *Tool {
|
||||
f, err := analyzeFunction(fn)
|
||||
if err != nil {
|
||||
panic(err)
|
@@ -1,6 +1,7 @@
|
||||
package agent
|
||||
package toolbox
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -52,7 +53,7 @@ func (r ToolResult) ToToolCallResponse() llms.ToolCallResponse {
|
||||
Content: r.Result,
|
||||
}
|
||||
}
|
||||
func (tb ToolBox) Execute(ctx *Context, call llms.ToolCall) (ToolResult, error) {
|
||||
func (tb ToolBox) Execute(ctx context.Context, call llms.ToolCall) (ToolResult, error) {
|
||||
if call.Type != "function" {
|
||||
return ToolResult{}, fmt.Errorf("unsupported tool type: %s", call.Type)
|
||||
}
|
||||
@@ -67,6 +68,14 @@ func (tb ToolBox) Execute(ctx *Context, call llms.ToolCall) (ToolResult, error)
|
||||
}
|
||||
|
||||
res, err := tool.Execute(ctx, call.FunctionCall.Arguments)
|
||||
if err != nil {
|
||||
return ToolResult{
|
||||
ID: call.ID,
|
||||
Name: tool.Name,
|
||||
Error: err,
|
||||
Source: res.Source,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return ToolResult{
|
||||
ID: call.ID,
|
||||
@@ -77,7 +86,7 @@ func (tb ToolBox) Execute(ctx *Context, call llms.ToolCall) (ToolResult, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (tb ToolBox) ExecuteAll(ctx *Context, calls []llms.ToolCall) (ToolResults, error) {
|
||||
func (tb ToolBox) ExecuteAll(ctx Context, calls []llms.ToolCall) (ToolResults, error) {
|
||||
var results []ToolResult
|
||||
|
||||
for _, call := range calls {
|
||||
@@ -92,7 +101,7 @@ func (tb ToolBox) ExecuteAll(ctx *Context, calls []llms.ToolCall) (ToolResults,
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (tb ToolBox) ExecuteConcurrent(ctx *Context, calls []llms.ToolCall) (ToolResults, error) {
|
||||
func (tb ToolBox) ExecuteConcurrent(ctx Context, calls []llms.ToolCall) (ToolResults, error) {
|
||||
var results []ToolResult
|
||||
var ch = make(chan ToolResult, len(calls))
|
||||
var eg = errgroup.Group{}
|
||||
@@ -124,13 +133,24 @@ func (tb ToolBox) ExecuteConcurrent(ctx *Context, calls []llms.ToolCall) (ToolRe
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (tb ToolBox) Run(ctx *Context, q Question) (Answers, error) {
|
||||
ctx.Messages = append(ctx.Messages, llms.MessageContent{
|
||||
Role: llms.ChatMessageTypeGeneric,
|
||||
Parts: []llms.ContentPart{llms.TextPart(q.Question)},
|
||||
})
|
||||
type Answers struct {
|
||||
Response llms.MessageContent
|
||||
Answers []Answer
|
||||
}
|
||||
|
||||
res, err := ctx.Agent.Model.GenerateContent(ctx, ctx.Messages)
|
||||
type Answer struct {
|
||||
Answer string
|
||||
Source string
|
||||
ToolCallResponse llms.ToolCallResponse `json:"-"`
|
||||
}
|
||||
|
||||
func (tb ToolBox) Run(ctx Context, model llms.Model, question string) (Answers, error) {
|
||||
ctx = ctx.WithMessages([]llms.MessageContent{{
|
||||
Role: llms.ChatMessageTypeGeneric,
|
||||
Parts: []llms.ContentPart{llms.TextPart(question)},
|
||||
}})
|
||||
|
||||
res, err := model.GenerateContent(ctx, ctx.GetMessages())
|
||||
if err != nil {
|
||||
return Answers{}, err
|
||||
}
|
Reference in New Issue
Block a user