@ouro.bot/cli 0.1.0-alpha.143 → 0.1.0-alpha.146

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.
@@ -2,8 +2,9 @@
2
2
  /**
3
3
  * Agent service layer — handles MCP-facing daemon commands.
4
4
  * Each handler receives { agent, friendId, ...params } and returns DaemonResponse.
5
- * For MVP, these read from agent state on the filesystem.
6
- * Full inference support can come later.
5
+ *
6
+ * DRY: uses the same shared functions the agent's own tools use (diary, session-recall).
7
+ * This file is a thin adapter — no reimplemented search, parsing, or state reading.
7
8
  */
8
9
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
10
  if (k2 === undefined) k2 = k;
@@ -55,413 +56,305 @@ exports.handleAgentReportComplete = handleAgentReportComplete;
55
56
  const fs = __importStar(require("fs"));
56
57
  const path = __importStar(require("path"));
57
58
  const identity_1 = require("../identity");
59
+ const diary_1 = require("../../mind/diary");
58
60
  const runtime_1 = require("../../nerves/runtime");
61
+ /** Format diary hits the same way the recall tool does. */
62
+ function formatDiaryHits(hits) {
63
+ return hits.map((f) => `[diary] ${f.text} (source=${f.source}, createdAt=${f.createdAt})`);
64
+ }
65
+ /** Read a file from the agent root, returning null if it doesn't exist. */
59
66
  function readAgentFile(agent, ...segments) {
60
67
  const filePath = path.join((0, identity_1.getAgentRoot)(agent), ...segments);
61
68
  if (!fs.existsSync(filePath))
62
69
  return null;
63
70
  return fs.readFileSync(filePath, "utf-8");
64
71
  }
