@thesashadev/girl-agent 0.2.2 → 0.3.1
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/CHANGELOG.md +35 -0
- package/dist/cli.js +676 -180
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1353,7 +1353,8 @@ function parseSessionLogTurns(raw, fromId, limit = 30) {
|
|
|
1353
1353
|
}
|
|
1354
1354
|
async function readRecentSessionTurns(slug, tz, fromId, limit = 30) {
|
|
1355
1355
|
const day = sessionDate(tz);
|
|
1356
|
-
const
|
|
1356
|
+
const days = [.../* @__PURE__ */ new Set([...await listSessionDays(slug), day])].filter((d) => d <= day).sort().slice(-4);
|
|
1357
|
+
const raw = (await Promise.all(days.map((d) => readSessionLog(slug, d)))).join("\n");
|
|
1357
1358
|
return parseSessionLogTurns(raw, fromId, limit);
|
|
1358
1359
|
}
|
|
1359
1360
|
async function readAgenda(slug) {
|
|
@@ -1836,8 +1837,8 @@ phoneAvailable=false \u043A\u043E\u0433\u0434\u0430: \u0441\u043F\u0438\u0442, \
|
|
|
1836
1837
|
}
|
|
1837
1838
|
async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(), conflict = null) {
|
|
1838
1839
|
const dateLocal = localDateStr(cfg.tz, now);
|
|
1839
|
-
const
|
|
1840
|
-
const existing = await readMd(cfg.slug,
|
|
1840
|
+
const path13 = `daily-life/${dateLocal}.md`;
|
|
1841
|
+
const existing = await readMd(cfg.slug, path13);
|
|
1841
1842
|
if (existing) {
|
|
1842
1843
|
try {
|
|
1843
1844
|
const m = existing.match(/<!--daily:(.+?)-->/s);
|
|
@@ -1869,7 +1870,7 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
1869
1870
|
dl = { dateLocal, vibe: "\u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0434\u0435\u043D\u044C", blocks: [], events: [], wants: [] };
|
|
1870
1871
|
}
|
|
1871
1872
|
const human = renderDailyLifeHuman(dl);
|
|
1872
|
-
await writeMd(cfg.slug,
|
|
1873
|
+
await writeMd(cfg.slug, path13, `${human}
|
|
1873
1874
|
|
|
1874
1875
|
<!--daily:${JSON.stringify(dl)}-->
|
|
1875
1876
|
`);
|
|
@@ -2070,15 +2071,131 @@ var init_conflict = __esm({
|
|
|
2070
2071
|
}
|
|
2071
2072
|
});
|
|
2072
2073
|
|
|
2073
|
-
// src/engine/
|
|
2074
|
+
// src/engine/memory-palace.ts
|
|
2075
|
+
import { promises as fs4 } from "fs";
|
|
2076
|
+
import { createHash } from "crypto";
|
|
2077
|
+
import path5 from "path";
|
|
2078
|
+
function wordsFrom(text) {
|
|
2079
|
+
return [...text.toLowerCase().matchAll(/[a-zа-яё0-9]{3,}/gi)].map((match) => match[0]).filter((token) => !STOP_WORDS.has(token));
|
|
2080
|
+
}
|
|
2081
|
+
function normalizedQuote(value) {
|
|
2082
|
+
return value.toLowerCase().replace(/\s+/g, " ").trim();
|
|
2083
|
+
}
|
|
2074
2084
|
function today(tz) {
|
|
2075
2085
|
return sessionDate(tz);
|
|
2076
2086
|
}
|
|
2087
|
+
function nowStamp() {
|
|
2088
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2089
|
+
}
|
|
2090
|
+
function wingFor(cfg) {
|
|
2091
|
+
return `primary-${cfg.ownerId ?? "unknown"}`;
|
|
2092
|
+
}
|
|
2093
|
+
function normalizeRoom(value) {
|
|
2094
|
+
const source = value.trim().toLowerCase() || "general";
|
|
2095
|
+
const slug = source.replace(/ё/g, "\u0435").replace(/[^a-zа-я0-9]+/gi, "-").replace(/^-+|-+$/g, "").slice(0, 60);
|
|
2096
|
+
return slug || "general";
|
|
2097
|
+
}
|
|
2098
|
+
function normalizeHall(value) {
|
|
2099
|
+
return HALLS.includes(value) ? value : "hall_facts";
|
|
2100
|
+
}
|
|
2101
|
+
function normalizeKeywords(value, quote, room) {
|
|
2102
|
+
const raw = Array.isArray(value) ? value.filter((x) => typeof x === "string") : [];
|
|
2103
|
+
const fallback = [...quote.toLowerCase().matchAll(/[a-zа-яё0-9]{3,}/gi)].map((match) => match[0]).filter((word) => !STOP_WORDS.has(word)).slice(0, 10);
|
|
2104
|
+
return [...new Set([...raw, room, ...fallback].map((x) => x.trim().toLowerCase()).filter(Boolean))].slice(0, 16);
|
|
2105
|
+
}
|
|
2106
|
+
function scoreClamp(value) {
|
|
2107
|
+
if (typeof value !== "number" || !Number.isFinite(value)) return 5;
|
|
2108
|
+
return Math.max(1, Math.min(10, Math.round(value)));
|
|
2109
|
+
}
|
|
2110
|
+
function safeId() {
|
|
2111
|
+
return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
2112
|
+
}
|
|
2113
|
+
function stableId(source, quote) {
|
|
2114
|
+
return createHash("sha1").update(`${source}
|
|
2115
|
+
${quote}`).digest("hex").slice(0, 16);
|
|
2116
|
+
}
|
|
2117
|
+
function asRecord(value) {
|
|
2118
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
2119
|
+
}
|
|
2120
|
+
function parseDrawer(raw) {
|
|
2121
|
+
const metaMatch = raw.match(/^<!--drawer:(.+?)-->\n/);
|
|
2122
|
+
if (!metaMatch) return null;
|
|
2123
|
+
try {
|
|
2124
|
+
const meta = JSON.parse(metaMatch[1] ?? "");
|
|
2125
|
+
const quote = raw.slice(metaMatch[0].length);
|
|
2126
|
+
if (!meta.id || !meta.ts || !meta.wing || !meta.room || !meta.hall || !meta.source || !quote.trim()) return null;
|
|
2127
|
+
return {
|
|
2128
|
+
id: meta.id,
|
|
2129
|
+
ts: meta.ts,
|
|
2130
|
+
wing: meta.wing,
|
|
2131
|
+
room: meta.room,
|
|
2132
|
+
hall: normalizeHall(meta.hall),
|
|
2133
|
+
source: meta.source,
|
|
2134
|
+
quote: quote.trim(),
|
|
2135
|
+
keywords: normalizeKeywords(meta.keywords, quote, meta.room),
|
|
2136
|
+
salience: scoreClamp(meta.salience)
|
|
2137
|
+
};
|
|
2138
|
+
} catch {
|
|
2139
|
+
return null;
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
function renderDrawer(drawer) {
|
|
2143
|
+
const meta = {
|
|
2144
|
+
id: drawer.id,
|
|
2145
|
+
ts: drawer.ts,
|
|
2146
|
+
wing: drawer.wing,
|
|
2147
|
+
room: drawer.room,
|
|
2148
|
+
hall: drawer.hall,
|
|
2149
|
+
source: drawer.source,
|
|
2150
|
+
keywords: drawer.keywords,
|
|
2151
|
+
salience: drawer.salience
|
|
2152
|
+
};
|
|
2153
|
+
return `<!--drawer:${JSON.stringify(meta)}-->
|
|
2154
|
+
${drawer.quote.trim()}
|
|
2155
|
+
`;
|
|
2156
|
+
}
|
|
2157
|
+
function drawerPath(drawer) {
|
|
2158
|
+
return `memory/palace/${drawer.wing}/${drawer.hall}/${drawer.room}/${drawer.id}.md`;
|
|
2159
|
+
}
|
|
2160
|
+
function parseJsonObject(raw) {
|
|
2161
|
+
try {
|
|
2162
|
+
const parsed = JSON.parse(raw);
|
|
2163
|
+
return asRecord(parsed);
|
|
2164
|
+
} catch {
|
|
2165
|
+
const match = raw.match(/\{[\s\S]*\}/);
|
|
2166
|
+
if (!match) return null;
|
|
2167
|
+
try {
|
|
2168
|
+
const parsed = JSON.parse(match[0]);
|
|
2169
|
+
return asRecord(parsed);
|
|
2170
|
+
} catch {
|
|
2171
|
+
return null;
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
function parsedDrawers(value) {
|
|
2176
|
+
if (!Array.isArray(value)) return [];
|
|
2177
|
+
const out = [];
|
|
2178
|
+
for (const item of value) {
|
|
2179
|
+
const rec = asRecord(item);
|
|
2180
|
+
if (!rec) continue;
|
|
2181
|
+
const quote = typeof rec.quote === "string" ? rec.quote.trim() : "";
|
|
2182
|
+
if (!quote) continue;
|
|
2183
|
+
const room = normalizeRoom(typeof rec.room === "string" ? rec.room : "");
|
|
2184
|
+
out.push({
|
|
2185
|
+
room,
|
|
2186
|
+
hall: normalizeHall(typeof rec.hall === "string" ? rec.hall : ""),
|
|
2187
|
+
quote,
|
|
2188
|
+
keywords: normalizeKeywords(rec.keywords, quote, room),
|
|
2189
|
+
salience: scoreClamp(rec.salience)
|
|
2190
|
+
});
|
|
2191
|
+
}
|
|
2192
|
+
return out;
|
|
2193
|
+
}
|
|
2077
2194
|
async function ensureDefaults(cfg) {
|
|
2078
2195
|
const defaults = [
|
|
2079
2196
|
["memory/facts.md", DEFAULT_FACTS],
|
|
2080
2197
|
["relationship/timeline.md", `# relationship timeline
|
|
2081
|
-
- ${(
|
|
2198
|
+
- ${nowStamp()}: \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0437\u0434\u0430\u043D, \u0441\u0442\u0430\u0434\u0438\u044F ${cfg.stage}`],
|
|
2082
2199
|
["life/week-plan.md", DEFAULT_WEEKLY],
|
|
2083
2200
|
["life/contacts.md", DEFAULT_SOCIAL],
|
|
2084
2201
|
["life/habits.md", DEFAULT_HABITS],
|
|
@@ -2087,14 +2204,85 @@ async function ensureDefaults(cfg) {
|
|
|
2087
2204
|
["time/promises.md", "# promises\n"],
|
|
2088
2205
|
["memory/uncertain.md", "# uncertain\n"]
|
|
2089
2206
|
];
|
|
2090
|
-
await Promise.all(defaults.map(async ([
|
|
2091
|
-
const current = await readMd(cfg.slug,
|
|
2092
|
-
if (!current.trim()) await writeMd(cfg.slug,
|
|
2207
|
+
await Promise.all(defaults.map(async ([path13, content]) => {
|
|
2208
|
+
const current = await readMd(cfg.slug, path13);
|
|
2209
|
+
if (!current.trim()) await writeMd(cfg.slug, path13, content + "\n");
|
|
2093
2210
|
}));
|
|
2094
2211
|
}
|
|
2095
|
-
|
|
2212
|
+
function scoreDrawer(drawer, tokens, query) {
|
|
2213
|
+
if (!tokens.length) return drawer.salience;
|
|
2214
|
+
const haystack = [
|
|
2215
|
+
drawer.quote,
|
|
2216
|
+
drawer.room,
|
|
2217
|
+
drawer.hall,
|
|
2218
|
+
drawer.keywords.join(" ")
|
|
2219
|
+
].join("\n").toLowerCase();
|
|
2220
|
+
let score = drawer.salience;
|
|
2221
|
+
for (const token of tokens) {
|
|
2222
|
+
if (haystack.includes(token)) score += drawer.keywords.includes(token) ? 4 : 2;
|
|
2223
|
+
}
|
|
2224
|
+
if (drawer.quote.toLowerCase().includes(query)) score += 4;
|
|
2225
|
+
return score;
|
|
2226
|
+
}
|
|
2227
|
+
async function listPalaceDrawers(cfg) {
|
|
2228
|
+
const root = `memory/palace/${wingFor(cfg)}`;
|
|
2229
|
+
const halls = await listChildDirs(cfg.slug, root);
|
|
2230
|
+
const drawers = [];
|
|
2231
|
+
for (const hall of halls) {
|
|
2232
|
+
const rooms = await listChildDirs(cfg.slug, `${root}/${hall}`);
|
|
2233
|
+
for (const room of rooms) {
|
|
2234
|
+
const files = await listChildFiles(cfg.slug, `${root}/${hall}/${room}`);
|
|
2235
|
+
for (const file of files) {
|
|
2236
|
+
if (!file.endsWith(".md")) continue;
|
|
2237
|
+
const drawer = parseDrawer(await readMd(cfg.slug, `${root}/${hall}/${room}/${file}`));
|
|
2238
|
+
if (drawer) drawers.push(drawer);
|
|
2239
|
+
}
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
return drawers;
|
|
2243
|
+
}
|
|
2244
|
+
async function listChildDirs(slug, rel) {
|
|
2245
|
+
try {
|
|
2246
|
+
const entries = await fs4.readdir(path5.join(profileDir(slug), rel), { withFileTypes: true });
|
|
2247
|
+
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
2248
|
+
} catch {
|
|
2249
|
+
return [];
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
async function listChildFiles(slug, rel) {
|
|
2253
|
+
try {
|
|
2254
|
+
const entries = await fs4.readdir(path5.join(profileDir(slug), rel), { withFileTypes: true });
|
|
2255
|
+
return entries.filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
2256
|
+
} catch {
|
|
2257
|
+
return [];
|
|
2258
|
+
}
|
|
2259
|
+
}
|
|
2260
|
+
function renderPalaceRecall(drawers) {
|
|
2261
|
+
if (!drawers.length) return "";
|
|
2262
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
2263
|
+
for (const drawer of drawers) {
|
|
2264
|
+
const key = `${drawer.hall}/${drawer.room}`;
|
|
2265
|
+
grouped.set(key, [...grouped.get(key) ?? [], drawer]);
|
|
2266
|
+
}
|
|
2267
|
+
const lines = ["## Memory Palace: \u0442\u043E\u0447\u043D\u044B\u0435 \u044F\u0449\u0438\u043A\u0438 \u043F\u043E \u0442\u0435\u043C\u0435"];
|
|
2268
|
+
for (const [key, group] of grouped) {
|
|
2269
|
+
lines.push(`### ${key}`);
|
|
2270
|
+
for (const drawer of group.slice(0, 4)) {
|
|
2271
|
+
lines.push(`- [${drawer.ts.slice(0, 10)}] ${drawer.quote}`);
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
lines.push("\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u044D\u0442\u0438 \u044F\u0449\u0438\u043A\u0438 \u043A\u0430\u043A \u0442\u043E\u0447\u043D\u0443\u044E \u043F\u0430\u043C\u044F\u0442\u044C. \u041D\u0435 \u0446\u0438\u0442\u0438\u0440\u0443\u0439 \u0441\u043B\u0443\u0436\u0435\u0431\u043D\u044B\u0435 hall/room/source, \u043D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438 \u0447\u0442\u043E \u044D\u0442\u043E \u0444\u0430\u0439\u043B \u0438\u043B\u0438 \u043F\u0430\u043C\u044F\u0442\u044C.");
|
|
2275
|
+
return lines.join("\n");
|
|
2276
|
+
}
|
|
2277
|
+
async function searchPalaceDrawers(cfg, query, limit = 8) {
|
|
2278
|
+
const normalized = query.toLowerCase();
|
|
2279
|
+
const tokens = wordsFrom(normalized);
|
|
2280
|
+
const scored = (await listPalaceDrawers(cfg)).map((drawer) => ({ drawer, score: scoreDrawer(drawer, tokens, normalized) })).filter((item) => item.score > item.drawer.salience || item.drawer.salience >= 8).sort((a, b) => b.score - a.score || b.drawer.ts.localeCompare(a.drawer.ts));
|
|
2281
|
+
return scored.slice(0, limit).map((item) => item.drawer);
|
|
2282
|
+
}
|
|
2283
|
+
async function loadMemoryPalaceContext(cfg, incoming) {
|
|
2096
2284
|
await ensureDefaults(cfg);
|
|
2097
|
-
const [facts, episodesRaw, timeline, attachment, openLoops, promises, weeklyLife, socialGraph, habits] = await Promise.all([
|
|
2285
|
+
const [facts, episodesRaw, timeline, attachment, openLoops, promises, weeklyLife, socialGraph, habits, palaceHits] = await Promise.all([
|
|
2098
2286
|
readMd(cfg.slug, "memory/facts.md"),
|
|
2099
2287
|
readMd(cfg.slug, `memory/episodes/${today(cfg.tz)}.md`),
|
|
2100
2288
|
readMd(cfg.slug, "relationship/timeline.md"),
|
|
@@ -2103,28 +2291,32 @@ async function loadRealismContext(cfg, incoming) {
|
|
|
2103
2291
|
readMd(cfg.slug, "time/promises.md"),
|
|
2104
2292
|
readMd(cfg.slug, "life/week-plan.md"),
|
|
2105
2293
|
readMd(cfg.slug, "life/contacts.md"),
|
|
2106
|
-
readMd(cfg.slug, "life/habits.md")
|
|
2294
|
+
readMd(cfg.slug, "life/habits.md"),
|
|
2295
|
+
incoming && incoming.trim().length > 3 ? searchPalaceDrawers(cfg, incoming, 10) : Promise.resolve([])
|
|
2107
2296
|
]);
|
|
2108
2297
|
const query = incoming?.toLowerCase() ?? "";
|
|
2109
2298
|
const factLines = facts.split("\n").filter((l) => l.trim());
|
|
2110
|
-
const
|
|
2299
|
+
const tokens = wordsFrom(query);
|
|
2300
|
+
const relevantFacts = tokens.length ? factLines.filter((l) => tokens.some((t) => l.toLowerCase().includes(t))).slice(-18).join("\n") || facts.slice(-1800) : facts.slice(-1800);
|
|
2111
2301
|
return {
|
|
2112
2302
|
facts: relevantFacts,
|
|
2113
|
-
episodes: episodesRaw.slice(-
|
|
2114
|
-
relationshipTimeline: timeline.slice(-
|
|
2303
|
+
episodes: episodesRaw.slice(-2200),
|
|
2304
|
+
relationshipTimeline: timeline.slice(-2200),
|
|
2115
2305
|
attachment: attachment.slice(-1200),
|
|
2116
|
-
time: [openLoops.slice(-
|
|
2306
|
+
time: [openLoops.slice(-1400), promises.slice(-1400)].filter(Boolean).join("\n\n"),
|
|
2117
2307
|
weeklyLife: weeklyLife.slice(-1200),
|
|
2118
2308
|
socialGraph: socialGraph.slice(-1200),
|
|
2119
2309
|
habits: habits.slice(-1200),
|
|
2120
|
-
openLoops: openLoops.slice(-
|
|
2310
|
+
openLoops: openLoops.slice(-1400),
|
|
2311
|
+
palace: renderPalaceRecall(palaceHits)
|
|
2121
2312
|
};
|
|
2122
2313
|
}
|
|
2123
|
-
function
|
|
2314
|
+
function memoryPalacePromptFragment(ctx) {
|
|
2124
2315
|
return [
|
|
2125
2316
|
"# \u0420\u0435\u0430\u043B\u0438\u0441\u0442\u0438\u0447\u043D\u0430\u044F \u043D\u0435\u043F\u0440\u0435\u0440\u044B\u0432\u043D\u043E\u0441\u0442\u044C",
|
|
2126
2317
|
"\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u044D\u0442\u0438 \u0434\u0430\u043D\u043D\u044B\u0435 \u043A\u0430\u043A \u0444\u043E\u043D, \u0430 \u043D\u0435 \u043A\u0430\u043A \u043E\u0442\u0447\u0451\u0442. \u041D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438, \u0447\u0442\u043E \u0443 \u0442\u0435\u0431\u044F \u0435\u0441\u0442\u044C \u043F\u0430\u043C\u044F\u0442\u044C, \u0444\u0430\u0439\u043B\u044B, \u0444\u0430\u043A\u0442\u044B \u0438\u043B\u0438 \u0441\u0438\u0441\u0442\u0435\u043C\u0430.",
|
|
2127
2318
|
"\u0415\u0441\u043B\u0438 \u0442\u043E\u0447\u043D\u043E\u0433\u043E \u0444\u0430\u043A\u0442\u0430 \u043D\u0435\u0442 \u2014 \u043D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439 \u0443\u0432\u0435\u0440\u0435\u043D\u043D\u043E; \u043E\u0442\u0432\u0435\u0447\u0430\u0439 \u0443\u043A\u043B\u043E\u043D\u0447\u0438\u0432\u043E \u0438\u043B\u0438 \u0443\u0442\u043E\u0447\u043D\u044F\u0439 \u043F\u043E-\u0447\u0435\u043B\u043E\u0432\u0435\u0447\u0435\u0441\u043A\u0438.",
|
|
2319
|
+
ctx.palace,
|
|
2128
2320
|
"## \u0424\u0430\u043A\u0442\u044B \u043E \u043D\u0451\u043C",
|
|
2129
2321
|
ctx.facts,
|
|
2130
2322
|
"## \u042D\u043F\u0438\u0437\u043E\u0434\u044B \u0442\u0435\u043A\u0443\u0449\u0435\u0433\u043E \u0434\u043D\u044F",
|
|
@@ -2143,53 +2335,221 @@ function realismPromptFragment(ctx) {
|
|
|
2143
2335
|
ctx.habits
|
|
2144
2336
|
].filter(Boolean).join("\n\n");
|
|
2145
2337
|
}
|
|
2338
|
+
async function appendDrawer(cfg, source, parsed) {
|
|
2339
|
+
const stamp = nowStamp();
|
|
2340
|
+
const quoteKey = normalizedQuote(parsed.quote);
|
|
2341
|
+
const duplicate = (await listPalaceDrawers(cfg)).find(
|
|
2342
|
+
(existing2) => normalizedQuote(existing2.quote) === quoteKey || existing2.room === parsed.room && existing2.hall === parsed.hall && normalizedQuote(existing2.quote).includes(quoteKey) || existing2.room === parsed.room && existing2.hall === parsed.hall && quoteKey.includes(normalizedQuote(existing2.quote))
|
|
2343
|
+
);
|
|
2344
|
+
if (duplicate && duplicate.salience >= parsed.salience) return;
|
|
2345
|
+
const drawer = {
|
|
2346
|
+
id: stableId(source, parsed.quote),
|
|
2347
|
+
ts: stamp,
|
|
2348
|
+
wing: wingFor(cfg),
|
|
2349
|
+
room: parsed.room,
|
|
2350
|
+
hall: parsed.hall,
|
|
2351
|
+
source,
|
|
2352
|
+
quote: parsed.quote,
|
|
2353
|
+
keywords: parsed.keywords,
|
|
2354
|
+
salience: parsed.salience
|
|
2355
|
+
};
|
|
2356
|
+
const existing = await readMd(cfg.slug, drawerPath(drawer));
|
|
2357
|
+
if (existing.trim()) return;
|
|
2358
|
+
await writeMd(cfg.slug, drawerPath(drawer), renderDrawer(drawer));
|
|
2359
|
+
await appendCompatibilityMemory(cfg, drawer);
|
|
2360
|
+
}
|
|
2361
|
+
async function appendCompatibilityMemory(cfg, drawer) {
|
|
2362
|
+
const stamp = drawer.ts;
|
|
2363
|
+
const line = `- ${stamp}: ${drawer.quote}
|
|
2364
|
+
`;
|
|
2365
|
+
if (drawer.hall === "hall_facts" || drawer.hall === "hall_preferences" || drawer.hall === "hall_discoveries") {
|
|
2366
|
+
await appendMd(cfg.slug, "memory/facts.md", line);
|
|
2367
|
+
await appendMd(cfg.slug, "memory/long-term.md", `
|
|
2368
|
+
## ${stamp.slice(0, 16)}
|
|
2369
|
+
- ${drawer.quote}`);
|
|
2370
|
+
} else if (drawer.hall === "hall_events" || drawer.hall === "hall_feelings") {
|
|
2371
|
+
await appendMd(cfg.slug, `memory/episodes/${today(cfg.tz)}.md`, line);
|
|
2372
|
+
} else if (drawer.hall === "hall_promises") {
|
|
2373
|
+
await appendMd(cfg.slug, "time/promises.md", line);
|
|
2374
|
+
} else if (drawer.hall === "hall_open_loops") {
|
|
2375
|
+
await appendMd(cfg.slug, "time/open-loops.md", line);
|
|
2376
|
+
} else if (drawer.hall === "hall_uncertain") {
|
|
2377
|
+
await appendMd(cfg.slug, "memory/uncertain.md", line);
|
|
2378
|
+
}
|
|
2379
|
+
if (drawer.hall === "hall_events" && drawer.salience >= 8) {
|
|
2380
|
+
await appendMd(cfg.slug, "relationship/timeline.md", line);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2146
2383
|
async function recordInteractionMemory(llm, cfg, incoming, reply) {
|
|
2147
2384
|
if (!incoming.trim()) return;
|
|
2385
|
+
await ensureDefaults(cfg);
|
|
2148
2386
|
const raw = await llm.chat([
|
|
2149
|
-
{
|
|
2150
|
-
|
|
2151
|
-
\
|
|
2152
|
-
|
|
2387
|
+
{
|
|
2388
|
+
role: "system",
|
|
2389
|
+
content: `\u0422\u044B \u0438\u0437\u0432\u043B\u0435\u043A\u0430\u0435\u0448\u044C \u043F\u0430\u043C\u044F\u0442\u044C \u0434\u043B\u044F Telegram-\u043F\u0435\u0440\u0441\u043E\u043D\u044B. \u041F\u0440\u0438\u043D\u0446\u0438\u043F MemPalace: \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u043A\u0438 \u0434\u043E\u0441\u043B\u043E\u0432\u043D\u043E, \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u0438 \u043D\u0435 \u0441\u0436\u0438\u043C\u0430\u0442\u044C. \u041D\u0443\u0436\u043D\u044B \u0442\u043E\u043B\u044C\u043A\u043E \u044F\u0432\u043D\u044B\u0435 \u0444\u0430\u043A\u0442\u044B, \u043F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F, \u043E\u0431\u0435\u0449\u0430\u043D\u0438\u044F, \u043E\u0442\u043A\u0440\u044B\u0442\u044B\u0435 \u043F\u0435\u0442\u043B\u0438, \u044D\u043C\u043E\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u044B\u0435 \u044D\u043F\u0438\u0437\u043E\u0434\u044B \u0438 \u0441\u043E\u043C\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u0435 \u0444\u0430\u043A\u0442\u044B. \u0415\u0441\u043B\u0438 \u0432\u0430\u0436\u043D\u0430 \u0446\u0435\u043B\u0430\u044F \u0444\u0440\u0430\u0437\u0430 \u2014 \u0441\u043E\u0445\u0440\u0430\u043D\u0438 \u0435\u0451 \u0446\u0435\u043B\u0438\u043A\u043E\u043C \u0431\u0435\u0437 \u043E\u0431\u0440\u0435\u0437\u043A\u0438 \u043D\u0438 \u043E\u0434\u043D\u043E\u0433\u043E \u0441\u043B\u043E\u0432\u0430. \u041D\u0435 \u0432\u044B\u0434\u0443\u043C\u044B\u0432\u0430\u0439.`
|
|
2390
|
+
},
|
|
2391
|
+
{
|
|
2392
|
+
role: "user",
|
|
2393
|
+
content: `\u041F\u0440\u043E\u0444\u0438\u043B\u044C: ${cfg.name}, \u0441\u0442\u0430\u0434\u0438\u044F ${cfg.stage}.
|
|
2394
|
+
\u041E\u043D \u043D\u0430\u043F\u0438\u0441\u0430\u043B:
|
|
2395
|
+
"""
|
|
2396
|
+
${incoming}
|
|
2397
|
+
"""
|
|
2398
|
+
|
|
2399
|
+
\u041E\u043D\u0430 \u043E\u0442\u0432\u0435\u0442\u0438\u043B\u0430:
|
|
2400
|
+
"""
|
|
2401
|
+
${reply ?? ""}
|
|
2402
|
+
"""
|
|
2153
2403
|
|
|
2154
|
-
JSON:
|
|
2404
|
+
\u0412\u0435\u0440\u043D\u0438 STRICT JSON:
|
|
2155
2405
|
{
|
|
2156
|
-
"
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2406
|
+
"drawers": [
|
|
2407
|
+
{
|
|
2408
|
+
"room": "\u043A\u043E\u0440\u043E\u0442\u043A\u0430\u044F \u0442\u0435\u043C\u0430 \u043D\u0430 \u0440\u0443\u0441\u0441\u043A\u043E\u043C \u0438\u043B\u0438 latin-slug",
|
|
2409
|
+
"hall": "hall_facts | hall_events | hall_discoveries | hall_preferences | hall_advice | hall_promises | hall_open_loops | hall_feelings | hall_uncertain",
|
|
2410
|
+
"quote": "\u0434\u043E\u0441\u043B\u043E\u0432\u043D\u0430\u044F \u0444\u0440\u0430\u0437\u0430/\u0444\u0440\u0430\u0433\u043C\u0435\u043D\u0442 \u0438\u0437 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438, \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u0430 \u0438 \u0431\u0435\u0437 \u043E\u0431\u0440\u0435\u0437\u043A\u0438 \u0432\u0430\u0436\u043D\u044B\u0445 \u0441\u043B\u043E\u0432",
|
|
2411
|
+
"keywords": ["\u0441\u043B\u043E\u0432\u0430 \u0434\u043B\u044F \u043F\u043E\u0438\u0441\u043A\u0430"],
|
|
2412
|
+
"salience": 1-10
|
|
2413
|
+
}
|
|
2414
|
+
]
|
|
2415
|
+
}`
|
|
2416
|
+
}
|
|
2417
|
+
], { temperature: 0.1, maxTokens: 3500, json: true });
|
|
2418
|
+
const parsed = parseJsonObject(raw);
|
|
2419
|
+
const drawers = parsedDrawers(parsed?.drawers).slice(0, 12);
|
|
2420
|
+
for (const drawer of drawers) {
|
|
2421
|
+
await appendDrawer(cfg, "interaction", drawer);
|
|
2169
2422
|
}
|
|
2170
|
-
const stamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
2171
|
-
const facts = Array.isArray(parsed.facts) ? parsed.facts.filter((x) => typeof x === "string" && x.trim()).slice(0, 8) : [];
|
|
2172
|
-
if (facts.length) await appendMd(cfg.slug, "memory/facts.md", facts.map((f) => `- ${stamp}: ${f}`).join("\n") + "\n");
|
|
2173
|
-
if (typeof parsed.episode === "string" && parsed.episode.trim()) await appendMd(cfg.slug, `memory/episodes/${today(cfg.tz)}.md`, `- ${stamp}: ${parsed.episode.trim()}
|
|
2174
|
-
`);
|
|
2175
|
-
if (typeof parsed.promise === "string" && parsed.promise.trim()) await appendMd(cfg.slug, "time/promises.md", `- ${stamp}: ${parsed.promise.trim()}
|
|
2176
|
-
`);
|
|
2177
|
-
if (typeof parsed.openLoop === "string" && parsed.openLoop.trim()) await appendMd(cfg.slug, "time/open-loops.md", `- ${stamp}: ${parsed.openLoop.trim()}
|
|
2178
|
-
`);
|
|
2179
|
-
if (typeof parsed.timeline === "string" && parsed.timeline.trim()) await appendMd(cfg.slug, "relationship/timeline.md", `- ${stamp}: ${parsed.timeline.trim()}
|
|
2180
|
-
`);
|
|
2181
|
-
const uncertain = Array.isArray(parsed.uncertain) ? parsed.uncertain.filter((x) => typeof x === "string" && x.trim()).slice(0, 6) : [];
|
|
2182
|
-
if (uncertain.length) await appendMd(cfg.slug, "memory/uncertain.md", uncertain.map((f) => `- ${stamp}: ${f}`).join("\n") + "\n");
|
|
2183
2423
|
}
|
|
2184
|
-
async function
|
|
2185
|
-
if (previousStage === nextStage) return;
|
|
2424
|
+
async function mineDailyLogToPalace(llm, cfg, day) {
|
|
2186
2425
|
await ensureDefaults(cfg);
|
|
2187
|
-
await
|
|
2188
|
-
|
|
2426
|
+
const log = await readSessionLog(cfg.slug, day);
|
|
2427
|
+
if (!log.trim()) return 0;
|
|
2428
|
+
const chunks = splitTextByChars(log, 12e3);
|
|
2429
|
+
let total = 0;
|
|
2430
|
+
for (let i = 0; i < chunks.length; i++) {
|
|
2431
|
+
const raw = await llm.chat([
|
|
2432
|
+
{
|
|
2433
|
+
role: "system",
|
|
2434
|
+
content: `\u0422\u044B \u043C\u0430\u0439\u043D\u0438\u0448\u044C \u0434\u043D\u0435\u0432\u043D\u043E\u0439 \u043B\u043E\u0433 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0432 Memory Palace. \u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0439 \u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C \u0444\u0430\u043A\u0442\u043E\u0432 \u0438 \u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u043E\u043A \u0434\u043E\u0441\u043B\u043E\u0432\u043D\u043E. \u041D\u0435 \u0441\u0443\u043C\u043C\u0430\u0440\u0438\u0437\u0438\u0440\u0443\u0439 \u0432\u043C\u0435\u0441\u0442\u043E quote: quote \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C \u043E\u0440\u0438\u0433\u0438\u043D\u0430\u043B\u044C\u043D\u044B\u043C \u0444\u0440\u0430\u0433\u043C\u0435\u043D\u0442\u043E\u043C \u043B\u043E\u0433\u0430. \u041C\u043E\u0436\u043D\u043E \u043C\u043D\u043E\u0433\u043E drawers, \u043D\u043E \u043A\u0430\u0436\u0434\u044B\u0439 \u2014 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0439 \u0430\u0442\u043E\u043C \u043F\u0430\u043C\u044F\u0442\u0438.`
|
|
2435
|
+
},
|
|
2436
|
+
{
|
|
2437
|
+
role: "user",
|
|
2438
|
+
content: `\u0414\u0435\u043D\u044C: ${day}. \u041F\u0440\u043E\u0444\u0438\u043B\u044C: ${cfg.name}, \u0441\u0442\u0430\u0434\u0438\u044F ${cfg.stage}.
|
|
2439
|
+
\u0427\u0430\u0441\u0442\u044C ${i + 1}/${chunks.length}. \u041B\u043E\u0433:
|
|
2440
|
+
"""
|
|
2441
|
+
${chunks[i] ?? ""}
|
|
2442
|
+
"""
|
|
2443
|
+
|
|
2444
|
+
\u0412\u0435\u0440\u043D\u0438 STRICT JSON:
|
|
2445
|
+
{
|
|
2446
|
+
"drawers": [
|
|
2447
|
+
{
|
|
2448
|
+
"room": "\u0442\u0435\u043C\u0430",
|
|
2449
|
+
"hall": "hall_facts | hall_events | hall_discoveries | hall_preferences | hall_advice | hall_promises | hall_open_loops | hall_feelings | hall_uncertain",
|
|
2450
|
+
"quote": "\u0434\u043E\u0441\u043B\u043E\u0432\u043D\u044B\u0439 \u0444\u0440\u0430\u0433\u043C\u0435\u043D\u0442 \u043B\u043E\u0433\u0430 \u0431\u0435\u0437 \u043E\u0431\u0440\u0435\u0437\u043A\u0438 \u0432\u0430\u0436\u043D\u044B\u0445 \u0441\u043B\u043E\u0432",
|
|
2451
|
+
"keywords": ["\u043F\u043E\u0438\u0441\u043A"],
|
|
2452
|
+
"salience": 1-10
|
|
2453
|
+
}
|
|
2454
|
+
]
|
|
2455
|
+
}`
|
|
2456
|
+
}
|
|
2457
|
+
], { temperature: 0.1, maxTokens: 8e3, json: true });
|
|
2458
|
+
const parsed = parseJsonObject(raw);
|
|
2459
|
+
const drawers = parsedDrawers(parsed?.drawers).slice(0, 80);
|
|
2460
|
+
for (const drawer of drawers) {
|
|
2461
|
+
await appendDrawer(cfg, `log/${day}`, drawer);
|
|
2462
|
+
}
|
|
2463
|
+
total += drawers.length;
|
|
2464
|
+
}
|
|
2465
|
+
if (total) {
|
|
2466
|
+
await writeMd(cfg.slug, `memory/palace/.mined/${day}.txt`, nowStamp() + "\n");
|
|
2467
|
+
}
|
|
2468
|
+
return total;
|
|
2189
2469
|
}
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2470
|
+
function splitTextByChars(text, maxChars) {
|
|
2471
|
+
if (text.length <= maxChars) return [text];
|
|
2472
|
+
const chunks = [];
|
|
2473
|
+
let current = "";
|
|
2474
|
+
for (const line of text.split(/\r?\n/)) {
|
|
2475
|
+
if (current.length + line.length + 1 > maxChars && current) {
|
|
2476
|
+
chunks.push(current);
|
|
2477
|
+
current = "";
|
|
2478
|
+
}
|
|
2479
|
+
current += current ? `
|
|
2480
|
+
${line}` : line;
|
|
2481
|
+
}
|
|
2482
|
+
if (current) chunks.push(current);
|
|
2483
|
+
return chunks;
|
|
2484
|
+
}
|
|
2485
|
+
async function mineUnminedDailyLogs(llm, cfg, maxDays = 3) {
|
|
2486
|
+
const todayDay = today(cfg.tz);
|
|
2487
|
+
const days = (await listSessionDays(cfg.slug)).filter((day) => day !== todayDay).reverse();
|
|
2488
|
+
let mined = 0;
|
|
2489
|
+
let checked = 0;
|
|
2490
|
+
for (const day of days) {
|
|
2491
|
+
if (checked >= maxDays) break;
|
|
2492
|
+
const mark = await readMd(cfg.slug, `memory/palace/.mined/${day}.txt`);
|
|
2493
|
+
if (mark.trim()) continue;
|
|
2494
|
+
checked++;
|
|
2495
|
+
mined += await mineDailyLogToPalace(llm, cfg, day);
|
|
2496
|
+
}
|
|
2497
|
+
return mined;
|
|
2498
|
+
}
|
|
2499
|
+
async function migrateExistingMemoryToPalace(cfg) {
|
|
2500
|
+
await ensureDefaults(cfg);
|
|
2501
|
+
const existing = await listPalaceDrawers(cfg);
|
|
2502
|
+
if (existing.length) return 0;
|
|
2503
|
+
let made = 0;
|
|
2504
|
+
const wing = wingFor(cfg);
|
|
2505
|
+
const migrateLines = async (source, content, hall, room) => {
|
|
2506
|
+
const lines = content.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("- "));
|
|
2507
|
+
for (const line of lines) {
|
|
2508
|
+
const quote = line.replace(/^-\s*/, "").trim();
|
|
2509
|
+
if (!quote) continue;
|
|
2510
|
+
const drawer = {
|
|
2511
|
+
id: safeId(),
|
|
2512
|
+
ts: nowStamp(),
|
|
2513
|
+
wing,
|
|
2514
|
+
room: normalizeRoom(room),
|
|
2515
|
+
hall,
|
|
2516
|
+
source,
|
|
2517
|
+
quote,
|
|
2518
|
+
keywords: normalizeKeywords([], quote, room),
|
|
2519
|
+
salience: hall === "hall_uncertain" ? 4 : 6
|
|
2520
|
+
};
|
|
2521
|
+
await writeMd(cfg.slug, drawerPath(drawer), renderDrawer(drawer));
|
|
2522
|
+
made++;
|
|
2523
|
+
}
|
|
2524
|
+
};
|
|
2525
|
+
await migrateLines("memory/facts.md", await readMd(cfg.slug, "memory/facts.md"), "hall_facts", "facts");
|
|
2526
|
+
await migrateLines("memory/uncertain.md", await readMd(cfg.slug, "memory/uncertain.md"), "hall_uncertain", "uncertain");
|
|
2527
|
+
await migrateLines("time/promises.md", await readMd(cfg.slug, "time/promises.md"), "hall_promises", "promises");
|
|
2528
|
+
await migrateLines("time/open-loops.md", await readMd(cfg.slug, "time/open-loops.md"), "hall_open_loops", "open-loops");
|
|
2529
|
+
const dailyDays = await listDailySummaries(cfg.slug);
|
|
2530
|
+
for (const day of dailyDays.slice(-30)) {
|
|
2531
|
+
const summary = await readDailySummary(cfg.slug, day);
|
|
2532
|
+
if (summary.trim()) {
|
|
2533
|
+
const drawer = {
|
|
2534
|
+
id: safeId(),
|
|
2535
|
+
ts: nowStamp(),
|
|
2536
|
+
wing,
|
|
2537
|
+
room: normalizeRoom(day),
|
|
2538
|
+
hall: "hall_events",
|
|
2539
|
+
source: `memory/daily/${day}.md`,
|
|
2540
|
+
quote: summary.trim(),
|
|
2541
|
+
keywords: normalizeKeywords([day], summary, day),
|
|
2542
|
+
salience: 5
|
|
2543
|
+
};
|
|
2544
|
+
await writeMd(cfg.slug, drawerPath(drawer), renderDrawer(drawer));
|
|
2545
|
+
made++;
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
return made;
|
|
2549
|
+
}
|
|
2550
|
+
var DEFAULT_FACTS, DEFAULT_ATTACHMENT, DEFAULT_WEEKLY, DEFAULT_SOCIAL, DEFAULT_HABITS, HALLS, STOP_WORDS;
|
|
2551
|
+
var init_memory_palace = __esm({
|
|
2552
|
+
"src/engine/memory-palace.ts"() {
|
|
2193
2553
|
"use strict";
|
|
2194
2554
|
init_esm_shims();
|
|
2195
2555
|
init_md();
|
|
@@ -2220,6 +2580,74 @@ apologyStyle: awkward_short`;
|
|
|
2220
2580
|
- \u043A\u043E\u0433\u0434\u0430 \u0443\u0441\u0442\u0430\u043B\u0430, \u0447\u0438\u0442\u0430\u0435\u0442 \u0438 \u043E\u0442\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u0435\u0442 \u043E\u0442\u0432\u0435\u0442
|
|
2221
2581
|
- \u0440\u0435\u0434\u043A\u043E \u043E\u0431\u044A\u044F\u0441\u043D\u044F\u0435\u0442 \u043F\u043E\u0447\u0435\u043C\u0443 \u043F\u0440\u043E\u043F\u0430\u043B\u0430
|
|
2222
2582
|
- \u043C\u043E\u0436\u0435\u0442 \u0432\u0441\u043F\u043E\u043C\u043D\u0438\u0442\u044C \u043C\u0435\u043B\u043A\u0443\u044E \u0434\u0435\u0442\u0430\u043B\u044C \u0447\u0435\u0440\u0435\u0437 \u0434\u0435\u043D\u044C, \u0435\u0441\u043B\u0438 \u043E\u043D\u0430 \u044D\u043C\u043E\u0446\u0438\u043E\u043D\u0430\u043B\u044C\u043D\u043E \u0437\u0430\u0446\u0435\u043F\u0438\u043B\u0430`;
|
|
2583
|
+
HALLS = [
|
|
2584
|
+
"hall_facts",
|
|
2585
|
+
"hall_events",
|
|
2586
|
+
"hall_discoveries",
|
|
2587
|
+
"hall_preferences",
|
|
2588
|
+
"hall_advice",
|
|
2589
|
+
"hall_promises",
|
|
2590
|
+
"hall_open_loops",
|
|
2591
|
+
"hall_feelings",
|
|
2592
|
+
"hall_uncertain"
|
|
2593
|
+
];
|
|
2594
|
+
STOP_WORDS = /* @__PURE__ */ new Set([
|
|
2595
|
+
"\u044D\u0442\u043E",
|
|
2596
|
+
"\u043A\u0430\u043A",
|
|
2597
|
+
"\u0447\u0442\u043E",
|
|
2598
|
+
"\u0438\u043B\u0438",
|
|
2599
|
+
"\u0435\u0441\u043B\u0438",
|
|
2600
|
+
"\u043E\u043D\u0430",
|
|
2601
|
+
"\u043E\u043D\u0438",
|
|
2602
|
+
"\u0435\u0433\u043E",
|
|
2603
|
+
"\u0435\u043C\u0443",
|
|
2604
|
+
"\u0442\u0435\u0431\u044F",
|
|
2605
|
+
"\u0442\u0435\u0431\u0435",
|
|
2606
|
+
"\u043C\u0435\u043D\u044F",
|
|
2607
|
+
"\u043C\u043D\u0435",
|
|
2608
|
+
"\u0434\u043B\u044F",
|
|
2609
|
+
"\u043F\u0440\u043E",
|
|
2610
|
+
"\u043D\u0430\u0434",
|
|
2611
|
+
"\u043F\u043E\u0434",
|
|
2612
|
+
"\u043F\u0440\u0438",
|
|
2613
|
+
"\u0431\u0435\u0437",
|
|
2614
|
+
"\u0435\u0449\u0435",
|
|
2615
|
+
"\u0435\u0449\u0451",
|
|
2616
|
+
"\u0443\u0436\u0435",
|
|
2617
|
+
"\u0442\u0430\u043C",
|
|
2618
|
+
"\u0442\u0443\u0442",
|
|
2619
|
+
"\u0442\u043E\u0436\u0435",
|
|
2620
|
+
"\u043F\u043E\u0441\u043B\u0435",
|
|
2621
|
+
"\u0441\u0435\u0439\u0447\u0430\u0441",
|
|
2622
|
+
"\u0449\u0430\u0441",
|
|
2623
|
+
"\u043A\u043E\u0433\u0434\u0430",
|
|
2624
|
+
"\u043F\u043E\u0447\u0435\u043C\u0443",
|
|
2625
|
+
"\u043F\u043E\u0442\u043E\u043C\u0443",
|
|
2626
|
+
"\u043E\u0447\u0435\u043D\u044C",
|
|
2627
|
+
"\u043F\u0440\u043E\u0441\u0442\u043E",
|
|
2628
|
+
"\u0432\u043E\u043E\u0431\u0449\u0435",
|
|
2629
|
+
"\u043A\u043E\u0440\u043E\u0447\u0435",
|
|
2630
|
+
"\u0442\u0438\u043F\u0430"
|
|
2631
|
+
]);
|
|
2632
|
+
}
|
|
2633
|
+
});
|
|
2634
|
+
|
|
2635
|
+
// src/engine/realism.ts
|
|
2636
|
+
async function maybeAdvanceRelationshipTimeline(cfg, previousStage, nextStage) {
|
|
2637
|
+
if (previousStage === nextStage) return;
|
|
2638
|
+
await migrateExistingMemoryToPalace(cfg);
|
|
2639
|
+
await appendMd(cfg.slug, "relationship/timeline.md", `- ${(/* @__PURE__ */ new Date()).toISOString()}: \u0441\u0442\u0430\u0434\u0438\u044F \u0438\u0437\u043C\u0435\u043D\u0438\u043B\u0430\u0441\u044C ${previousStage} \u2192 ${nextStage}
|
|
2640
|
+
`);
|
|
2641
|
+
}
|
|
2642
|
+
var loadRealismContext, realismPromptFragment;
|
|
2643
|
+
var init_realism = __esm({
|
|
2644
|
+
"src/engine/realism.ts"() {
|
|
2645
|
+
"use strict";
|
|
2646
|
+
init_esm_shims();
|
|
2647
|
+
init_md();
|
|
2648
|
+
init_memory_palace();
|
|
2649
|
+
loadRealismContext = loadMemoryPalaceContext;
|
|
2650
|
+
realismPromptFragment = memoryPalacePromptFragment;
|
|
2223
2651
|
}
|
|
2224
2652
|
});
|
|
2225
2653
|
|
|
@@ -2509,8 +2937,8 @@ ${ignoreTendency}`,
|
|
|
2509
2937
|
`\u0421\u0442\u0430\u0434\u0438\u044F: ${stage.label}`,
|
|
2510
2938
|
`\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435 \u0441\u0442\u0430\u0434\u0438\u0438: ${stage.description}`,
|
|
2511
2939
|
`Score: ${JSON.stringify(rel.score)}`,
|
|
2512
|
-
longTerm ? `## long-term memory \u043E \u044E\u0437\u0435\u0440\u0435
|
|
2513
|
-
${longTerm}` : "",
|
|
2940
|
+
longTerm.trim() ? `## legacy long-term memory \u043E \u044E\u0437\u0435\u0440\u0435
|
|
2941
|
+
${longTerm.slice(-2200)}` : "",
|
|
2514
2942
|
recall
|
|
2515
2943
|
].filter(Boolean).join("\n\n");
|
|
2516
2944
|
}
|
|
@@ -3539,7 +3967,8 @@ autonomous:${dateKey} created=0`.trim() + "\n");
|
|
|
3539
3967
|
const rel = await readRelationship(cfg.slug);
|
|
3540
3968
|
const persona = (await readMd(cfg.slug, "persona.md")).slice(0, 900);
|
|
3541
3969
|
const speech = (await readMd(cfg.slug, "speech.md")).slice(0, 600);
|
|
3542
|
-
const
|
|
3970
|
+
const palace = await searchPalaceDrawers(cfg, history.slice(-8).map((m) => m.content).join("\n"), 8);
|
|
3971
|
+
const longTerm = palace.length ? palace.map((d) => `- [${d.ts.slice(0, 10)} ${d.hall}/${d.room}] ${d.quote}`).join("\n") : (await readMd(cfg.slug, "memory/long-term.md")).slice(-1200);
|
|
3543
3972
|
const histStr = history.slice(-16).map((m) => `${m.role === "user" ? "\u043E\u043D" : "\u043E\u043D\u0430"}: ${m.content}`).join("\n");
|
|
3544
3973
|
const stateBlock = [
|
|
3545
3974
|
`# \u0421\u0442\u0430\u0434\u0438\u044F: ${stage.label} (${cfg.stage})`,
|
|
@@ -3674,6 +4103,7 @@ var init_agenda = __esm({
|
|
|
3674
4103
|
init_md();
|
|
3675
4104
|
init_stages();
|
|
3676
4105
|
init_communication();
|
|
4106
|
+
init_memory_palace();
|
|
3677
4107
|
SYS_EXTRACT = `\u0422\u044B \u2014 \u043C\u043E\u0434\u0443\u043B\u044C \u0430\u0441\u0441\u0438\u0441\u0442\u0435\u043D\u0442\u0430-\u0434\u0435\u0432\u0443\u0448\u043A\u0438. \u0422\u0432\u043E\u044F \u0437\u0430\u0434\u0430\u0447\u0430: \u043F\u043E\u0441\u043B\u0435 \u043A\u0430\u0436\u0434\u043E\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u0430\u0440\u043D\u044F \u043F\u043E\u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C, \u043D\u0435 \u0443\u043F\u043E\u043C\u044F\u043D\u0443\u043B \u043B\u0438 \u043E\u043D \u0447\u0442\u043E-\u0442\u043E \u043F\u0440\u043E \u0441\u0432\u043E\u0451 \u0431\u0443\u0434\u0443\u0449\u0435\u0435 (\u043F\u043B\u0430\u043D\u044B, \u0441\u043E\u0431\u044B\u0442\u0438\u044F, \u0434\u0435\u043B\u0430, \u0434\u0435\u0434\u043B\u0430\u0439\u043D\u044B, \u0440\u0430\u0431\u043E\u0442\u0443, \u0441\u043E\u0440\u0435\u0432\u043D\u043E\u0432\u0430\u043D\u0438\u044F, \u044D\u043A\u0437\u0430\u043C\u0435\u043D\u044B, \u043F\u043E\u0435\u0437\u0434\u043A\u0438), \u043D\u0430 \u0447\u0442\u043E \u041E\u041D\u0410 \u0431\u044B \u043F\u0435\u0440\u0435\u0436\u0438\u0432\u0430\u043B\u0430 / \u0445\u043E\u0442\u0435\u043B\u0430 \u0443\u0437\u043D\u0430\u0442\u044C / \u043E\u0442\u043C\u0435\u0442\u0438\u043B\u0430 \u043F\u0440\u043E \u0441\u0435\u0431\u044F \u2014 \u043A\u0430\u043A \u0436\u0438\u0432\u043E\u0439 \u0447\u0435\u043B\u043E\u0432\u0435\u043A, \u043D\u0435 \u043A\u0430\u043B\u0435\u043D\u0434\u0430\u0440\u044C. \u0422\u0430\u043A\u0436\u0435 \u043F\u043E\u043D\u044F\u0442\u044C, \u0435\u0441\u0442\u044C \u043B\u0438 \u0443 \u041D\u0415\u0401 \u043F\u043E\u0432\u043E\u0434 \u043F\u0440\u043E\u0430\u043A\u0442\u0438\u0432\u043D\u043E \u043D\u0430\u043F\u0438\u0441\u0430\u0442\u044C \u0435\u043C\u0443 \u043F\u043E\u0437\u0436\u0435 (\u0431\u0435\u0437 \u044F\u0432\u043D\u043E\u0433\u043E \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u0430 \u043E\u0442 \u043D\u0435\u0433\u043E).
|
|
3678
4108
|
|
|
3679
4109
|
\u0412\u0410\u0416\u041D\u041E:
|
|
@@ -3832,6 +4262,7 @@ async function buildDailySummary(llm, cfg, day) {
|
|
|
3832
4262
|
const log = await readSessionLog(cfg.slug, day);
|
|
3833
4263
|
if (!log || log.length < 50) return null;
|
|
3834
4264
|
try {
|
|
4265
|
+
await mineDailyLogToPalace(llm, cfg, day).catch(() => 0);
|
|
3835
4266
|
const raw = await llm.chat([
|
|
3836
4267
|
{ role: "system", content: SYS3 },
|
|
3837
4268
|
{
|
|
@@ -3840,7 +4271,7 @@ async function buildDailySummary(llm, cfg, day) {
|
|
|
3840
4271
|
|
|
3841
4272
|
\u041B\u043E\u0433 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0437\u0430 \u0434\u0435\u043D\u044C:
|
|
3842
4273
|
"""
|
|
3843
|
-
${log.slice(
|
|
4274
|
+
${log.slice(-8e3)}
|
|
3844
4275
|
"""
|
|
3845
4276
|
|
|
3846
4277
|
\u0412\u0435\u0440\u043D\u0438 STRICT JSON:
|
|
@@ -3907,18 +4338,19 @@ var init_daily_summarizer = __esm({
|
|
|
3907
4338
|
"use strict";
|
|
3908
4339
|
init_esm_shims();
|
|
3909
4340
|
init_md();
|
|
4341
|
+
init_memory_palace();
|
|
3910
4342
|
SYS3 = `\u0422\u044B \u2014 \u0432\u043D\u0443\u0442\u0440\u0435\u043D\u043D\u0438\u0439 \u0434\u043D\u0435\u0432\u043D\u0438\u043A \u0434\u0435\u0432\u0443\u0448\u043A\u0438. \u041F\u043E \u0441\u044B\u0440\u043E\u043C\u0443 \u043B\u043E\u0433\u0443 \u0435\u0451 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0437\u0430 \u0434\u0435\u043D\u044C \u043D\u0430\u043F\u0438\u0448\u0438 \u041A\u0420\u0410\u0422\u041A\u0423\u042E \u0441\u0432\u043E\u0434\u043A\u0443 \u0434\u043B\u044F \u0434\u043E\u043B\u0433\u043E\u0441\u0440\u043E\u0447\u043D\u043E\u0439 \u043F\u0430\u043C\u044F\u0442\u0438. \u041E\u0442 \u043F\u0435\u0440\u0432\u043E\u0433\u043E \u043B\u0438\u0446\u0430, \u0432 \u0435\u0451 \u043C\u0430\u043D\u0435\u0440\u0435 (lowercase, \u0431\u0435\u0437 markdown). \u0427\u0442\u043E \u0431\u044B\u043B\u043E, \u0447\u0442\u043E \u043E\u0431\u0441\u0443\u0436\u0434\u0430\u043B\u0438, \u043A\u0430\u043A \u043E\u043D\u0430 \u0432 \u0438\u0442\u043E\u0433\u0435 \u0432\u043E\u0441\u043F\u0440\u0438\u043D\u044F\u043B\u0430 \u0435\u0433\u043E, \u043A\u0430\u043A\u0438\u0435 \u043F\u043E\u044F\u0432\u0438\u043B\u0438\u0441\u044C \u043D\u043E\u0432\u044B\u0435 \u0444\u0430\u043A\u0442\u044B \u043E \u043D\u0451\u043C, \u0431\u0435\u0441\u0438\u043B\u043E \u043B\u0438 \u0447\u0442\u043E-\u0442\u043E.`;
|
|
3911
4343
|
}
|
|
3912
4344
|
});
|
|
3913
4345
|
|
|
3914
4346
|
// src/engine/stickers.ts
|
|
3915
|
-
import { promises as
|
|
3916
|
-
import
|
|
4347
|
+
import { promises as fs5 } from "fs";
|
|
4348
|
+
import path6 from "path";
|
|
3917
4349
|
async function libraryPath(cfg) {
|
|
3918
4350
|
const rel = "stickers/library.md";
|
|
3919
4351
|
const current = await readMd(cfg.slug, rel);
|
|
3920
4352
|
if (!current.trim()) await writeMd(cfg.slug, rel, DEFAULT_LIBRARY);
|
|
3921
|
-
return
|
|
4353
|
+
return path6.join(profileDir(cfg.slug), rel);
|
|
3922
4354
|
}
|
|
3923
4355
|
async function listStickers(cfg) {
|
|
3924
4356
|
await libraryPath(cfg);
|
|
@@ -3938,8 +4370,8 @@ async function pickSticker(cfg, mood = "") {
|
|
|
3938
4370
|
}
|
|
3939
4371
|
async function addStickerToLibrary(cfg, fileId, emoji = "", tags = []) {
|
|
3940
4372
|
await libraryPath(cfg);
|
|
3941
|
-
const p =
|
|
3942
|
-
await
|
|
4373
|
+
const p = path6.join(profileDir(cfg.slug), "stickers/library.md");
|
|
4374
|
+
await fs5.appendFile(p, `${fileId} | ${emoji} | ${tags.join(",")}
|
|
3943
4375
|
`, "utf8");
|
|
3944
4376
|
}
|
|
3945
4377
|
var DEFAULT_LIBRARY;
|
|
@@ -4642,6 +5074,7 @@ var init_runtime = __esm({
|
|
|
4642
5074
|
init_conflict();
|
|
4643
5075
|
init_daily_summarizer();
|
|
4644
5076
|
init_realism();
|
|
5077
|
+
init_memory_palace();
|
|
4645
5078
|
init_media();
|
|
4646
5079
|
init_security();
|
|
4647
5080
|
init_stickers();
|
|
@@ -4839,7 +5272,7 @@ var init_runtime = __esm({
|
|
|
4839
5272
|
async historyFor(key, fromId, restore = false) {
|
|
4840
5273
|
const existing = this.histories.get(key);
|
|
4841
5274
|
if (existing) return existing;
|
|
4842
|
-
const restored = restore ? await readRecentSessionTurns(this.cfg.slug, this.cfg.tz, fromId,
|
|
5275
|
+
const restored = restore ? await readRecentSessionTurns(this.cfg.slug, this.cfg.tz, fromId, 80) : [];
|
|
4843
5276
|
const hist = restored.map((t) => ({ role: t.role, content: t.content, ts: t.ts }));
|
|
4844
5277
|
this.histories.set(key, hist);
|
|
4845
5278
|
this.hydratePresenceTrackers(key, hist);
|
|
@@ -5097,6 +5530,8 @@ ${m.text}` : media;
|
|
|
5097
5530
|
}
|
|
5098
5531
|
const made = await closeStaleSessions(this.llm, this.cfg);
|
|
5099
5532
|
if (made > 0) this.emit("event", { type: "info", text: `daily summaries: +${made}` });
|
|
5533
|
+
const mined = await mineUnminedDailyLogs(this.llm, this.cfg, 2).catch(() => 0);
|
|
5534
|
+
if (mined > 0) this.emit("event", { type: "info", text: `memory palace drawers: +${mined}` });
|
|
5100
5535
|
}
|
|
5101
5536
|
/**
|
|
5102
5537
|
* Issue #81 — периодически выставляет статус «онлайн» в Telegram
|
|
@@ -5343,6 +5778,8 @@ ${m.text}` : media;
|
|
|
5343
5778
|
}
|
|
5344
5779
|
this.emit("event", { type: "ignored", text: incomingText, reason: tick.ignoreReason ?? tick.intent });
|
|
5345
5780
|
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> ignored (${tick.intent}: ${tick.ignoreReason ?? ""})`);
|
|
5781
|
+
recordInteractionMemory(this.llm, this.cfg, incomingText).catch(() => {
|
|
5782
|
+
});
|
|
5346
5783
|
return;
|
|
5347
5784
|
}
|
|
5348
5785
|
let delaySec = tick.delaySec;
|
|
@@ -5382,7 +5819,7 @@ intent=${tick.intent}
|
|
|
5382
5819
|
\u043A\u043E\u043B-\u0432\u043E \u043F\u0443\u0437\u044B\u0440\u0435\u0439: ${tick.bubbles}${presenceHint ? `
|
|
5383
5820
|
\u0434\u043E\u0441\u0442\u0443\u043F\u043D\u043E\u0441\u0442\u044C: ${presenceHint}` : ""}
|
|
5384
5821
|
${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u0434\u043D\u043E\u0441\u043B\u043E\u0436\u043D\u043E: '\u043E\u043A', '\u044F\u0441\u043D\u043E', '\u0438?', '\u043D\u0443 \u043E\u043A'. \u0411\u0435\u0437 \u043E\u0431\u044A\u044F\u0441\u043D\u0435\u043D\u0438\u0439." : tick.bubbles > 1 ? "\u0420\u0430\u0437\u0431\u0435\u0439 \u043E\u0442\u0432\u0435\u0442 \u043D\u0430 \u043F\u0443\u0437\u044B\u0440\u0438 \u0421\u0422\u0420\u041E\u0413\u041E \u0441\u0442\u0440\u043E\u043A\u043E\u0439 '---' (\u0442\u0440\u0438 \u0434\u0435\u0444\u0438\u0441\u0430 \u043D\u0430 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0439 \u0441\u0442\u0440\u043E\u043A\u0435) \u043C\u0435\u0436\u0434\u0443 \u043D\u0438\u043C\u0438. \u041A\u0410\u0416\u0414\u042B\u0419 \u043F\u0443\u0437\u044B\u0440\u044C \u2014 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0432 \u0442\u0433. \u0417\u0410\u041F\u0420\u0415\u0429\u0415\u041D\u041E \u0440\u0430\u0441\u043A\u0438\u0434\u044B\u0432\u0430\u0442\u044C \u043E\u0434\u043D\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u043D\u0430 \u043D\u0435\u0441\u043A\u043E\u043B\u044C\u043A\u043E \u0441\u0442\u0440\u043E\u043A \u0447\u0435\u0440\u0435\u0437 \u043F\u0435\u0440\u0435\u043D\u043E\u0441 \u0441\u0442\u0440\u043E\u043A\u0438 \u0431\u0435\u0437 '---' \u2014 \u0432 \u0442\u0433 \u044D\u0442\u043E \u0432\u044B\u0433\u043B\u044F\u0434\u0438\u0442 \u043A\u0430\u043A \u043E\u0434\u043D\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0432 \u0441\u0442\u043E\u043B\u0431\u0438\u043A, \u0447\u0442\u043E \u043F\u0430\u043B\u0438\u0442 \u0418\u0418. \u041F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E:\\n\\n\u043F\u0440\u0438\u0432\u0435\u0442\\n---\\n\u043A\u0430\u043A \u0441\u0430\u043C\\n\\n\u041D\u0435\u043F\u0440\u0430\u0432\u0438\u043B\u044C\u043D\u043E:\\n\\n\u043F\u0440\u0438\u0432\u0435\u0442\\n\u043A\u0430\u043A \u0441\u0430\u043C" : "\u041E\u0434\u0438\u043D \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0439 \u043E\u0442\u0432\u0435\u0442, \u0431\u0435\u0437 '---'."}${scopeHint}` },
|
|
5385
|
-
...hist.slice(-
|
|
5822
|
+
...hist.slice(-60).map((t) => ({ role: t.role, content: t.content }))
|
|
5386
5823
|
];
|
|
5387
5824
|
const image = imagePartFromMedia(incoming?.media);
|
|
5388
5825
|
if (image) {
|
|
@@ -6250,22 +6687,41 @@ ${persona}`;
|
|
|
6250
6687
|
}
|
|
6251
6688
|
});
|
|
6252
6689
|
|
|
6690
|
+
// src/migrations/0114-memory-palace.ts
|
|
6691
|
+
var migration0114;
|
|
6692
|
+
var init_memory_palace2 = __esm({
|
|
6693
|
+
"src/migrations/0114-memory-palace.ts"() {
|
|
6694
|
+
"use strict";
|
|
6695
|
+
init_esm_shims();
|
|
6696
|
+
init_memory_palace();
|
|
6697
|
+
migration0114 = {
|
|
6698
|
+
id: "0114-memory-palace",
|
|
6699
|
+
description: "\u041F\u0435\u0440\u0435\u043D\u0435\u0441\u0442\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u0444\u0430\u0439\u043B\u044B \u043F\u0430\u043C\u044F\u0442\u0438 \u0432 \u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0443 Memory Palace",
|
|
6700
|
+
async migrate(ctx) {
|
|
6701
|
+
const made = await migrateExistingMemoryToPalace(ctx.config);
|
|
6702
|
+
if (made > 0) ctx.log(`memory palace drawers: +${made}`);
|
|
6703
|
+
return ctx.config;
|
|
6704
|
+
}
|
|
6705
|
+
};
|
|
6706
|
+
}
|
|
6707
|
+
});
|
|
6708
|
+
|
|
6253
6709
|
// src/migrations/index.ts
|
|
6254
|
-
import { promises as
|
|
6255
|
-
import
|
|
6710
|
+
import { promises as fs6 } from "fs";
|
|
6711
|
+
import path7 from "path";
|
|
6256
6712
|
import { readFileSync } from "fs";
|
|
6257
6713
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6258
6714
|
async function readMigrationState() {
|
|
6259
6715
|
try {
|
|
6260
|
-
const raw = await
|
|
6716
|
+
const raw = await fs6.readFile(MIGRATIONS_FILE(), "utf8");
|
|
6261
6717
|
return JSON.parse(raw);
|
|
6262
6718
|
} catch {
|
|
6263
6719
|
return { appliedMigrations: [], lastRunVersion: "0.0.0", lastRunAt: "" };
|
|
6264
6720
|
}
|
|
6265
6721
|
}
|
|
6266
6722
|
async function writeMigrationState(state) {
|
|
6267
|
-
await
|
|
6268
|
-
await
|
|
6723
|
+
await fs6.mkdir(DATA_ROOT, { recursive: true });
|
|
6724
|
+
await fs6.writeFile(MIGRATIONS_FILE(), JSON.stringify(state, null, 2), "utf8");
|
|
6269
6725
|
}
|
|
6270
6726
|
async function pendingMigrations() {
|
|
6271
6727
|
const state = await readMigrationState();
|
|
@@ -6358,15 +6814,15 @@ function formatUpdateWarnings(warnings) {
|
|
|
6358
6814
|
function currentVersion() {
|
|
6359
6815
|
try {
|
|
6360
6816
|
const here = fileURLToPath3(import.meta.url);
|
|
6361
|
-
let dir =
|
|
6817
|
+
let dir = path7.dirname(here);
|
|
6362
6818
|
for (let i = 0; i < 5; i++) {
|
|
6363
|
-
const candidate =
|
|
6819
|
+
const candidate = path7.join(dir, "package.json");
|
|
6364
6820
|
try {
|
|
6365
6821
|
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
6366
6822
|
if (pkg.name === "@thesashadev/girl-agent" && pkg.version) return pkg.version;
|
|
6367
6823
|
} catch {
|
|
6368
6824
|
}
|
|
6369
|
-
dir =
|
|
6825
|
+
dir = path7.dirname(dir);
|
|
6370
6826
|
}
|
|
6371
6827
|
return "unknown";
|
|
6372
6828
|
} catch {
|
|
@@ -6381,10 +6837,12 @@ var init_migrations = __esm({
|
|
|
6381
6837
|
init_md();
|
|
6382
6838
|
init_add_use_wss_default();
|
|
6383
6839
|
init_ensure_communication_md();
|
|
6384
|
-
|
|
6840
|
+
init_memory_palace2();
|
|
6841
|
+
MIGRATIONS_FILE = () => path7.join(DATA_ROOT, ".migrations.json");
|
|
6385
6842
|
ALL_MIGRATIONS = [
|
|
6386
6843
|
migration0112,
|
|
6387
|
-
migration0113
|
|
6844
|
+
migration0113,
|
|
6845
|
+
migration0114
|
|
6388
6846
|
];
|
|
6389
6847
|
}
|
|
6390
6848
|
});
|
|
@@ -6542,23 +7000,23 @@ __export(addons_exports, {
|
|
|
6542
7000
|
updateSettings: () => updateSettings,
|
|
6543
7001
|
validateManifest: () => validateManifest
|
|
6544
7002
|
});
|
|
6545
|
-
import { promises as
|
|
6546
|
-
import
|
|
7003
|
+
import { promises as fs9 } from "fs";
|
|
7004
|
+
import path10 from "path";
|
|
6547
7005
|
import os3 from "os";
|
|
6548
7006
|
import { execFile } from "child_process";
|
|
6549
7007
|
import { promisify } from "util";
|
|
6550
7008
|
function addonsDir() {
|
|
6551
|
-
const root = process.env.GIRL_AGENT_DATA ?
|
|
6552
|
-
return
|
|
7009
|
+
const root = process.env.GIRL_AGENT_DATA ? path10.resolve(process.env.GIRL_AGENT_DATA, "..") : path10.join(os3.homedir(), ".local", "share", "girl-agent");
|
|
7010
|
+
return path10.join(root, "addons");
|
|
6553
7011
|
}
|
|
6554
7012
|
async function ensureDir() {
|
|
6555
7013
|
const dir = addonsDir();
|
|
6556
|
-
await
|
|
7014
|
+
await fs9.mkdir(dir, { recursive: true });
|
|
6557
7015
|
return dir;
|
|
6558
7016
|
}
|
|
6559
7017
|
async function readJsonOrEmpty(p, fallback) {
|
|
6560
7018
|
try {
|
|
6561
|
-
const raw = await
|
|
7019
|
+
const raw = await fs9.readFile(p, "utf8");
|
|
6562
7020
|
return JSON.parse(raw);
|
|
6563
7021
|
} catch {
|
|
6564
7022
|
return fallback;
|
|
@@ -6566,12 +7024,12 @@ async function readJsonOrEmpty(p, fallback) {
|
|
|
6566
7024
|
}
|
|
6567
7025
|
async function listInstalled() {
|
|
6568
7026
|
const dir = await ensureDir();
|
|
6569
|
-
const indexPath =
|
|
7027
|
+
const indexPath = path10.join(dir, "installed.json");
|
|
6570
7028
|
return await readJsonOrEmpty(indexPath, []);
|
|
6571
7029
|
}
|
|
6572
7030
|
async function writeInstalled(list) {
|
|
6573
7031
|
const dir = await ensureDir();
|
|
6574
|
-
await
|
|
7032
|
+
await fs9.writeFile(path10.join(dir, "installed.json"), JSON.stringify(list, null, 2), "utf8");
|
|
6575
7033
|
}
|
|
6576
7034
|
async function fetchRegistry() {
|
|
6577
7035
|
try {
|
|
@@ -6585,17 +7043,17 @@ async function fetchRegistry() {
|
|
|
6585
7043
|
}
|
|
6586
7044
|
}
|
|
6587
7045
|
async function unpackGaa(gaaPath) {
|
|
6588
|
-
const tmpDir =
|
|
6589
|
-
await
|
|
7046
|
+
const tmpDir = path10.join(os3.tmpdir(), `gaa-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
7047
|
+
await fs9.mkdir(tmpDir, { recursive: true });
|
|
6590
7048
|
await execFileAsync("unzip", ["-o", "-q", gaaPath, "-d", tmpDir]);
|
|
6591
|
-
const entries = await
|
|
7049
|
+
const entries = await fs9.readdir(tmpDir);
|
|
6592
7050
|
if (entries.length === 1) {
|
|
6593
|
-
const sub =
|
|
6594
|
-
const st = await
|
|
7051
|
+
const sub = path10.join(tmpDir, entries[0]);
|
|
7052
|
+
const st = await fs9.stat(sub);
|
|
6595
7053
|
if (st.isDirectory()) {
|
|
6596
|
-
const innerManifest =
|
|
7054
|
+
const innerManifest = path10.join(sub, "manifest.json");
|
|
6597
7055
|
try {
|
|
6598
|
-
await
|
|
7056
|
+
await fs9.access(innerManifest);
|
|
6599
7057
|
return sub;
|
|
6600
7058
|
} catch {
|
|
6601
7059
|
}
|
|
@@ -6604,34 +7062,34 @@ async function unpackGaa(gaaPath) {
|
|
|
6604
7062
|
return tmpDir;
|
|
6605
7063
|
}
|
|
6606
7064
|
async function packGaa(addonDir, outputPath) {
|
|
6607
|
-
const manifestPath =
|
|
6608
|
-
const manifestRaw = await
|
|
7065
|
+
const manifestPath = path10.join(addonDir, "manifest.json");
|
|
7066
|
+
const manifestRaw = await fs9.readFile(manifestPath, "utf8");
|
|
6609
7067
|
const manifest = JSON.parse(manifestRaw);
|
|
6610
7068
|
validateManifest(manifest);
|
|
6611
|
-
const out = outputPath ??
|
|
7069
|
+
const out = outputPath ?? path10.join(process.cwd(), `${manifest.id}.gaa`);
|
|
6612
7070
|
try {
|
|
6613
|
-
await
|
|
7071
|
+
await fs9.unlink(out);
|
|
6614
7072
|
} catch {
|
|
6615
7073
|
}
|
|
6616
|
-
const dirName =
|
|
6617
|
-
const parentDir =
|
|
7074
|
+
const dirName = path10.basename(addonDir);
|
|
7075
|
+
const parentDir = path10.dirname(addonDir);
|
|
6618
7076
|
await execFileAsync("zip", ["-r", "-q", out, dirName], { cwd: parentDir });
|
|
6619
7077
|
return out;
|
|
6620
7078
|
}
|
|
6621
7079
|
async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
6622
|
-
const manifestPath =
|
|
6623
|
-
const manifestRaw = await
|
|
7080
|
+
const manifestPath = path10.join(addonDir, "manifest.json");
|
|
7081
|
+
const manifestRaw = await fs9.readFile(manifestPath, "utf8");
|
|
6624
7082
|
const manifest = JSON.parse(manifestRaw);
|
|
6625
7083
|
validateManifest(manifest);
|
|
6626
7084
|
const applied = [];
|
|
6627
7085
|
const installedFiles = [];
|
|
6628
|
-
const filesDir =
|
|
7086
|
+
const filesDir = path10.join(addonDir, "files");
|
|
6629
7087
|
try {
|
|
6630
|
-
const fileStat = await
|
|
7088
|
+
const fileStat = await fs9.stat(filesDir);
|
|
6631
7089
|
if (fileStat.isDirectory() && profileSlug) {
|
|
6632
7090
|
const fileEntries = await walkDir(filesDir);
|
|
6633
7091
|
for (const relPath of fileEntries) {
|
|
6634
|
-
const content = await
|
|
7092
|
+
const content = await fs9.readFile(path10.join(filesDir, relPath), "utf8");
|
|
6635
7093
|
await writeMd(profileSlug, relPath, content);
|
|
6636
7094
|
installedFiles.push(relPath);
|
|
6637
7095
|
}
|
|
@@ -6639,9 +7097,9 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
6639
7097
|
}
|
|
6640
7098
|
} catch {
|
|
6641
7099
|
}
|
|
6642
|
-
const patchPath =
|
|
7100
|
+
const patchPath = path10.join(addonDir, "config.patch.json");
|
|
6643
7101
|
try {
|
|
6644
|
-
const patchRaw = await
|
|
7102
|
+
const patchRaw = await fs9.readFile(patchPath, "utf8");
|
|
6645
7103
|
const patch = JSON.parse(patchRaw);
|
|
6646
7104
|
if (profileSlug) {
|
|
6647
7105
|
const cfg = await readConfig(profileSlug);
|
|
@@ -6653,11 +7111,11 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
6653
7111
|
}
|
|
6654
7112
|
} catch {
|
|
6655
7113
|
}
|
|
6656
|
-
const codePatchPath =
|
|
7114
|
+
const codePatchPath = path10.join(addonDir, "code.patch");
|
|
6657
7115
|
try {
|
|
6658
|
-
const patchContent = await
|
|
7116
|
+
const patchContent = await fs9.readFile(codePatchPath, "utf8");
|
|
6659
7117
|
if (patchContent.trim()) {
|
|
6660
|
-
const projectRoot =
|
|
7118
|
+
const projectRoot = path10.resolve(import.meta.url.replace("file://", ""), "../../../");
|
|
6661
7119
|
try {
|
|
6662
7120
|
await execFileAsync("git", ["apply", "--check", codePatchPath], { cwd: projectRoot });
|
|
6663
7121
|
await execFileAsync("git", ["apply", codePatchPath], { cwd: projectRoot });
|
|
@@ -6668,25 +7126,25 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
6668
7126
|
}
|
|
6669
7127
|
} catch {
|
|
6670
7128
|
}
|
|
6671
|
-
const themePath =
|
|
7129
|
+
const themePath = path10.join(addonDir, "theme.css");
|
|
6672
7130
|
try {
|
|
6673
|
-
const css = await
|
|
7131
|
+
const css = await fs9.readFile(themePath, "utf8");
|
|
6674
7132
|
const dir2 = await ensureDir();
|
|
6675
|
-
await
|
|
7133
|
+
await fs9.writeFile(path10.join(dir2, `theme-${manifest.id}.css`), css, "utf8");
|
|
6676
7134
|
applied.push("\u0442\u0435\u043C\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430");
|
|
6677
7135
|
} catch {
|
|
6678
7136
|
}
|
|
6679
7137
|
const dir = await ensureDir();
|
|
6680
|
-
const addonStorePath =
|
|
6681
|
-
await
|
|
6682
|
-
await
|
|
7138
|
+
const addonStorePath = path10.join(dir, manifest.id);
|
|
7139
|
+
await fs9.mkdir(addonStorePath, { recursive: true });
|
|
7140
|
+
await fs9.copyFile(manifestPath, path10.join(addonStorePath, "manifest.json"));
|
|
6683
7141
|
const allFiles = await walkDir(addonDir);
|
|
6684
7142
|
for (const f of allFiles) {
|
|
6685
7143
|
if (f === "manifest.json") continue;
|
|
6686
|
-
const src =
|
|
6687
|
-
const dst =
|
|
6688
|
-
await
|
|
6689
|
-
await
|
|
7144
|
+
const src = path10.join(addonDir, f);
|
|
7145
|
+
const dst = path10.join(addonStorePath, f);
|
|
7146
|
+
await fs9.mkdir(path10.dirname(dst), { recursive: true });
|
|
7147
|
+
await fs9.copyFile(src, dst);
|
|
6690
7148
|
}
|
|
6691
7149
|
const list = await listInstalled();
|
|
6692
7150
|
const item = {
|
|
@@ -6707,7 +7165,7 @@ async function installFromGaa(gaaPath, profileSlug) {
|
|
|
6707
7165
|
try {
|
|
6708
7166
|
return await installFromDir(dir, profileSlug, "file");
|
|
6709
7167
|
} finally {
|
|
6710
|
-
await
|
|
7168
|
+
await fs9.rm(dir, { recursive: true, force: true }).catch(() => {
|
|
6711
7169
|
});
|
|
6712
7170
|
}
|
|
6713
7171
|
}
|
|
@@ -6730,12 +7188,12 @@ async function installFromRegistry(id, registryManifest, profileSlug) {
|
|
|
6730
7188
|
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
6731
7189
|
if (!res.ok) throw new Error(`\u041D\u0435 \u0443\u0434\u0430\u043B\u043E\u0441\u044C \u0441\u043A\u0430\u0447\u0430\u0442\u044C \u0430\u0434\u0434\u043E\u043D: HTTP ${res.status}`);
|
|
6732
7190
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
6733
|
-
const tmpGaa =
|
|
6734
|
-
await
|
|
7191
|
+
const tmpGaa = path10.join(os3.tmpdir(), `${id}-${Date.now()}.gaa`);
|
|
7192
|
+
await fs9.writeFile(tmpGaa, buf);
|
|
6735
7193
|
try {
|
|
6736
7194
|
return await installFromGaa(tmpGaa, profileSlug);
|
|
6737
7195
|
} finally {
|
|
6738
|
-
await
|
|
7196
|
+
await fs9.unlink(tmpGaa).catch(() => {
|
|
6739
7197
|
});
|
|
6740
7198
|
}
|
|
6741
7199
|
}
|
|
@@ -6744,11 +7202,11 @@ async function uninstall(id) {
|
|
|
6744
7202
|
const next = list.filter((a) => a.manifest.id !== id);
|
|
6745
7203
|
if (next.length === list.length) return false;
|
|
6746
7204
|
const dir = addonsDir();
|
|
6747
|
-
const addonStore =
|
|
6748
|
-
await
|
|
7205
|
+
const addonStore = path10.join(dir, id);
|
|
7206
|
+
await fs9.rm(addonStore, { recursive: true, force: true }).catch(() => {
|
|
6749
7207
|
});
|
|
6750
|
-
const themePath =
|
|
6751
|
-
await
|
|
7208
|
+
const themePath = path10.join(dir, `theme-${id}.css`);
|
|
7209
|
+
await fs9.unlink(themePath).catch(() => {
|
|
6752
7210
|
});
|
|
6753
7211
|
await writeInstalled(next);
|
|
6754
7212
|
return true;
|
|
@@ -6779,11 +7237,11 @@ function validateManifest(m) {
|
|
|
6779
7237
|
}
|
|
6780
7238
|
async function walkDir(dir, prefix = "") {
|
|
6781
7239
|
const result = [];
|
|
6782
|
-
const entries = await
|
|
7240
|
+
const entries = await fs9.readdir(dir, { withFileTypes: true });
|
|
6783
7241
|
for (const e of entries) {
|
|
6784
7242
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
6785
7243
|
if (e.isDirectory()) {
|
|
6786
|
-
result.push(...await walkDir(
|
|
7244
|
+
result.push(...await walkDir(path10.join(dir, e.name), rel));
|
|
6787
7245
|
} else {
|
|
6788
7246
|
result.push(rel);
|
|
6789
7247
|
}
|
|
@@ -6803,16 +7261,16 @@ function deepMerge(target, source) {
|
|
|
6803
7261
|
}
|
|
6804
7262
|
async function getAddonReadme(id) {
|
|
6805
7263
|
const dir = addonsDir();
|
|
6806
|
-
const readmePath =
|
|
7264
|
+
const readmePath = path10.join(dir, id, "README.md");
|
|
6807
7265
|
try {
|
|
6808
|
-
return await
|
|
7266
|
+
return await fs9.readFile(readmePath, "utf8");
|
|
6809
7267
|
} catch {
|
|
6810
7268
|
return null;
|
|
6811
7269
|
}
|
|
6812
7270
|
}
|
|
6813
7271
|
async function getAddonFiles(id) {
|
|
6814
7272
|
const dir = addonsDir();
|
|
6815
|
-
const addonDir =
|
|
7273
|
+
const addonDir = path10.join(dir, id);
|
|
6816
7274
|
try {
|
|
6817
7275
|
return await walkDir(addonDir);
|
|
6818
7276
|
} catch {
|
|
@@ -6855,9 +7313,9 @@ var HttpError = class extends Error {
|
|
|
6855
7313
|
};
|
|
6856
7314
|
var Router = class {
|
|
6857
7315
|
routes = [];
|
|
6858
|
-
add(method,
|
|
7316
|
+
add(method, path13, handler) {
|
|
6859
7317
|
const paramNames = [];
|
|
6860
|
-
const parts =
|
|
7318
|
+
const parts = path13.split("/").map((part) => {
|
|
6861
7319
|
if (part.startsWith(":")) {
|
|
6862
7320
|
paramNames.push(part.slice(1));
|
|
6863
7321
|
return "([^/]+)";
|
|
@@ -6872,20 +7330,20 @@ var Router = class {
|
|
|
6872
7330
|
handler
|
|
6873
7331
|
});
|
|
6874
7332
|
}
|
|
6875
|
-
get(
|
|
6876
|
-
this.add("GET",
|
|
7333
|
+
get(path13, h) {
|
|
7334
|
+
this.add("GET", path13, h);
|
|
6877
7335
|
}
|
|
6878
|
-
post(
|
|
6879
|
-
this.add("POST",
|
|
7336
|
+
post(path13, h) {
|
|
7337
|
+
this.add("POST", path13, h);
|
|
6880
7338
|
}
|
|
6881
|
-
put(
|
|
6882
|
-
this.add("PUT",
|
|
7339
|
+
put(path13, h) {
|
|
7340
|
+
this.add("PUT", path13, h);
|
|
6883
7341
|
}
|
|
6884
|
-
delete(
|
|
6885
|
-
this.add("DELETE",
|
|
7342
|
+
delete(path13, h) {
|
|
7343
|
+
this.add("DELETE", path13, h);
|
|
6886
7344
|
}
|
|
6887
|
-
patch(
|
|
6888
|
-
this.add("PATCH",
|
|
7345
|
+
patch(path13, h) {
|
|
7346
|
+
this.add("PATCH", path13, h);
|
|
6889
7347
|
}
|
|
6890
7348
|
match(method, pathname) {
|
|
6891
7349
|
for (const r of this.routes) {
|
|
@@ -7377,25 +7835,31 @@ function fallbackBusySchedule(name, age) {
|
|
|
7377
7835
|
init_llm();
|
|
7378
7836
|
init_llm_update();
|
|
7379
7837
|
init_llm2();
|
|
7380
|
-
import { promises as
|
|
7381
|
-
import
|
|
7838
|
+
import { promises as fs7 } from "fs";
|
|
7839
|
+
import path8 from "path";
|
|
7382
7840
|
var MEMORY_FILES = [
|
|
7383
7841
|
"persona.md",
|
|
7384
7842
|
"speech.md",
|
|
7385
7843
|
"boundaries.md",
|
|
7386
7844
|
"communication.md",
|
|
7387
7845
|
"long-term.md",
|
|
7388
|
-
"memory/long-term.md"
|
|
7846
|
+
"memory/long-term.md",
|
|
7847
|
+
"memory/facts.md",
|
|
7848
|
+
"memory/uncertain.md",
|
|
7849
|
+
"relationship/timeline.md",
|
|
7850
|
+
"time/open-loops.md",
|
|
7851
|
+
"time/promises.md"
|
|
7389
7852
|
];
|
|
7390
7853
|
function isAllowedMemoryPath(p) {
|
|
7391
7854
|
if (!p || typeof p !== "string") return false;
|
|
7392
7855
|
if (p.includes("..")) return false;
|
|
7393
|
-
if (
|
|
7856
|
+
if (path8.isAbsolute(p)) return false;
|
|
7394
7857
|
if (p.startsWith("config.json")) return false;
|
|
7395
7858
|
if (p.startsWith("agenda.json")) return false;
|
|
7396
7859
|
if (MEMORY_FILES.includes(p)) return true;
|
|
7397
7860
|
if (/^memory\/daily\/\d{4}-\d{2}-\d{2}\.md$/.test(p)) return true;
|
|
7398
7861
|
if (/^memory\/episodes\/[\w\-]{1,80}\.md$/.test(p)) return true;
|
|
7862
|
+
if (/^memory\/palace\/[\w\-]{1,80}\/[\w\-]{1,80}\/[\w\-]{1,80}\/[\w\-]{1,120}\.md$/.test(p)) return true;
|
|
7399
7863
|
if (/^log\/\d{4}-\d{2}-\d{2}\.md$/.test(p)) return true;
|
|
7400
7864
|
return false;
|
|
7401
7865
|
}
|
|
@@ -7565,20 +8029,40 @@ function registerProfileRoutes(r) {
|
|
|
7565
8029
|
const entries = [];
|
|
7566
8030
|
for (const f of MEMORY_FILES) entries.push({ rel: f });
|
|
7567
8031
|
try {
|
|
7568
|
-
const dailyDir =
|
|
7569
|
-
const list = await
|
|
8032
|
+
const dailyDir = path8.join(dir, "memory", "daily");
|
|
8033
|
+
const list = await fs7.readdir(dailyDir);
|
|
7570
8034
|
for (const f of list) if (/^\d{4}-\d{2}-\d{2}\.md$/.test(f)) entries.push({ rel: `memory/daily/${f}` });
|
|
7571
8035
|
} catch {
|
|
7572
8036
|
}
|
|
7573
8037
|
try {
|
|
7574
|
-
const epDir =
|
|
7575
|
-
const list = await
|
|
8038
|
+
const epDir = path8.join(dir, "memory", "episodes");
|
|
8039
|
+
const list = await fs7.readdir(epDir);
|
|
7576
8040
|
for (const f of list) if (/^[\w\-]{1,80}\.md$/.test(f)) entries.push({ rel: `memory/episodes/${f}` });
|
|
7577
8041
|
} catch {
|
|
7578
8042
|
}
|
|
8043
|
+
try {
|
|
8044
|
+
const palaceDir = path8.join(dir, "memory", "palace");
|
|
8045
|
+
const wings = await fs7.readdir(palaceDir, { withFileTypes: true });
|
|
8046
|
+
for (const wing of wings) {
|
|
8047
|
+
if (!wing.isDirectory() || !/^[\w\-]{1,80}$/.test(wing.name)) continue;
|
|
8048
|
+
const halls = await fs7.readdir(path8.join(palaceDir, wing.name), { withFileTypes: true });
|
|
8049
|
+
for (const hall of halls) {
|
|
8050
|
+
if (!hall.isDirectory() || !/^[\w\-]{1,80}$/.test(hall.name)) continue;
|
|
8051
|
+
const rooms = await fs7.readdir(path8.join(palaceDir, wing.name, hall.name), { withFileTypes: true });
|
|
8052
|
+
for (const room of rooms) {
|
|
8053
|
+
if (!room.isDirectory() || !/^[\w\-]{1,80}$/.test(room.name)) continue;
|
|
8054
|
+
const drawers = await fs7.readdir(path8.join(palaceDir, wing.name, hall.name, room.name));
|
|
8055
|
+
for (const drawer of drawers) {
|
|
8056
|
+
if (/^[\w\-]{1,120}\.md$/.test(drawer)) entries.push({ rel: `memory/palace/${wing.name}/${hall.name}/${room.name}/${drawer}` });
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
8059
|
+
}
|
|
8060
|
+
}
|
|
8061
|
+
} catch {
|
|
8062
|
+
}
|
|
7579
8063
|
for (const e of entries) {
|
|
7580
8064
|
try {
|
|
7581
|
-
const stat = await
|
|
8065
|
+
const stat = await fs7.stat(path8.join(dir, e.rel));
|
|
7582
8066
|
items.push({ path: e.rel, size: stat.size, mtime: stat.mtimeMs });
|
|
7583
8067
|
} catch {
|
|
7584
8068
|
}
|
|
@@ -7947,9 +8431,9 @@ function registerPresetRoutes(r) {
|
|
|
7947
8431
|
// src/webui/routes/system.ts
|
|
7948
8432
|
init_esm_shims();
|
|
7949
8433
|
init_md();
|
|
7950
|
-
import { promises as
|
|
8434
|
+
import { promises as fs8 } from "fs";
|
|
7951
8435
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
7952
|
-
import
|
|
8436
|
+
import path9 from "path";
|
|
7953
8437
|
import os2 from "os";
|
|
7954
8438
|
var cachedVersion = null;
|
|
7955
8439
|
async function readPackageVersion() {
|
|
@@ -7957,15 +8441,15 @@ async function readPackageVersion() {
|
|
|
7957
8441
|
const candidates = [];
|
|
7958
8442
|
try {
|
|
7959
8443
|
const here = fileURLToPath4(import.meta.url);
|
|
7960
|
-
candidates.push(
|
|
7961
|
-
candidates.push(
|
|
7962
|
-
candidates.push(
|
|
8444
|
+
candidates.push(path9.resolve(path9.dirname(here), "..", "package.json"));
|
|
8445
|
+
candidates.push(path9.resolve(path9.dirname(here), "..", "..", "package.json"));
|
|
8446
|
+
candidates.push(path9.resolve(path9.dirname(here), "..", "..", "..", "package.json"));
|
|
7963
8447
|
} catch {
|
|
7964
8448
|
}
|
|
7965
|
-
candidates.push(
|
|
8449
|
+
candidates.push(path9.resolve(process.cwd(), "package.json"));
|
|
7966
8450
|
for (const c of candidates) {
|
|
7967
8451
|
try {
|
|
7968
|
-
const raw = await
|
|
8452
|
+
const raw = await fs8.readFile(c, "utf8");
|
|
7969
8453
|
const parsed = JSON.parse(raw);
|
|
7970
8454
|
if (parsed.name === "@thesashadev/girl-agent" && parsed.version) {
|
|
7971
8455
|
cachedVersion = parsed.version;
|
|
@@ -8016,8 +8500,8 @@ function registerSystemRoutes(r) {
|
|
|
8016
8500
|
// src/webui/routes/addons.ts
|
|
8017
8501
|
init_esm_shims();
|
|
8018
8502
|
init_addons();
|
|
8019
|
-
import { promises as
|
|
8020
|
-
import
|
|
8503
|
+
import { promises as fs10 } from "fs";
|
|
8504
|
+
import path11 from "path";
|
|
8021
8505
|
import os4 from "os";
|
|
8022
8506
|
function registerAddonRoutes(r) {
|
|
8023
8507
|
r.get("/api/addons", async () => {
|
|
@@ -8044,13 +8528,13 @@ function registerAddonRoutes(r) {
|
|
|
8044
8528
|
const data = body;
|
|
8045
8529
|
if (!data?.gaaBase64) throw new HttpError(400, "gaaBase64 required");
|
|
8046
8530
|
const buf = Buffer.from(data.gaaBase64, "base64");
|
|
8047
|
-
const tmpPath =
|
|
8048
|
-
await
|
|
8531
|
+
const tmpPath = path11.join(os4.tmpdir(), `upload-${Date.now()}.gaa`);
|
|
8532
|
+
await fs10.writeFile(tmpPath, buf);
|
|
8049
8533
|
try {
|
|
8050
8534
|
const result = await installFromGaa(tmpPath, data.profileSlug);
|
|
8051
8535
|
return { ok: true, installed: result.addon, applied: result.applied };
|
|
8052
8536
|
} finally {
|
|
8053
|
-
await
|
|
8537
|
+
await fs10.unlink(tmpPath).catch(() => {
|
|
8054
8538
|
});
|
|
8055
8539
|
}
|
|
8056
8540
|
});
|
|
@@ -8062,13 +8546,13 @@ function registerAddonRoutes(r) {
|
|
|
8062
8546
|
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
8063
8547
|
if (!res.ok) throw new HttpError(502, `fetch failed: HTTP ${res.status}`);
|
|
8064
8548
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
8065
|
-
const tmpPath =
|
|
8066
|
-
await
|
|
8549
|
+
const tmpPath = path11.join(os4.tmpdir(), `url-${Date.now()}.gaa`);
|
|
8550
|
+
await fs10.writeFile(tmpPath, buf);
|
|
8067
8551
|
try {
|
|
8068
8552
|
const result = await installFromGaa(tmpPath, data.profileSlug);
|
|
8069
8553
|
return { ok: true, installed: result.addon, applied: result.applied };
|
|
8070
8554
|
} finally {
|
|
8071
|
-
await
|
|
8555
|
+
await fs10.unlink(tmpPath).catch(() => {
|
|
8072
8556
|
});
|
|
8073
8557
|
}
|
|
8074
8558
|
} else {
|
|
@@ -8145,7 +8629,7 @@ var ASSISTANT_SYSTEM = `\u0422\u044B \u2014 \u0432\u0441\u0442\u0440\u043E\u0435
|
|
|
8145
8629
|
- set_stage { stage: string } \u2014 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u0438\u0442\u044C \u0441\u0442\u0430\u0434\u0438\u044E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u0439 (id \u0438\u0437 \u0441\u043F\u0438\u0441\u043A\u0430).
|
|
8146
8630
|
- set_communication_preset { id: string } \u2014 \u043F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u043F\u0440\u0435\u0441\u0435\u0442 \u043E\u0431\u0449\u0435\u043D\u0438\u044F \u0438 \u0437\u0430\u043F\u0438\u0441\u0430\u0442\u044C communication.md.
|
|
8147
8631
|
- write_memory { file: string, content: string } \u2014 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u0430\u0442\u044C \u0444\u0430\u0439\u043B \u043F\u0430\u043C\u044F\u0442\u0438.
|
|
8148
|
-
\u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0435 \u0444\u0430\u0439\u043B\u044B: persona.md, speech.md, boundaries.md, communication.md, long-term.md.
|
|
8632
|
+
\u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C\u044B\u0435 \u0444\u0430\u0439\u043B\u044B: persona.md, speech.md, boundaries.md, communication.md, long-term.md, memory/long-term.md, memory/facts.md, memory/uncertain.md, time/promises.md, time/open-loops.md.
|
|
8149
8633
|
- append_memory { file: string, content: string } \u2014 \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0441\u0442\u0440\u043E\u043A\u0443 \u0432 \u0444\u0430\u0439\u043B \u043F\u0430\u043C\u044F\u0442\u0438.
|
|
8150
8634
|
- generate_persona { name?: string, age?: number, nationality?: string, notes?: string } \u2014 LLM-\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F persona.md/speech.md/communication.md (\u044D\u0442\u043E \u0437\u0430\u043D\u0438\u043C\u0430\u0435\u0442 ~30s).
|
|
8151
8635
|
- runtime_action { action: "start"|"stop"|"pause"|"resume"|"restart" } \u2014 \u0443\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0440\u0430\u043D\u0442\u0430\u0439\u043C\u043E\u043C.
|
|
@@ -8275,7 +8759,19 @@ var ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
|
8275
8759
|
"communication.initiative",
|
|
8276
8760
|
"communication.lifeSharing"
|
|
8277
8761
|
]);
|
|
8278
|
-
var ALLOWED_MEMORY = /* @__PURE__ */ new Set([
|
|
8762
|
+
var ALLOWED_MEMORY = /* @__PURE__ */ new Set([
|
|
8763
|
+
"persona.md",
|
|
8764
|
+
"speech.md",
|
|
8765
|
+
"boundaries.md",
|
|
8766
|
+
"communication.md",
|
|
8767
|
+
"long-term.md",
|
|
8768
|
+
"memory/long-term.md",
|
|
8769
|
+
"memory/facts.md",
|
|
8770
|
+
"memory/uncertain.md",
|
|
8771
|
+
"time/promises.md",
|
|
8772
|
+
"time/open-loops.md",
|
|
8773
|
+
"relationship/timeline.md"
|
|
8774
|
+
]);
|
|
8279
8775
|
async function applyTool(cfg, call) {
|
|
8280
8776
|
switch (call.tool) {
|
|
8281
8777
|
case "set_field": {
|
|
@@ -8437,8 +8933,8 @@ ${preset.description}
|
|
|
8437
8933
|
return { changed: false, message: `unknown tool: ${call.tool}` };
|
|
8438
8934
|
}
|
|
8439
8935
|
}
|
|
8440
|
-
function setNested(obj,
|
|
8441
|
-
const parts =
|
|
8936
|
+
function setNested(obj, path13, value) {
|
|
8937
|
+
const parts = path13.split(".");
|
|
8442
8938
|
let cur = obj;
|
|
8443
8939
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
8444
8940
|
const p = parts[i];
|
|
@@ -8457,14 +8953,14 @@ var DEFAULT_PROXY = "https://tgproxy.girl-agent.com";
|
|
|
8457
8953
|
function proxyUrl() {
|
|
8458
8954
|
return process.env.GIRL_AGENT_AUTH_PROXY ?? DEFAULT_PROXY;
|
|
8459
8955
|
}
|
|
8460
|
-
async function post(
|
|
8461
|
-
const res = await fetch(`${proxyUrl()}${
|
|
8956
|
+
async function post(path13, body) {
|
|
8957
|
+
const res = await fetch(`${proxyUrl()}${path13}`, {
|
|
8462
8958
|
method: "POST",
|
|
8463
8959
|
headers: { "Content-Type": "application/json" },
|
|
8464
8960
|
body: JSON.stringify(body)
|
|
8465
8961
|
});
|
|
8466
8962
|
const data = await res.json();
|
|
8467
|
-
if (!res.ok) throw new Error(data.error ?? `proxy ${
|
|
8963
|
+
if (!res.ok) throw new Error(data.error ?? `proxy ${path13} failed (${res.status})`);
|
|
8468
8964
|
return data;
|
|
8469
8965
|
}
|
|
8470
8966
|
function remoteSendCode(phone) {
|
|
@@ -8851,8 +9347,8 @@ init_esm_shims();
|
|
|
8851
9347
|
init_llm2();
|
|
8852
9348
|
init_stages();
|
|
8853
9349
|
init_communication();
|
|
8854
|
-
import
|
|
8855
|
-
import
|
|
9350
|
+
import fs11 from "fs/promises";
|
|
9351
|
+
import path12 from "path";
|
|
8856
9352
|
import os6 from "os";
|
|
8857
9353
|
init_md();
|
|
8858
9354
|
init_runtime();
|
|
@@ -8935,7 +9431,7 @@ async function runServer(rawArgv) {
|
|
|
8935
9431
|
}
|
|
8936
9432
|
if (!args.yes) {
|
|
8937
9433
|
process.stderr.write(`\u043F\u0440\u043E\u0444\u0438\u043B\u044C \u041D\u0415 \u0443\u0434\u0430\u043B\u0451\u043D: \u0434\u043E\u0431\u0430\u0432\u044C --yes \u0434\u043B\u044F \u043F\u043E\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043D\u0438\u044F.
|
|
8938
|
-
\u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${
|
|
9434
|
+
\u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${path12.join(DATA_ROOT, args.profile)}
|
|
8939
9435
|
`);
|
|
8940
9436
|
process.exit(1);
|
|
8941
9437
|
}
|
|
@@ -8997,7 +9493,7 @@ data dir: ${DATA_ROOT}
|
|
|
8997
9493
|
}
|
|
8998
9494
|
async function persistAndMaybeStart(cfg, args) {
|
|
8999
9495
|
await writeConfig(cfg);
|
|
9000
|
-
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${
|
|
9496
|
+
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${path12.join(DATA_ROOT, cfg.slug)}
|
|
9001
9497
|
`);
|
|
9002
9498
|
if (cfg.llm.apiKey || findPreset(cfg.llm.presetId)?.apiKeyRequired === false) {
|
|
9003
9499
|
try {
|
|
@@ -9114,10 +9610,10 @@ function configFromEnv() {
|
|
|
9114
9610
|
};
|
|
9115
9611
|
}
|
|
9116
9612
|
async function loadConfigFile(file) {
|
|
9117
|
-
const abs =
|
|
9613
|
+
const abs = path12.isAbsolute(file) ? file : path12.join(process.cwd(), file);
|
|
9118
9614
|
let raw;
|
|
9119
9615
|
try {
|
|
9120
|
-
raw = await
|
|
9616
|
+
raw = await fs11.readFile(abs, "utf-8");
|
|
9121
9617
|
} catch (e) {
|
|
9122
9618
|
process.stderr.write(`[server] \u043D\u0435 \u043C\u043E\u0433\u0443 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C ${abs}: ${e?.message ?? e}
|
|
9123
9619
|
`);
|