@@ -10,18 +10,22 @@ import (
1010 "context"
1111 "errors"
1212 "fmt"
13- "strings"
1413
1514 "github.com/bit8bytes/gogantic/agents/tools"
1615 "github.com/bit8bytes/gogantic/inputs/roles"
1716 "github.com/bit8bytes/gogantic/llms"
18- "github.com/bit8bytes/gogantic/outputs/jsonout"
1917)
2018
2119type llm interface {
2220 Generate (ctx context.Context , messages []llms.Message ) (* llms.ContentResponse , error )
2321}
2422
23+ type store interface {
24+ Add (ctx context.Context , msgs ... llms.Message ) error
25+ List (ctx context.Context ) ([]llms.Message , error )
26+ Clear (ctx context.Context ) error
27+ }
28+
2529// Tool represents an action the agent can perform.
2630// Each tool must provide a name, description, and execution logic.
2731type Tool interface {
@@ -41,40 +45,41 @@ type parser interface {
4145type Agent struct {
4246 model llm
4347 tools map [string ]Tool
44- Messages []llms. Message
48+ History store
4549 actions []Action
4650 parser parser
4751 finalAnswer string
4852}
4953
50- // New creates an agent with the given model and tools.
51- // The agent is initialized with a ReAct system prompt.
52- func New (model llm , tools []Tool ) * Agent {
53- p := jsonout .NewParser [AgentResponse ]()
54- t := toolNames (tools )
55-
54+ // New creates an agent with the given model, tools, storage, and parser.
55+ // For the ReAct pattern, prefer NewReAct.
56+ func New (model llm , tools []Tool , storage store , p parser ) * Agent {
5657 return & Agent {
57- model : model ,
58- tools : t ,
59- Messages : buildReActPrompt ( t , p . Instructions ()) ,
60- parser : p ,
58+ model : model ,
59+ tools : toolNames ( tools ) ,
60+ History : storage ,
61+ parser : p ,
6162 }
6263}
6364
6465// Task sets the user's question or task for the agent to solve.
6566// Call this before starting the Plan-Act loop.
66- func (a * Agent ) Task (prompt string ) error {
67- a . Messages = append ( a . Messages , llms.Message {
67+ func (a * Agent ) Task (ctx context. Context , prompt string ) error {
68+ return a . History . Add ( ctx , llms.Message {
6869 Role : roles .User ,
6970 Content : "Question: " + prompt ,
7071 })
71- return nil
7272}
7373
7474// Plan calls the LLM to decide the next action or provide a final answer.
7575// Returns Response.Finish=true when the task is complete.
7676func (a * Agent ) Plan (ctx context.Context ) (* Response , error ) {
77- generated , err := a .model .Generate (ctx , a .Messages )
77+ history , err := a .History .List (ctx )
78+ if err != nil {
79+ return nil , err
80+ }
81+
82+ generated , err := a .model .Generate (ctx , history )
7883 if err != nil {
7984 return nil , err
8085 }
@@ -84,7 +89,7 @@ func (a *Agent) Plan(ctx context.Context) (*Response, error) {
8489 return nil , fmt .Errorf ("failed to parse agent response: %w" , err )
8590 }
8691
87- a .addAssistantMessage (generated .Result )
92+ a .addAssistantMessage (ctx , generated .Result )
8893
8994 if parsed .FinalAnswer != "" {
9095 a .finalAnswer = parsed .FinalAnswer
@@ -119,19 +124,19 @@ func (a *Agent) Act(ctx context.Context) {
119124func (a * Agent ) handleAction (ctx context.Context , action Action ) bool {
120125 t , exists := a .tools [action .Tool ]
121126 if ! exists {
122- a .addObservationMessage ("The action " + action .Tool + " doesn't exist." )
127+ a .addObservationMessage (ctx , "The action " + action .Tool + " doesn't exist." )
123128 return false
124129 }
125130
126131 observation , err := t .Execute (ctx , tools.Input {
127132 Content : action .ToolInput ,
128133 })
129134 if err != nil {
130- a .addObservationMessage ("Error: " + err .Error ())
135+ a .addObservationMessage (ctx , "Error: " + err .Error ())
131136 return false
132137 }
133138
134- a .addObservationMessage (observation .Content )
139+ a .addObservationMessage (ctx , observation .Content )
135140 return true
136141}
137142
@@ -148,34 +153,6 @@ func (a *Agent) Answer() (string, error) {
148153 return a .finalAnswer , nil
149154}
150155
151- func buildReActPrompt (tools map [string ]Tool , jsonInstructions string ) []llms.Message {
152- var toolDescriptions strings.Builder
153- for _ , t := range tools {
154- fmt .Fprintf (& toolDescriptions , "- %s: %s\n " , t .Name (), t .Description ())
155- }
156-
157- return []llms.Message {
158- {
159- Role : roles .System ,
160- Content : fmt .Sprintf (`
161- You are an helpful agent. Answer questions using the available tools.
162- Do not estimate or predict values. Use only values returned by tools.
163-
164- Available tools:
165- %s
166- %s
167-
168- Respond with a JSON object on each turn with these fields:
169- - "thought": your reasoning about what to do next
170- - "action": the exact tool name to call (empty string when giving final answer)
171- - "action_input": the input to pass to the tool (empty string when giving final answer)
172- - "final_answer": your final answer (empty string when calling a tool)
173-
174- Think step by step. Do not hallucinate.` , toolDescriptions .String (), jsonInstructions ),
175- },
176- }
177- }
178-
179156func toolNames (tools []Tool ) map [string ]Tool {
180157 t := make (map [string ]Tool , len (tools ))
181158 for _ , tool := range tools {
0 commit comments