openbot 0.1.18 → 0.1.22
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/README.md +1 -1
- package/dist/agents/browser-agent.js +31 -0
- package/dist/agents/os-agent.js +31 -0
- package/dist/cli.js +13 -3
- package/dist/config.js +1 -1
- package/dist/handlers/init.js +22 -3
- package/dist/handlers/session-change.js +21 -0
- package/dist/handlers/tab-change.js +14 -0
- package/dist/models.js +53 -0
- package/dist/open-bot.js +166 -0
- package/dist/plugins/agent/index.js +81 -0
- package/dist/plugins/brain/identity.js +76 -0
- package/dist/plugins/brain/index.js +269 -0
- package/dist/plugins/brain/memory.js +120 -0
- package/dist/plugins/brain/prompt.js +64 -0
- package/dist/plugins/brain/types.js +60 -0
- package/dist/plugins/brain/ui.js +7 -0
- package/dist/plugins/browser/index.js +629 -0
- package/dist/plugins/browser/ui.js +13 -0
- package/dist/plugins/file-system/index.js +166 -0
- package/dist/plugins/file-system/ui.js +6 -0
- package/dist/plugins/llm/index.js +81 -0
- package/dist/plugins/meta-agent/index.js +570 -0
- package/dist/plugins/meta-agent/ui.js +11 -0
- package/dist/plugins/shell/index.js +95 -0
- package/dist/plugins/shell/ui.js +6 -0
- package/dist/plugins/skills/index.js +275 -0
- package/dist/plugins/skills/types.js +50 -0
- package/dist/plugins/skills/ui.js +12 -0
- package/dist/registry/agent-registry.js +35 -0
- package/dist/registry/index.js +3 -0
- package/dist/registry/plugin-registry.js +27 -0
- package/dist/registry/yaml-agent-loader.js +100 -0
- package/dist/server.js +35 -31
- package/dist/session.js +79 -1
- package/dist/ui/header.js +52 -0
- package/dist/ui/layout.js +22 -1
- package/dist/ui/navigation.js +5 -6
- package/dist/ui/settings.js +44 -0
- package/dist/ui/sidebar.js +83 -4
- package/dist/ui/skills.js +7 -0
- package/dist/ui/thread.js +15 -10
- package/package.json +12 -13
- package/dist/agent.js +0 -103
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { createIdentityModule } from "./identity.js";
|
|
4
|
+
import { createMemoryModule } from "./memory.js";
|
|
5
|
+
import { buildBrainPrompt } from "./prompt.js";
|
|
6
|
+
// Re-exports
|
|
7
|
+
export { brainToolDefinitions } from "./types.js";
|
|
8
|
+
export { buildBrainPrompt } from "./prompt.js";
|
|
9
|
+
// --- Helpers ---
|
|
10
|
+
function expandPath(p) {
|
|
11
|
+
if (p.startsWith("~/")) {
|
|
12
|
+
return path.join(process.env.HOME || "", p.slice(2));
|
|
13
|
+
}
|
|
14
|
+
return p;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a prompt-builder function bound to a baseDir.
|
|
18
|
+
* Returns the brain's portion of the system prompt (identity + memory).
|
|
19
|
+
*/
|
|
20
|
+
export function createBrainPromptBuilder(baseDir) {
|
|
21
|
+
const expandedBase = expandPath(baseDir);
|
|
22
|
+
const modules = {
|
|
23
|
+
identity: createIdentityModule(expandedBase),
|
|
24
|
+
memory: createMemoryModule(expandedBase),
|
|
25
|
+
};
|
|
26
|
+
return async (context) => buildBrainPrompt(expandedBase, modules, context);
|
|
27
|
+
}
|
|
28
|
+
// --- Plugin ---
|
|
29
|
+
/**
|
|
30
|
+
* Brain Plugin for Melony
|
|
31
|
+
*
|
|
32
|
+
* Provides the bot's "brain": identity and long-term memory with recall.
|
|
33
|
+
* Skills are managed by the separate skills plugin.
|
|
34
|
+
*
|
|
35
|
+
* Architecture: thin facade that delegates to focused sub-modules
|
|
36
|
+
* (identity, memory) — each independently testable and replaceable.
|
|
37
|
+
*/
|
|
38
|
+
export const brainPlugin = (options) => (builder) => {
|
|
39
|
+
const { baseDir } = options;
|
|
40
|
+
const expandedBase = expandPath(baseDir);
|
|
41
|
+
// Create sub-modules
|
|
42
|
+
const identity = createIdentityModule(expandedBase);
|
|
43
|
+
const memory = createMemoryModule(expandedBase);
|
|
44
|
+
// ─── Initialization ───────────────────────────────────────────────
|
|
45
|
+
builder.on("init", async function* (_event, context) {
|
|
46
|
+
yield {
|
|
47
|
+
type: "brain:status",
|
|
48
|
+
data: { message: "Initializing brain..." },
|
|
49
|
+
};
|
|
50
|
+
await fs.mkdir(expandedBase, { recursive: true, mode: 0o700 });
|
|
51
|
+
await identity.initialize();
|
|
52
|
+
await memory.initialize();
|
|
53
|
+
yield {
|
|
54
|
+
type: "brain:status",
|
|
55
|
+
data: { message: "Brain initialized", severity: "success" },
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
// ─── Memory: Remember ─────────────────────────────────────────────
|
|
59
|
+
builder.on("action:remember", async function* (event) {
|
|
60
|
+
const { content, tags = [], toolCallId } = event.data;
|
|
61
|
+
try {
|
|
62
|
+
const entry = await memory.store(content, tags);
|
|
63
|
+
yield {
|
|
64
|
+
type: "brain:status",
|
|
65
|
+
data: { message: "Remembered", severity: "success" },
|
|
66
|
+
};
|
|
67
|
+
yield {
|
|
68
|
+
type: "action:taskResult",
|
|
69
|
+
data: {
|
|
70
|
+
action: "remember",
|
|
71
|
+
toolCallId,
|
|
72
|
+
result: {
|
|
73
|
+
success: true,
|
|
74
|
+
memoryId: entry.id,
|
|
75
|
+
message: `Stored in memory with id ${entry.id}`,
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
yield {
|
|
82
|
+
type: "brain:status",
|
|
83
|
+
data: {
|
|
84
|
+
message: `Failed to remember: ${error.message}`,
|
|
85
|
+
severity: "error",
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
yield {
|
|
89
|
+
type: "action:taskResult",
|
|
90
|
+
data: {
|
|
91
|
+
action: "remember",
|
|
92
|
+
toolCallId,
|
|
93
|
+
result: { error: error.message },
|
|
94
|
+
},
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
// ─── Memory: Recall ────────────────────────────────────────────────
|
|
99
|
+
builder.on("action:recall", async function* (event) {
|
|
100
|
+
const { query, tags, limit, toolCallId } = event.data;
|
|
101
|
+
try {
|
|
102
|
+
const results = await memory.recall(query, { tags, limit });
|
|
103
|
+
yield {
|
|
104
|
+
type: "action:taskResult",
|
|
105
|
+
data: {
|
|
106
|
+
action: "recall",
|
|
107
|
+
toolCallId,
|
|
108
|
+
result: {
|
|
109
|
+
count: results.length,
|
|
110
|
+
memories: results.map((e) => ({
|
|
111
|
+
id: e.id,
|
|
112
|
+
content: e.content,
|
|
113
|
+
tags: e.tags,
|
|
114
|
+
createdAt: e.createdAt,
|
|
115
|
+
})),
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
yield {
|
|
122
|
+
type: "action:taskResult",
|
|
123
|
+
data: {
|
|
124
|
+
action: "recall",
|
|
125
|
+
toolCallId,
|
|
126
|
+
result: { error: error.message },
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
// ─── Memory: Forget ────────────────────────────────────────────────
|
|
132
|
+
builder.on("action:forget", async function* (event) {
|
|
133
|
+
const { memoryId, toolCallId } = event.data;
|
|
134
|
+
try {
|
|
135
|
+
const removed = await memory.forget(memoryId);
|
|
136
|
+
yield {
|
|
137
|
+
type: "brain:status",
|
|
138
|
+
data: {
|
|
139
|
+
message: removed ? "Memory removed" : "Memory not found",
|
|
140
|
+
severity: removed ? "success" : "error",
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
yield {
|
|
144
|
+
type: "action:taskResult",
|
|
145
|
+
data: {
|
|
146
|
+
action: "forget",
|
|
147
|
+
toolCallId,
|
|
148
|
+
result: {
|
|
149
|
+
success: removed,
|
|
150
|
+
message: removed
|
|
151
|
+
? "Memory removed"
|
|
152
|
+
: `Memory "${memoryId}" not found`,
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
yield {
|
|
159
|
+
type: "action:taskResult",
|
|
160
|
+
data: {
|
|
161
|
+
action: "forget",
|
|
162
|
+
toolCallId,
|
|
163
|
+
result: { error: error.message },
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
// ─── Memory: Journal ───────────────────────────────────────────────
|
|
169
|
+
builder.on("action:journal", async function* (event) {
|
|
170
|
+
const { content, toolCallId } = event.data;
|
|
171
|
+
try {
|
|
172
|
+
await memory.addJournalEntry(content);
|
|
173
|
+
yield {
|
|
174
|
+
type: "brain:status",
|
|
175
|
+
data: { message: "Journal entry added", severity: "success" },
|
|
176
|
+
};
|
|
177
|
+
yield {
|
|
178
|
+
type: "action:taskResult",
|
|
179
|
+
data: {
|
|
180
|
+
action: "journal",
|
|
181
|
+
toolCallId,
|
|
182
|
+
result: { success: true, message: "Journal entry added" },
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
yield {
|
|
188
|
+
type: "brain:status",
|
|
189
|
+
data: {
|
|
190
|
+
message: `Failed to journal: ${error.message}`,
|
|
191
|
+
severity: "error",
|
|
192
|
+
},
|
|
193
|
+
};
|
|
194
|
+
yield {
|
|
195
|
+
type: "action:taskResult",
|
|
196
|
+
data: {
|
|
197
|
+
action: "journal",
|
|
198
|
+
toolCallId,
|
|
199
|
+
result: { error: error.message },
|
|
200
|
+
},
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
// ─── Identity: Update ──────────────────────────────────────────────
|
|
205
|
+
builder.on("action:updateIdentity", async function* (event) {
|
|
206
|
+
const { content, toolCallId } = event.data;
|
|
207
|
+
try {
|
|
208
|
+
await identity.updateIdentity(content);
|
|
209
|
+
yield {
|
|
210
|
+
type: "brain:status",
|
|
211
|
+
data: { message: "Identity updated", severity: "success" },
|
|
212
|
+
};
|
|
213
|
+
yield {
|
|
214
|
+
type: "action:taskResult",
|
|
215
|
+
data: {
|
|
216
|
+
action: "updateIdentity",
|
|
217
|
+
toolCallId,
|
|
218
|
+
result: {
|
|
219
|
+
success: true,
|
|
220
|
+
message: "Identity updated. Changes will take effect on next initialization.",
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
yield {
|
|
227
|
+
type: "brain:status",
|
|
228
|
+
data: {
|
|
229
|
+
message: `Failed to update identity: ${error.message}`,
|
|
230
|
+
severity: "error",
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
yield {
|
|
234
|
+
type: "action:taskResult",
|
|
235
|
+
data: {
|
|
236
|
+
action: "updateIdentity",
|
|
237
|
+
toolCallId,
|
|
238
|
+
result: { error: error.message },
|
|
239
|
+
},
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
// ─── Identity: Read ────────────────────────────────────────────────
|
|
244
|
+
builder.on("action:readIdentity", async function* (event) {
|
|
245
|
+
const { file, toolCallId } = event.data;
|
|
246
|
+
try {
|
|
247
|
+
const content = await identity.readFile(file);
|
|
248
|
+
yield {
|
|
249
|
+
type: "action:taskResult",
|
|
250
|
+
data: {
|
|
251
|
+
action: "readIdentity",
|
|
252
|
+
toolCallId,
|
|
253
|
+
result: { file, content },
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
yield {
|
|
259
|
+
type: "action:taskResult",
|
|
260
|
+
data: {
|
|
261
|
+
action: "readIdentity",
|
|
262
|
+
toolCallId,
|
|
263
|
+
result: { error: `Could not read ${file}: ${error.message}` },
|
|
264
|
+
},
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
};
|
|
269
|
+
export default brainPlugin;
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import * as fs from "node:fs/promises";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
// --- Factory ---
|
|
4
|
+
export function createMemoryModule(baseDir) {
|
|
5
|
+
const memoryDir = path.join(baseDir, "memory");
|
|
6
|
+
const indexPath = path.join(memoryDir, "index.json");
|
|
7
|
+
const journalDir = path.join(memoryDir, "journal");
|
|
8
|
+
// --- Helpers ---
|
|
9
|
+
async function loadIndex() {
|
|
10
|
+
try {
|
|
11
|
+
const data = await fs.readFile(indexPath, "utf-8");
|
|
12
|
+
return JSON.parse(data);
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return { entries: [] };
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function saveIndex(index) {
|
|
19
|
+
await fs.writeFile(indexPath, JSON.stringify(index, null, 2), "utf-8");
|
|
20
|
+
}
|
|
21
|
+
function generateId() {
|
|
22
|
+
const timestamp = Date.now().toString(36);
|
|
23
|
+
const random = Math.random().toString(36).substring(2, 6);
|
|
24
|
+
return `mem_${timestamp}_${random}`;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Simple keyword-based relevance scoring.
|
|
28
|
+
* Splits query into terms (ignoring short words) and counts how many
|
|
29
|
+
* appear in the entry's content + tags. Returns a 0-1 score.
|
|
30
|
+
*/
|
|
31
|
+
function scoreMatch(entry, query) {
|
|
32
|
+
const queryTerms = query
|
|
33
|
+
.toLowerCase()
|
|
34
|
+
.split(/\s+/)
|
|
35
|
+
.filter((t) => t.length > 2);
|
|
36
|
+
if (queryTerms.length === 0)
|
|
37
|
+
return 0;
|
|
38
|
+
const searchable = `${entry.content} ${entry.tags.join(" ")}`.toLowerCase();
|
|
39
|
+
let matched = 0;
|
|
40
|
+
for (const term of queryTerms) {
|
|
41
|
+
if (searchable.includes(term)) {
|
|
42
|
+
matched++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return matched / queryTerms.length;
|
|
46
|
+
}
|
|
47
|
+
// --- Module ---
|
|
48
|
+
return {
|
|
49
|
+
async initialize() {
|
|
50
|
+
await fs.mkdir(memoryDir, { recursive: true });
|
|
51
|
+
await fs.mkdir(journalDir, { recursive: true });
|
|
52
|
+
try {
|
|
53
|
+
await fs.access(indexPath);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
await saveIndex({ entries: [] });
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
async store(content, tags = []) {
|
|
60
|
+
const index = await loadIndex();
|
|
61
|
+
const entry = {
|
|
62
|
+
id: generateId(),
|
|
63
|
+
content,
|
|
64
|
+
tags,
|
|
65
|
+
createdAt: new Date().toISOString(),
|
|
66
|
+
};
|
|
67
|
+
index.entries.push(entry);
|
|
68
|
+
await saveIndex(index);
|
|
69
|
+
return entry;
|
|
70
|
+
},
|
|
71
|
+
async recall(query, options) {
|
|
72
|
+
const { tags, limit = 5 } = options || {};
|
|
73
|
+
const index = await loadIndex();
|
|
74
|
+
let candidates = index.entries;
|
|
75
|
+
// Filter by tags if provided
|
|
76
|
+
if (tags && tags.length > 0) {
|
|
77
|
+
candidates = candidates.filter((entry) => tags.some((tag) => entry.tags.includes(tag)));
|
|
78
|
+
}
|
|
79
|
+
// Score and sort by relevance
|
|
80
|
+
const scored = candidates
|
|
81
|
+
.map((entry) => ({ entry, score: scoreMatch(entry, query) }))
|
|
82
|
+
.filter(({ score }) => score > 0)
|
|
83
|
+
.sort((a, b) => b.score - a.score)
|
|
84
|
+
.slice(0, limit);
|
|
85
|
+
// If no keyword matches found, fall back to most recent entries
|
|
86
|
+
if (scored.length === 0) {
|
|
87
|
+
return candidates.slice(-limit).reverse();
|
|
88
|
+
}
|
|
89
|
+
return scored.map(({ entry }) => entry);
|
|
90
|
+
},
|
|
91
|
+
async forget(memoryId) {
|
|
92
|
+
const index = await loadIndex();
|
|
93
|
+
const before = index.entries.length;
|
|
94
|
+
index.entries = index.entries.filter((e) => e.id !== memoryId);
|
|
95
|
+
if (index.entries.length < before) {
|
|
96
|
+
await saveIndex(index);
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
return false;
|
|
100
|
+
},
|
|
101
|
+
async addJournalEntry(content) {
|
|
102
|
+
const today = new Date().toISOString().split("T")[0]; // e.g., "2026-02-12"
|
|
103
|
+
const journalPath = path.join(journalDir, `${today}.md`);
|
|
104
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
105
|
+
const entry = `\n## ${timestamp}\n${content}\n`;
|
|
106
|
+
try {
|
|
107
|
+
await fs.access(journalPath);
|
|
108
|
+
await fs.appendFile(journalPath, entry, "utf-8");
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
const header = `# Journal - ${today}\n`;
|
|
112
|
+
await fs.writeFile(journalPath, header + entry, "utf-8");
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
async getRecentFacts(limit = 3) {
|
|
116
|
+
const index = await loadIndex();
|
|
117
|
+
return index.entries.slice(-limit);
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// --- Prompt Builder ---
|
|
2
|
+
/**
|
|
3
|
+
* Build the brain's section of the system prompt.
|
|
4
|
+
*
|
|
5
|
+
* Includes only what the brain owns:
|
|
6
|
+
* - Environment context
|
|
7
|
+
* - Identity + Soul (small, static)
|
|
8
|
+
* - A handful of the most recent memories
|
|
9
|
+
* - Brain capability instructions
|
|
10
|
+
*
|
|
11
|
+
* Skills are handled by the separate skills plugin and composed
|
|
12
|
+
* at the top level in open-bot.ts.
|
|
13
|
+
*/
|
|
14
|
+
export async function buildBrainPrompt(baseDir, modules, context) {
|
|
15
|
+
const parts = [];
|
|
16
|
+
const state = context?.state;
|
|
17
|
+
const currentCwd = state?.cwd || process.cwd();
|
|
18
|
+
// 1. Environment context
|
|
19
|
+
const now = new Date();
|
|
20
|
+
parts.push(`## Environment
|
|
21
|
+
You are running as a global system agent.
|
|
22
|
+
- **Current Time**: ${now.toLocaleString()} (${Intl.DateTimeFormat().resolvedOptions().timeZone})
|
|
23
|
+
- **Current Working Directory (CWD)**: ${currentCwd}
|
|
24
|
+
- **System Access**: You have access to the entire file system (root: /).
|
|
25
|
+
- **Bot Home (Internal State)**: ${baseDir}
|
|
26
|
+
|
|
27
|
+
### Path Rules:
|
|
28
|
+
1. **Shell Commands**: All commands (executeCommand) run in the CWD: ${currentCwd}.
|
|
29
|
+
2. **File Operations**: Relative paths in readFile, writeFile, listFiles, etc. resolve against the CWD.
|
|
30
|
+
3. **Changing Directory**: Use \`cd <path>\` in executeCommand to move. Your CWD is persisted across turns.
|
|
31
|
+
4. **Skills/Memory**: To access your own skills and memory, use absolute paths starting with "${baseDir}/".
|
|
32
|
+
|
|
33
|
+
When you want to execute skill scripts, always use the full path to the skill directory.`);
|
|
34
|
+
// 2. Identity (small, always included)
|
|
35
|
+
const soul = await modules.identity.getSoul();
|
|
36
|
+
if (soul)
|
|
37
|
+
parts.push(soul);
|
|
38
|
+
const identity = await modules.identity.getIdentity();
|
|
39
|
+
if (identity)
|
|
40
|
+
parts.push(identity);
|
|
41
|
+
// 3. Recent memories (lean — just a few to keep context fresh)
|
|
42
|
+
const recentFacts = await modules.memory.getRecentFacts(3);
|
|
43
|
+
if (recentFacts.length > 0) {
|
|
44
|
+
const factsList = recentFacts
|
|
45
|
+
.map((f) => `- ${f.content}${f.tags.length > 0 ? ` [${f.tags.join(", ")}]` : ""}`)
|
|
46
|
+
.join("\n");
|
|
47
|
+
parts.push(`## Recent Memory
|
|
48
|
+
|
|
49
|
+
These are your most recent memories. Use \`recall\` to search for more specific information.
|
|
50
|
+
|
|
51
|
+
${factsList}`);
|
|
52
|
+
}
|
|
53
|
+
// 4. Brain capabilities
|
|
54
|
+
parts.push(`## Brain Capabilities
|
|
55
|
+
|
|
56
|
+
You have a brain with long-term memory:
|
|
57
|
+
- Use \`remember\` to store important facts, user preferences, or learned context
|
|
58
|
+
- Use \`recall\` to search your memory when you need past information
|
|
59
|
+
- Use \`forget\` to remove outdated or incorrect memories
|
|
60
|
+
- Use \`journal\` to record session notes and reflections
|
|
61
|
+
- Use \`updateIdentity\` to refine your personality in IDENTITY.md
|
|
62
|
+
- SOUL.md contains your core values and is protected from modification`);
|
|
63
|
+
return parts.join("\n\n");
|
|
64
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
// --- Tool Definitions ---
|
|
3
|
+
export const brainToolDefinitions = {
|
|
4
|
+
// Memory tools
|
|
5
|
+
remember: {
|
|
6
|
+
description: "Store something important in long-term memory. Use for user preferences, learned facts, project context, etc.",
|
|
7
|
+
inputSchema: z.object({
|
|
8
|
+
content: z
|
|
9
|
+
.string()
|
|
10
|
+
.describe("The information to remember"),
|
|
11
|
+
tags: z
|
|
12
|
+
.array(z.string())
|
|
13
|
+
.optional()
|
|
14
|
+
.describe("Tags for categorization (e.g., 'user-preference', 'project', 'learning')"),
|
|
15
|
+
}),
|
|
16
|
+
},
|
|
17
|
+
recall: {
|
|
18
|
+
description: "Search your memory for relevant information. Use before answering questions that might relate to past interactions.",
|
|
19
|
+
inputSchema: z.object({
|
|
20
|
+
query: z.string().describe("What to search for in memory"),
|
|
21
|
+
tags: z
|
|
22
|
+
.array(z.string())
|
|
23
|
+
.optional()
|
|
24
|
+
.describe("Filter by specific tags"),
|
|
25
|
+
limit: z
|
|
26
|
+
.number()
|
|
27
|
+
.optional()
|
|
28
|
+
.describe("Max results to return (default: 5)"),
|
|
29
|
+
}),
|
|
30
|
+
},
|
|
31
|
+
forget: {
|
|
32
|
+
description: "Remove a specific memory entry by ID.",
|
|
33
|
+
inputSchema: z.object({
|
|
34
|
+
memoryId: z
|
|
35
|
+
.string()
|
|
36
|
+
.describe("The ID of the memory entry to remove"),
|
|
37
|
+
}),
|
|
38
|
+
},
|
|
39
|
+
journal: {
|
|
40
|
+
description: "Add a journal entry for today. Use for session notes, learnings, and reflections.",
|
|
41
|
+
inputSchema: z.object({
|
|
42
|
+
content: z.string().describe("Journal entry content"),
|
|
43
|
+
}),
|
|
44
|
+
},
|
|
45
|
+
// Identity tools
|
|
46
|
+
updateIdentity: {
|
|
47
|
+
description: "Update your identity file to refine your personality and traits.",
|
|
48
|
+
inputSchema: z.object({
|
|
49
|
+
content: z.string().describe("New content for IDENTITY.md"),
|
|
50
|
+
}),
|
|
51
|
+
},
|
|
52
|
+
readIdentity: {
|
|
53
|
+
description: "Read your current identity or soul configuration.",
|
|
54
|
+
inputSchema: z.object({
|
|
55
|
+
file: z
|
|
56
|
+
.enum(["IDENTITY.md", "SOUL.md"])
|
|
57
|
+
.describe("Which identity file to read"),
|
|
58
|
+
}),
|
|
59
|
+
},
|
|
60
|
+
};
|