65
- /** Read agent memory from multiple possible locations. */
66
- function readAgentMemory(agent) {
67
- // Try memory/MEMORY.md first, then psyche/memory/facts.jsonl
68
- return readAgentFile(agent, "memory", "MEMORY.md")
69
- ?? readAgentFile(agent, "psyche", "memory", "facts.jsonl");
72
+ /** Resolve the diary root for a specific agent. */
73
+ function agentDiaryRoot(agent) {
74
+ return (0, diary_1.resolveDiaryRoot)(path.join((0, identity_1.getAgentRoot)(agent), "psyche", "memory"));
75
+ }
76
+ /** Read inner dialog runtime status. */
77
+ function readInnerDialogStatus(agent) {
78
+ const content = readAgentFile(agent, "state", "sessions", "self", "inner", "runtime.json");
79
+ if (!content)
80
+ return null;
81
+ try {
82
+ const data = JSON.parse(content);
83
+ return { status: data.status ?? "unknown", lastCompletedAt: data.lastCompletedAt ?? "" };
84
+ }
85
+ catch {
86
+ return null;
87
+ }
88
+ }
89
+ function safeReaddir(dirPath) {
90
+ try {
91
+ return fs.readdirSync(dirPath).map(String);
92
+ /* v8 ignore start — catch is defensive; tested paths don't trigger fs errors */
93
+ }
94
+ catch {
95
+ return [];
96
+ }
97
+ /* v8 ignore stop */
98
+ }
99
+ function safeIsDir(dirPath) {
100
+ try {
101
+ return fs.statSync(dirPath).isDirectory();
102
+ /* v8 ignore start — catch is defensive; tested paths don't trigger fs errors */
103
+ }
104
+ catch {
105
+ return false;
106
+ }
107
+ /* v8 ignore stop */
70
108
  }
71
- function listStateFiles(agent, ...segments) {
72
- const dirPath = path.join((0, identity_1.getAgentStateRoot)(agent), ...segments);
73
- if (!fs.existsSync(dirPath))
109
+ /** Enumerate sessions from state/sessions/, reading session.json files. */
110
+ function enumerateSessions(agent) {
111
+ const sessionsDir = path.join((0, identity_1.getAgentRoot)(agent), "state", "sessions");
112
+ if (!fs.existsSync(sessionsDir))
74
113
  return [];
75
- return fs.readdirSync(dirPath).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl") || f.endsWith(".md"));
114
+ const sessions = [];
115
+ for (const friendId of safeReaddir(sessionsDir)) {
116
+ const friendPath = path.join(sessionsDir, friendId);
117
+ if (!safeIsDir(friendPath))
118
+ continue;
119
+ for (const channel of safeReaddir(friendPath)) {
120
+ const channelPath = path.join(friendPath, channel);
121
+ if (!safeIsDir(channelPath))
122
+ continue;
123
+ for (const key of safeReaddir(channelPath)) {
124
+ const sessionFile = path.join(channelPath, key, "session.json");
125
+ if (!fs.existsSync(sessionFile))
126
+ continue;
127
+ try {
128
+ const data = JSON.parse(fs.readFileSync(sessionFile, "utf-8"));
129
+ sessions.push({ friendId, channel, key, lastUsage: data.lastUsage ?? "" });
130
+ }
131
+ catch { /* skip malformed */ }
132
+ }
133
+ }
134
+ }
135
+ return sessions;
76
136
  }
137
+ /** List markdown files in {agentRoot}/tasks/. */
138
+ function listTaskFiles(agent) {
139
+ const tasksDir = path.join((0, identity_1.getAgentRoot)(agent), "tasks");
140
+ if (!fs.existsSync(tasksDir))
141
+ return [];
142
+ try {
143
+ return fs.readdirSync(tasksDir).map(String).filter((f) => f.endsWith(".md"));
144
+ }
145
+ catch {
146
+ return [];
147
+ }
148
+ }
149
+ function emit(event, message, meta) {
150
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event, message, meta });
151
+ }
152
+ // ─── Handlers ────────────────────────────────────────────────────────────────
77
153
  async function handleAgentStatus(params) {
78
- (0, runtime_1.emitNervesEvent)({
79
- component: "daemon",
80
- event: "daemon.agent_service_start",
81
- message: "handling agent.status",
82
- meta: { agent: params.agent, friendId: params.friendId },
83
- });
84
- const sessionFiles = listStateFiles(params.agent, "sessions");
85
- const memoryContent = readAgentMemory(params.agent);
86
- (0, runtime_1.emitNervesEvent)({
87
- component: "daemon",
88
- event: "daemon.agent_service_end",
89
- message: "completed agent.status",
90
- meta: { agent: params.agent },
91
- });
154
+ (0, runtime_1.emitNervesEvent)({ component: "daemon", event: "daemon.agent_service_start", message: "handling agent.status", meta: { agent: params.agent } });
155
+ const diaryRoot = agentDiaryRoot(params.agent);
156
+ const facts = (0, diary_1.readDiaryEntries)(diaryRoot);
157
+ const innerStatus = readInnerDialogStatus(params.agent);
158
+ const sessions = enumerateSessions(params.agent);
159
+ emit("daemon.agent_service_end", "completed agent.status", { agent: params.agent });
92
160
  return {
93
161
  ok: true,
94
162
  message: `Agent ${params.agent} status`,
95
163
  data: {
96
164
  agent: params.agent,
97
- status: "active",
98
- sessionCount: sessionFiles.length,
99
- hasMemory: memoryContent !== null,
165
+ innerStatus: innerStatus?.status ?? "unknown",
166
+ lastThoughtAt: innerStatus?.lastCompletedAt ?? null,
167
+ sessionCount: sessions.length,
168
+ hasMemory: facts.length > 0,
169
+ factCount: facts.length,
100
170
  },
101
171
  };
102
172
  }
103
173
  async function handleAgentAsk(params) {
104
- (0, runtime_1.emitNervesEvent)({
105
- component: "daemon",
106
- event: "daemon.agent_service_start",
107
- message: "handling agent.ask",
108
- meta: { agent: params.agent, friendId: params.friendId },
109
- });
174
+ emit("daemon.agent_service_start", "handling agent.ask", { agent: params.agent });
110
175
  const question = params.question;
111
176
  if (!question) {
112
- (0, runtime_1.emitNervesEvent)({
113
- level: "error",
114
- component: "daemon",
115
- event: "daemon.agent_service_error",
116
- message: "agent.ask missing question parameter",
117
- meta: { agent: params.agent },
118
- });
177
+ emit("daemon.agent_service_error", "agent.ask missing question", { agent: params.agent });
119
178
  return { ok: false, error: "Missing required parameter: question" };
120
179
  }
121
- // MVP: return memory + recent session context without running inference
122
- const memoryContent = readAgentMemory(params.agent);
123
- const context = memoryContent
124
- ? `Based on agent memory:\n${memoryContent.slice(0, 2000)}`
125
- : `Agent ${params.agent} has no memory file. Question was: ${question}`;
126
- (0, runtime_1.emitNervesEvent)({
127
- component: "daemon",
128
- event: "daemon.agent_service_end",
129
- message: "completed agent.ask",
130
- meta: { agent: params.agent },
131
- });
180
+ // Use the same searchDiaryEntries the recall tool uses (substring fallback — no embedding provider in shim)
181
+ const diaryRoot = agentDiaryRoot(params.agent);
182
+ const hits = await (0, diary_1.searchDiaryEntries)(question, (0, diary_1.readDiaryEntries)(diaryRoot));
183
+ const context = hits.length > 0
184
+ ? hits.slice(0, 10).map((f) => f.text).join("\n")
185
+ : `No relevant memories found for: ${question}`;
186
+ emit("daemon.agent_service_end", "completed agent.ask", { agent: params.agent });
132
187
  return { ok: true, message: context };
133
188
  }
