From 6189b8f0a70829a781c8d9db8be33d460ba59a83 Mon Sep 17 00:00:00 2001 From: Virgil Date: Tue, 31 Mar 2026 11:52:01 +0000 Subject: [PATCH] fix(brain): accept php data envelope Co-Authored-By: Virgil --- pkg/brain/direct.go | 13 ++++- pkg/brain/direct_test.go | 121 ++++++++++++++++++++++++--------------- 2 files changed, 84 insertions(+), 50 deletions(-) diff --git a/pkg/brain/direct.go b/pkg/brain/direct.go index bfb2854..cc5c98e 100644 --- a/pkg/brain/direct.go +++ b/pkg/brain/direct.go @@ -145,10 +145,9 @@ func (s *DirectSubsystem) remember(ctx context.Context, _ *mcp.CallToolRequest, } payload, _ := result.Value.(map[string]any) - id, _ := payload["id"].(string) return nil, RememberOutput{ Success: true, - MemoryID: id, + MemoryID: stringField(payloadMap(payload), "id"), Timestamp: time.Now(), }, nil } @@ -242,7 +241,8 @@ func (s *DirectSubsystem) list(ctx context.Context, _ *mcp.CallToolRequest, inpu func memoriesFromPayload(payload map[string]any) []Memory { var memories []Memory - if mems, ok := payload["memories"].([]any); ok { + source := payloadMap(payload) + if mems, ok := source["memories"].([]any); ok { for _, m := range mems { memoryMap, ok := m.(map[string]any) if !ok { @@ -283,3 +283,10 @@ func memoriesFromPayload(payload map[string]any) []Memory { } return memories } + +func payloadMap(payload map[string]any) map[string]any { + if data, ok := payload["data"].(map[string]any); ok && len(data) > 0 { + return data + } + return payload +} diff --git a/pkg/brain/direct_test.go b/pkg/brain/direct_test.go index 2b3643a..ec98bfc 100644 --- a/pkg/brain/direct_test.go +++ b/pkg/brain/direct_test.go @@ -201,7 +201,9 @@ func TestDirect_Remember_Good(t *testing.T) { assert.Equal(t, "observation", body["type"]) w.Header().Set("Content-Type", "application/json") - w.Write([]byte(core.JSONMarshalString(map[string]any{"id": "mem-abc"}))) + w.Write([]byte(core.JSONMarshalString(map[string]any{ + "data": map[string]any{"id": "mem-abc"}, + }))) })) defer srv.Close() @@ -217,6 +219,19 @@ func TestDirect_Remember_Good(t *testing.T) { assert.False(t, out.Timestamp.IsZero()) } +func TestDirect_Remember_Ugly_LegacyTopLevelID(t *testing.T) { + srv := httptest.NewServer(jsonHandler(map[string]any{"id": "mem-legacy"})) + defer srv.Close() + + _, out, err := newTestDirect(srv).remember(context.Background(), nil, RememberInput{ + Content: "legacy payload", + Type: "observation", + }) + require.NoError(t, err) + assert.True(t, out.Success) + assert.Equal(t, "mem-legacy", out.MemoryID) +} + func TestDirect_Remember_Bad_APIError(t *testing.T) { srv := httptest.NewServer(errorHandler(http.StatusInternalServerError, `{"error":"db down"}`)) defer srv.Close() @@ -242,25 +257,27 @@ func TestDirect_Recall_Good_WithMemories(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(core.JSONMarshalString(map[string]any{ - "memories": []any{ - map[string]any{ - "id": "mem-1", - "content": "Use Qdrant for vector search", - "type": "decision", - "project": "agent", - "agent_id": "virgil", - "score": 0.95, - "source": "manual", - "created_at": "2026-03-03T12:00:00Z", - }, - map[string]any{ - "id": "mem-2", - "content": "DuckDB for embedded use", - "type": "architecture", - "project": "agent", - "agent_id": "cladius", - "score": 0.88, - "created_at": "2026-03-04T10:00:00Z", + "data": map[string]any{ + "memories": []any{ + map[string]any{ + "id": "mem-1", + "content": "Use Qdrant for vector search", + "type": "decision", + "project": "agent", + "agent_id": "virgil", + "score": 0.95, + "source": "manual", + "created_at": "2026-03-03T12:00:00Z", + }, + map[string]any{ + "id": "mem-2", + "content": "DuckDB for embedded use", + "type": "architecture", + "project": "agent", + "agent_id": "cladius", + "score": 0.88, + "created_at": "2026-03-04T10:00:00Z", + }, }, }, }))) @@ -293,7 +310,9 @@ func TestDirect_Recall_Good_DefaultTopK(t *testing.T) { assert.Equal(t, float64(10), body["top_k"]) w.Header().Set("Content-Type", "application/json") - w.Write([]byte(core.JSONMarshalString(map[string]any{"memories": []any{}}))) + w.Write([]byte(core.JSONMarshalString(map[string]any{ + "data": map[string]any{"memories": []any{}}, + }))) })) defer srv.Close() @@ -315,7 +334,9 @@ func TestDirect_Recall_Good_WithFilters(t *testing.T) { assert.Equal(t, "decision", body["type"]) w.Header().Set("Content-Type", "application/json") - w.Write([]byte(core.JSONMarshalString(map[string]any{"memories": []any{}}))) + w.Write([]byte(core.JSONMarshalString(map[string]any{ + "data": map[string]any{"memories": []any{}}, + }))) })) defer srv.Close() @@ -332,7 +353,9 @@ func TestDirect_Recall_Good_WithFilters(t *testing.T) { } func TestDirect_Recall_Good_EmptyMemories(t *testing.T) { - srv := httptest.NewServer(jsonHandler(map[string]any{"memories": []any{}})) + srv := httptest.NewServer(jsonHandler(map[string]any{ + "data": map[string]any{"memories": []any{}}, + })) defer srv.Close() _, out, err := newTestDirect(srv).recall(context.Background(), nil, RecallInput{Query: "nothing"}) @@ -395,29 +418,31 @@ func TestDirect_List_Good_WithMemories(t *testing.T) { w.Header().Set("Content-Type", "application/json") w.Write([]byte(core.JSONMarshalString(map[string]any{ - "memories": []any{ - map[string]any{ - "id": "mem-list-1", - "content": "Use the review queue for completed workspaces", - "type": "decision", - "project": "agent", - "agent_id": "codex", - "confidence": 0.73, - "tags": []any{"queue", "review"}, - "updated_at": "2026-03-30T10:00:00Z", - "created_at": "2026-03-30T09:00:00Z", - "expires_at": "2026-04-01T00:00:00Z", - "source": "manual", - "supersedes_id": "mem-old", - }, - map[string]any{ - "id": "mem-list-2", - "content": "AgentCompleted should key on workspace", - "type": "architecture", - "project": "agent", - "agent_id": "cladius", - "score": 0.91, - "created_at": "2026-03-31T08:00:00Z", + "data": map[string]any{ + "memories": []any{ + map[string]any{ + "id": "mem-list-1", + "content": "Use the review queue for completed workspaces", + "type": "decision", + "project": "agent", + "agent_id": "codex", + "confidence": 0.73, + "tags": []any{"queue", "review"}, + "updated_at": "2026-03-30T10:00:00Z", + "created_at": "2026-03-30T09:00:00Z", + "expires_at": "2026-04-01T00:00:00Z", + "source": "manual", + "supersedes_id": "mem-old", + }, + map[string]any{ + "id": "mem-list-2", + "content": "AgentCompleted should key on workspace", + "type": "architecture", + "project": "agent", + "agent_id": "cladius", + "score": 0.91, + "created_at": "2026-03-31T08:00:00Z", + }, }, }, }))) @@ -448,7 +473,9 @@ func TestDirect_List_Good_WithMemories(t *testing.T) { } func TestDirect_List_Good_EmptyMemories(t *testing.T) { - srv := httptest.NewServer(jsonHandler(map[string]any{"memories": []any{}})) + srv := httptest.NewServer(jsonHandler(map[string]any{ + "data": map[string]any{"memories": []any{}}, + })) defer srv.Close() _, out, err := newTestDirect(srv).list(context.Background(), nil, ListInput{})