-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmemory.go
More file actions
130 lines (114 loc) · 3.17 KB
/
memory.go
File metadata and controls
130 lines (114 loc) · 3.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package syndicate
import (
"errors"
"fmt"
"sync"
)
// Memory defines the interface for managing a history of chat messages.
type Memory interface {
// Add appends a message to the memory.
Add(message Message)
// Get returns all stored chat messages.
Get() []Message
}
// MemoryConfig holds the configuration for creating custom memory implementations
type MemoryConfig struct {
addFunc func(message Message)
getFunc func() []Message
}
// MemoryOption defines a function that configures a Memory implementation
type MemoryOption func(*MemoryConfig) error
// WithAddHandler sets the function to handle adding messages
func WithAddHandler(addFunc func(message Message)) MemoryOption {
return func(config *MemoryConfig) error {
if addFunc == nil {
return errors.New("addFunc cannot be nil")
}
config.addFunc = addFunc
return nil
}
}
// WithGetHandler sets the function to handle retrieving messages
func WithGetHandler(getFunc func() []Message) MemoryOption {
return func(config *MemoryConfig) error {
if getFunc == nil {
return errors.New("getFunc cannot be nil")
}
config.getFunc = getFunc
return nil
}
}
// customMemory implements Memory using provided functions
type customMemory struct {
addFunc func(message Message)
getFunc func() []Message
}
func (c *customMemory) Add(message Message) {
if c.addFunc != nil {
c.addFunc(message)
}
}
func (c *customMemory) Get() []Message {
if c.getFunc != nil {
return c.getFunc()
}
return []Message{}
}
// NewMemory creates a custom Memory implementation using functional options.
// Returns an error if required handlers are not provided.
//
// Example:
//
// memory, err := syndicate.NewMemory(
// syndicate.WithAddHandler(func(msg syndicate.Message) {
// // Your custom add logic here
// }),
// syndicate.WithGetHandler(func() []syndicate.Message {
// // Your custom get logic here
// return messages
// }),
// )
// if err != nil {
// log.Fatal(err)
// }
func NewMemory(options ...MemoryOption) (Memory, error) {
config := &MemoryConfig{}
for _, option := range options {
if err := option(config); err != nil {
return nil, fmt.Errorf("failed to apply memory option: %w", err)
}
}
// Validate that both handlers are provided
if config.addFunc == nil {
return nil, errors.New("WithAddHandler is required when creating custom memory")
}
if config.getFunc == nil {
return nil, errors.New("WithGetHandler is required when creating custom memory")
}
return &customMemory{
addFunc: config.addFunc,
getFunc: config.getFunc,
}, nil
}
// NewSimpleMemory creates a basic in-memory storage for chat messages.
// This function cannot fail, so it doesn't return an error.
func NewSimpleMemory() Memory {
messages := make([]Message, 0)
var mutex sync.RWMutex
// We know these handlers are valid, so we can ignore the error
memory, _ := NewMemory(
WithAddHandler(func(message Message) {
mutex.Lock()
defer mutex.Unlock()
messages = append(messages, message)
}),
WithGetHandler(func() []Message {
mutex.RLock()
defer mutex.RUnlock()
copyMessages := make([]Message, len(messages))
copy(copyMessages, messages)
return copyMessages
}),
)
return memory
}