@ouro.bot/cli 0.1.0-alpha.341 → 0.1.0-alpha.343
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 +5 -5
- package/SerpentGuide.ouro/psyche/identities/the-serpent.md +1 -1
- package/changelog.json +13 -0
- package/dist/heart/attachments/sources/bluebubbles.js +1 -1
- package/dist/heart/attachments/store.js +2 -2
- package/dist/heart/bundle-state.js +1 -1
- package/dist/heart/config-registry.js +2 -2
- package/dist/heart/core.js +10 -2
- package/dist/heart/daemon/agent-service.js +18 -18
- package/dist/heart/daemon/daemon-tombstone.js +1 -1
- package/dist/heart/daemon/daemon.js +2 -2
- package/dist/heart/daemon/hooks/bundle-meta.js +4 -4
- package/dist/heart/hatch/hatch-flow.js +1 -1
- package/dist/heart/hatch/specialist-prompt.js +1 -1
- package/dist/heart/hatch/specialist-tools.js +7 -7
- package/dist/heart/kept-notes.js +357 -0
- package/dist/heart/mcp/mcp-server.js +10 -10
- package/dist/heart/outlook/outlook-http-hooks.js +2 -2
- package/dist/heart/outlook/outlook-http-routes.js +4 -4
- package/dist/heart/outlook/outlook-read.js +3 -3
- package/dist/heart/outlook/readers/continuity-readers.js +3 -3
- package/dist/heart/outlook/readers/runtime-readers.js +2 -2
- package/dist/heart/session-events.js +3 -2
- package/dist/heart/{session-recall.js → session-transcript.js} +4 -4
- package/dist/heart/target-resolution.js +5 -5
- package/dist/heart/tool-description.js +4 -4
- package/dist/mind/diary.js +3 -3
- package/dist/mind/embedding-provider.js +1 -1
- package/dist/mind/file-state.js +1 -1
- package/dist/mind/friends/resolver.js +1 -1
- package/dist/mind/friends/types.js +1 -1
- package/dist/mind/{associative-recall.js → note-search.js} +17 -17
- package/dist/mind/prompt.js +12 -12
- package/dist/nerves/coverage/audit-rules.js +15 -6
- package/dist/nerves/coverage/audit.js +27 -1
- package/dist/nerves/coverage/cli.js +1 -1
- package/dist/nerves/coverage/file-completeness.js +2 -2
- package/dist/outlook-ui/assets/{index-DC7sZefn.js → index-xTdv64BV.js} +2 -2
- package/dist/outlook-ui/index.html +1 -1
- package/dist/repertoire/bitwarden-store.js +1 -1
- package/dist/repertoire/bundle-templates.js +1 -1
- package/dist/repertoire/skills.js +1 -1
- package/dist/repertoire/tools-base.js +3 -3
- package/dist/repertoire/tools-bridge.js +9 -9
- package/dist/repertoire/tools-continuity.js +2 -2
- package/dist/repertoire/{tools-memory.js → tools-notes.js} +6 -6
- package/dist/repertoire/tools-session.js +12 -12
- package/dist/senses/bluebubbles/attachment-cache.js +3 -3
- package/dist/senses/bluebubbles/index.js +1 -1
- package/dist/senses/bluebubbles/media.js +1 -1
- package/dist/senses/cli/image-paste.js +4 -4
- package/dist/senses/inner-dialog.js +2 -2
- package/dist/senses/surface-tool.js +1 -1
- package/package.json +1 -1
- package/skills/agent-commerce.md +1 -1
- package/skills/configure-dev-tools.md +2 -2
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.gatherKeptNotesCandidates = gatherKeptNotesCandidates;
|
|
37
|
+
exports.renderKeptNotesOutcome = renderKeptNotesOutcome;
|
|
38
|
+
exports.injectKeptNotes = injectKeptNotes;
|
|
39
|
+
exports.createKeptNotesJudge = createKeptNotesJudge;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const diary_1 = require("../mind/diary");
|
|
43
|
+
const runtime_1 = require("../nerves/runtime");
|
|
44
|
+
const DEFAULT_TIMEOUT_MS = 2500;
|
|
45
|
+
const MAX_CANDIDATES = 8;
|
|
46
|
+
const NOOP_CALLBACKS = {
|
|
47
|
+
onModelStart() { },
|
|
48
|
+
onModelStreamStart() { },
|
|
49
|
+
onTextChunk() { },
|
|
50
|
+
onReasoningChunk() { },
|
|
51
|
+
onToolStart() { },
|
|
52
|
+
onToolEnd() { },
|
|
53
|
+
onError() { },
|
|
54
|
+
};
|
|
55
|
+
function elapsedSince(startedAt) {
|
|
56
|
+
return Math.max(0, Date.now() - startedAt);
|
|
57
|
+
}
|
|
58
|
+
function latestUserText(messages) {
|
|
59
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
60
|
+
const message = messages[i];
|
|
61
|
+
if (message.role !== "user" || typeof message.content !== "string")
|
|
62
|
+
continue;
|
|
63
|
+
const text = message.content.trim();
|
|
64
|
+
if (text)
|
|
65
|
+
return text;
|
|
66
|
+
}
|
|
67
|
+
return "";
|
|
68
|
+
}
|
|
69
|
+
function tokenize(text) {
|
|
70
|
+
return new Set(text
|
|
71
|
+
.toLowerCase()
|
|
72
|
+
.split(/[^a-z0-9]+/g)
|
|
73
|
+
.map((token) => token.trim())
|
|
74
|
+
.filter((token) => token.length > 2));
|
|
75
|
+
}
|
|
76
|
+
function scoreText(queryTerms, text) {
|
|
77
|
+
const textTerms = tokenize(text);
|
|
78
|
+
let matches = 0;
|
|
79
|
+
for (const term of queryTerms) {
|
|
80
|
+
if (textTerms.has(term))
|
|
81
|
+
matches += 1;
|
|
82
|
+
}
|
|
83
|
+
return matches / queryTerms.size;
|
|
84
|
+
}
|
|
85
|
+
function readJournalIndex(journalDir) {
|
|
86
|
+
try {
|
|
87
|
+
const parsed = JSON.parse(fs.readFileSync(path.join(journalDir, ".index.json"), "utf8"));
|
|
88
|
+
if (!Array.isArray(parsed))
|
|
89
|
+
return [];
|
|
90
|
+
return parsed
|
|
91
|
+
.filter((entry) => (typeof entry === "object" &&
|
|
92
|
+
entry !== null &&
|
|
93
|
+
typeof entry.filename === "string" &&
|
|
94
|
+
typeof entry.preview === "string"));
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function journalDirForDiaryRoot(diaryRoot, explicitJournalDir) {
|
|
101
|
+
if (explicitJournalDir)
|
|
102
|
+
return explicitJournalDir;
|
|
103
|
+
return path.join(path.dirname(diaryRoot), "journal");
|
|
104
|
+
}
|
|
105
|
+
function diaryCandidate(fact) {
|
|
106
|
+
return {
|
|
107
|
+
text: fact.text,
|
|
108
|
+
source: { kind: "diary", label: "diary", ref: fact.id },
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function friendNoteCandidates(friend, queryTerms) {
|
|
112
|
+
if (!friend)
|
|
113
|
+
return [];
|
|
114
|
+
return Object.entries(friend.notes ?? {})
|
|
115
|
+
.map(([key, note]) => {
|
|
116
|
+
const text = `${friend.name} / ${key}: ${note.value}`;
|
|
117
|
+
return {
|
|
118
|
+
candidate: {
|
|
119
|
+
text,
|
|
120
|
+
source: { kind: "friend-note", label: `friend note: ${friend.name}`, ref: key },
|
|
121
|
+
},
|
|
122
|
+
score: scoreText(queryTerms, `${key} ${note.value}`),
|
|
123
|
+
};
|
|
124
|
+
})
|
|
125
|
+
.filter((entry) => entry.score > 0);
|
|
126
|
+
}
|
|
127
|
+
function gatherKeptNotesCandidates(query, options = {}) {
|
|
128
|
+
const queryTerms = tokenize(query);
|
|
129
|
+
if (queryTerms.size === 0)
|
|
130
|
+
return [];
|
|
131
|
+
const diaryRoot = (0, diary_1.resolveDiaryRoot)(options.diaryRoot);
|
|
132
|
+
const diaryEntries = (0, diary_1.readDiaryEntries)(diaryRoot);
|
|
133
|
+
const diaryCandidates = diaryEntries
|
|
134
|
+
.map((fact) => ({ candidate: diaryCandidate(fact), score: scoreText(queryTerms, fact.text) }))
|
|
135
|
+
.filter((entry) => entry.score > 0);
|
|
136
|
+
const journalDir = journalDirForDiaryRoot(diaryRoot, options.journalDir);
|
|
137
|
+
const journalCandidates = readJournalIndex(journalDir)
|
|
138
|
+
.map((entry) => ({
|
|
139
|
+
candidate: {
|
|
140
|
+
text: `${entry.filename}: ${entry.preview}`,
|
|
141
|
+
source: { kind: "journal", label: "journal", ref: entry.filename },
|
|
142
|
+
},
|
|
143
|
+
score: scoreText(queryTerms, `${entry.filename} ${entry.preview}`),
|
|
144
|
+
}))
|
|
145
|
+
.filter((entry) => entry.score > 0);
|
|
146
|
+
return [...diaryCandidates, ...journalCandidates, ...friendNoteCandidates(options.friend, queryTerms)]
|
|
147
|
+
.sort((left, right) => right.score - left.score)
|
|
148
|
+
.slice(0, MAX_CANDIDATES)
|
|
149
|
+
.map((entry) => entry.candidate);
|
|
150
|
+
}
|
|
151
|
+
function selectedSources(candidates, indexes) {
|
|
152
|
+
if (!indexes || indexes.length === 0)
|
|
153
|
+
return [];
|
|
154
|
+
const sources = [];
|
|
155
|
+
for (const index of indexes) {
|
|
156
|
+
if (!Number.isInteger(index))
|
|
157
|
+
continue;
|
|
158
|
+
const candidate = candidates[index];
|
|
159
|
+
if (candidate)
|
|
160
|
+
sources.push(candidate.source);
|
|
161
|
+
}
|
|
162
|
+
return sources;
|
|
163
|
+
}
|
|
164
|
+
function isFirstPerson(text) {
|
|
165
|
+
return /^(i|i'm|i’ve|i've|my|me)\b/i.test(text.trim());
|
|
166
|
+
}
|
|
167
|
+
function foundLine(text) {
|
|
168
|
+
const trimmed = text.trim();
|
|
169
|
+
if (isFirstPerson(trimmed))
|
|
170
|
+
return trimmed;
|
|
171
|
+
return `I kept this: ${trimmed}`;
|
|
172
|
+
}
|
|
173
|
+
function fuzzyLine(text) {
|
|
174
|
+
const trimmed = text.trim();
|
|
175
|
+
if (isFirstPerson(trimmed))
|
|
176
|
+
return trimmed;
|
|
177
|
+
return `I may have kept something related: ${trimmed}`;
|
|
178
|
+
}
|
|
179
|
+
const SOURCE_KIND_ORDER = ["diary", "journal", "friend-note"];
|
|
180
|
+
const SOURCE_KIND_LABELS = {
|
|
181
|
+
diary: "my diary",
|
|
182
|
+
journal: "my journal",
|
|
183
|
+
"friend-note": "my friend notes",
|
|
184
|
+
};
|
|
185
|
+
function joinLabels(labels) {
|
|
186
|
+
if (labels.length === 1)
|
|
187
|
+
return labels[0];
|
|
188
|
+
if (labels.length === 2)
|
|
189
|
+
return `${labels[0]} and ${labels[1]}`;
|
|
190
|
+
return `${labels.slice(0, -1).join(", ")}, and ${labels[labels.length - 1]}`;
|
|
191
|
+
}
|
|
192
|
+
function sourceHeading(sources) {
|
|
193
|
+
const sourceKinds = new Set(sources.map((source) => source.kind));
|
|
194
|
+
const labels = SOURCE_KIND_ORDER
|
|
195
|
+
.filter((kind) => sourceKinds.has(kind))
|
|
196
|
+
.map((kind) => SOURCE_KIND_LABELS[kind]);
|
|
197
|
+
if (labels.length === 0)
|
|
198
|
+
return "## from notes i chose to keep";
|
|
199
|
+
return `## from ${joinLabels(labels)}`;
|
|
200
|
+
}
|
|
201
|
+
function renderKeptNotesOutcome(outcome) {
|
|
202
|
+
if (outcome.status === "found") {
|
|
203
|
+
return `${sourceHeading(outcome.sources)}\nThis may matter now:\n${foundLine(outcome.note)}`;
|
|
204
|
+
}
|
|
205
|
+
if (outcome.status === "fuzzy") {
|
|
206
|
+
return `${sourceHeading(outcome.sources)}\nThis is only a possible match; I should verify it before relying on it:\n${fuzzyLine(outcome.hint)}`;
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
function finish(outcome, traceId) {
|
|
211
|
+
(0, runtime_1.emitNervesEvent)({
|
|
212
|
+
component: "mind",
|
|
213
|
+
event: "mind.kept_notes_end",
|
|
214
|
+
trace_id: traceId,
|
|
215
|
+
message: "kept notes completed",
|
|
216
|
+
meta: { status: outcome.status, elapsedMs: outcome.elapsedMs },
|
|
217
|
+
});
|
|
218
|
+
return outcome;
|
|
219
|
+
}
|
|
220
|
+
async function withTimeout(promise, timeoutMs) {
|
|
221
|
+
return await new Promise((resolve, reject) => {
|
|
222
|
+
const timeout = setTimeout(() => resolve("timeout"), timeoutMs);
|
|
223
|
+
promise
|
|
224
|
+
.then((value) => {
|
|
225
|
+
clearTimeout(timeout);
|
|
226
|
+
resolve(value);
|
|
227
|
+
})
|
|
228
|
+
.catch((error) => {
|
|
229
|
+
clearTimeout(timeout);
|
|
230
|
+
reject(error);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
async function injectKeptNotes(messages, options = {}) {
|
|
235
|
+
const startedAt = Date.now();
|
|
236
|
+
const systemMessage = messages[0];
|
|
237
|
+
const query = latestUserText(messages);
|
|
238
|
+
if (systemMessage?.role !== "system" || typeof systemMessage.content !== "string" || !query) {
|
|
239
|
+
return { status: "none", elapsedMs: elapsedSince(startedAt), pressure: [] };
|
|
240
|
+
}
|
|
241
|
+
(0, runtime_1.emitNervesEvent)({
|
|
242
|
+
component: "mind",
|
|
243
|
+
event: "mind.kept_notes_start",
|
|
244
|
+
trace_id: options.traceId,
|
|
245
|
+
message: "kept notes started",
|
|
246
|
+
meta: { channel: options.channel ?? "unknown" },
|
|
247
|
+
});
|
|
248
|
+
try {
|
|
249
|
+
const candidates = gatherKeptNotesCandidates(query, options);
|
|
250
|
+
if (candidates.length === 0 || !options.judge) {
|
|
251
|
+
return finish({ status: "none", elapsedMs: elapsedSince(startedAt), pressure: [] }, options.traceId);
|
|
252
|
+
}
|
|
253
|
+
const judged = await withTimeout(options.judge({ query, candidates }), options.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
254
|
+
if (judged === "timeout") {
|
|
255
|
+
return finish({ status: "timeout", elapsedMs: elapsedSince(startedAt) }, options.traceId);
|
|
256
|
+
}
|
|
257
|
+
const elapsedMs = elapsedSince(startedAt);
|
|
258
|
+
const outcome = judged.status === "found"
|
|
259
|
+
? { status: "found", note: judged.note, sources: selectedSources(candidates, judged.sourceIndexes), elapsedMs }
|
|
260
|
+
: judged.status === "fuzzy"
|
|
261
|
+
? { status: "fuzzy", hint: judged.hint, sources: selectedSources(candidates, judged.sourceIndexes), elapsedMs }
|
|
262
|
+
: { status: "none", pressure: judged.pressure, elapsedMs };
|
|
263
|
+
if (outcome.status === "found" || outcome.status === "fuzzy") {
|
|
264
|
+
const rendered = renderKeptNotesOutcome(outcome);
|
|
265
|
+
messages[0] = { role: "system", content: `${systemMessage.content}\n\n${rendered}` };
|
|
266
|
+
(0, runtime_1.emitNervesEvent)({
|
|
267
|
+
component: "mind",
|
|
268
|
+
event: "mind.kept_notes_injected",
|
|
269
|
+
trace_id: options.traceId,
|
|
270
|
+
message: "kept notes injected",
|
|
271
|
+
meta: { status: outcome.status, sourceCount: outcome.sources.length },
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
return finish(outcome, options.traceId);
|
|
275
|
+
}
|
|
276
|
+
catch (error) {
|
|
277
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
278
|
+
const outcome = { status: "error", reason, elapsedMs: elapsedSince(startedAt) };
|
|
279
|
+
(0, runtime_1.emitNervesEvent)({
|
|
280
|
+
level: "warn",
|
|
281
|
+
component: "mind",
|
|
282
|
+
event: "mind.kept_notes_error",
|
|
283
|
+
trace_id: options.traceId,
|
|
284
|
+
message: "kept notes failed",
|
|
285
|
+
meta: { reason },
|
|
286
|
+
});
|
|
287
|
+
return finish(outcome, options.traceId);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function parseJudgeResult(content) {
|
|
291
|
+
try {
|
|
292
|
+
const parsed = JSON.parse(content);
|
|
293
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
294
|
+
return { status: "none", pressure: ["invalid kept notes judge output"] };
|
|
295
|
+
}
|
|
296
|
+
const record = parsed;
|
|
297
|
+
if (record.status === "found" && typeof record.note === "string" && record.note.trim()) {
|
|
298
|
+
return {
|
|
299
|
+
status: "found",
|
|
300
|
+
note: record.note.trim(),
|
|
301
|
+
sourceIndexes: Array.isArray(record.sourceIndexes) ? record.sourceIndexes.filter((index) => typeof index === "number") : undefined,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
if (record.status === "fuzzy" && typeof record.hint === "string" && record.hint.trim()) {
|
|
305
|
+
return {
|
|
306
|
+
status: "fuzzy",
|
|
307
|
+
hint: record.hint.trim(),
|
|
308
|
+
sourceIndexes: Array.isArray(record.sourceIndexes) ? record.sourceIndexes.filter((index) => typeof index === "number") : undefined,
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
if (record.status === "none") {
|
|
312
|
+
return {
|
|
313
|
+
status: "none",
|
|
314
|
+
pressure: Array.isArray(record.pressure) ? record.pressure.filter((value) => typeof value === "string") : [],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
return { status: "none", pressure: ["invalid kept notes judge output"] };
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
return { status: "none", pressure: ["invalid kept notes judge output"] };
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function createJudgePrompt(input) {
|
|
324
|
+
const candidates = input.candidates
|
|
325
|
+
.map((candidate, index) => `${index}. [${candidate.source.kind}] ${candidate.text}`)
|
|
326
|
+
.join("\n");
|
|
327
|
+
return [
|
|
328
|
+
{
|
|
329
|
+
role: "system",
|
|
330
|
+
content: [
|
|
331
|
+
"Decide whether these intentionally kept notes matter to the user's current turn.",
|
|
332
|
+
"Return only JSON.",
|
|
333
|
+
"Use found when a note clearly helps, fuzzy when a note is close but uncertain, and none when nothing should be surfaced.",
|
|
334
|
+
"Shapes: {\"status\":\"found\",\"note\":\"...\",\"sourceIndexes\":[0]}, {\"status\":\"fuzzy\",\"hint\":\"...\",\"sourceIndexes\":[0]}, or {\"status\":\"none\",\"pressure\":[]}.",
|
|
335
|
+
].join("\n"),
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
role: "user",
|
|
339
|
+
content: `Current turn:\n${input.query}\n\nCandidates:\n${candidates}`,
|
|
340
|
+
},
|
|
341
|
+
];
|
|
342
|
+
}
|
|
343
|
+
function createKeptNotesJudge(runtime, signal) {
|
|
344
|
+
return async (input) => {
|
|
345
|
+
const messages = createJudgePrompt(input);
|
|
346
|
+
runtime.resetTurnState?.(messages);
|
|
347
|
+
const result = await runtime.streamTurn({
|
|
348
|
+
messages,
|
|
349
|
+
activeTools: [],
|
|
350
|
+
callbacks: NOOP_CALLBACKS,
|
|
351
|
+
signal,
|
|
352
|
+
toolChoiceRequired: false,
|
|
353
|
+
reasoningEffort: "low",
|
|
354
|
+
});
|
|
355
|
+
return parseJudgeResult(result.content ?? "");
|
|
356
|
+
};
|
|
357
|
+
}
|
|
@@ -92,7 +92,7 @@ const TOOL_TO_COMMAND = {
|
|
|
92
92
|
catchup: "agent.catchup",
|
|
93
93
|
delegate: "agent.delegate",
|
|
94
94
|
get_context: "agent.getContext",
|
|
95
|
-
|
|
95
|
+
search_notes: "agent.searchNotes",
|
|
96
96
|
get_task: "agent.getTask",
|
|
97
97
|
check_scope: "agent.checkScope",
|
|
98
98
|
request_decision: "agent.requestDecision",
|
|
@@ -270,7 +270,7 @@ function createMcpServer(options) {
|
|
|
270
270
|
catchup: "handleAgentCatchup",
|
|
271
271
|
delegate: "handleAgentDelegate",
|
|
272
272
|
get_context: "handleAgentGetContext",
|
|
273
|
-
|
|
273
|
+
search_notes: "handleAgentSearchNotes",
|
|
274
274
|
get_task: "handleAgentGetTask",
|
|
275
275
|
check_scope: "handleAgentCheckScope",
|
|
276
276
|
request_decision: "handleAgentRequestDecision",
|
|
@@ -498,7 +498,7 @@ function getToolSchemas() {
|
|
|
498
498
|
return [
|
|
499
499
|
{
|
|
500
500
|
name: "ask",
|
|
501
|
-
description: "Ask the agent a question. The agent uses its
|
|
501
|
+
description: "Ask the agent a question. The agent uses its diary, journal, and recent session context to provide a useful answer.",
|
|
502
502
|
inputSchema: {
|
|
503
503
|
type: "object",
|
|
504
504
|
properties: {
|
|
@@ -509,7 +509,7 @@ function getToolSchemas() {
|
|
|
509
509
|
},
|
|
510
510
|
{
|
|
511
511
|
name: "status",
|
|
512
|
-
description: "Get the agent's current status including active sessions,
|
|
512
|
+
description: "Get the agent's current status including active sessions, diary and journal state, and activity level.",
|
|
513
513
|
inputSchema: {
|
|
514
514
|
type: "object",
|
|
515
515
|
properties: {},
|
|
@@ -537,19 +537,19 @@ function getToolSchemas() {
|
|
|
537
537
|
},
|
|
538
538
|
{
|
|
539
539
|
name: "get_context",
|
|
540
|
-
description: "Get the agent's current working context including
|
|
540
|
+
description: "Get the agent's current working context including note summary, active tasks, and relevant state.",
|
|
541
541
|
inputSchema: {
|
|
542
542
|
type: "object",
|
|
543
543
|
properties: {},
|
|
544
544
|
},
|
|
545
545
|
},
|
|
546
546
|
{
|
|
547
|
-
name: "
|
|
548
|
-
description: "Search the agent's
|
|
547
|
+
name: "search_notes",
|
|
548
|
+
description: "Search the agent's diary for information about a specific topic. Returns matching diary lines.",
|
|
549
549
|
inputSchema: {
|
|
550
550
|
type: "object",
|
|
551
551
|
properties: {
|
|
552
|
-
query: { type: "string", description: "Search term to look for in agent
|
|
552
|
+
query: { type: "string", description: "Search term to look for in agent notes" },
|
|
553
553
|
},
|
|
554
554
|
required: ["query"],
|
|
555
555
|
},
|
|
@@ -587,7 +587,7 @@ function getToolSchemas() {
|
|
|
587
587
|
},
|
|
588
588
|
{
|
|
589
589
|
name: "check_guidance",
|
|
590
|
-
description: "Get guidance from the agent on how to approach a topic. The agent searches its
|
|
590
|
+
description: "Get guidance from the agent on how to approach a topic. The agent searches its diary, journal, and session context for relevant guidance.",
|
|
591
591
|
inputSchema: {
|
|
592
592
|
type: "object",
|
|
593
593
|
properties: {
|
|
@@ -631,7 +631,7 @@ function getToolSchemas() {
|
|
|
631
631
|
},
|
|
632
632
|
{
|
|
633
633
|
name: "send_message",
|
|
634
|
-
description: "Send a message to the agent and get a synchronous response. This runs a full agent turn — the agent can use tools, think, and respond. For multi-turn conversations, call repeatedly — the agent
|
|
634
|
+
description: "Send a message to the agent and get a synchronous response. This runs a full agent turn — the agent can use tools, think, and respond. For multi-turn conversations, call repeatedly — the agent keeps prior turns in this session.",
|
|
635
635
|
inputSchema: {
|
|
636
636
|
type: "object",
|
|
637
637
|
properties: {
|
|
@@ -47,14 +47,14 @@ function createOutlookHttpReadHooks(options) {
|
|
|
47
47
|
readAgentCoding: options.readAgentCoding ?? ((agentName) => (0, outlook_read_1.readCodingDeep)(agentRoot(agentName))),
|
|
48
48
|
readAgentAttention: options.readAgentAttention ?? ((agentName) => (0, outlook_read_1.readAttentionView)(agentName, readOptions)),
|
|
49
49
|
readAgentBridges: options.readAgentBridges ?? ((agentName) => (0, outlook_read_1.readBridgeInventory)(agentRoot(agentName))),
|
|
50
|
-
|
|
50
|
+
readAgentNotes: options.readAgentNotes ?? ((agentName) => (0, outlook_read_1.readNotesView)(agentRoot(agentName))),
|
|
51
51
|
readAgentFriends: options.readAgentFriends ?? ((agentName) => (0, outlook_read_1.readFriendView)(agentName, readOptions)),
|
|
52
52
|
readAgentContinuity: options.readAgentContinuity ?? ((agentName) => (0, outlook_read_1.readOutlookContinuity)(agentRoot(agentName), agentName)),
|
|
53
53
|
readAgentOrientation: options.readAgentOrientation ?? ((agentName) => (0, outlook_read_1.readOrientationView)(agentRoot(agentName), agentName)),
|
|
54
54
|
readAgentObligations: options.readAgentObligations ?? ((agentName) => (0, outlook_read_1.readObligationDetailView)(agentRoot(agentName))),
|
|
55
55
|
readAgentChanges: options.readAgentChanges ?? ((agentName) => (0, outlook_read_1.readChangesView)(agentRoot(agentName))),
|
|
56
56
|
readAgentSelfFix: options.readAgentSelfFix ?? ((agentName) => (0, outlook_read_1.readSelfFixView)(agentRoot(agentName))),
|
|
57
|
-
|
|
57
|
+
readAgentNoteDecisions: options.readAgentNoteDecisions ?? ((agentName) => (0, outlook_read_1.readNoteDecisionView)(agentRoot(agentName))),
|
|
58
58
|
readAgentHabits: options.readAgentHabits ?? ((agentName) => (0, outlook_read_1.readHabitView)(agentRoot(agentName))),
|
|
59
59
|
readDaemonHealth: options.readDaemonHealth ?? (() => (0, outlook_read_1.readDaemonHealthDeep)(options.healthPath)),
|
|
60
60
|
readLogs: options.readLogs ?? (() => (0, outlook_read_1.readLogView)(options.logPath ?? null)),
|
|
@@ -142,8 +142,8 @@ function handleAgentRoute(request, response, context) {
|
|
|
142
142
|
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentBridges(agent));
|
|
143
143
|
return;
|
|
144
144
|
}
|
|
145
|
-
if (surface === "
|
|
146
|
-
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.
|
|
145
|
+
if (surface === "notes") {
|
|
146
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentNotes(agent));
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
149
|
if (surface === "friends") {
|
|
@@ -170,8 +170,8 @@ function handleAgentRoute(request, response, context) {
|
|
|
170
170
|
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentSelfFix(agent));
|
|
171
171
|
return;
|
|
172
172
|
}
|
|
173
|
-
if (surface === "
|
|
174
|
-
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.
|
|
173
|
+
if (surface === "note-decisions") {
|
|
174
|
+
(0, outlook_http_response_1.writeJson)(response, 200, options.hooks.readAgentNoteDecisions(agent));
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
177
|
if (surface === "dismiss-obligation" && request.method === "POST") {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.readSelfFixView = exports.readOutlookContinuity = exports.readOrientationView = exports.readObligationDetailView = exports.
|
|
3
|
+
exports.readSelfFixView = exports.readOutlookContinuity = exports.readOrientationView = exports.readObligationDetailView = exports.readNoteDecisionView = exports.readChangesView = exports.readNeedsMeView = exports.readNotesView = exports.readLogView = exports.readHabitView = exports.readFriendView = exports.readDeskPrefs = exports.readDaemonHealthDeep = exports.readCodingDeep = exports.readBridgeInventory = exports.readAttentionView = exports.readSessionTranscript = exports.readSessionInventory = exports.readOutlookMachineState = exports.readOutlookAgentState = exports.readObligationSummary = void 0;
|
|
4
4
|
var agent_machine_1 = require("./readers/agent-machine");
|
|
5
5
|
Object.defineProperty(exports, "readObligationSummary", { enumerable: true, get: function () { return agent_machine_1.readObligationSummary; } });
|
|
6
6
|
Object.defineProperty(exports, "readOutlookAgentState", { enumerable: true, get: function () { return agent_machine_1.readOutlookAgentState; } });
|
|
@@ -17,11 +17,11 @@ Object.defineProperty(exports, "readDeskPrefs", { enumerable: true, get: functio
|
|
|
17
17
|
Object.defineProperty(exports, "readFriendView", { enumerable: true, get: function () { return runtime_readers_1.readFriendView; } });
|
|
18
18
|
Object.defineProperty(exports, "readHabitView", { enumerable: true, get: function () { return runtime_readers_1.readHabitView; } });
|
|
19
19
|
Object.defineProperty(exports, "readLogView", { enumerable: true, get: function () { return runtime_readers_1.readLogView; } });
|
|
20
|
-
Object.defineProperty(exports, "
|
|
20
|
+
Object.defineProperty(exports, "readNotesView", { enumerable: true, get: function () { return runtime_readers_1.readNotesView; } });
|
|
21
21
|
Object.defineProperty(exports, "readNeedsMeView", { enumerable: true, get: function () { return runtime_readers_1.readNeedsMeView; } });
|
|
22
22
|
var continuity_readers_1 = require("./readers/continuity-readers");
|
|
23
23
|
Object.defineProperty(exports, "readChangesView", { enumerable: true, get: function () { return continuity_readers_1.readChangesView; } });
|
|
24
|
-
Object.defineProperty(exports, "
|
|
24
|
+
Object.defineProperty(exports, "readNoteDecisionView", { enumerable: true, get: function () { return continuity_readers_1.readNoteDecisionView; } });
|
|
25
25
|
Object.defineProperty(exports, "readObligationDetailView", { enumerable: true, get: function () { return continuity_readers_1.readObligationDetailView; } });
|
|
26
26
|
Object.defineProperty(exports, "readOrientationView", { enumerable: true, get: function () { return continuity_readers_1.readOrientationView; } });
|
|
27
27
|
Object.defineProperty(exports, "readOutlookContinuity", { enumerable: true, get: function () { return continuity_readers_1.readOutlookContinuity; } });
|
|
@@ -38,7 +38,7 @@ exports.readOrientationView = readOrientationView;
|
|
|
38
38
|
exports.readObligationDetailView = readObligationDetailView;
|
|
39
39
|
exports.readChangesView = readChangesView;
|
|
40
40
|
exports.readSelfFixView = readSelfFixView;
|
|
41
|
-
exports.
|
|
41
|
+
exports.readNoteDecisionView = readNoteDecisionView;
|
|
42
42
|
const fs = __importStar(require("fs"));
|
|
43
43
|
const path = __importStar(require("path"));
|
|
44
44
|
const runtime_1 = require("../../../nerves/runtime");
|
|
@@ -304,8 +304,8 @@ function readSelfFixView(agentRoot) {
|
|
|
304
304
|
steps,
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
|
-
function
|
|
308
|
-
const logPath = path.join(agentRoot, "state", "outlook", "
|
|
307
|
+
function readNoteDecisionView(agentRoot, limit = 50) {
|
|
308
|
+
const logPath = path.join(agentRoot, "state", "outlook", "note-decisions.jsonl");
|
|
309
309
|
let lines = [];
|
|
310
310
|
try {
|
|
311
311
|
const raw = fs.readFileSync(logPath, "utf-8");
|
|
@@ -37,7 +37,7 @@ exports.readCodingDeep = readCodingDeep;
|
|
|
37
37
|
exports.readAttentionView = readAttentionView;
|
|
38
38
|
exports.readBridgeInventory = readBridgeInventory;
|
|
39
39
|
exports.readDaemonHealthDeep = readDaemonHealthDeep;
|
|
40
|
-
exports.
|
|
40
|
+
exports.readNotesView = readNotesView;
|
|
41
41
|
exports.readFriendView = readFriendView;
|
|
42
42
|
exports.readLogView = readLogView;
|
|
43
43
|
exports.readHabitView = readHabitView;
|
|
@@ -314,7 +314,7 @@ function readDaemonHealthDeep(healthPath) {
|
|
|
314
314
|
}
|
|
315
315
|
}
|
|
316
316
|
/* v8 ignore stop */
|
|
317
|
-
function
|
|
317
|
+
function readNotesView(agentRoot) {
|
|
318
318
|
const diaryRoot = path.join(agentRoot, "diary");
|
|
319
319
|
const effectiveDiaryRoot = fs.existsSync(diaryRoot) ? diaryRoot : null;
|
|
320
320
|
const diaryEntries = [];
|
|
@@ -64,13 +64,14 @@ function formatElapsed(ms) {
|
|
|
64
64
|
const days = Math.floor(hours / 24);
|
|
65
65
|
return `${days}d ago`;
|
|
66
66
|
}
|
|
67
|
+
const LEGACY_WRITTEN_NOTE_PREFIX = "mem" + "ory";
|
|
67
68
|
const TOOL_NAME_MIGRATIONS = {
|
|
68
69
|
final_answer: "settle",
|
|
69
70
|
no_response: "observe",
|
|
70
71
|
go_inward: "ponder",
|
|
71
72
|
descend: "ponder",
|
|
72
|
-
|
|
73
|
-
|
|
73
|
+
[`${LEGACY_WRITTEN_NOTE_PREFIX}_save`]: "diary_write",
|
|
74
|
+
[`${LEGACY_WRITTEN_NOTE_PREFIX}_search`]: "search_notes",
|
|
74
75
|
};
|
|
75
76
|
function normalizeUsage(usage) {
|
|
76
77
|
if (!usage || typeof usage !== "object")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.summarizeSessionTail = summarizeSessionTail;
|
|
4
4
|
exports.searchSessionTranscript = searchSessionTranscript;
|
|
5
5
|
const runtime_1 = require("../nerves/runtime");
|
|
6
6
|
const session_events_1 = require("./session-events");
|
|
@@ -91,11 +91,11 @@ function buildSearchExcerpts(messages, query, maxMatches) {
|
|
|
91
91
|
.slice(0, maxMatches)
|
|
92
92
|
.map((candidate) => candidate.excerpt);
|
|
93
93
|
}
|
|
94
|
-
async function
|
|
94
|
+
async function summarizeSessionTail(options) {
|
|
95
95
|
(0, runtime_1.emitNervesEvent)({
|
|
96
96
|
component: "daemon",
|
|
97
|
-
event: "daemon.
|
|
98
|
-
message: "
|
|
97
|
+
event: "daemon.session_tail_summary",
|
|
98
|
+
message: "summarizing session transcript tail",
|
|
99
99
|
meta: {
|
|
100
100
|
friendId: options.friendId,
|
|
101
101
|
channel: options.channel,
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.listTargetSessionCandidates = listTargetSessionCandidates;
|
|
4
4
|
exports.formatTargetSessionCandidates = formatTargetSessionCandidates;
|
|
5
|
-
const
|
|
5
|
+
const session_transcript_1 = require("./session-transcript");
|
|
6
6
|
const session_activity_1 = require("./session-activity");
|
|
7
7
|
const trust_explanation_1 = require("../mind/friends/trust-explanation");
|
|
8
8
|
const runtime_1 = require("../nerves/runtime");
|
|
@@ -71,7 +71,7 @@ async function listTargetSessionCandidates(input) {
|
|
|
71
71
|
friend,
|
|
72
72
|
channel: entry.channel,
|
|
73
73
|
});
|
|
74
|
-
const
|
|
74
|
+
const sessionTail = await (0, session_transcript_1.summarizeSessionTail)({
|
|
75
75
|
sessionPath: entry.sessionPath,
|
|
76
76
|
friendId: entry.friendId,
|
|
77
77
|
channel: entry.channel,
|
|
@@ -80,9 +80,9 @@ async function listTargetSessionCandidates(input) {
|
|
|
80
80
|
summarize: input.summarize,
|
|
81
81
|
trustLevel: trust.level,
|
|
82
82
|
});
|
|
83
|
-
const snapshot =
|
|
84
|
-
?
|
|
85
|
-
:
|
|
83
|
+
const snapshot = sessionTail.kind === "ok"
|
|
84
|
+
? sessionTail.snapshot
|
|
85
|
+
: sessionTail.kind === "empty"
|
|
86
86
|
? "recent focus: no recent visible messages"
|
|
87
87
|
: "recent focus: session transcript unavailable";
|
|
88
88
|
const delivery = describeDelivery({
|
|
@@ -55,12 +55,12 @@ const TOOL_DESCRIPTIONS = {
|
|
|
55
55
|
return "searching code...";
|
|
56
56
|
return `searching code for '${truncate(p, 40)}'...`;
|
|
57
57
|
},
|
|
58
|
-
//
|
|
59
|
-
|
|
58
|
+
// Notes and knowledge
|
|
59
|
+
search_notes: (args) => {
|
|
60
60
|
const q = args.query;
|
|
61
61
|
if (!q)
|
|
62
|
-
return "searching
|
|
63
|
-
return `searching
|
|
62
|
+
return "searching notes...";
|
|
63
|
+
return `searching notes for '${truncate(q, 40)}'...`;
|
|
64
64
|
},
|
|
65
65
|
diary_write: (args) => {
|
|
66
66
|
const about = args.about;
|
package/dist/mind/diary.js
CHANGED
|
@@ -45,7 +45,7 @@ const path = __importStar(require("path"));
|
|
|
45
45
|
const crypto_1 = require("crypto");
|
|
46
46
|
const identity_1 = require("../heart/identity");
|
|
47
47
|
const runtime_1 = require("../nerves/runtime");
|
|
48
|
-
const
|
|
48
|
+
const note_search_1 = require("./note-search");
|
|
49
49
|
const diary_integrity_1 = require("./diary-integrity");
|
|
50
50
|
const embedding_provider_1 = require("./embedding-provider");
|
|
51
51
|
const DEDUP_THRESHOLD = 0.6;
|
|
@@ -164,7 +164,7 @@ function appendEntriesWithDedup(stores, incoming, options) {
|
|
|
164
164
|
Array.isArray(fact.embedding) && fact.embedding.length > 0 &&
|
|
165
165
|
Array.isArray(prior.embedding) && prior.embedding.length > 0 &&
|
|
166
166
|
fact.embedding.length === prior.embedding.length) {
|
|
167
|
-
return (0,
|
|
167
|
+
return (0, note_search_1.cosineSimilarity)(fact.embedding, prior.embedding) > semanticThreshold;
|
|
168
168
|
}
|
|
169
169
|
return false;
|
|
170
170
|
});
|
|
@@ -353,7 +353,7 @@ async function searchDiaryEntries(query, facts, embeddingProvider) {
|
|
|
353
353
|
.filter((fact) => fact.embedding.length === queryEmbedding.length)
|
|
354
354
|
.map((fact) => ({
|
|
355
355
|
fact,
|
|
356
|
-
score: (0,
|
|
356
|
+
score: (0, note_search_1.cosineSimilarity)(queryEmbedding, fact.embedding),
|
|
357
357
|
}))
|
|
358
358
|
.filter((entry) => entry.score > 0)
|
|
359
359
|
.sort((left, right) => right.score - left.score)
|