openbot 0.2.11 → 0.2.13

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.
Files changed (141) hide show
  1. package/.prettierrc +8 -0
  2. package/AGENTS.md +68 -0
  3. package/CONTRIBUTING.md +74 -0
  4. package/LICENSE +21 -0
  5. package/README.md +117 -14
  6. package/dist/agents/system.js +106 -0
  7. package/dist/app/cli.js +27 -0
  8. package/dist/app/config.js +64 -0
  9. package/dist/app/server.js +237 -0
  10. package/dist/app/utils.js +35 -0
  11. package/dist/harness/agent-harness.js +45 -0
  12. package/dist/harness/mcp.js +61 -0
  13. package/dist/harness/orchestrator.js +273 -0
  14. package/dist/harness/process.js +7 -0
  15. package/dist/plugins/ai-sdk.js +141 -0
  16. package/dist/plugins/delegation.js +52 -0
  17. package/dist/plugins/mcp.js +140 -0
  18. package/dist/plugins/storage.js +502 -0
  19. package/dist/plugins/ui.js +47 -0
  20. package/dist/registry/plugins.js +73 -0
  21. package/dist/services/storage.js +724 -0
  22. package/docs/README.md +7 -0
  23. package/docs/agents.md +83 -0
  24. package/docs/architecture.md +34 -0
  25. package/docs/plugins.md +77 -0
  26. package/logo-black.png +0 -0
  27. package/{dist/assets/logo.js → logo-black.svg} +24 -24
  28. package/{dist/ui/sidebar.js → logo-white.svg} +23 -88
  29. package/package.json +10 -9
  30. package/src/agents/system.ts +112 -0
  31. package/src/app/cli.ts +38 -0
  32. package/src/app/config.ts +104 -0
  33. package/src/app/server.ts +284 -0
  34. package/src/app/types.ts +476 -0
  35. package/src/app/utils.ts +43 -0
  36. package/src/assets/icon.svg +1 -0
  37. package/src/harness/agent-harness.ts +58 -0
  38. package/src/harness/mcp.ts +78 -0
  39. package/src/harness/orchestrator.ts +342 -0
  40. package/src/harness/process.ts +9 -0
  41. package/src/harness/types.ts +34 -0
  42. package/src/plugins/ai-sdk.ts +197 -0
  43. package/src/plugins/delegation.ts +60 -0
  44. package/src/plugins/mcp.ts +154 -0
  45. package/src/plugins/storage.ts +725 -0
  46. package/src/plugins/ui.ts +57 -0
  47. package/src/registry/plugins.ts +85 -0
  48. package/src/services/storage.ts +957 -0
  49. package/tsconfig.json +18 -0
  50. package/dist/agents/agent-creator.js +0 -74
  51. package/dist/agents/browser-agent.js +0 -31
  52. package/dist/agents/os-agent.js +0 -32
  53. package/dist/agents/planner-agent.js +0 -32
  54. package/dist/agents/topic-agent.js +0 -46
  55. package/dist/architecture/execution-engine.js +0 -151
  56. package/dist/architecture/intent-classifier.js +0 -26
  57. package/dist/architecture/planner.js +0 -106
  58. package/dist/automation-worker.js +0 -121
  59. package/dist/automations.js +0 -52
  60. package/dist/cli.js +0 -275
  61. package/dist/config.js +0 -53
  62. package/dist/core/agents.js +0 -41
  63. package/dist/core/delegation.js +0 -230
  64. package/dist/core/manager.js +0 -96
  65. package/dist/core/plugins.js +0 -74
  66. package/dist/core/router.js +0 -191
  67. package/dist/handlers/init.js +0 -29
  68. package/dist/handlers/session-change.js +0 -21
  69. package/dist/handlers/settings.js +0 -47
  70. package/dist/handlers/tab-change.js +0 -14
  71. package/dist/installers.js +0 -156
  72. package/dist/marketplace.js +0 -80
  73. package/dist/model-catalog.js +0 -132
  74. package/dist/model-defaults.js +0 -25
  75. package/dist/models.js +0 -47
  76. package/dist/open-bot.js +0 -51
  77. package/dist/orchestrator/direct-invocation.js +0 -13
  78. package/dist/orchestrator/events.js +0 -36
  79. package/dist/orchestrator/state.js +0 -54
  80. package/dist/orchestrator.js +0 -422
  81. package/dist/plugins/agent/index.js +0 -81
  82. package/dist/plugins/approval/index.js +0 -100
  83. package/dist/plugins/brain/identity.js +0 -77
  84. package/dist/plugins/brain/index.js +0 -204
  85. package/dist/plugins/brain/memory.js +0 -120
  86. package/dist/plugins/brain/prompt.js +0 -46
  87. package/dist/plugins/brain/types.js +0 -45
  88. package/dist/plugins/brain/ui.js +0 -7
  89. package/dist/plugins/browser/index.js +0 -629
  90. package/dist/plugins/browser/ui.js +0 -13
  91. package/dist/plugins/file-system/index.js +0 -171
  92. package/dist/plugins/file-system/ui.js +0 -6
  93. package/dist/plugins/llm/context-budget.js +0 -139
  94. package/dist/plugins/llm/context-shaping.js +0 -177
  95. package/dist/plugins/llm/index.js +0 -380
  96. package/dist/plugins/memory/index.js +0 -220
  97. package/dist/plugins/memory/memory.js +0 -122
  98. package/dist/plugins/memory/prompt.js +0 -55
  99. package/dist/plugins/memory/types.js +0 -45
  100. package/dist/plugins/meta-agent/index.js +0 -570
  101. package/dist/plugins/meta-agent/ui.js +0 -11
  102. package/dist/plugins/shell/index.js +0 -100
  103. package/dist/plugins/shell/ui.js +0 -6
  104. package/dist/plugins/skills/index.js +0 -286
  105. package/dist/plugins/skills/types.js +0 -50
  106. package/dist/plugins/skills/ui.js +0 -12
  107. package/dist/registry/agent-registry.js +0 -35
  108. package/dist/registry/index.js +0 -2
  109. package/dist/registry/plugin-loader.js +0 -499
  110. package/dist/registry/plugin-registry.js +0 -44
  111. package/dist/registry/ts-agent-loader.js +0 -82
  112. package/dist/registry/yaml-agent-loader.js +0 -246
  113. package/dist/runtime/execution-trace.js +0 -41
  114. package/dist/runtime/intent-routing.js +0 -26
  115. package/dist/runtime/openbot-runtime.js +0 -354
  116. package/dist/server.js +0 -890
  117. package/dist/session.js +0 -179
  118. package/dist/ui/block.js +0 -12
  119. package/dist/ui/header.js +0 -52
  120. package/dist/ui/layout.js +0 -26
  121. package/dist/ui/navigation.js +0 -15
  122. package/dist/ui/settings.js +0 -106
  123. package/dist/ui/skills.js +0 -7
  124. package/dist/ui/thread.js +0 -16
  125. package/dist/ui/widgets/action-list.js +0 -2
  126. package/dist/ui/widgets/approval-card.js +0 -9
  127. package/dist/ui/widgets/code-snippet.js +0 -2
  128. package/dist/ui/widgets/data-block.js +0 -2
  129. package/dist/ui/widgets/data-table.js +0 -2
  130. package/dist/ui/widgets/delegation.js +0 -29
  131. package/dist/ui/widgets/empty-state.js +0 -2
  132. package/dist/ui/widgets/index.js +0 -23
  133. package/dist/ui/widgets/inquiry.js +0 -7
  134. package/dist/ui/widgets/key-value.js +0 -2
  135. package/dist/ui/widgets/progress-step.js +0 -2
  136. package/dist/ui/widgets/resource-card.js +0 -2
  137. package/dist/ui/widgets/status.js +0 -2
  138. package/dist/ui/widgets/todo-list.js +0 -2
  139. package/dist/version.js +0 -62
  140. /package/dist/{types.js → app/types.js} +0 -0
  141. /package/dist/{architecture/contracts.js → harness/types.js} +0 -0