134
189
  async function handleAgentCatchup(params) {
135
- (0, runtime_1.emitNervesEvent)({
136
- component: "daemon",
137
- event: "daemon.agent_service_start",
138
- message: "handling agent.catchup",
139
- meta: { agent: params.agent, friendId: params.friendId },
140
- });
141
- const sessionFiles = listStateFiles(params.agent, "sessions");
142
- const recentSessions = sessionFiles.slice(-5);
143
- (0, runtime_1.emitNervesEvent)({
144
- component: "daemon",
145
- event: "daemon.agent_service_end",
146
- message: "completed agent.catchup",
147
- meta: { agent: params.agent },
148
- });
190
+ emit("daemon.agent_service_start", "handling agent.catchup", { agent: params.agent });
191
+ const sessions = enumerateSessions(params.agent);
192
+ const sorted = sessions.sort((a, b) => (b.lastUsage || "").localeCompare(a.lastUsage || ""));
193
+ const recentSessions = sorted.slice(0, 5);
194
+ const innerStatus = readInnerDialogStatus(params.agent);
195
+ const parts = [];
196
+ if (innerStatus) {
197
+ parts.push(`Inner dialog: ${innerStatus.status} (last completed: ${innerStatus.lastCompletedAt || "never"})`);
198
+ }
199
+ if (recentSessions.length > 0) {
200
+ parts.push(`Recent sessions (${recentSessions.length}):`);
201
+ for (const s of recentSessions) {
202
+ parts.push(` - ${s.friendId}/${s.channel}/${s.key} (${s.lastUsage || "unknown"})`);
203
+ }
204
+ }
205
+ else {
206
+ parts.push("No recent sessions");
207
+ }
208
+ emit("daemon.agent_service_end", "completed agent.catchup", { agent: params.agent });
149
209
  return {
150
210
  ok: true,
151
- message: recentSessions.length > 0
152
- ? `Recent activity: ${recentSessions.length} recent sessions found`
153
- : `No recent activity for ${params.agent}`,
154
- data: { recentSessions },
211
+ /* v8 ignore next — parts always has at least one element (either sessions or "No recent sessions") */
212
+ message: parts.length > 0 ? parts.join("\n") : `No recent activity for ${params.agent}`,
213
+ data: { recentSessions, innerStatus },
155
214
  };
156
215
  }
157
216
  async function handleAgentDelegate(params) {
158
- (0, runtime_1.emitNervesEvent)({
159
- component: "daemon",
160
- event: "daemon.agent_service_start",
161
- message: "handling agent.delegate",
162
- meta: { agent: params.agent, friendId: params.friendId },
163
- });
217
+ emit("daemon.agent_service_start", "handling agent.delegate", { agent: params.agent });
164
218
  const task = params.task;
165
219
  if (!task) {
166
- (0, runtime_1.emitNervesEvent)({
167
- level: "error",
168
- component: "daemon",
169
- event: "daemon.agent_service_error",
170
- message: "agent.delegate missing task parameter",
171
- meta: { agent: params.agent },
172
- });
220
+ emit("daemon.agent_service_error", "agent.delegate missing task", { agent: params.agent });
173
221
  return { ok: false, error: "Missing required parameter: task" };
174
222
  }
175
- (0, runtime_1.emitNervesEvent)({
176
- component: "daemon",
177
- event: "daemon.agent_service_end",
178
- message: "completed agent.delegate",
179
- meta: { agent: params.agent },
180
- });
181
- return {
182
- ok: true,
183
- message: `Task queued for delegate to ${params.agent}: ${task}`,
184
- data: { task, context: params.context ?? null, queuedAt: new Date().toISOString() },
185
- };
223
+ emit("daemon.agent_service_end", "completed agent.delegate", { agent: params.agent });
224
+ return { ok: true, message: `Task queued: ${task}`, data: { task, context: params.context ?? null, queuedAt: new Date().toISOString() } };
186
225
  }
