diff options
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | storage/memory.go | 10 | ||||
-rw-r--r-- | storage/storage_test.go | 31 | ||||
-rw-r--r-- | tools.go | 10 |
4 files changed, 39 insertions, 14 deletions
@@ -38,7 +38,7 @@ - separate messages that are stored and chat and send to the bot, i.e. option to omit tool calls and thinking (there might be a point where they are no longer needed in ctx); + - option to remove <thinking> from chat history; + - connection to a model status; (need to be tied to some event, perhaps its own shortcut even) + -- char card is the sys message, but how about giving tools to char that does not have it? +- char card is the sys message, but how about giving tools to char that does not have it? + - lets say we have two (or more) agents with the same name across multiple chats. These agents go and ask db for topics they memorised. Now they can access topics that aren't meant for them. (so memory should have an option: shareable; that indicates if that memory can be shared across chats); - server mode: no tui but api calls with the func calling, rag, other middleware; - boolean flag to use/not use tools. I see it as a msg from a tool to an llm "Hey, it might be good idea to use me!"; diff --git a/storage/memory.go b/storage/memory.go index 088ce1c..c9fc853 100644 --- a/storage/memory.go +++ b/storage/memory.go @@ -9,7 +9,13 @@ type Memories interface { } func (p ProviderSQL) Memorise(m *models.Memory) (*models.Memory, error) { - query := "INSERT INTO memories (agent, topic, mind) VALUES (:agent, :topic, :mind) RETURNING *;" + query := ` + INSERT INTO memories (agent, topic, mind) + VALUES (:agent, :topic, :mind) + ON CONFLICT (agent, topic) DO UPDATE + SET mind = excluded.mind, + updated_at = CURRENT_TIMESTAMP + RETURNING *;` stmt, err := p.db.PrepareNamed(query) if err != nil { p.logger.Error("failed to prepare stmt", "query", query, "error", err) @@ -19,7 +25,7 @@ func (p ProviderSQL) Memorise(m *models.Memory) (*models.Memory, error) { var memory models.Memory err = stmt.Get(&memory, m) if err != nil { - p.logger.Error("failed to insert memory", "query", query, "error", err) + p.logger.Error("failed to upsert memory", "query", query, "error", err) return nil, err } return &memory, nil diff --git a/storage/storage_test.go b/storage/storage_test.go index f6af4f5..ff3b5e6 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -38,22 +38,27 @@ CREATE TABLE IF NOT EXISTS memories ( logger: slog.New(slog.NewJSONHandler(os.Stdout, nil)), } // Create a sample memory for testing - sampleMemory := &models.Memory{ + sampleMemory := models.Memory{ Agent: "testAgent", Topic: "testTopic", Mind: "testMind", CreatedAt: time.Now(), UpdatedAt: time.Now(), } + sampleMemoryRewrite := models.Memory{ + Agent: "testAgent", + Topic: "testTopic", + Mind: "same topic, new mind", + } cases := []struct { - memory *models.Memory + memories []models.Memory }{ - {memory: sampleMemory}, + {memories: []models.Memory{sampleMemory, sampleMemoryRewrite}}, } for i, tc := range cases { t.Run(fmt.Sprintf("run_%d", i), func(t *testing.T) { // Recall topics: get no rows - topics, err := provider.RecallTopics(tc.memory.Agent) + topics, err := provider.RecallTopics(tc.memories[0].Agent) if err != nil { t.Fatalf("Failed to recall topics: %v", err) } @@ -61,12 +66,12 @@ CREATE TABLE IF NOT EXISTS memories ( t.Fatalf("Expected no topics, got: %v", topics) } // Memorise - _, err = provider.Memorise(tc.memory) + _, err = provider.Memorise(&tc.memories[0]) if err != nil { t.Fatalf("Failed to memorise: %v", err) } // Recall topics: has topics - topics, err = provider.RecallTopics(tc.memory.Agent) + topics, err = provider.RecallTopics(tc.memories[0].Agent) if err != nil { t.Fatalf("Failed to recall topics: %v", err) } @@ -74,12 +79,20 @@ CREATE TABLE IF NOT EXISTS memories ( t.Fatalf("Expected topics, got none") } // Recall - content, err := provider.Recall(tc.memory.Agent, tc.memory.Topic) + content, err := provider.Recall(tc.memories[0].Agent, tc.memories[0].Topic) if err != nil { t.Fatalf("Failed to recall: %v", err) } - if content != tc.memory.Mind { - t.Fatalf("Expected content: %v, got: %v", tc.memory.Mind, content) + if content != tc.memories[0].Mind { + t.Fatalf("Expected content: %v, got: %v", tc.memories[0].Mind, content) + } + // rewrite mind of same agent-topic + newMem, err := provider.Memorise(&tc.memories[1]) + if err != nil { + t.Fatalf("Failed to memorise: %v", err) + } + if newMem.Mind == tc.memories[0].Mind { + t.Fatalf("Failed to change mind: %v", newMem.Mind) } }) } @@ -37,15 +37,21 @@ Your current tools: ] </tools> To make a function call return a json object within __tool_call__ tags; -Example: +<example_request> __tool_call__ { "name":"recall", -"args": "Adam" +"args": "Adam's number" } __tool_call__ +</example_request> Tool call is addressed to the tool agent, avoid sending more info than tool call itself, while making a call. When done right, tool call will be delivered to the tool agent. tool agent will respond with the results of the call. +<example_response> +tool: +under the topic: Adam's number is stored: +559-996 +</example_response> After that you are free to respond to the user. ` basicCard = &models.CharCard{ |