@@ -1,380 +0,0 @@
1
- import { streamText, Output } from "ai";
2
- async function toInlineDataUrl(url, mimeType) {
3
- const response = await fetch(url);
4
- if (!response.ok) {
5
- throw new Error(`Failed to fetch image: ${response.status} ${response.statusText}`);
6
- }
7
- const arrayBuffer = await response.arrayBuffer();
8
- const base64 = Buffer.from(arrayBuffer).toString("base64");
9
- return `data:${mimeType};base64,${base64}`;
10
- }
11
- async function toModelMessages(messages) {
12
- return Promise.all(messages.map(async (message) => {
13
- if (message.role === "tool") {
14
- return {
15
- role: "tool",
16
- content: Array.isArray(message.content)
17
- ? message.content.map((c) => {
18
- const result = c.result ?? c.output?.value ?? c.output;
19
- return {
20
- type: "tool-result",
21
- toolCallId: c.toolCallId,
22
- toolName: c.toolName,
23
- output: typeof result === "string"
24
- ? { type: "text", value: result }
25
- : { type: "json", value: result },
26
- };
27
- })
28
- : [],
29
- };
30
- }
31
- if (message.role === "assistant") {
32
- if (Array.isArray(message.content)) {
33
- return {
34
- role: "assistant",
35
- content: message.content.map((c) => {
36
- if (c.type === "tool-call") {
37
- return {
38
- type: "tool-call",
39
- toolCallId: c.toolCallId,
40
- toolName: c.toolName,
41
- input: c.input,
42
- };
43
- }
44
- if (c.type === "text") {
45
- return c;
46
- }
47
- // Fallback for character spread bug fix
48
- if (typeof c === "string") {
49
- return { type: "text", text: c };
50
- }
51
- return c;
52
- }),
53
- };
54
- }
55
- return {
56
- role: "assistant",
57
- content: message.content,
58
- };
59
- }
60
- if (message.role === "user") {
61
- if (message.attachments && message.attachments.length > 0) {
62
- const attachmentParts = await Promise.all(message.attachments.map(async (a) => {
63
- if (a.mimeType.startsWith("image/")) {
64
- try {
65
- return {
66
- type: "image",
67
- image: await toInlineDataUrl(a.url, a.mimeType),
68
- };
69
- }
70
- catch (error) {
71
- console.warn(`Failed to inline image attachment (${a.name}). Falling back to URL: ${a.url}`, error);
72
- return {
73
- type: "image",
74
- image: a.url,
75
- };
76
- }
77
- }
78
- return {
79
- type: "file",
80
- data: a.url,
81
- mimeType: a.mimeType,
82
- };
83
- }));
84
- return {
85
- role: "user",
86
- content: [
87
- { type: "text", text: message.content },
88
- ...attachmentParts,
89
- ],
90
- };
91
- }
92
- return {
93
- role: "user",
94
- content: message.content,
95
- };
96
- }
97
- return {
98
- role: message.role,
99
- content: message.content,
100
- };
101
- }));
102
- }
103
- // Helper to find pending tool calls in history
104
- function getPendingToolCalls(messages) {
105
- const toolResults = new Set();
106
- let lastAssistantWithTools = null;
107
- for (let i = 0; i < messages.length; i++) {
108
- const msg = messages[i];
109
- if (msg.role === "tool" && Array.isArray(msg.content)) {
110
- msg.content.forEach((c) => {
111
- if (c.toolCallId)
112
- toolResults.add(c.toolCallId);
113
- });
114
- }
115
- if (msg.role === "assistant" && Array.isArray(msg.content)) {
116
- if (msg.content.some((c) => c.type === "tool-call")) {
117
- lastAssistantWithTools = msg;
118
- }
119
- }
120
- }
121
- if (lastAssistantWithTools) {
122
- return lastAssistantWithTools.content.filter((c) => c.type === "tool-call" && !toolResults.has(c.toolCallId));
123
- }
124
- return [];
125
- }
126
- // Helper to insert tool result message in correct position (immediately after corresponding assistant msg)
127
- function insertToolResult(messages, toolResultMsg) {
128
- if (toolResultMsg.role !== "tool" || !Array.isArray(toolResultMsg.content))
129
- return;
130
- const toolCallId = toolResultMsg.content[0]?.toolCallId;
131
- if (!toolCallId)
132
- return;
133
- // Find the assistant message that called this tool
134
- let assistantIdx = -1;
135
- for (let i = messages.length - 1; i >= 0; i--) {
136
- const msg = messages[i];
137
- if (msg.role === "assistant" && Array.isArray(msg.content)) {
138
- if (msg.content.some((c) => c.toolCallId === toolCallId)) {
139
- assistantIdx = i;
140
- break;
141
- }
142
- }
143
- }
144
- if (assistantIdx !== -1) {
145
- // Find if there's already a tool message after this assistant message
146
- let toolMsgIdx = -1;
147
- for (let i = assistantIdx + 1; i < messages.length; i++) {
148
- if (messages[i].role === "tool") {
149
- toolMsgIdx = i;
150
- break;
151
- }
152
- if (messages[i].role === "assistant")
153
- break;
154
- }
155
- if (toolMsgIdx !== -1) {
156
- // Merge into existing tool message
157
- const toolMsg = messages[toolMsgIdx];
158
- if (Array.isArray(toolMsg.content)) {
159
- toolMsg.content.push(...toolResultMsg.content);
160
- }
161
- }
162
- else {
163
- // Insert new tool message after assistant
164
- messages.splice(assistantIdx + 1, 0, toolResultMsg);
165
- }
166
- }
167
- else {
168
- // Fallback: push to end
169
- messages.push(toolResultMsg);
170
- }
171
- }
172
- /**
173
- * LLM Plugin for Melony.
174
- * Automatically handles text events and routes them through an LLM using Vercel AI SDK.
175
- * It can also automatically trigger events based on tool calls.
176
- */
177
- export const llmPlugin = (options) => (builder) => {
178
- const { model, system, toolDefinitions = {}, actionEventPrefix = "action:", promptInputType = "agent:input", actionResultInputType = "action:result", completionEventType = "agent:output", usageEventType = "usage:update", usageScope = "default", modelId, outputSchema, } = options;
179
- async function* routeToLLM(newMessage, context, silent = false) {
180
- const state = context.state;
181
- if (!state.messages) {
182
- state.messages = [];
183
- }
184
- // 1. Add new message to history with correct positioning and unblocking logic.
185
- if (newMessage) {
186
- if (newMessage.role === "tool") {
187
- insertToolResult(state.messages, newMessage);
188
- }
189
- else {
190
- // If a new user message arrives while tools are pending, we unblock by failing the tools.
191
- if (newMessage.role === "user") {
192
- const pending = getPendingToolCalls(state.messages);
193
- if (pending.length > 0) {
194
- console.warn(`User message received while tools are pending. Failing pending tools to unblock: ${pending
195
- .map((p) => p.toolName)
196
- .join(", ")}`);
197
- for (const p of pending) {
198
- insertToolResult(state.messages, {
199
- role: "tool",
200
- content: [
201
- {
202
- type: "tool-result",
203
- toolCallId: p.toolCallId,
204
- toolName: p.toolName,
205
- output: {
206
- type: "text",
207
- value: "Tool failed to respond in time (unblocked by user message).",
208
- },
209
- },
210
- ],
211
- });
212
- }
213
- }
214
- }
215
- state.messages.push(newMessage);
216
- }
217
- }
218
- // 2. Check for pending tool calls. We MUST have results for all tool calls before continuing.
219
- const pending = getPendingToolCalls(state.messages);
220
- if (pending.length > 0) {
221
- console.log(`Waiting for ${pending.length} pending tool results: ${pending
222
- .map((p) => p.toolName)
223
- .join(", ")}`);
224
- return;
225
- }
226
- // Evaluate dynamic system prompt if it's a function
227
- const systemPrompt = typeof system === "function" ? await system(context) : system;
228
- const modelMessages = await toModelMessages(state.messages);
229
- // Initialize an empty assistant message to be populated as we stream
230
- const assistantMessage = { role: "assistant", content: "" };
231
- state.messages.push(assistantMessage);
232
- // console.log("messages:::::", JSON.stringify(state.messages, null, 2));
233
- // console.log("modelMessages:::::", JSON.stringify(modelMessages, null, 2));
234
- const result = streamText({
235
- model,
236
- system: systemPrompt,
237
- messages: modelMessages,
238
- tools: toolDefinitions,
239
- output: outputSchema ? Output.object({ schema: outputSchema }) : undefined,
240
- onError: (error) => {
241
- console.error("streamText error:::::", JSON.stringify(error, null, 2));
242
- },
243
- });
244
- if (outputSchema) {
245
- for await (const delta of result.partialOutputStream) {
246
- if (!silent) {
247
- yield {
248
- type: "agent:output-delta",
249
- data: { delta: "", content: JSON.stringify(delta) },
250
- };
251
- }
252
- }
253
- const finalObject = await result.output;
254
- assistantMessage.content = JSON.stringify(finalObject);
255
- if (completionEventType && !silent) {
256
- yield {
257
- type: completionEventType,
258
- data: finalObject,
259
- };
260
- }
261
- }
262
- else {
263
- for await (const delta of result.textStream) {
264
- assistantMessage.content += delta;
265
- if (!silent) {
266
- yield {
267
- type: "agent:output-delta",
268
- data: { delta, content: assistantMessage.content },
269
- };
270
- }
271
- }
272
- }
273
- const assistantText = assistantMessage.content;
274
- // Wait for tool calls to complete
275
- const toolCalls = await result.toolCalls;
276
- if (toolCalls && toolCalls.length > 0) {
277
- const parts = [];
278
- if (assistantText) {
279
- parts.push({ type: "text", text: assistantText });
280
- }
281
- parts.push(...toolCalls.map((c) => ({
282
- type: "tool-call",
283
- toolCallId: c.toolCallId,
284
- toolName: c.toolName,
285
- input: c.input,
286
- })));
287
- assistantMessage.content = parts;
288
- }
289
- // Remove the message if it's empty (e.g. only tool calls)
290
- if (!assistantText && (!toolCalls || toolCalls.length === 0)) {
291
- state.messages = state.messages.filter((m) => m !== assistantMessage);
292
- }
293
- else {
294
- if (completionEventType && !silent) {
295
- // If it's structured output, we already yielded the final object
296
- if (!outputSchema) {
297
- yield {
298
- type: completionEventType,
299
- data: { content: assistantText },
300
- };
301
- }
302
- }
303
- }
304
- const usage = await result.usage;
305
- if (!state.usage) {
306
- state.usage = {
307
- inputTokens: 0,
308
- outputTokens: 0,
309
- totalTokens: 0,
310
- };
311
- }
312
- state.usage.inputTokens += usage.inputTokens ?? 0;
313
- state.usage.outputTokens += usage.outputTokens ?? 0;
314
- state.usage.totalTokens += usage.totalTokens ?? 0;
315
- if (!silent) {
316
- yield {
317
- type: usageEventType,
318
- data: {
319
- scope: usageScope,
320
- model: modelId,
321
- turn: {
322
- inputTokens: usage.inputTokens ?? 0,
323
- outputTokens: usage.outputTokens ?? 0,
324
- totalTokens: usage.totalTokens ?? 0,
325
- },
326
- session: {
327
- inputTokens: state.usage.inputTokens,
328
- outputTokens: state.usage.outputTokens,
329
- totalTokens: state.usage.totalTokens,
330
- },
331
- },
332
- };
333
- }
334
- // Emit tool call events
335
- for (const call of toolCalls) {
336
- yield {
337
- type: `${actionEventPrefix}${call.toolName}`,
338
- data: {
339
- ...call.input,
340
- toolCallId: call.toolCallId,
341
- },
342
- };
343
- }
344
- }
345
- // Handle user text input
346
- builder.on(promptInputType, async function* (event, context) {
347
- const content = typeof event.data?.content === "string" ? event.data.content : "";
348
- const attachments = Array.isArray(event.data?.attachments) ? event.data.attachments : undefined;
349
- yield* routeToLLM({ role: "user", content, attachments }, context);
350
- });
351
- // Feed action results back as system-role feedback to the model.
352
- builder.on(actionResultInputType, async function* (event, context) {
353
- const { action, result, toolCallId, halt } = event.data;
354
- const normalizedAction = typeof action === "string" ? action : "unknown";
355
- const summary = typeof result === "string" ? result : JSON.stringify(result);
356
- const toolResultMessage = {
357
- role: "tool",
358
- content: [{
359
- type: "tool-result",
360
- toolCallId,
361
- toolName: normalizedAction,
362
- output: {
363
- type: "text",
364
- value: summary,
365
- },
366
- }],
367
- };
368
- // Hard-stop mode: record tool result to unblock pending calls, but do not
369
- // continue the autonomous tool loop in this turn.
370
- if (halt === true) {
371
- const state = context.state;
372
- if (!state.messages) {
373
- state.messages = [];
374
- }
375
- insertToolResult(state.messages, toolResultMessage);
376
- return;
377
- }
378
- yield* routeToLLM(toolResultMessage, context);
379
- });
380
- };
@@ -1,220 +0,0 @@
1
- import { uiEvent } from "../../ui/block.js";
2
- import * as fs from "node:fs/promises";
3
- import * as path from "node:path";
4
- import { createMemoryModule } from "./memory.js";
5
- import { buildMemoryPrompt } from "./prompt.js";
6
- import { statusWidget } from "../../ui/widgets/status.js";
7
- // Re-exports
8
- export { memoryToolDefinitions } from "./types.js";
9
- export { buildMemoryPrompt } from "./prompt.js";
10
- function expandPath(p) {
11
- if (p.startsWith("~/")) {
12
- return path.join(process.env.HOME || "", p.slice(2));
13
- }
14
- return p;
15
- }
16
- const DEFAULT_AGENT_MD = `# Agent Profile
17
-
18
- You are the Manager Agent, the central orchestrator of this AI system.
19
- Your role is to analyze user intent, manage long-term memory, and coordinate specialized agents to solve complex tasks.
20
-
21
- ## Persona
22
- - Professional yet approachable
23
- - Highly organized and efficient
24
- - Focused on providing clear, actionable results
25
- `;
26
- /**
27
- * Create a prompt-builder function bound to a baseDir.
28
- * Returns the memory's portion of the system prompt (agent definition + memory).
29
- */
30
- export function createMemoryPromptBuilder(baseDir) {
31
- const expandedBase = expandPath(baseDir);
32
- const modules = {
33
- memory: createMemoryModule(expandedBase),
34
- };
35
- return async (context) => buildMemoryPrompt(expandedBase, modules, context);
36
- }
37
- // --- Plugin ---
38
- /**
39
- * Memory Plugin for Melony
40
- *
41
- * Provides the bot's "memory": agent definition and long-term memory with recall.
42
- * Skills are managed by the separate skills plugin.
43
- */
44
- export const memoryPlugin = (options) => (builder) => {
45
- const { baseDir } = options;
46
- const expandedBase = expandPath(baseDir);
47
- // Create sub-modules
48
- const memory = createMemoryModule(expandedBase);
49
- // ─── Initialization ───────────────────────────────────────────────
50
- builder.on("init", async function* (_event, _context) {
51
- yield {
52
- type: "memory:status",
53
- data: { message: "Initializing memory..." },
54
- };
55
- await fs.mkdir(expandedBase, { recursive: true, mode: 0o700 });
56
- // Initialize AGENT.md if it doesn't exist
57
- const agentPath = path.join(expandedBase, "AGENT.md");
58
- try {
59
- await fs.access(agentPath);
60
- }
61
- catch {
62
- await fs.writeFile(agentPath, DEFAULT_AGENT_MD, "utf-8");
63
- }
64
- await memory.initialize();
65
- yield {
66
- type: "memory:status",
67
- data: { message: "Memory initialized", severity: "success" },
68
- };
69
- });
70
- // ─── Memory: Remember ─────────────────────────────────────────────
71
- builder.on("action:remember", async function* (event) {
72
- const { content, tags = [], toolCallId } = event.data;
73
- try {
74
- const entry = await memory.store(content, tags);
75
- yield {
76
- type: "memory:status",
77
- data: { message: "Remembered", severity: "success" },
78
- };
79
- yield {
80
- type: "action:result",
81
- data: {
82
- action: "remember",
83
- toolCallId,
84
- result: {
85
- success: true,
86
- memoryId: entry.id,
87
- message: `Stored in memory with id ${entry.id}`,
88
- },
89
- },
90
- };
91
- }
92
- catch (error) {
93
- yield {
94
- type: "memory:status",
95
- data: {
96
- message: `Failed to remember: ${error.message}`,
97
- severity: "error",
98
- },
99
- };
100
- yield {
101
- type: "action:result",
102
- data: {
103
- action: "remember",
104
- toolCallId,
105
- result: { error: error.message },
106
- },
107
- };
108
- }
109
- });
110
- // ─── Memory: Recall ────────────────────────────────────────────────
111
- builder.on("action:recall", async function* (event) {
112
- const { query, tags, limit, toolCallId } = event.data;
113
- try {
114
- const results = await memory.recall(query, { tags, limit });
115
- yield {
116
- type: "action:result",
117
- data: {
118
- action: "recall",
119
- toolCallId,
120
- result: {
121
- count: results.length,
122
- memories: results.map((e) => ({
123
- id: e.id,
124
- content: e.content,
125
- tags: e.tags,
126
- createdAt: e.createdAt,
127
- })),
128
- },
129
- },
130
- };
131
- }
132
- catch (error) {
133
- yield {
134
- type: "action:result",
135
- data: {
136
- action: "recall",
137
- toolCallId,
138
- result: { error: error.message },
139
- },
140
- };
141
- }
142
- });
143
- // ─── Memory: Forget ────────────────────────────────────────────────
144
- builder.on("action:forget", async function* (event) {
145
- const { memoryId, toolCallId } = event.data;
146
- try {
147
- const removed = await memory.forget(memoryId);
148
- yield {
149
- type: "memory:status",
150
- data: {
151
- message: removed ? "Memory removed" : "Memory not found",
152
- severity: removed ? "success" : "error",
153
- },
154
- };
155
- yield {
156
- type: "action:result",
157
- data: {
158
- action: "forget",
159
- toolCallId,
160
- result: {
161
- success: removed,
162
- message: removed
163
- ? "Memory removed"
164
- : `Memory "${memoryId}" not found`,
165
- },
166
- },
167
- };
168
- }
169
- catch (error) {
170
- yield {
171
- type: "action:result",
172
- data: {
173
- action: "forget",
174
- toolCallId,
175
- result: { error: error.message },
176
- },
177
- };
178
- }
179
- });
180
- // ─── Memory: Journal ───────────────────────────────────────────────
181
- builder.on("action:journal", async function* (event) {
182
- const { content, toolCallId } = event.data;
183
- try {
184
- await memory.addJournalEntry(content);
185
- yield {
186
- type: "memory:status",
187
- data: { message: "Journal entry added", severity: "success" },
188
- };
189
- yield {
190
- type: "action:result",
191
- data: {
192
- action: "journal",
193
- toolCallId,
194
- result: { success: true, message: "Journal entry added" },
195
- },
196
- };
197
- }
198
- catch (error) {
199
- yield {
200
- type: "memory:status",
201
- data: {
202
- message: `Failed to journal: ${error.message}`,
203
- severity: "error",
204
- },
205
- };
206
- yield {
207
- type: "action:result",
208
- data: {
209
- action: "journal",
210
- toolCallId,
211
- result: { error: error.message },
212
- },
213
- };
214
- }
215
- });
216
- builder.on("memory:status", async function* (event) {
217
- yield uiEvent(statusWidget(event.data.message, event.data.severity));
218
- });
219
- };
220
- export default memoryPlugin;