187
226
  async function handleAgentGetContext(params) {
188
- (0, runtime_1.emitNervesEvent)({
189
- component: "daemon",
190
- event: "daemon.agent_service_start",
191
- message: "handling agent.getContext",
192
- meta: { agent: params.agent, friendId: params.friendId },
193
- });
194
- const memoryContent = readAgentMemory(params.agent);
195
- const taskFiles = listStateFiles(params.agent, "tasks");
196
- (0, runtime_1.emitNervesEvent)({
197
- component: "daemon",
198
- event: "daemon.agent_service_end",
199
- message: "completed agent.getContext",
200
- meta: { agent: params.agent },
201
- });
227
+ emit("daemon.agent_service_start", "handling agent.getContext", { agent: params.agent });
228
+ const query = (params.question ?? params.query ?? params.topic);
229
+ const diaryRoot = agentDiaryRoot(params.agent);
230
+ const facts = (0, diary_1.readDiaryEntries)(diaryRoot);
231
+ const innerStatus = readInnerDialogStatus(params.agent);
232
+ const sessions = enumerateSessions(params.agent);
233
+ const taskFiles = listTaskFiles(params.agent);
234
+ let memorySummary = null;
235
+ if (query) {
236
+ const hits = await (0, diary_1.searchDiaryEntries)(query, facts);
237
+ memorySummary = hits.length > 0
238
+ ? hits.slice(0, 10).map((f) => f.text).join("\n")
239
+ : `No relevant memories for: ${query}`;
240
+ }
241
+ else {
242
+ const recent = facts.slice(-10);
243
+ if (recent.length > 0)
244
+ memorySummary = recent.map((f) => f.text).join("\n");
245
+ }
246
+ emit("daemon.agent_service_end", "completed agent.getContext", { agent: params.agent });
202
247
  return {
203
248
  ok: true,
204
249
  data: {
205
250
  agent: params.agent,
206
- hasMemory: memoryContent !== null,
207
- memorySummary: memoryContent ? memoryContent.slice(0, 500) : null,
251
+ hasMemory: facts.length > 0,
252
+ factCount: facts.length,
253
+ memorySummary,
208
254
  taskCount: taskFiles.length,
255
+ sessionCount: sessions.length,
256
+ innerStatus: innerStatus?.status ?? null,
209
257
  },
210
258
  };
211
259
  }
212
260
  async function handleAgentSearchMemory(params) {
213
- (0, runtime_1.emitNervesEvent)({
214
- component: "daemon",
215
- event: "daemon.agent_service_start",
216
- message: "handling agent.searchMemory",
217
- meta: { agent: params.agent, friendId: params.friendId },
218
- });
261
+ emit("daemon.agent_service_start", "handling agent.searchMemory", { agent: params.agent });
219
262
  const query = params.query;
220
263
  if (!query) {
221
- (0, runtime_1.emitNervesEvent)({
222
- level: "error",
223
- component: "daemon",
224
- event: "daemon.agent_service_error",
225
- message: "agent.searchMemory missing query parameter",
226
- meta: { agent: params.agent },
227
- });
264
+ emit("daemon.agent_service_error", "agent.searchMemory missing query", { agent: params.agent });
228
265
  return { ok: false, error: "Missing required parameter: query" };
229
266
  }
230
- // MVP: simple substring search in memory file
231
- const memoryContent = readAgentMemory(params.agent);
232
- const matches = [];
233
- if (memoryContent) {
234
- const lines = memoryContent.split("\n");
235
- const queryLower = query.toLowerCase();
236
- for (const line of lines) {
237
- if (line.toLowerCase().includes(queryLower)) {
238
- matches.push(line.trim());
239
- }
240
- }
241
- }
242
- (0, runtime_1.emitNervesEvent)({
243
- component: "daemon",
244
- event: "daemon.agent_service_end",
245
- message: "completed agent.searchMemory",
246
- meta: { agent: params.agent, matchCount: matches.length },
247
- });
267
+ // Same searchDiaryEntries as the recall tool
268
+ const diaryRoot = agentDiaryRoot(params.agent);
269
+ const hits = await (0, diary_1.searchDiaryEntries)(query, (0, diary_1.readDiaryEntries)(diaryRoot));
270
+ const formatted = formatDiaryHits(hits.slice(0, 20));
271
+ emit("daemon.agent_service_end", "completed agent.searchMemory", { agent: params.agent, matchCount: hits.length });
248
272
  return {
249
273
  ok: true,
250
- message: matches.length > 0 ? `Found ${matches.length} matches` : "No matches found",
251
- data: { query, matches: matches.slice(0, 20) },
274
+ message: hits.length > 0 ? `Found ${hits.length} matches` : "No matches found",
275
+ data: { query, matches: formatted },
252
276
  };
253
277
  }
