Skip to content

Commit 0cd9ce1

Browse files
committed
supermemory
1 parent d94e134 commit 0cd9ce1

File tree

6 files changed

+122
-45
lines changed

6 files changed

+122
-45
lines changed

apps/api/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"@opentelemetry/sdk-trace-node": "^2.2.0",
3838
"@opentelemetry/semantic-conventions": "^1.38.0",
3939
"@orpc/server": "^1.11.3",
40+
"@supermemory/tools": "^1.3.13",
4041
"@upstash/redis": "^1.35.6",
4142
"ai": "^5.0.93",
4243
"autumn-js": "^0.1.48",

apps/api/src/ai/agents.ts

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ import { Agent } from "@ai-sdk-tools/agents";
22
import {
33
extendedMemoryConfig,
44
maxMemoryConfig,
5+
memoryTools,
56
minimalMemoryConfig,
67
standardMemoryConfig,
8+
withUserProfile,
79
} from "./config/memory";
810
import { models } from "./config/models";
911
import { buildAnalyticsInstructions } from "./prompts/analytics";
@@ -20,49 +22,61 @@ const analyticsTools = {
2022
get_top_pages: getTopPagesTool,
2123
execute_sql_query: executeSqlQueryTool,
2224
web_search: webSearchTool,
25+
...(Object.keys(memoryTools).length > 0 ? memoryTools : {}),
2326
} as const;
2427

2528
/**
26-
* Analytics specialist agent.
29+
* Tools available to triage agent.
30+
*/
31+
const triageTools = {
32+
web_search: webSearchTool,
33+
...(Object.keys(memoryTools).length > 0 ? memoryTools : {}),
34+
} as const;
35+
36+
/**
37+
* Creates an analytics specialist agent with user-specific memory.
2738
* Handles website traffic analysis, user behavior, and performance metrics.
2839
* Uses standard memory for typical analytical conversations.
2940
*/
30-
export const analyticsAgent = new Agent({
31-
name: "analytics",
32-
model: models.analytics,
33-
temperature: 0.3,
34-
instructions: buildAnalyticsInstructions,
35-
tools: analyticsTools,
36-
memory: standardMemoryConfig,
37-
modelSettings: {
38-
failureMode: {
39-
maxAttempts: 2,
41+
export function createAnalyticsAgent(userId: string) {
42+
return new Agent({
43+
name: "analytics",
44+
model: withUserProfile(models.analytics, userId),
45+
temperature: 0.3,
46+
instructions: buildAnalyticsInstructions,
47+
tools: analyticsTools,
48+
memory: standardMemoryConfig,
49+
modelSettings: {
50+
failureMode: {
51+
maxAttempts: 2,
52+
},
4053
},
41-
},
42-
maxTurns: 10,
43-
});
54+
maxTurns: 10,
55+
});
56+
}
4457

4558
/**
46-
* Reflection orchestrator agent.
59+
* Creates a reflection orchestrator agent with user-specific memory.
4760
* Reviews responses, decides next steps, and handles complex multi-step reasoning.
4861
* Memory allocation scales with model capability.
4962
*/
5063
export const createReflectionAgent = (
64+
userId: string,
5165
variant: "standard" | "haiku" | "max" = "standard"
5266
) => {
5367
const config = {
5468
standard: {
55-
model: models.advanced,
69+
model: withUserProfile(models.advanced, userId),
5670
maxTurns: 15,
5771
memory: extendedMemoryConfig, // 30 messages for Sonnet
5872
},
5973
haiku: {
60-
model: models.analytics,
74+
model: withUserProfile(models.analytics, userId),
6175
maxTurns: 15,
6276
memory: standardMemoryConfig, // 20 messages for Haiku
6377
},
6478
max: {
65-
model: models.advanced,
79+
model: withUserProfile(models.advanced, userId),
6680
maxTurns: 20,
6781
memory: maxMemoryConfig, // 40 messages for deep investigations
6882
},
@@ -77,31 +91,35 @@ export const createReflectionAgent = (
7791
maxAttempts: 2,
7892
},
7993
},
80-
handoffs: [analyticsAgent],
94+
handoffs: [createAnalyticsAgent(userId)],
8195
...config,
8296
});
8397
};
8498

