@@ -65,33 +65,28 @@ func main() {
6565 client := syndicate.NewOpenAIClient (" YOUR_API_KEY" )
6666
6767 // Create an order processing agent
68- orderAgent , _ := syndicate.NewAgent ().
69- SetClient (client).
70- SetName (" OrderAgent" ).
71- SetConfigPrompt (" You process customer orders." ).
72- SetModel (openai.GPT4 ).
73- Build ()
68+ orderAgent , _ := syndicate.NewAgent (
69+ syndicate.WithClient (client),
70+ syndicate.WithName (" OrderAgent" ),
71+ syndicate.WithSystemPrompt (" You process customer orders." ),
72+ syndicate.WithModel (openai.GPT4 ),
73+ syndicate.WithMemory (syndicate.NewSimpleMemory ()),
74+ )
7475
7576 // Create a summary agent
76- summaryAgent , _ := syndicate.NewAgent ().
77- SetClient (client).
78- SetName (" SummaryAgent" ).
79- SetConfigPrompt (" You summarize order details." ).
80- SetModel (openai.GPT4 ).
81- Build ()
82-
83- // Create a pipeline with both agents
84- system := syndicate.NewSyndicate ().
85- RecruitAgent (orderAgent).
86- RecruitAgent (summaryAgent).
87- DefinePipeline ([]string {" OrderAgent" , " SummaryAgent" }).
88- Build ()
89-
90- // Process user input
91- response , _ := system.ExecutePipeline (
77+ summaryAgent , _ := syndicate.NewAgent (
78+ syndicate.WithClient (client),
79+ syndicate.WithName (" SummaryAgent" ),
80+ syndicate.WithSystemPrompt (" You summarize order details." ),
81+ syndicate.WithModel (openai.GPT4 ),
82+ syndicate.WithMemory (syndicate.NewSimpleMemory ()),
83+ )
84+
85+ // Use agents directly for chat
86+ response , _ := orderAgent.Chat (
9287 context.Background (),
93- " User" ,
94- " I'd like to order two pizzas for delivery to 123 Main St."
88+ syndicate. WithUserName ( " User" ) ,
89+ syndicate. WithInput ( " I'd like to order two pizzas for delivery to 123 Main St." ),
9590 )
9691
9792 fmt.Println (response)
@@ -248,25 +243,27 @@ Here's an example of what a `Handler` for the `SaveOrder` tool might look like:
248243package main
249244
250245import (
246+ " context"
251247 " encoding/json"
252248 " fmt"
253249 " log"
254250
255251 syndicate " github.com/Dieg0Code/syndicate-go"
252+ openai " github.com/sashabaranov/go-openai"
256253)
257254
258255type MenuItemSchema struct {
259- ItemName string ` json:"item_name" description:"Menu item name" required:"true"`
260- Quantity int ` json:"quantity" description:"Quantity ordered by the user" required:"true"`
261- Price int ` json:"price" description:"Menu item price" required:"true"`
256+ ItemName string ` json:"item_name" description:"Menu item name" required:"true"`
257+ Quantity int ` json:"quantity" description:"Quantity ordered by the user" required:"true"`
258+ Price int ` json:"price" description:"Menu item price" required:"true"`
262259}
263260
264261type UserOrderFunctionSchema struct {
265- MenuItems []MenuItemSchema ` json:"menu_items" description:"List of ordered menu items" required:"true"`
266- DeliveryAddress string ` json:"delivery_address" description:"Order delivery address" required:"true"`
267- UserName string ` json:"user_name" description:"User's name placing the order" required:"true"`
268- PhoneNumber string ` json:"phone_number" description:"User's phone number" required:"true"`
269- PaymentMethod string ` json:"payment_method" description:"Payment method (cash or transfer only)" required:"true" enum:"cash,transfer"`
262+ MenuItems []MenuItemSchema ` json:"menu_items" description:"List of ordered menu items" required:"true"`
263+ DeliveryAddress string ` json:"delivery_address" description:"Order delivery address" required:"true"`
264+ UserName string ` json:"user_name" description:"User's name placing the order" required:"true"`
265+ PhoneNumber string ` json:"phone_number" description:"User's phone number" required:"true"`
266+ PaymentMethod string ` json:"payment_method" description:"Payment method (cash or transfer only)" required:"true" enum:"cash,transfer"`
270267}
271268
272269type SaveOrderTool struct {
@@ -287,7 +284,6 @@ func (s *SaveOrderTool) GetDefinition() syndicate.ToolDefinition {
287284 Name: " SaveOrder" ,
288285 Description: " Retrieves the user's order. The user must provide the requested menu items, delivery address, name, phone number, and payment method. The payment method can only be cash or bank transfer." ,
289286 Parameters: schema,
290- Strict: true ,
291287 }
292288}
293289
@@ -308,26 +304,38 @@ func (s *SaveOrderTool) Execute(args json.RawMessage) (interface{}, error) {
308304}
309305
310306func main () {
307+ // Initialize OpenAI client
308+ client := syndicate.NewOpenAIClient (" YOUR_API_KEY" )
309+
310+ // Create memory for the agent
311+ memory := syndicate.NewSimpleMemory ()
312+
311313 // Create a new instance of the tool
312314 saveOrderTool := NewSaveOrderTool ()
313315
314- // Create a new instance of an agent
315- agent , err := syndicate.NewAgent ().
316- SetClient (client).
317- SetName ( " HelloAgent " ).
318- SetConfigPrompt ( " <YOUR_PROMPT> " ).
319- SetMemory (memoryAgentOne).
320- SetModel (openai. GPT4 ).
321- EquipTool (saveOrderTool). // Equip the tool to the agent 🧰
322- Build ( )
316+ // ✅ Create agent using functional options pattern
317+ agent , err := syndicate.NewAgent (
318+ syndicate. WithClient (client),
319+ syndicate. WithName ( " OrderAgent " ),
320+ syndicate. WithSystemPrompt ( " You are a helpful restaurant assistant that processes customer orders. Always collect all required information before calling the SaveOrder tool. " ),
321+ syndicate. WithModel (openai. GPT4 ),
322+ syndicate. WithMemory (memory),
323+ syndicate. WithTools (saveOrderTool), // ✅ Equip the tool to the agent 🧰
324+ )
323325 if err != nil {
324326 fmt.Printf (" Error creating agent: %v \n " , err)
327+ return
325328 }
326329
327- // Process a sample input with the agent 🧠
328- response , err := agent.Process (context.Background (), " Jhon Doe" , " What is on the menu?" )
330+ // ✅ Chat with the agent using functional options
331+ response , err := agent.Chat (
332+ context.Background (),
333+ syndicate.WithUserName (" John Doe" ),
334+ syndicate.WithInput (" I want to order 2 pizzas for delivery to 123 Main St. My phone is 555-1234 and I'll pay with cash." ),
335+ )
329336 if err != nil {
330337 fmt.Printf (" Error processing input: %v \n " , err)
338+ return
331339 }
332340
333341 fmt.Println (" \n Agent Response:" )
@@ -349,58 +357,167 @@ By simply implementing the `Tool` interface and adding the tool to the agent, yo
349357<details >
350358 <summary ><b >Memory Management</b ></summary >
351359
352- Implement long-term memory for the agent using the ` Memory ` interface. This allows the agent to retain context across conversations and improve its responses over time.
360+ Agents can remember conversations across multiple interactions using the Memory interface.
361+
362+ ### Built-in Simple Memory
363+
364+ For most cases, use the built-in memory:
353365
354366``` go
355- package main
367+ agent , _ := syndicate.NewAgent (
368+ syndicate.WithClient (client),
369+ syndicate.WithName (" ChatAgent" ),
370+ syndicate.WithSystemPrompt (" You are a helpful assistant." ),
371+ syndicate.WithModel (openai.GPT4 ),
372+ syndicate.WithMemory (syndicate.NewSimpleMemory ()), // ✅ Remembers conversations
373+ )
356374
375+ // First conversation
376+ response1 , _ := agent.Chat (ctx,
377+ syndicate.WithUserName (" Alice" ),
378+ syndicate.WithInput (" My favorite color is blue." ))
357379
358- /* Import necessary packages */
380+ // Later conversation - agent remembers!
381+ response2 , _ := agent.Chat (ctx,
382+ syndicate.WithUserName (" Alice" ),
383+ syndicate.WithInput (" What's my favorite color?" ))
384+ ```
359385
360- type ChatMemory struct {
386+ ### Custom Memory Implementation
361387
362- /* These fields are important for the memory system */
388+ Use ` NewMemory ` with functional options for custom storage:
363389
364- Name string // Name of the sender
365- Role string // Role of the sender (user or assistant)
366- Content string // Content of the message
367- ToolCallID string // ID of the tool call (if applicable)
368- ToolCalls datatype.JSON // Tool calls made during the conversation
390+ ``` go
391+ package main
369392
370- /* Add any other fields you need for your memory system */
393+ import (
394+ " database/sql"
395+ " encoding/json"
396+ " sync"
371397
372- }
398+ syndicate " github.com/Dieg0Code/syndicate-go"
399+ _ " github.com/lib/pq"
400+ )
373401
374- type MyMemory struct {
375- /* Define your necessary dependencies here */
402+ // Database-backed memory example
403+ func NewDatabaseMemory (db *sql .DB , agentID string ) (syndicate .Memory , error ) {
404+ var mu sync.RWMutex
405+
406+ return syndicate.NewMemory (
407+ // Handle adding messages to database
408+ syndicate.WithAddHandler (func (message syndicate.Message ) {
409+ mu.Lock ()
410+ defer mu.Unlock ()
411+
412+ messageData , _ := json.Marshal (message)
413+ query := ` INSERT INTO agent_messages (agent_id, message_data) VALUES ($1, $2)`
414+ db.Exec (query, agentID, messageData)
415+ }),
416+
417+ // Handle retrieving messages from database
418+ syndicate.WithGetHandler (func () []syndicate.Message {
419+ mu.RLock ()
420+ defer mu.RUnlock ()
421+
422+ query := ` SELECT message_data FROM agent_messages WHERE agent_id = $1 ORDER BY created_at`
423+ rows , err := db.Query (query, agentID)
424+ if err != nil {
425+ return []syndicate.Message {}
426+ }
427+ defer rows.Close ()
428+
429+ var messages []syndicate.Message
430+ for rows.Next () {
431+ var messageData []byte
432+ if rows.Scan (&messageData) == nil {
433+ var message syndicate.Message
434+ if json.Unmarshal (messageData, &message) == nil {
435+ messages = append (messages, message)
436+ }
437+ }
438+ }
439+ return messages
440+ }),
441+ )
376442}
377443
378- func NewMyMemory (/* Dependencies */) syndicate .Memory {
379- return &MyMemory{
380- /* Initialize your dependencies here */
381- }
444+ // Redis-backed memory example
445+ func NewRedisMemory (client *redis .Client , agentID string ) (syndicate .Memory , error ) {
446+ key := fmt.Sprintf (" agent:%s :messages" , agentID)
447+
448+ return syndicate.NewMemory (
449+ syndicate.WithAddHandler (func (message syndicate.Message ) {
450+ messageData , _ := json.Marshal (message)
451+ client.LPush (context.Background (), key, messageData)
452+ }),
453+
454+ syndicate.WithGetHandler (func () []syndicate.Message {
455+ result := client.LRange (context.Background (), key, 0 , -1 )
456+ messagesData , _ := result.Result ()
457+
458+ var messages []syndicate.Message
459+ // Reverse to maintain chronological order
460+ for i := len (messagesData) - 1 ; i >= 0 ; i-- {
461+ var message syndicate.Message
462+ if json.Unmarshal ([]byte (messagesData[i]), &message) == nil {
463+ messages = append (messages, message)
464+ }
465+ }
466+ return messages
467+ }),
468+ )
382469}
383470
384- func (m *MyMemory ) Get () []syndicate .Message {
385- m.mutex .RLock ()
386- defer m.mutex .RUnlock ()
387- ctx := context.Background ()
471+ // Usage with custom memory
472+ func main () {
473+ db , _ := sql.Open (" postgres" , " postgres://user:password@localhost/dbname" )
474+
475+ // Create custom database memory using functional options
476+ dbMemory , err := NewDatabaseMemory (db, " agent-123" )
477+ if err != nil {
478+ log.Fatal (err)
479+ }
388480
389- /* Implement the logic to retrieve messages from your memory system */
481+ agent , _ := syndicate.NewAgent (
482+ syndicate.WithClient (client),
483+ syndicate.WithName (" PersistentAgent" ),
484+ syndicate.WithMemory (dbMemory), // ✅ Custom memory with functional options
485+ // ... other options
486+ )
390487
391- return messages
488+ // Conversations persist across application restarts!
489+ response , _ := agent.Chat (ctx,
490+ syndicate.WithUserName (" Bob" ),
491+ syndicate.WithInput (" Remember that I'm working on project X." ))
392492}
493+ ```
393494
394- func func (m *MyMemory ) Add (message syndicate .Message ) {
395- m.mutex .Lock ()
396- defer m.mutex .Unlock ()
397- ctx := context.Background ()
495+ ### Memory Interface
398496
399- /* Implement the logic to add messages to your memory system */
497+ All memory implementations use this interface:
400498
499+ ``` go
500+ type Memory interface {
501+ Add (message Message ) // Store a new message
502+ Get () []Message // Retrieve all stored messages
401503}
504+
505+ // Create custom memory with functional options
506+ memory , err := syndicate.NewMemory (
507+ syndicate.WithAddHandler (func (msg syndicate.Message ) {
508+ // Your custom add logic
509+ }),
510+ syndicate.WithGetHandler (func () []syndicate.Message {
511+ // Your custom get logic
512+ return messages
513+ }),
514+ )
402515```
403516
517+ ** ✅ Use ` NewSimpleMemory() ` for development and testing**
518+ ** ✅ Use ` NewMemory() ` with functional options for production persistence**
519+ ** ✅ Both handlers (WithAddHandler and WithGetHandler) are required**
520+
404521</details >
405522
406523<details >
0 commit comments