254
278
  async function handleAgentGetTask(params) {
255
- (0, runtime_1.emitNervesEvent)({
256
- component: "daemon",
257
- event: "daemon.agent_service_start",
258
- message: "handling agent.getTask",
259
- meta: { agent: params.agent, friendId: params.friendId },
260
- });
261
- const taskFiles = listStateFiles(params.agent, "tasks");
262
- (0, runtime_1.emitNervesEvent)({
263
- component: "daemon",
264
- event: "daemon.agent_service_end",
265
- message: "completed agent.getTask",
266
- meta: { agent: params.agent },
279
+ emit("daemon.agent_service_start", "handling agent.getTask", { agent: params.agent });
280
+ const taskFiles = listTaskFiles(params.agent);
281
+ const activeTasks = taskFiles.filter((f) => f.toLowerCase().includes("doing") && !f.toLowerCase().includes("done"));
282
+ const taskNames = activeTasks.length > 0 ? activeTasks : taskFiles;
283
+ const tasks = taskNames.map((name) => {
284
+ const content = readAgentFile(params.agent, "tasks", name);
285
+ const firstLine = content?.split("\n").find((l) => l.trim().length > 0)?.trim() ?? "";
286
+ return { name, statusLine: firstLine };
267
287
  });
288
+ emit("daemon.agent_service_end", "completed agent.getTask", { agent: params.agent });
268
289
  return {
269
290
  ok: true,
270
- message: taskFiles.length > 0
271
- ? `Current tasks: ${taskFiles.join(", ")}`
272
- : `No active tasks for ${params.agent}`,
273
- data: { tasks: taskFiles },
291
+ message: tasks.length > 0 ? `Tasks (${tasks.length}): ${tasks.map((t) => t.name).join(", ")}` : `No active tasks for ${params.agent}`,
292
+ data: { tasks, activeCount: activeTasks.length, totalCount: taskFiles.length },
274
293
  };
275
294
  }
276
295
  async function handleAgentCheckScope(params) {
277
- (0, runtime_1.emitNervesEvent)({
278
- component: "daemon",
279
- event: "daemon.agent_service_start",
280
- message: "handling agent.checkScope",
281
- meta: { agent: params.agent, friendId: params.friendId },
282
- });
296
+ emit("daemon.agent_service_start", "handling agent.checkScope", { agent: params.agent });
283
297
  const item = params.item;
284
298
  if (!item) {
285
- (0, runtime_1.emitNervesEvent)({
286
- level: "error",
287
- component: "daemon",
288
- event: "daemon.agent_service_error",
289
- message: "agent.checkScope missing item parameter",
290
- meta: { agent: params.agent },
291
- });
299
+ emit("daemon.agent_service_error", "agent.checkScope missing item", { agent: params.agent });
292
300
  return { ok: false, error: "Missing required parameter: item" };
293
301
  }
294
- (0, runtime_1.emitNervesEvent)({
295
- component: "daemon",
296
- event: "daemon.agent_service_end",
297
- message: "completed agent.checkScope",
298
- meta: { agent: params.agent },
299
- });
300
- return {
301
- ok: true,
302
- message: `Scope check for: ${item}`,
303
- data: { item, inScope: true, reason: "MVP: scope check requires inference — defaulting to in-scope" },
304
- };
302
+ emit("daemon.agent_service_end", "completed agent.checkScope", { agent: params.agent });
303
+ return { ok: true, message: `Scope check for: ${item}`, data: { item, inScope: true, reason: "MVP: scope check requires inference — defaulting to in-scope" } };
305
304
  }
306
305
  async function handleAgentRequestDecision(params) {
307
- (0, runtime_1.emitNervesEvent)({
308
- component: "daemon",
309
- event: "daemon.agent_service_start",
310
- message: "handling agent.requestDecision",
311
- meta: { agent: params.agent, friendId: params.friendId },
312
- });
306
+ emit("daemon.agent_service_start", "handling agent.requestDecision", { agent: params.agent });
313
307
  const topic = params.topic;
314
308
  if (!topic) {
315
- (0, runtime_1.emitNervesEvent)({
316
- level: "error",
317
- component: "daemon",
318
- event: "daemon.agent_service_error",
319
- message: "agent.requestDecision missing topic parameter",
320
- meta: { agent: params.agent },
321
- });
309
+ emit("daemon.agent_service_error", "agent.requestDecision missing topic", { agent: params.agent });
322
310
  return { ok: false, error: "Missing required parameter: topic" };
323
311
  }
324
- (0, runtime_1.emitNervesEvent)({
325
- component: "daemon",
326
- event: "daemon.agent_service_end",
327
- message: "completed agent.requestDecision",
328
- meta: { agent: params.agent },
329
- });
330
- return {
331
- ok: true,
332
- message: `Decision request queued: ${topic}`,
333
- data: {
334
- topic,
335
- options: params.options ?? null,
336
- status: "pending",
337
- note: "MVP: decision requires inference — queued for agent review",
338
- },
339
- };
312
+ emit("daemon.agent_service_end", "completed agent.requestDecision", { agent: params.agent });
313
+ return { ok: true, message: `Decision request queued: ${topic}`, data: { topic, options: params.options ?? null, status: "pending" } };
340
314
  }
341
315
  async function handleAgentCheckGuidance(params) {
342
- (0, runtime_1.emitNervesEvent)({
343
- component: "daemon",
344
- event: "daemon.agent_service_start",
345
- message: "handling agent.checkGuidance",
346
- meta: { agent: params.agent, friendId: params.friendId },
347
- });
316
+ emit("daemon.agent_service_start", "handling agent.checkGuidance", { agent: params.agent });
348
317
  const topic = params.topic;
349
318
  if (!topic) {
350
- (0, runtime_1.emitNervesEvent)({
351
- level: "error",
352
- component: "daemon",
353
- event: "daemon.agent_service_error",
354
- message: "agent.checkGuidance missing topic parameter",
355
- meta: { agent: params.agent },
356
- });
319
+ emit("daemon.agent_service_error", "agent.checkGuidance missing topic", { agent: params.agent });
357
320
  return { ok: false, error: "Missing required parameter: topic" };
358
321
  }
359
- // MVP: check memory for relevant guidance
360
- const memoryContent = readAgentMemory(params.agent);
361
- let guidance = `No specific guidance found for: ${topic}`;
362
- if (memoryContent) {
363
- const lines = memoryContent.split("\n");
364
- const topicLower = topic.toLowerCase();
365
- const relevant = lines.filter((line) => line.toLowerCase().includes(topicLower));
366
- if (relevant.length > 0) {
367
- guidance = `Relevant guidance:\n${relevant.slice(0, 10).join("\n")}`;
368
- }
369
- }
370
- (0, runtime_1.emitNervesEvent)({
371
- component: "daemon",
372
- event: "daemon.agent_service_end",
373
- message: "completed agent.checkGuidance",
374
- meta: { agent: params.agent },
375
- });
322
+ // Same searchDiaryEntries as the recall tool
323
+ const diaryRoot = agentDiaryRoot(params.agent);
324
+ const hits = await (0, diary_1.searchDiaryEntries)(topic, (0, diary_1.readDiaryEntries)(diaryRoot));
325
+ const guidance = hits.length > 0
326
+ ? `Relevant guidance:\n${hits.slice(0, 10).map((f) => f.text).join("\n")}`
327
+ : `No specific guidance found for: ${topic}`;
328
+ emit("daemon.agent_service_end", "completed agent.checkGuidance", { agent: params.agent });
376
329
  return { ok: true, message: guidance };
377
330
  }
378
331
  async function handleAgentReportProgress(params) {
379
- (0, runtime_1.emitNervesEvent)({
380
- component: "daemon",
381
- event: "daemon.agent_service_start",
382
- message: "handling agent.reportProgress",
383
- meta: { agent: params.agent, friendId: params.friendId },
384
- });
332
+ emit("daemon.agent_service_start", "handling agent.reportProgress", { agent: params.agent });
385
333
  const summary = params.summary;
386
334
  if (!summary) {
387
- (0, runtime_1.emitNervesEvent)({
388
- level: "error",
389
- component: "daemon",
390
- event: "daemon.agent_service_error",
391
- message: "agent.reportProgress missing summary parameter",
392
- meta: { agent: params.agent },
393
- });
335
+ emit("daemon.agent_service_error", "agent.reportProgress missing summary", { agent: params.agent });
394
336
  return { ok: false, error: "Missing required parameter: summary" };
395
337
  }
396
- (0, runtime_1.emitNervesEvent)({
397
- component: "daemon",
398
- event: "daemon.agent_service_end",
399
- message: "completed agent.reportProgress",
400
- meta: { agent: params.agent },
401
- });
402
- return {
403
- ok: true,
404
- message: `Progress noted: ${summary}`,
405
- data: { summary, receivedAt: new Date().toISOString() },
406
- };
338
+ emit("daemon.agent_service_end", "completed agent.reportProgress", { agent: params.agent });
339
+ return { ok: true, message: `Progress noted: ${summary}`, data: { summary, receivedAt: new Date().toISOString() } };
407
340
  }
408
341
  async function handleAgentReportBlocker(params) {
409
- (0, runtime_1.emitNervesEvent)({
410
- component: "daemon",
411
- event: "daemon.agent_service_start",
412
- message: "handling agent.reportBlocker",
413
- meta: { agent: params.agent, friendId: params.friendId },
414
- });
342
+ emit("daemon.agent_service_start", "handling agent.reportBlocker", { agent: params.agent });
415
343
  const blocker = params.blocker;
416
344
  if (!blocker) {
417
- (0, runtime_1.emitNervesEvent)({
418
- level: "error",
419
- component: "daemon",
420
- event: "daemon.agent_service_error",
421
- message: "agent.reportBlocker missing blocker parameter",
422
- meta: { agent: params.agent },
423
- });
345
+ emit("daemon.agent_service_error", "agent.reportBlocker missing blocker", { agent: params.agent });
424
346
  return { ok: false, error: "Missing required parameter: blocker" };
425
347
  }
426
- (0, runtime_1.emitNervesEvent)({
427
- component: "daemon",
428
- event: "daemon.agent_service_end",
429
- message: "completed agent.reportBlocker",
430
- meta: { agent: params.agent },
431
- });
432
- return {
433
- ok: true,
434
- message: `Blocker reported: ${blocker}`,
435
- data: { blocker, receivedAt: new Date().toISOString() },
436
- };
348
+ emit("daemon.agent_service_end", "completed agent.reportBlocker", { agent: params.agent });
349
+ return { ok: true, message: `Blocker reported: ${blocker}`, data: { blocker, receivedAt: new Date().toISOString() } };
437
350
  }
438
351
  async function handleAgentReportComplete(params) {
439
- (0, runtime_1.emitNervesEvent)({
440
- component: "daemon",
441
- event: "daemon.agent_service_start",
442
- message: "handling agent.reportComplete",
443
- meta: { agent: params.agent, friendId: params.friendId },
444
- });
352
+ emit("daemon.agent_service_start", "handling agent.reportComplete", { agent: params.agent });
445
353
  const summary = params.summary;
446
354
  if (!summary) {
447
- (0, runtime_1.emitNervesEvent)({
448
- level: "error",
449
- component: "daemon",
450
- event: "daemon.agent_service_error",
451
- message: "agent.reportComplete missing summary parameter",
452
- meta: { agent: params.agent },
453
- });
355
+ emit("daemon.agent_service_error", "agent.reportComplete missing summary", { agent: params.agent });
454
356
  return { ok: false, error: "Missing required parameter: summary" };
455
357
  }
456
- (0, runtime_1.emitNervesEvent)({
457
- component: "daemon",
458
- event: "daemon.agent_service_end",
459
- message: "completed agent.reportComplete",
460
- meta: { agent: params.agent },
461
- });
462
- return {
463
- ok: true,
464
- message: `Completion reported: ${summary}`,
465
- data: { summary, receivedAt: new Date().toISOString() },
466
- };
358
+ emit("daemon.agent_service_end", "completed agent.reportComplete", { agent: params.agent });
359
+ return { ok: true, message: `Completion reported: ${summary}`, data: { summary, receivedAt: new Date().toISOString() } };
467
360
  }