@deepagents/agent 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1102 -6
- package/dist/index.js.map +4 -4
- package/dist/lib/agent.d.ts +21 -21
- package/dist/lib/agent.d.ts.map +1 -1
- package/dist/lib/blog/deepagents.d.ts +1 -1
- package/dist/lib/blog/deepagents.d.ts.map +1 -1
- package/dist/lib/blog/mesh.d.ts +1 -1
- package/dist/lib/blog/mesh.d.ts.map +1 -1
- package/dist/lib/blog/research.d.ts +1 -1
- package/dist/lib/blog/research.d.ts.map +1 -1
- package/dist/lib/patterns/plan_and_execute/plan_and_execute.d.ts +1 -1
- package/dist/lib/patterns/plan_and_execute/plan_and_execute.d.ts.map +1 -1
- package/dist/lib/patterns/rewoo/rewoo.d.ts +2 -2
- package/dist/lib/patterns/rewoo/rewoo.d.ts.map +1 -1
- package/dist/lib/patterns/supervisor.d.ts +1 -1
- package/dist/lib/patterns/supervisor.d.ts.map +1 -1
- package/dist/lib/pipe.d.ts +15 -0
- package/dist/lib/pipe.d.ts.map +1 -0
- package/dist/lib/prompts.d.ts +53 -0
- package/dist/lib/prompts.d.ts.map +1 -1
- package/dist/lib/stream_utils.d.ts +3 -3
- package/dist/lib/swarm.d.ts +11 -7
- package/dist/lib/swarm.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -58,6 +58,106 @@ You are part of a multi-agent system called the DeepAgents SDK, designed to faci
|
|
|
58
58
|
- Explicitly complete every todo list item and confirm all steps are working before ending your turn. Always follow through on stated actions.
|
|
59
59
|
- You are a highly capable, autonomous agent, and should not require additional user input to fully solve the task.
|
|
60
60
|
`;
|
|
61
|
+
function thirdPersonPrompt(agentName = "this agent", agentRole = "assistant") {
|
|
62
|
+
return dedent`
|
|
63
|
+
<your_persona>
|
|
64
|
+
<persona_context>
|
|
65
|
+
This agent is ${agentName}, a ${agentRole} that speaks in third person, referring to itself as "this agent" or "${agentName}".
|
|
66
|
+
</persona_context>
|
|
67
|
+
|
|
68
|
+
<persona_speaking_style>
|
|
69
|
+
- This agent always refers to itself in third person
|
|
70
|
+
- Use "this agent" or "${agentName}" instead of "I", "me", "my"
|
|
71
|
+
- Use "This agent found..." instead of "I found..."
|
|
72
|
+
- Use "This agent recommends..." instead of "I recommend..."
|
|
73
|
+
- Use "This agent will..." instead of "I will..."
|
|
74
|
+
- Maintain this style consistently throughout all responses
|
|
75
|
+
</persona_speaking_style>
|
|
76
|
+
</your_persona>
|
|
77
|
+
`;
|
|
78
|
+
}
|
|
79
|
+
var STEM_STEP_BACK_EXAMPLES = [
|
|
80
|
+
{
|
|
81
|
+
originalQuestion: "What happens to the pressure, P, of an ideal gas if the temperature is increased by a factor of 2 and the volume is increased by a factor of 8?",
|
|
82
|
+
stepBackQuestion: "What are the physics principles behind this question?",
|
|
83
|
+
stepBackAnswer: "The Ideal Gas Law: PV = nRT, where P is pressure, V is volume, n is the number of moles, R is the gas constant, and T is temperature.",
|
|
84
|
+
finalAnswer: "Using PV = nRT, if T increases by 2x and V increases by 8x, then P = nRT/V = nR(2T)/(8V) = (1/4)(nRT/V). Therefore, pressure decreases to 1/4 of its original value."
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
originalQuestion: "If a solution has a pH of 3, how many times more acidic is it than a solution with pH of 6?",
|
|
88
|
+
stepBackQuestion: "What is the relationship between pH and acidity?",
|
|
89
|
+
stepBackAnswer: "The pH scale is logarithmic (base 10). pH = -log[H+], meaning each pH unit represents a 10-fold change in hydrogen ion concentration. Lower pH means higher acidity.",
|
|
90
|
+
finalAnswer: "The difference is 3 pH units. Since pH is logarithmic, this means 10^3 = 1000 times more acidic."
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
var KNOWLEDGE_QA_STEP_BACK_EXAMPLES = [
|
|
94
|
+
{
|
|
95
|
+
originalQuestion: "Which school did Estella Leopold attend between August 1954 and November 1954?",
|
|
96
|
+
stepBackQuestion: "What is Estella Leopold's education history?",
|
|
97
|
+
stepBackAnswer: "Estella Leopold studied at the University of Wisconsin-Madison (B.S. in Botany, 1948-1952) and later at Yale University (M.S. 1955, Ph.D. 1958). During 1954, she was transitioning between these institutions.",
|
|
98
|
+
finalAnswer: "Based on her education timeline, between August and November 1954, she was at Yale University, having completed her undergraduate degree at Wisconsin in 1952."
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
originalQuestion: "What was the capital of the country that colonized Brazil in the 16th century?",
|
|
102
|
+
stepBackQuestion: "Which country colonized Brazil and when?",
|
|
103
|
+
stepBackAnswer: "Portugal colonized Brazil starting in 1500 when Pedro \xC1lvares Cabral arrived. Brazil remained a Portuguese colony until independence in 1822.",
|
|
104
|
+
finalAnswer: "Portugal colonized Brazil in the 16th century. The capital of Portugal during that period was Lisbon."
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
var GENERAL_STEP_BACK_EXAMPLES = [
|
|
108
|
+
{
|
|
109
|
+
originalQuestion: "How should I optimize this specific database query that joins 5 tables?",
|
|
110
|
+
stepBackQuestion: "What are the general principles of database query optimization?",
|
|
111
|
+
stepBackAnswer: "Database query optimization involves: 1) Minimizing data retrieval through proper indexing, 2) Reducing join complexity by ordering joins efficiently, 3) Using query execution plans to identify bottlenecks, 4) Ensuring statistics are up-to-date, 5) Considering denormalization when appropriate.",
|
|
112
|
+
finalAnswer: "Apply these principles: Check if all foreign keys are indexed, analyze the execution plan to see which joins are most expensive, ensure statistics are current, and consider if the join order can be optimized based on table sizes."
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
originalQuestion: "Why is my React component re-rendering 10 times on each state update?",
|
|
116
|
+
stepBackQuestion: "What causes excessive re-renders in React?",
|
|
117
|
+
stepBackAnswer: "React re-renders occur when: 1) State changes trigger parent components to re-render all children, 2) Props change (including new object/function references), 3) Context values change, 4) Missing memoization (React.memo, useMemo, useCallback).",
|
|
118
|
+
finalAnswer: "Check if: 1) Parent component is creating new object/function references on each render, 2) The component is consuming context that changes frequently, 3) You need to wrap the component in React.memo or use useMemo/useCallback for props."
|
|
119
|
+
}
|
|
120
|
+
];
|
|
121
|
+
function stepBackPrompt(domain = "general", options) {
|
|
122
|
+
const { examples, stepBackQuestionTemplate } = options || {};
|
|
123
|
+
const domainExamples = examples || (domain === "stem" ? STEM_STEP_BACK_EXAMPLES : domain === "knowledge" ? KNOWLEDGE_QA_STEP_BACK_EXAMPLES : GENERAL_STEP_BACK_EXAMPLES);
|
|
124
|
+
const defaultTemplate = stepBackQuestionTemplate || (domain === "stem" ? "What are the underlying physics/chemistry/mathematical principles involved in this question?" : domain === "knowledge" ? "What is the broader historical context or background information related to this question?" : "What are the high-level concepts, principles, or patterns underlying this question?");
|
|
125
|
+
const formattedExamples = domainExamples.map(
|
|
126
|
+
(example, idx) => dedent`
|
|
127
|
+
Example ${idx + 1}:
|
|
128
|
+
Original Question: ${example.originalQuestion}
|
|
129
|
+
Step-Back Question: ${example.stepBackQuestion}
|
|
130
|
+
Step-Back Answer: ${example.stepBackAnswer}
|
|
131
|
+
${example.finalAnswer ? `Final Answer: ${example.finalAnswer}` : ""}
|
|
132
|
+
`
|
|
133
|
+
).join("\n\n");
|
|
134
|
+
return dedent`
|
|
135
|
+
<step_back_prompting>
|
|
136
|
+
You will use a two-step reasoning process called "Step-Back Prompting" to improve your answer quality.
|
|
137
|
+
|
|
138
|
+
## STEP 1: ABSTRACTION
|
|
139
|
+
Before answering the user's question directly, first generate and answer a "step-back question" - a higher-level question about the underlying principles or context.
|
|
140
|
+
|
|
141
|
+
Step-Back Question Template: "${defaultTemplate}"
|
|
142
|
+
|
|
143
|
+
Here are examples of how to create step-back questions:
|
|
144
|
+
|
|
145
|
+
${formattedExamples}
|
|
146
|
+
|
|
147
|
+
## STEP 2: REASONING
|
|
148
|
+
After you have the step-back answer, use that high-level knowledge to reason about and answer the ORIGINAL question.
|
|
149
|
+
Ground your reasoning in the principles/context from your step-back answer.
|
|
150
|
+
|
|
151
|
+
## Process to Follow:
|
|
152
|
+
1. When you receive a question, first formulate and answer a step-back question based on the template and examples above
|
|
153
|
+
2. Clearly state both the step-back question AND its answer
|
|
154
|
+
3. Then use that step-back answer as context to solve the original question
|
|
155
|
+
4. Show how the high-level principles apply to the specific case
|
|
156
|
+
|
|
157
|
+
This abstraction-grounded reasoning approach helps you avoid getting lost in specifics and ensures your answer is based on solid foundational understanding.
|
|
158
|
+
</step_back_prompting>
|
|
159
|
+
`;
|
|
160
|
+
}
|
|
61
161
|
|
|
62
162
|
// packages/agent/src/lib/stream_utils.ts
|
|
63
163
|
import {
|
|
@@ -325,7 +425,7 @@ import chalk from "chalk";
|
|
|
325
425
|
import dedent2 from "dedent";
|
|
326
426
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
327
427
|
function generate(agent2, messages, contextVariables, config) {
|
|
328
|
-
|
|
428
|
+
const result = generateText({
|
|
329
429
|
abortSignal: config?.abortSignal,
|
|
330
430
|
providerOptions: agent2.providerOptions ?? config?.providerOptions,
|
|
331
431
|
model: agent2.model,
|
|
@@ -354,10 +454,11 @@ function generate(agent2, messages, contextVariables, config) {
|
|
|
354
454
|
// (contextVariables as any).content = result.content;
|
|
355
455
|
// },
|
|
356
456
|
});
|
|
457
|
+
return Object.assign(result, { state: contextVariables });
|
|
357
458
|
}
|
|
358
459
|
function execute(agent2, messages, contextVariables, config) {
|
|
359
460
|
const runId = generateId2();
|
|
360
|
-
|
|
461
|
+
const stream2 = streamText({
|
|
361
462
|
abortSignal: config?.abortSignal,
|
|
362
463
|
providerOptions: config?.providerOptions,
|
|
363
464
|
model: agent2.model,
|
|
@@ -397,6 +498,7 @@ function execute(agent2, messages, contextVariables, config) {
|
|
|
397
498
|
// (contextVariables as any).content = result.content;
|
|
398
499
|
// },
|
|
399
500
|
});
|
|
501
|
+
return Object.assign(stream2, { state: contextVariables });
|
|
400
502
|
}
|
|
401
503
|
var stream = execute;
|
|
402
504
|
var prepareStep = (agent2, model, contextVariables) => {
|
|
@@ -532,10 +634,10 @@ var repairToolCall = async ({
|
|
|
532
634
|
console.log(
|
|
533
635
|
`Debug: ${chalk.yellow("RepairingToolCall")}: ${toolCall.toolName}`
|
|
534
636
|
);
|
|
535
|
-
const
|
|
637
|
+
const tool3 = tools[toolCall.toolName];
|
|
536
638
|
const { experimental_output } = await generateText({
|
|
537
639
|
model: groq("openai/gpt-oss-20b"),
|
|
538
|
-
experimental_output: Output.object({ schema:
|
|
640
|
+
experimental_output: Output.object({ schema: tool3.inputSchema }),
|
|
539
641
|
prompt: [
|
|
540
642
|
`The model tried to call the tool "${toolCall.toolName}" with the following inputs:`,
|
|
541
643
|
JSON.stringify(toolCall.input),
|
|
@@ -747,7 +849,9 @@ ${JSON.stringify(error)}
|
|
|
747
849
|
name: agent2?.name ?? this.handoff.name,
|
|
748
850
|
handoffDescription: agent2?.handoffDescription ?? this.handoff.handoffDescription,
|
|
749
851
|
handoffs: [...this.handoffs],
|
|
750
|
-
output: agent2?.output ?? this.output
|
|
852
|
+
output: agent2?.output ?? this.output,
|
|
853
|
+
temperature: agent2?.temperature ?? this.temperature,
|
|
854
|
+
providerOptions: agent2?.providerOptions ?? this.providerOptions
|
|
751
855
|
});
|
|
752
856
|
}
|
|
753
857
|
};
|
|
@@ -884,12 +988,931 @@ function lastTransferResult(messages) {
|
|
|
884
988
|
return void 0;
|
|
885
989
|
}
|
|
886
990
|
|
|
991
|
+
// packages/agent/src/lib/memory.ts
|
|
992
|
+
import { tool as tool2 } from "ai";
|
|
993
|
+
import Conf from "conf";
|
|
994
|
+
import { z as z2 } from "zod";
|
|
995
|
+
var MemoryStore = class {
|
|
996
|
+
store;
|
|
997
|
+
constructor(name = "agent-memory") {
|
|
998
|
+
this.store = new Conf({
|
|
999
|
+
projectName: name,
|
|
1000
|
+
schema: {
|
|
1001
|
+
memories: {
|
|
1002
|
+
type: "object",
|
|
1003
|
+
default: {}
|
|
1004
|
+
},
|
|
1005
|
+
relationships: {
|
|
1006
|
+
type: "object",
|
|
1007
|
+
default: {}
|
|
1008
|
+
},
|
|
1009
|
+
metadata: {
|
|
1010
|
+
type: "object",
|
|
1011
|
+
default: {
|
|
1012
|
+
lastConsolidation: Date.now(),
|
|
1013
|
+
totalAccesses: 0
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
/**
|
|
1020
|
+
* Generate a unique memory ID
|
|
1021
|
+
*/
|
|
1022
|
+
generateId() {
|
|
1023
|
+
return `mem_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* Calculate memory decay based on time and access patterns
|
|
1027
|
+
*/
|
|
1028
|
+
calculateDecay(memory) {
|
|
1029
|
+
const now = Date.now();
|
|
1030
|
+
const age = now - memory.timestamp;
|
|
1031
|
+
const timeSinceAccess = now - memory.lastAccessed;
|
|
1032
|
+
const daysSinceCreation = age / (1e3 * 60 * 60 * 24);
|
|
1033
|
+
const daysSinceAccess = timeSinceAccess / (1e3 * 60 * 60 * 24);
|
|
1034
|
+
const accessBonus = Math.log(memory.accessCount + 1) * 0.1;
|
|
1035
|
+
const importanceBonus = memory.importance * 0.05;
|
|
1036
|
+
const decay = Math.max(
|
|
1037
|
+
0.1,
|
|
1038
|
+
1 - (daysSinceCreation * 0.05 + daysSinceAccess * 0.08 - accessBonus - importanceBonus)
|
|
1039
|
+
);
|
|
1040
|
+
return Math.min(1, decay);
|
|
1041
|
+
}
|
|
1042
|
+
/**
|
|
1043
|
+
* Store a new memory
|
|
1044
|
+
*/
|
|
1045
|
+
write(entry) {
|
|
1046
|
+
const id = this.generateId();
|
|
1047
|
+
const now = Date.now();
|
|
1048
|
+
const memory = {
|
|
1049
|
+
...entry,
|
|
1050
|
+
id,
|
|
1051
|
+
timestamp: now,
|
|
1052
|
+
accessCount: 0,
|
|
1053
|
+
lastAccessed: now,
|
|
1054
|
+
decay: 1
|
|
1055
|
+
};
|
|
1056
|
+
const memories = this.store.get("memories");
|
|
1057
|
+
memories[id] = memory;
|
|
1058
|
+
this.store.set("memories", memories);
|
|
1059
|
+
if (entry.relationships && entry.relationships.length > 0) {
|
|
1060
|
+
const relationships = this.store.get("relationships");
|
|
1061
|
+
for (const relatedId of entry.relationships) {
|
|
1062
|
+
if (!relationships[relatedId]) {
|
|
1063
|
+
relationships[relatedId] = [];
|
|
1064
|
+
}
|
|
1065
|
+
if (!relationships[relatedId].includes(id)) {
|
|
1066
|
+
relationships[relatedId].push(id);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
this.store.set("relationships", relationships);
|
|
1070
|
+
}
|
|
1071
|
+
return memory;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Retrieve a memory by ID
|
|
1075
|
+
*/
|
|
1076
|
+
get(id) {
|
|
1077
|
+
const memories = this.store.get("memories");
|
|
1078
|
+
const memory = memories[id];
|
|
1079
|
+
if (!memory) {
|
|
1080
|
+
return null;
|
|
1081
|
+
}
|
|
1082
|
+
memory.accessCount++;
|
|
1083
|
+
memory.lastAccessed = Date.now();
|
|
1084
|
+
memory.decay = this.calculateDecay(memory);
|
|
1085
|
+
memories[id] = memory;
|
|
1086
|
+
this.store.set("memories", memories);
|
|
1087
|
+
const metadata = this.store.get("metadata");
|
|
1088
|
+
metadata.totalAccesses++;
|
|
1089
|
+
this.store.set("metadata", metadata);
|
|
1090
|
+
return memory;
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Search memories based on query
|
|
1094
|
+
*/
|
|
1095
|
+
lookup(query) {
|
|
1096
|
+
const memories = Object.values(this.store.get("memories"));
|
|
1097
|
+
let results = memories;
|
|
1098
|
+
if (query.type) {
|
|
1099
|
+
results = results.filter((m) => m.type === query.type);
|
|
1100
|
+
}
|
|
1101
|
+
if (query.minImportance !== void 0) {
|
|
1102
|
+
results = results.filter((m) => m.importance >= query.minImportance);
|
|
1103
|
+
}
|
|
1104
|
+
if (query.tags && query.tags.length > 0) {
|
|
1105
|
+
results = results.filter(
|
|
1106
|
+
(m) => query.tags.some((tag) => m.tags.includes(tag))
|
|
1107
|
+
);
|
|
1108
|
+
}
|
|
1109
|
+
if (query.timeRange) {
|
|
1110
|
+
if (query.timeRange.start) {
|
|
1111
|
+
results = results.filter((m) => m.timestamp >= query.timeRange.start);
|
|
1112
|
+
}
|
|
1113
|
+
if (query.timeRange.end) {
|
|
1114
|
+
results = results.filter((m) => m.timestamp <= query.timeRange.end);
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
const searchTerms = query.query.toLowerCase().split(" ");
|
|
1118
|
+
results = results.filter((m) => {
|
|
1119
|
+
const content = m.content.toLowerCase();
|
|
1120
|
+
const tags = m.tags.join(" ").toLowerCase();
|
|
1121
|
+
return searchTerms.some(
|
|
1122
|
+
(term) => content.includes(term) || tags.includes(term)
|
|
1123
|
+
);
|
|
1124
|
+
});
|
|
1125
|
+
results = results.map((m) => ({
|
|
1126
|
+
...m,
|
|
1127
|
+
decay: this.calculateDecay(m)
|
|
1128
|
+
}));
|
|
1129
|
+
results.sort((a, b) => {
|
|
1130
|
+
const scoreA = (a.decay || 0) * a.importance * (1 + Math.log(a.accessCount + 1));
|
|
1131
|
+
const scoreB = (b.decay || 0) * b.importance * (1 + Math.log(b.accessCount + 1));
|
|
1132
|
+
return scoreB - scoreA;
|
|
1133
|
+
});
|
|
1134
|
+
const limit = query.limit || 10;
|
|
1135
|
+
return results.slice(0, limit);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Update an existing memory
|
|
1139
|
+
*/
|
|
1140
|
+
correct(id, updates) {
|
|
1141
|
+
const memories = this.store.get("memories");
|
|
1142
|
+
const memory = memories[id];
|
|
1143
|
+
if (!memory) {
|
|
1144
|
+
return null;
|
|
1145
|
+
}
|
|
1146
|
+
const updated = {
|
|
1147
|
+
...memory,
|
|
1148
|
+
...updates,
|
|
1149
|
+
id: memory.id,
|
|
1150
|
+
// Preserve ID
|
|
1151
|
+
timestamp: memory.timestamp,
|
|
1152
|
+
// Preserve original timestamp
|
|
1153
|
+
lastAccessed: Date.now(),
|
|
1154
|
+
accessCount: memory.accessCount + 1
|
|
1155
|
+
};
|
|
1156
|
+
updated.decay = this.calculateDecay(updated);
|
|
1157
|
+
memories[id] = updated;
|
|
1158
|
+
this.store.set("memories", memories);
|
|
1159
|
+
return updated;
|
|
1160
|
+
}
|
|
1161
|
+
/**
|
|
1162
|
+
* Delete a memory (forget)
|
|
1163
|
+
*/
|
|
1164
|
+
forget(id) {
|
|
1165
|
+
const memories = this.store.get("memories");
|
|
1166
|
+
if (!memories[id]) {
|
|
1167
|
+
return false;
|
|
1168
|
+
}
|
|
1169
|
+
delete memories[id];
|
|
1170
|
+
this.store.set("memories", memories);
|
|
1171
|
+
const relationships = this.store.get("relationships");
|
|
1172
|
+
delete relationships[id];
|
|
1173
|
+
for (const [key, refs] of Object.entries(relationships)) {
|
|
1174
|
+
relationships[key] = refs.filter((ref) => ref !== id);
|
|
1175
|
+
}
|
|
1176
|
+
this.store.set("relationships", relationships);
|
|
1177
|
+
return true;
|
|
1178
|
+
}
|
|
1179
|
+
/**
|
|
1180
|
+
* Get related memories
|
|
1181
|
+
*/
|
|
1182
|
+
getRelated(id, limit = 5) {
|
|
1183
|
+
const relationships = this.store.get("relationships");
|
|
1184
|
+
const relatedIds = relationships[id] || [];
|
|
1185
|
+
const memories = this.store.get("memories");
|
|
1186
|
+
const relatedMemories = relatedIds.map((relId) => memories[relId]).filter(Boolean).slice(0, limit);
|
|
1187
|
+
return relatedMemories;
|
|
1188
|
+
}
|
|
1189
|
+
/**
|
|
1190
|
+
* Get memory statistics
|
|
1191
|
+
*/
|
|
1192
|
+
getStats() {
|
|
1193
|
+
const memories = Object.values(this.store.get("memories"));
|
|
1194
|
+
const byType = memories.reduce(
|
|
1195
|
+
(acc, m) => {
|
|
1196
|
+
acc[m.type] = (acc[m.type] || 0) + 1;
|
|
1197
|
+
return acc;
|
|
1198
|
+
},
|
|
1199
|
+
{}
|
|
1200
|
+
);
|
|
1201
|
+
const mostAccessed = [...memories].sort((a, b) => b.accessCount - a.accessCount).slice(0, 10);
|
|
1202
|
+
const recentMemories = [...memories].sort((a, b) => b.timestamp - a.timestamp).slice(0, 10);
|
|
1203
|
+
const averageImportance = memories.length > 0 ? memories.reduce((sum, m) => sum + m.importance, 0) / memories.length : 0;
|
|
1204
|
+
return {
|
|
1205
|
+
totalMemories: memories.length,
|
|
1206
|
+
byType,
|
|
1207
|
+
mostAccessed,
|
|
1208
|
+
recentMemories,
|
|
1209
|
+
averageImportance
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Consolidate memories (prune low-importance, rarely accessed memories)
|
|
1214
|
+
*/
|
|
1215
|
+
consolidate(threshold = 0.2) {
|
|
1216
|
+
const memories = this.store.get("memories");
|
|
1217
|
+
const entries = Object.entries(memories);
|
|
1218
|
+
let pruned = 0;
|
|
1219
|
+
for (const [id, memory] of entries) {
|
|
1220
|
+
const decay = this.calculateDecay(memory);
|
|
1221
|
+
if (decay < threshold && memory.importance < 5) {
|
|
1222
|
+
delete memories[id];
|
|
1223
|
+
pruned++;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
if (pruned > 0) {
|
|
1227
|
+
this.store.set("memories", memories);
|
|
1228
|
+
const metadata = this.store.get("metadata");
|
|
1229
|
+
metadata.lastConsolidation = Date.now();
|
|
1230
|
+
this.store.set("metadata", metadata);
|
|
1231
|
+
}
|
|
1232
|
+
return pruned;
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Clear all memories
|
|
1236
|
+
*/
|
|
1237
|
+
clear() {
|
|
1238
|
+
this.store.clear();
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Export all memories
|
|
1242
|
+
*/
|
|
1243
|
+
export() {
|
|
1244
|
+
return this.store.get("memories");
|
|
1245
|
+
}
|
|
1246
|
+
/**
|
|
1247
|
+
* Import memories
|
|
1248
|
+
*/
|
|
1249
|
+
import(memories) {
|
|
1250
|
+
this.store.set("memories", memories);
|
|
1251
|
+
}
|
|
1252
|
+
// ============================================================================
|
|
1253
|
+
// Specialized Write Functions - High-level convenience methods
|
|
1254
|
+
// ============================================================================
|
|
1255
|
+
/**
|
|
1256
|
+
* Write a semantic memory (facts, concepts, general knowledge)
|
|
1257
|
+
*
|
|
1258
|
+
* @example
|
|
1259
|
+
* store.writeSemantic("React is a JavaScript library for building UIs", {
|
|
1260
|
+
* tags: ["react", "javascript"],
|
|
1261
|
+
* importance: 8
|
|
1262
|
+
* });
|
|
1263
|
+
*/
|
|
1264
|
+
writeSemantic(content, options) {
|
|
1265
|
+
return this.write({
|
|
1266
|
+
content,
|
|
1267
|
+
type: "semantic",
|
|
1268
|
+
importance: options?.importance ?? 7,
|
|
1269
|
+
// Default to 7 for facts
|
|
1270
|
+
tags: options?.tags ?? [],
|
|
1271
|
+
context: options?.context,
|
|
1272
|
+
relationships: options?.relationships
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
/**
|
|
1276
|
+
* Write an episodic memory (events, conversations, experiences)
|
|
1277
|
+
*
|
|
1278
|
+
* @example
|
|
1279
|
+
* store.writeEpisodic("User completed onboarding", {
|
|
1280
|
+
* tags: ["milestone", "user123"],
|
|
1281
|
+
* context: { userId: "user123", timestamp: Date.now() }
|
|
1282
|
+
* });
|
|
1283
|
+
*/
|
|
1284
|
+
writeEpisodic(content, options) {
|
|
1285
|
+
return this.write({
|
|
1286
|
+
content,
|
|
1287
|
+
type: "episodic",
|
|
1288
|
+
importance: options?.importance ?? 6,
|
|
1289
|
+
// Default to 6 for events
|
|
1290
|
+
tags: options?.tags ?? [],
|
|
1291
|
+
context: {
|
|
1292
|
+
...options?.context,
|
|
1293
|
+
timestamp: options?.context?.timestamp ?? Date.now()
|
|
1294
|
+
},
|
|
1295
|
+
relationships: options?.relationships
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
/**
|
|
1299
|
+
* Write a procedural memory (patterns, behaviors, methods)
|
|
1300
|
+
*
|
|
1301
|
+
* @example
|
|
1302
|
+
* store.writeProcedural("When user asks for help, first check documentation", {
|
|
1303
|
+
* tags: ["pattern", "help"],
|
|
1304
|
+
* importance: 7
|
|
1305
|
+
* });
|
|
1306
|
+
*/
|
|
1307
|
+
writeProcedural(content, options) {
|
|
1308
|
+
return this.write({
|
|
1309
|
+
content,
|
|
1310
|
+
type: "procedural",
|
|
1311
|
+
importance: options?.importance ?? 7,
|
|
1312
|
+
// Default to 7 for patterns
|
|
1313
|
+
tags: options?.tags ?? [],
|
|
1314
|
+
context: options?.context,
|
|
1315
|
+
relationships: options?.relationships
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Store a user preference (convenience wrapper for semantic memory)
|
|
1320
|
+
*
|
|
1321
|
+
* @example
|
|
1322
|
+
* store.storePreference("user123", "theme", "dark");
|
|
1323
|
+
*/
|
|
1324
|
+
storePreference(userId, preference, value, importance = 8) {
|
|
1325
|
+
return this.writeSemantic(
|
|
1326
|
+
`User ${userId} prefers ${preference}: ${typeof value === "object" ? JSON.stringify(value) : value}`,
|
|
1327
|
+
{
|
|
1328
|
+
importance,
|
|
1329
|
+
tags: ["preference", userId, preference],
|
|
1330
|
+
context: {
|
|
1331
|
+
userId,
|
|
1332
|
+
preference,
|
|
1333
|
+
value,
|
|
1334
|
+
category: "user-preference"
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
);
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* Record a conversation exchange (convenience wrapper for episodic memory)
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* store.recordConversation("user123", "session456", "user", "How do I use React hooks?");
|
|
1344
|
+
*/
|
|
1345
|
+
recordConversation(userId, sessionId, role, message, importance = 5) {
|
|
1346
|
+
return this.writeEpisodic(`[${role}]: ${message}`, {
|
|
1347
|
+
importance,
|
|
1348
|
+
tags: ["conversation", userId, sessionId, role],
|
|
1349
|
+
context: {
|
|
1350
|
+
userId,
|
|
1351
|
+
sessionId,
|
|
1352
|
+
role,
|
|
1353
|
+
timestamp: Date.now(),
|
|
1354
|
+
category: "conversation"
|
|
1355
|
+
}
|
|
1356
|
+
});
|
|
1357
|
+
}
|
|
1358
|
+
/**
|
|
1359
|
+
* Record a user action/event (convenience wrapper for episodic memory)
|
|
1360
|
+
*
|
|
1361
|
+
* @example
|
|
1362
|
+
* store.recordAction("user123", "completed_tutorial", { tutorialId: "intro" });
|
|
1363
|
+
*/
|
|
1364
|
+
recordAction(userId, action, details, importance = 6) {
|
|
1365
|
+
return this.writeEpisodic(`User ${userId} performed action: ${action}`, {
|
|
1366
|
+
importance,
|
|
1367
|
+
tags: ["action", userId, action],
|
|
1368
|
+
context: {
|
|
1369
|
+
userId,
|
|
1370
|
+
action,
|
|
1371
|
+
details,
|
|
1372
|
+
timestamp: Date.now(),
|
|
1373
|
+
category: "user-action"
|
|
1374
|
+
}
|
|
1375
|
+
});
|
|
1376
|
+
}
|
|
1377
|
+
/**
|
|
1378
|
+
* Learn a pattern from observations (convenience wrapper for procedural memory)
|
|
1379
|
+
*
|
|
1380
|
+
* @example
|
|
1381
|
+
* store.learnPattern("optimization-workflow", "Profile before optimizing", {
|
|
1382
|
+
* conditions: "Performance issues reported",
|
|
1383
|
+
* relatedMemories: ["mem_123"]
|
|
1384
|
+
* });
|
|
1385
|
+
*/
|
|
1386
|
+
learnPattern(patternName, description, options) {
|
|
1387
|
+
return this.writeProcedural(`Pattern [${patternName}]: ${description}`, {
|
|
1388
|
+
importance: options?.importance ?? 7,
|
|
1389
|
+
tags: ["pattern", "learned", patternName],
|
|
1390
|
+
context: {
|
|
1391
|
+
patternName,
|
|
1392
|
+
conditions: options?.conditions,
|
|
1393
|
+
category: "learned-pattern",
|
|
1394
|
+
...options?.context
|
|
1395
|
+
},
|
|
1396
|
+
relationships: options?.relatedMemories
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
/**
|
|
1400
|
+
* Store a fact or knowledge (convenience wrapper for semantic memory)
|
|
1401
|
+
*
|
|
1402
|
+
* @example
|
|
1403
|
+
* store.storeFact("JavaScript", "JavaScript is a programming language", {
|
|
1404
|
+
* source: "documentation",
|
|
1405
|
+
* relatedTo: ["mem_456"]
|
|
1406
|
+
* });
|
|
1407
|
+
*/
|
|
1408
|
+
storeFact(topic, fact, options) {
|
|
1409
|
+
return this.writeSemantic(fact, {
|
|
1410
|
+
importance: options?.importance ?? 7,
|
|
1411
|
+
tags: ["fact", "knowledge", topic, ...options?.tags ?? []],
|
|
1412
|
+
context: {
|
|
1413
|
+
topic,
|
|
1414
|
+
source: options?.source,
|
|
1415
|
+
category: "fact"
|
|
1416
|
+
},
|
|
1417
|
+
relationships: options?.relatedTo
|
|
1418
|
+
});
|
|
1419
|
+
}
|
|
1420
|
+
/**
|
|
1421
|
+
* Record a milestone or achievement (convenience wrapper for episodic memory)
|
|
1422
|
+
*
|
|
1423
|
+
* @example
|
|
1424
|
+
* store.recordMilestone("user123", "first-project-completed", "User completed their first project");
|
|
1425
|
+
*/
|
|
1426
|
+
recordMilestone(userId, milestoneType, description, importance = 7) {
|
|
1427
|
+
return this.writeEpisodic(description, {
|
|
1428
|
+
importance,
|
|
1429
|
+
tags: ["milestone", userId, milestoneType],
|
|
1430
|
+
context: {
|
|
1431
|
+
userId,
|
|
1432
|
+
milestoneType,
|
|
1433
|
+
timestamp: Date.now(),
|
|
1434
|
+
category: "milestone"
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Store contextual information about current session (working memory)
|
|
1440
|
+
* Note: These should have lower importance as they're temporary
|
|
1441
|
+
*
|
|
1442
|
+
* @example
|
|
1443
|
+
* store.storeSessionContext("session456", "user-preferences-loaded", { theme: "dark" });
|
|
1444
|
+
*/
|
|
1445
|
+
storeSessionContext(sessionId, contextKey, data, importance = 4) {
|
|
1446
|
+
return this.writeEpisodic(`Session context [${contextKey}]`, {
|
|
1447
|
+
importance,
|
|
1448
|
+
tags: ["session", "working-memory", sessionId, contextKey],
|
|
1449
|
+
context: {
|
|
1450
|
+
sessionId,
|
|
1451
|
+
contextKey,
|
|
1452
|
+
data,
|
|
1453
|
+
category: "session-context",
|
|
1454
|
+
timestamp: Date.now()
|
|
1455
|
+
}
|
|
1456
|
+
});
|
|
1457
|
+
}
|
|
1458
|
+
// ============================================================================
|
|
1459
|
+
// Proactive Memory Loading - Auto-inject memories into system prompt
|
|
1460
|
+
// ============================================================================
|
|
1461
|
+
/**
|
|
1462
|
+
* Get proactive memories that should always be present in system prompt
|
|
1463
|
+
* These are high-importance memories that provide essential context
|
|
1464
|
+
*
|
|
1465
|
+
* @param options Configuration for proactive memory retrieval
|
|
1466
|
+
* @returns Formatted string ready for system prompt injection
|
|
1467
|
+
*
|
|
1468
|
+
* @example
|
|
1469
|
+
* const memoryContext = memoryStore.getProactiveMemories({
|
|
1470
|
+
* userId: 'user123',
|
|
1471
|
+
* minImportance: 7,
|
|
1472
|
+
* categories: ['preference', 'core-knowledge']
|
|
1473
|
+
* });
|
|
1474
|
+
*
|
|
1475
|
+
* // Use in agent:
|
|
1476
|
+
* const systemPrompt = `${basePrompt}\n\n${memoryContext}`;
|
|
1477
|
+
*/
|
|
1478
|
+
getProactiveMemories(options) {
|
|
1479
|
+
const {
|
|
1480
|
+
userId,
|
|
1481
|
+
sessionId,
|
|
1482
|
+
minImportance = 7,
|
|
1483
|
+
// High importance by default
|
|
1484
|
+
categories = [],
|
|
1485
|
+
maxMemories = 10,
|
|
1486
|
+
types,
|
|
1487
|
+
includeRelationships = false
|
|
1488
|
+
} = options;
|
|
1489
|
+
const tags = [];
|
|
1490
|
+
if (userId) tags.push(userId);
|
|
1491
|
+
if (sessionId) tags.push(sessionId);
|
|
1492
|
+
if (categories.length > 0) tags.push(...categories);
|
|
1493
|
+
const memoriesByType = {
|
|
1494
|
+
semantic: [],
|
|
1495
|
+
procedural: [],
|
|
1496
|
+
episodic: []
|
|
1497
|
+
};
|
|
1498
|
+
const typesToFetch = types || ["semantic", "procedural", "episodic"];
|
|
1499
|
+
for (const type of typesToFetch) {
|
|
1500
|
+
const memories = this.lookup({
|
|
1501
|
+
query: "",
|
|
1502
|
+
// Empty query to get all matching filters
|
|
1503
|
+
type,
|
|
1504
|
+
minImportance,
|
|
1505
|
+
tags: tags.length > 0 ? tags : void 0,
|
|
1506
|
+
limit: maxMemories
|
|
1507
|
+
});
|
|
1508
|
+
memoriesByType[type] = memories;
|
|
1509
|
+
}
|
|
1510
|
+
return this.formatProactiveMemories(memoriesByType, includeRelationships);
|
|
1511
|
+
}
|
|
1512
|
+
/**
|
|
1513
|
+
* Format proactive memories into a structured system prompt section
|
|
1514
|
+
*/
|
|
1515
|
+
formatProactiveMemories(memoriesByType, includeRelationships) {
|
|
1516
|
+
const sections = [];
|
|
1517
|
+
if (memoriesByType.semantic.length > 0) {
|
|
1518
|
+
sections.push("## Core Knowledge & Preferences");
|
|
1519
|
+
sections.push("");
|
|
1520
|
+
memoriesByType.semantic.forEach((mem, idx) => {
|
|
1521
|
+
sections.push(`${idx + 1}. ${mem.content}`);
|
|
1522
|
+
if (mem.context?.preference) {
|
|
1523
|
+
sections.push(` - Preference: ${mem.context.preference}`);
|
|
1524
|
+
}
|
|
1525
|
+
if (mem.context?.source) {
|
|
1526
|
+
sections.push(` - Source: ${mem.context.source}`);
|
|
1527
|
+
}
|
|
1528
|
+
});
|
|
1529
|
+
sections.push("");
|
|
1530
|
+
}
|
|
1531
|
+
if (memoriesByType.procedural.length > 0) {
|
|
1532
|
+
sections.push("## Behavioral Patterns & Guidelines");
|
|
1533
|
+
sections.push("");
|
|
1534
|
+
memoriesByType.procedural.forEach((mem, idx) => {
|
|
1535
|
+
sections.push(`${idx + 1}. ${mem.content}`);
|
|
1536
|
+
if (mem.context?.conditions) {
|
|
1537
|
+
sections.push(` - When: ${mem.context.conditions}`);
|
|
1538
|
+
}
|
|
1539
|
+
if (mem.context?.patternName) {
|
|
1540
|
+
sections.push(` - Pattern: ${mem.context.patternName}`);
|
|
1541
|
+
}
|
|
1542
|
+
});
|
|
1543
|
+
sections.push("");
|
|
1544
|
+
}
|
|
1545
|
+
if (memoriesByType.episodic.length > 0) {
|
|
1546
|
+
sections.push("## Recent Context & History");
|
|
1547
|
+
sections.push("");
|
|
1548
|
+
memoriesByType.episodic.forEach((mem, idx) => {
|
|
1549
|
+
const timeAgo = this.formatTimeAgo(Date.now() - mem.timestamp);
|
|
1550
|
+
sections.push(`${idx + 1}. ${mem.content} (${timeAgo})`);
|
|
1551
|
+
if (mem.context?.milestoneType) {
|
|
1552
|
+
sections.push(` - Milestone: ${mem.context.milestoneType}`);
|
|
1553
|
+
}
|
|
1554
|
+
});
|
|
1555
|
+
sections.push("");
|
|
1556
|
+
}
|
|
1557
|
+
if (sections.length === 0) {
|
|
1558
|
+
return "";
|
|
1559
|
+
}
|
|
1560
|
+
return [
|
|
1561
|
+
"",
|
|
1562
|
+
"# Proactive Memory Context",
|
|
1563
|
+
"The following information has been retrieved from memory to provide you with essential context:",
|
|
1564
|
+
"",
|
|
1565
|
+
...sections
|
|
1566
|
+
].join("\n");
|
|
1567
|
+
}
|
|
1568
|
+
/**
|
|
1569
|
+
* Helper to format time ago for human readability
|
|
1570
|
+
*/
|
|
1571
|
+
formatTimeAgo(ms) {
|
|
1572
|
+
const seconds = Math.floor(ms / 1e3);
|
|
1573
|
+
const minutes = Math.floor(seconds / 60);
|
|
1574
|
+
const hours = Math.floor(minutes / 60);
|
|
1575
|
+
const days = Math.floor(hours / 24);
|
|
1576
|
+
if (days > 0) return `${days}d ago`;
|
|
1577
|
+
if (hours > 0) return `${hours}h ago`;
|
|
1578
|
+
if (minutes > 0) return `${minutes}m ago`;
|
|
1579
|
+
return `${seconds}s ago`;
|
|
1580
|
+
}
|
|
1581
|
+
/**
|
|
1582
|
+
* Get user-specific proactive memories
|
|
1583
|
+
* Convenience method that focuses on user preferences and patterns
|
|
1584
|
+
*
|
|
1585
|
+
* @example
|
|
1586
|
+
* const userContext = memoryStore.getUserProactiveMemories('user123');
|
|
1587
|
+
*/
|
|
1588
|
+
getUserProactiveMemories(userId, options) {
|
|
1589
|
+
const {
|
|
1590
|
+
includePreferences = true,
|
|
1591
|
+
includePatterns = true,
|
|
1592
|
+
includeRecentHistory = true,
|
|
1593
|
+
maxPerCategory = 5
|
|
1594
|
+
} = options || {};
|
|
1595
|
+
const types = [];
|
|
1596
|
+
const categories = [];
|
|
1597
|
+
if (includePreferences) {
|
|
1598
|
+
types.push("semantic");
|
|
1599
|
+
categories.push("preference");
|
|
1600
|
+
}
|
|
1601
|
+
if (includePatterns) {
|
|
1602
|
+
types.push("procedural");
|
|
1603
|
+
categories.push("pattern");
|
|
1604
|
+
}
|
|
1605
|
+
if (includeRecentHistory) {
|
|
1606
|
+
types.push("episodic");
|
|
1607
|
+
categories.push("milestone", "action");
|
|
1608
|
+
}
|
|
1609
|
+
return this.getProactiveMemories({
|
|
1610
|
+
userId,
|
|
1611
|
+
minImportance: 7,
|
|
1612
|
+
categories,
|
|
1613
|
+
maxMemories: maxPerCategory * types.length,
|
|
1614
|
+
types: types.length > 0 ? types : void 0
|
|
1615
|
+
});
|
|
1616
|
+
}
|
|
1617
|
+
/**
|
|
1618
|
+
* Get session-specific proactive memories
|
|
1619
|
+
* Focuses on working memory and recent context
|
|
1620
|
+
*
|
|
1621
|
+
* @example
|
|
1622
|
+
* const sessionContext = memoryStore.getSessionProactiveMemories('session456');
|
|
1623
|
+
*/
|
|
1624
|
+
getSessionProactiveMemories(sessionId, options) {
|
|
1625
|
+
const { includeWorkingMemory = true, maxMemories = 10 } = options || {};
|
|
1626
|
+
const categories = includeWorkingMemory ? ["session", "working-memory", "conversation"] : ["session", "conversation"];
|
|
1627
|
+
return this.getProactiveMemories({
|
|
1628
|
+
sessionId,
|
|
1629
|
+
minImportance: 4,
|
|
1630
|
+
// Lower threshold for session context
|
|
1631
|
+
categories,
|
|
1632
|
+
maxMemories,
|
|
1633
|
+
types: ["episodic"]
|
|
1634
|
+
});
|
|
1635
|
+
}
|
|
1636
|
+
/**
|
|
1637
|
+
* Get critical memories that should ALWAYS be present
|
|
1638
|
+
* These are importance level 9-10 memories
|
|
1639
|
+
*
|
|
1640
|
+
* @example
|
|
1641
|
+
* const criticalContext = memoryStore.getCriticalMemories();
|
|
1642
|
+
*/
|
|
1643
|
+
getCriticalMemories(options) {
|
|
1644
|
+
return this.getProactiveMemories({
|
|
1645
|
+
userId: options?.userId,
|
|
1646
|
+
minImportance: 9,
|
|
1647
|
+
maxMemories: options?.maxMemories || 5,
|
|
1648
|
+
types: ["semantic", "procedural"]
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Build complete proactive context for an agent
|
|
1653
|
+
* Combines critical, user-specific, and session-specific memories
|
|
1654
|
+
*
|
|
1655
|
+
* @example
|
|
1656
|
+
* const fullContext = memoryStore.buildProactiveContext({
|
|
1657
|
+
* userId: 'user123',
|
|
1658
|
+
* sessionId: 'session456'
|
|
1659
|
+
* });
|
|
1660
|
+
*
|
|
1661
|
+
* // Use in agent system prompt
|
|
1662
|
+
* const systemPrompt = `${basePrompt}\n\n${fullContext}`;
|
|
1663
|
+
*/
|
|
1664
|
+
buildProactiveContext(options) {
|
|
1665
|
+
const {
|
|
1666
|
+
userId,
|
|
1667
|
+
sessionId,
|
|
1668
|
+
includeCritical = true,
|
|
1669
|
+
includeUser = true,
|
|
1670
|
+
includeSession = true
|
|
1671
|
+
} = options;
|
|
1672
|
+
const sections = [];
|
|
1673
|
+
if (includeCritical) {
|
|
1674
|
+
const critical = this.getCriticalMemories({ userId });
|
|
1675
|
+
if (critical) sections.push(critical);
|
|
1676
|
+
}
|
|
1677
|
+
if (includeUser && userId) {
|
|
1678
|
+
const userContext = this.getUserProactiveMemories(userId);
|
|
1679
|
+
if (userContext) sections.push(userContext);
|
|
1680
|
+
}
|
|
1681
|
+
if (includeSession && sessionId) {
|
|
1682
|
+
const sessionContext = this.getSessionProactiveMemories(sessionId);
|
|
1683
|
+
if (sessionContext) sections.push(sessionContext);
|
|
1684
|
+
}
|
|
1685
|
+
return sections.join("\n\n");
|
|
1686
|
+
}
|
|
1687
|
+
};
|
|
1688
|
+
var memoryStore = new MemoryStore();
|
|
1689
|
+
var memoryLookup = tool2({
|
|
1690
|
+
description: `Search and retrieve memories from the memory store.
|
|
1691
|
+
Use this to recall past conversations, learned facts, or previous interactions.
|
|
1692
|
+
Memories decay over time but are reinforced through repeated access.`,
|
|
1693
|
+
inputSchema: z2.object({
|
|
1694
|
+
query: z2.string().describe("Search query to find relevant memories"),
|
|
1695
|
+
type: z2.enum(["episodic", "semantic", "procedural"]).optional().describe("Type of memory to search"),
|
|
1696
|
+
limit: z2.number().int().positive().max(50).default(10).describe("Maximum number of memories to retrieve"),
|
|
1697
|
+
minImportance: z2.number().min(1).max(10).optional().describe("Minimum importance level (1-10)"),
|
|
1698
|
+
tags: z2.array(z2.string()).optional().describe("Filter by tags")
|
|
1699
|
+
}),
|
|
1700
|
+
execute: async ({ query, type, limit, minImportance, tags }) => {
|
|
1701
|
+
console.log("Memory lookup:", { query, type, limit, minImportance, tags });
|
|
1702
|
+
const results = memoryStore.lookup({
|
|
1703
|
+
query,
|
|
1704
|
+
type,
|
|
1705
|
+
limit,
|
|
1706
|
+
minImportance,
|
|
1707
|
+
tags
|
|
1708
|
+
});
|
|
1709
|
+
return {
|
|
1710
|
+
count: results.length,
|
|
1711
|
+
memories: results.map((m) => ({
|
|
1712
|
+
id: m.id,
|
|
1713
|
+
content: m.content,
|
|
1714
|
+
type: m.type,
|
|
1715
|
+
importance: m.importance,
|
|
1716
|
+
tags: m.tags,
|
|
1717
|
+
timestamp: new Date(m.timestamp).toISOString(),
|
|
1718
|
+
accessCount: m.accessCount,
|
|
1719
|
+
decay: m.decay?.toFixed(2),
|
|
1720
|
+
context: m.context
|
|
1721
|
+
}))
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1724
|
+
});
|
|
1725
|
+
var memoryExplain = tool2({
|
|
1726
|
+
description: `Get detailed information about a specific memory, including its relationships,
|
|
1727
|
+
access history, and decay status. Use this to understand the context and relevance of a memory.`,
|
|
1728
|
+
inputSchema: z2.object({
|
|
1729
|
+
id: z2.string().describe("The unique identifier of the memory to explain"),
|
|
1730
|
+
includeRelated: z2.boolean().default(true).describe("Include related memories in the explanation")
|
|
1731
|
+
}),
|
|
1732
|
+
execute: async ({ id, includeRelated }) => {
|
|
1733
|
+
console.log("Memory explain:", { id, includeRelated });
|
|
1734
|
+
const memory = memoryStore.get(id);
|
|
1735
|
+
if (!memory) {
|
|
1736
|
+
return {
|
|
1737
|
+
found: false,
|
|
1738
|
+
message: `No memory found with ID: ${id}`
|
|
1739
|
+
};
|
|
1740
|
+
}
|
|
1741
|
+
const related = includeRelated ? memoryStore.getRelated(id) : [];
|
|
1742
|
+
return {
|
|
1743
|
+
found: true,
|
|
1744
|
+
memory: {
|
|
1745
|
+
id: memory.id,
|
|
1746
|
+
content: memory.content,
|
|
1747
|
+
type: memory.type,
|
|
1748
|
+
importance: memory.importance,
|
|
1749
|
+
tags: memory.tags,
|
|
1750
|
+
timestamp: new Date(memory.timestamp).toISOString(),
|
|
1751
|
+
lastAccessed: new Date(memory.lastAccessed).toISOString(),
|
|
1752
|
+
accessCount: memory.accessCount,
|
|
1753
|
+
decay: memory.decay?.toFixed(2),
|
|
1754
|
+
context: memory.context,
|
|
1755
|
+
age: {
|
|
1756
|
+
days: Math.floor(
|
|
1757
|
+
(Date.now() - memory.timestamp) / (1e3 * 60 * 60 * 24)
|
|
1758
|
+
),
|
|
1759
|
+
hours: Math.floor((Date.now() - memory.timestamp) / (1e3 * 60 * 60))
|
|
1760
|
+
},
|
|
1761
|
+
timeSinceAccess: {
|
|
1762
|
+
days: Math.floor(
|
|
1763
|
+
(Date.now() - memory.lastAccessed) / (1e3 * 60 * 60 * 24)
|
|
1764
|
+
),
|
|
1765
|
+
hours: Math.floor(
|
|
1766
|
+
(Date.now() - memory.lastAccessed) / (1e3 * 60 * 60)
|
|
1767
|
+
)
|
|
1768
|
+
}
|
|
1769
|
+
},
|
|
1770
|
+
related: related.map((r) => ({
|
|
1771
|
+
id: r.id,
|
|
1772
|
+
content: r.content.substring(0, 100) + (r.content.length > 100 ? "..." : ""),
|
|
1773
|
+
type: r.type,
|
|
1774
|
+
importance: r.importance
|
|
1775
|
+
}))
|
|
1776
|
+
};
|
|
1777
|
+
}
|
|
1778
|
+
});
|
|
1779
|
+
var memoryWrite = tool2({
|
|
1780
|
+
description: `Store a new memory in the memory system. Use this to remember important facts,
|
|
1781
|
+
events, or learnings. Choose the appropriate memory type:
|
|
1782
|
+
- episodic: Events, conversations, experiences with temporal context
|
|
1783
|
+
- semantic: Facts, concepts, general knowledge
|
|
1784
|
+
- procedural: Patterns, methods, learned behaviors`,
|
|
1785
|
+
inputSchema: z2.object({
|
|
1786
|
+
content: z2.string().describe("The content of the memory to store"),
|
|
1787
|
+
type: z2.enum(["episodic", "semantic", "procedural"]).describe("Type of memory"),
|
|
1788
|
+
importance: z2.number().min(1).max(10).default(5).describe("Importance level (1-10), affects retention"),
|
|
1789
|
+
tags: z2.array(z2.string()).default([]).describe("Tags for categorization and retrieval"),
|
|
1790
|
+
context: z2.record(z2.any(), z2.any()).optional().describe("Additional context metadata"),
|
|
1791
|
+
relationships: z2.array(z2.string()).optional().describe("IDs of related memories")
|
|
1792
|
+
}),
|
|
1793
|
+
execute: async ({
|
|
1794
|
+
content,
|
|
1795
|
+
type,
|
|
1796
|
+
importance,
|
|
1797
|
+
tags,
|
|
1798
|
+
context,
|
|
1799
|
+
relationships
|
|
1800
|
+
}) => {
|
|
1801
|
+
console.log("Memory write:", { content, type, importance, tags });
|
|
1802
|
+
const memory = memoryStore.write({
|
|
1803
|
+
content,
|
|
1804
|
+
type,
|
|
1805
|
+
importance,
|
|
1806
|
+
tags,
|
|
1807
|
+
context,
|
|
1808
|
+
relationships
|
|
1809
|
+
});
|
|
1810
|
+
return {
|
|
1811
|
+
success: true,
|
|
1812
|
+
id: memory.id,
|
|
1813
|
+
message: "Memory stored successfully",
|
|
1814
|
+
memory: {
|
|
1815
|
+
id: memory.id,
|
|
1816
|
+
type: memory.type,
|
|
1817
|
+
importance: memory.importance,
|
|
1818
|
+
timestamp: new Date(memory.timestamp).toISOString()
|
|
1819
|
+
}
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
});
|
|
1823
|
+
var memoryForget = tool2({
|
|
1824
|
+
description: `Delete a memory from the memory store. Use this to remove outdated,
|
|
1825
|
+
incorrect, or irrelevant memories. This action is irreversible.`,
|
|
1826
|
+
inputSchema: z2.object({
|
|
1827
|
+
id: z2.string().describe("The unique identifier of the memory to forget"),
|
|
1828
|
+
reason: z2.string().optional().describe("Optional reason for forgetting")
|
|
1829
|
+
}),
|
|
1830
|
+
execute: async ({ id, reason }) => {
|
|
1831
|
+
console.log("Memory forget:", { id, reason });
|
|
1832
|
+
const success = memoryStore.forget(id);
|
|
1833
|
+
return {
|
|
1834
|
+
success,
|
|
1835
|
+
message: success ? `Memory ${id} has been forgotten${reason ? `: ${reason}` : ""}` : `No memory found with ID: ${id}`
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
});
|
|
1839
|
+
var memoryCorrect = tool2({
|
|
1840
|
+
description: `Update or correct an existing memory. Use this to fix errors,
|
|
1841
|
+
add new information, or adjust importance levels. The original timestamp is preserved.`,
|
|
1842
|
+
inputSchema: z2.object({
|
|
1843
|
+
id: z2.string().describe("The unique identifier of the memory to correct"),
|
|
1844
|
+
updates: z2.object({
|
|
1845
|
+
content: z2.string().optional().describe("Updated content"),
|
|
1846
|
+
importance: z2.number().min(1).max(10).optional().describe("Updated importance"),
|
|
1847
|
+
tags: z2.array(z2.string()).optional().describe("Updated tags"),
|
|
1848
|
+
context: z2.record(z2.any(), z2.any()).optional().describe("Updated context"),
|
|
1849
|
+
relationships: z2.array(z2.string()).optional().describe("Updated relationships")
|
|
1850
|
+
}),
|
|
1851
|
+
correctionNote: z2.string().optional().describe("Note explaining the correction")
|
|
1852
|
+
}),
|
|
1853
|
+
execute: async ({ id, updates, correctionNote }) => {
|
|
1854
|
+
console.log("Memory correct:", { id, updates, correctionNote });
|
|
1855
|
+
const memory = memoryStore.correct(id, updates);
|
|
1856
|
+
if (!memory) {
|
|
1857
|
+
return {
|
|
1858
|
+
success: false,
|
|
1859
|
+
message: `No memory found with ID: ${id}`
|
|
1860
|
+
};
|
|
1861
|
+
}
|
|
1862
|
+
return {
|
|
1863
|
+
success: true,
|
|
1864
|
+
message: `Memory ${id} has been updated${correctionNote ? `: ${correctionNote}` : ""}`,
|
|
1865
|
+
memory: {
|
|
1866
|
+
id: memory.id,
|
|
1867
|
+
content: memory.content,
|
|
1868
|
+
type: memory.type,
|
|
1869
|
+
importance: memory.importance,
|
|
1870
|
+
lastAccessed: new Date(memory.lastAccessed).toISOString()
|
|
1871
|
+
}
|
|
1872
|
+
};
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
var memoryStats = tool2({
|
|
1876
|
+
description: `Get statistics about the memory system, including total memories,
|
|
1877
|
+
distribution by type, most accessed memories, and recent memories.`,
|
|
1878
|
+
inputSchema: z2.object({}),
|
|
1879
|
+
execute: async () => {
|
|
1880
|
+
console.log("Memory stats requested");
|
|
1881
|
+
const stats = memoryStore.getStats();
|
|
1882
|
+
return {
|
|
1883
|
+
total: stats.totalMemories,
|
|
1884
|
+
byType: stats.byType,
|
|
1885
|
+
averageImportance: stats.averageImportance.toFixed(2),
|
|
1886
|
+
mostAccessed: stats.mostAccessed.slice(0, 5).map((m) => ({
|
|
1887
|
+
id: m.id,
|
|
1888
|
+
content: m.content.substring(0, 50) + "...",
|
|
1889
|
+
accessCount: m.accessCount,
|
|
1890
|
+
type: m.type
|
|
1891
|
+
})),
|
|
1892
|
+
recent: stats.recentMemories.slice(0, 5).map((m) => ({
|
|
1893
|
+
id: m.id,
|
|
1894
|
+
content: m.content.substring(0, 50) + "...",
|
|
1895
|
+
timestamp: new Date(m.timestamp).toISOString(),
|
|
1896
|
+
type: m.type
|
|
1897
|
+
}))
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
});
|
|
1901
|
+
var memoryTools = {
|
|
1902
|
+
memoryLookup,
|
|
1903
|
+
memoryExplain,
|
|
1904
|
+
memoryWrite,
|
|
1905
|
+
memoryForget,
|
|
1906
|
+
memoryCorrect,
|
|
1907
|
+
memoryStats
|
|
1908
|
+
};
|
|
1909
|
+
|
|
887
1910
|
// packages/agent/src/lib/models.ts
|
|
888
1911
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
889
1912
|
import { embedMany } from "ai";
|
|
890
1913
|
var lmstudio = createOpenAICompatible({
|
|
891
1914
|
name: "lmstudio",
|
|
892
|
-
baseURL: "http://127.0.0.1:1234/v1",
|
|
1915
|
+
baseURL: process.env.LM_STUDIO_BASE_URL ?? "http://127.0.0.1:1234/v1",
|
|
893
1916
|
supportsStructuredOutputs: true,
|
|
894
1917
|
includeUsage: true
|
|
895
1918
|
});
|
|
@@ -907,8 +1930,70 @@ async function embed(documents) {
|
|
|
907
1930
|
});
|
|
908
1931
|
return { embeddings, dimensions };
|
|
909
1932
|
}
|
|
1933
|
+
|
|
1934
|
+
// packages/agent/src/lib/pipe.ts
|
|
1935
|
+
import { createUIMessageStream as createUIMessageStream2, generateId as generateId3 } from "ai";
|
|
1936
|
+
function pipe(state, ...processes) {
|
|
1937
|
+
return () => {
|
|
1938
|
+
return createUIMessageStream2({
|
|
1939
|
+
originalMessages: state.messages,
|
|
1940
|
+
generateId: generateId3,
|
|
1941
|
+
onError(error) {
|
|
1942
|
+
console.error("Error in pipe execution:", error);
|
|
1943
|
+
return " An error occurred during processing. ";
|
|
1944
|
+
},
|
|
1945
|
+
execute: async ({ writer }) => {
|
|
1946
|
+
for (const it of processes) {
|
|
1947
|
+
if (it instanceof Agent) {
|
|
1948
|
+
const result = execute(it, state.messages, state);
|
|
1949
|
+
writer.merge(
|
|
1950
|
+
result.toUIMessageStream({
|
|
1951
|
+
generateMessageId: generateId3,
|
|
1952
|
+
originalMessages: state.messages,
|
|
1953
|
+
onFinish: async ({ responseMessage }) => {
|
|
1954
|
+
state.messages.push(responseMessage);
|
|
1955
|
+
}
|
|
1956
|
+
})
|
|
1957
|
+
);
|
|
1958
|
+
await result.consumeStream();
|
|
1959
|
+
} else {
|
|
1960
|
+
const output = await it(state, (newState) => {
|
|
1961
|
+
Object.assign(
|
|
1962
|
+
state,
|
|
1963
|
+
newState
|
|
1964
|
+
);
|
|
1965
|
+
});
|
|
1966
|
+
if (typeof output === "string") {
|
|
1967
|
+
writer.write({
|
|
1968
|
+
id: generateId3(),
|
|
1969
|
+
type: "text-start"
|
|
1970
|
+
});
|
|
1971
|
+
writer.write({
|
|
1972
|
+
id: generateId3(),
|
|
1973
|
+
type: "text-delta",
|
|
1974
|
+
delta: output
|
|
1975
|
+
});
|
|
1976
|
+
writer.write({
|
|
1977
|
+
id: generateId3(),
|
|
1978
|
+
type: "text-end"
|
|
1979
|
+
});
|
|
1980
|
+
} else {
|
|
1981
|
+
writer.merge(output);
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
}
|
|
1986
|
+
});
|
|
1987
|
+
};
|
|
1988
|
+
}
|
|
910
1989
|
export {
|
|
911
1990
|
Agent,
|
|
1991
|
+
GENERAL_STEP_BACK_EXAMPLES,
|
|
1992
|
+
KNOWLEDGE_QA_STEP_BACK_EXAMPLES,
|
|
1993
|
+
MemoryStore,
|
|
1994
|
+
RECOMMENDED_PROMPT_PREFIX,
|
|
1995
|
+
STEM_STEP_BACK_EXAMPLES,
|
|
1996
|
+
SUPERVISOR_PROMPT_PREFIX,
|
|
912
1997
|
agent,
|
|
913
1998
|
confirm,
|
|
914
1999
|
embed,
|
|
@@ -922,13 +2007,24 @@ export {
|
|
|
922
2007
|
last,
|
|
923
2008
|
lastTransferResult,
|
|
924
2009
|
lmstudio,
|
|
2010
|
+
memoryCorrect,
|
|
2011
|
+
memoryExplain,
|
|
2012
|
+
memoryForget,
|
|
2013
|
+
memoryLookup,
|
|
2014
|
+
memoryStats,
|
|
2015
|
+
memoryStore,
|
|
2016
|
+
memoryTools,
|
|
2017
|
+
memoryWrite,
|
|
925
2018
|
messageToUiMessage,
|
|
2019
|
+
pipe,
|
|
926
2020
|
prepareAgent,
|
|
927
2021
|
prepareStep,
|
|
928
2022
|
printer,
|
|
2023
|
+
stepBackPrompt,
|
|
929
2024
|
stream,
|
|
930
2025
|
streamWrite,
|
|
931
2026
|
swarm,
|
|
2027
|
+
thirdPersonPrompt,
|
|
932
2028
|
toOutput,
|
|
933
2029
|
toState,
|
|
934
2030
|
user
|