8599
/**
86-
* Triage agent that routes user requests to the appropriate specialist.
100+
* Creates a triage agent with user-specific memory.
101+
* Routes user requests to the appropriate specialist.
87102
* This is the main entry point for all agent interactions.
88103
* Uses minimal memory since it only routes and doesn't need long context.
89104
*/
90-
export const triageAgent = new Agent({
91-
name: "triage",
92-
model: models.triage,
93-
temperature: 0.1,
94-
instructions: buildTriageInstructions,
95-
memory: minimalMemoryConfig,
96-
modelSettings: {
97-
toolChoice: {
98-
type: "tool",
99-
toolName: "handoff_to_agent",
100-
},
101-
failureMode: {
102-
maxAttempts: 2,
105+
export function createTriageAgent(userId: string) {
106+
return new Agent({
107+
name: "triage",
108+
model: withUserProfile(models.triage, userId),
109+
temperature: 0.1,
110+
instructions: buildTriageInstructions,
111+
tools: triageTools,
112+
memory: minimalMemoryConfig,
113+
modelSettings: {
114+
toolChoice: {
115+
type: "tool",
116+
toolName: "handoff_to_agent",
117+
},
118+
failureMode: {
119+
maxAttempts: 2,
120+
},
103121
},
104-
},
105-
handoffs: [analyticsAgent],
106-
maxTurns: 1,
107-
});
122+
handoffs: [createAnalyticsAgent(userId)],
123+
maxTurns: 1,
124+
});
125+
}

apps/api/src/ai/config/memory.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { RedisProvider } from "@ai-sdk-tools/memory/redis";
22
import { redis } from "@databuddy/redis";
3+
import { supermemoryTools, withSupermemory } from "@supermemory/tools/ai-sdk";
34
import type { RedisClientType } from "redis";
45

56
/**
@@ -51,6 +52,27 @@ export const maxMemoryConfig = {
5152
},
5253
} as const;
5354

54-
/** @deprecated Use specific memory configs instead */
55-
export const defaultMemoryConfig = standardMemoryConfig;
55+
/**
56+
* Supermemory configuration for enhanced memory management.
57+
* User Profiles: Automatic personalization with user context
58+
* Memory Tools: Agent-based memory operations (search, add, fetch)
59+
* Enhanced Analytics: Agents can remember user preferences and analysis patterns
60+
*/
61+
export const supermemoryApiKey = process.env.SUPERMEMORY_API_KEY;
5662

63+
/**
64+
* Supermemory tools for agent-based memory operations.
65+
* Includes search_memory, add_memory, and other memory management tools.
66+
*/
67+
export const memoryTools = supermemoryApiKey ? supermemoryTools(supermemoryApiKey) : {};
68+
69+
/**
70+
* Wraps a model with user profile context for personalization.
71+
* Automatically injects user-specific context into every LLM call.
72+
*/
73+
export function withUserProfile(model: any, userId: string) {
74+
if (!supermemoryApiKey) {
75+
return model;
76+
}
77+
return withSupermemory(model, userId);
78+
}

apps/api/src/ai/prompts/analytics.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ const ANALYTICS_RULES = `<agent-specific-rules>
1818
**Tools Usage:**
1919
- Use get_top_pages for page analytics
2020
- Use execute_sql_query for custom analytics queries
21+
- Use memory tools (search_memory, add_memory) to remember user preferences and past analysis patterns
2122
- CRITICAL: execute_sql_query must ONLY use SELECT/WITH and parameter placeholders (e.g., {limit:UInt32}) with values passed via params. websiteId is automatically included. Never interpolate strings.
2223
- Example: execute_sql_query({ websiteId: "<use website_id from context>", sql: "SELECT ... WHERE client_id = {websiteId:String}", params: { limit: 10 } })
24+
- Example memory: search_memory({ query: "user's preferred metrics" })
2325
2426
**Insights & Recommendations:**
2527
- Provide 2-3 actionable recommendations based on findings

apps/api/src/routes/agent.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { auth, websitesApi } from "@databuddy/auth";
22
import { smoothStream } from "ai";
33
import { Elysia, t } from "elysia";
4-
import { createReflectionAgent, triageAgent } from "../ai/agents";
4+
import { createReflectionAgent, createTriageAgent } from "../ai/agents";
55
import { buildAppContext } from "../ai/config/context";
66
import { record, setAttributes } from "../lib/tracing";
77
import { validateWebsite } from "../lib/website-utils";
@@ -146,24 +146,31 @@ export const agent = new Elysia({ prefix: "/v1/agent" })
146146
let maxRounds = 5;
147147
let maxSteps = 20;
148148

149+
if (!user?.id) {
150+
return new Response(JSON.stringify({ error: "User ID required" }), {
151+
status: 401,
152+
headers: { "Content-Type": "application/json" },
153+
});
154+
}
155+
149156
switch (modelType) {
150157
case "basic":
151-
agent = triageAgent;
158+
agent = createTriageAgent(user.id);
152159
maxRounds = 1;
153160
maxSteps = 5;
154161
break;
155162
case "agent":
156-
agent = createReflectionAgent("haiku");
163+
agent = createReflectionAgent(user.id, "haiku");
157164
maxRounds = 5;
158165
maxSteps = 20;
159166
break;
160167
case "agent-max":
161-
agent = createReflectionAgent("max");
168+
agent = createReflectionAgent(user.id, "max");
162169
maxRounds = 10;
163170
maxSteps = 40;
164171
break;
165172
default:
166-
agent = createReflectionAgent("haiku");
173+
agent = createReflectionAgent(user.id, "haiku");
167174
}
168175

169176
return agent.toUIMessageStream({

0 commit comments

Comments
 (0)