@thesashadev/girl-agent 0.3.2 → 0.4.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 +59 -0
- package/dist/cli.js +555 -358
- package/dist/webui/assets/index-DFiDtSFH.css +1 -0
- package/dist/webui/assets/index-LKeOBmb0.js +61 -0
- package/dist/webui/index.html +2 -2
- package/package.json +4 -3
- package/dist/webui/assets/index-CCEv0aHQ.js +0 -61
- package/dist/webui/assets/index-EHFCI2nE.css +0 -1
package/dist/cli.js
CHANGED
|
@@ -503,6 +503,7 @@ __export(bot_exports, {
|
|
|
503
503
|
makeBotAdapter: () => makeBotAdapter
|
|
504
504
|
});
|
|
505
505
|
import { Bot } from "grammy";
|
|
506
|
+
import path3 from "path";
|
|
506
507
|
function makeBotAdapter(cfg) {
|
|
507
508
|
const token = cfg.telegram.botToken;
|
|
508
509
|
if (!token) throw new Error("BOT_TOKEN missing");
|
|
@@ -511,7 +512,7 @@ function makeBotAdapter(cfg) {
|
|
|
511
512
|
return {
|
|
512
513
|
async start(onMessage) {
|
|
513
514
|
bot.on("message", async (ctx) => {
|
|
514
|
-
const media = detectBotMedia(ctx.message);
|
|
515
|
+
const media = await detectBotMedia(bot, token, ctx.message);
|
|
515
516
|
const text = ctx.message.text ?? ctx.message.caption ?? "";
|
|
516
517
|
if (!text && !media) return;
|
|
517
518
|
const msg = {
|
|
@@ -611,18 +612,45 @@ function makeBotAdapter(cfg) {
|
|
|
611
612
|
}
|
|
612
613
|
};
|
|
613
614
|
}
|
|
614
|
-
function detectBotMedia(message) {
|
|
615
|
+
async function detectBotMedia(bot, token, message) {
|
|
615
616
|
if (message.photo?.length) {
|
|
616
617
|
const p = message.photo[message.photo.length - 1];
|
|
617
|
-
|
|
618
|
+
const out = { kind: "photo", caption: message.caption, fileId: p.file_id, mimeType: "image/jpeg" };
|
|
619
|
+
await hydrateBotImage(bot, token, out);
|
|
620
|
+
return out;
|
|
618
621
|
}
|
|
619
622
|
if (message.voice) return { kind: "voice", caption: message.caption, fileId: message.voice.file_id, mimeType: message.voice.mime_type };
|
|
620
623
|
if (message.video_note) return { kind: "video_note", fileId: message.video_note.file_id };
|
|
621
624
|
if (message.video) return { kind: "video", caption: message.caption, fileId: message.video.file_id, mimeType: message.video.mime_type };
|
|
622
|
-
if (message.sticker)
|
|
625
|
+
if (message.sticker) {
|
|
626
|
+
const out = { kind: "sticker", fileId: message.sticker.file_id, emoji: message.sticker.emoji, mimeType: message.sticker.mime_type };
|
|
627
|
+
if (!message.sticker.is_animated && !message.sticker.is_video) await hydrateBotImage(bot, token, out);
|
|
628
|
+
return out;
|
|
629
|
+
}
|
|
623
630
|
if (message.document) return { kind: "document", caption: message.caption, fileId: message.document.file_id, mimeType: message.document.mime_type };
|
|
624
631
|
return void 0;
|
|
625
632
|
}
|
|
633
|
+
async function hydrateBotImage(bot, token, media) {
|
|
634
|
+
if (!media.fileId) return;
|
|
635
|
+
try {
|
|
636
|
+
const file = await bot.api.getFile(media.fileId);
|
|
637
|
+
if (!file.file_path) return;
|
|
638
|
+
const url = `https://api.telegram.org/file/bot${token}/${file.file_path}`;
|
|
639
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(1e4) });
|
|
640
|
+
if (!res.ok) return;
|
|
641
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
642
|
+
media.base64 = buf.toString("base64");
|
|
643
|
+
media.mimeType = media.mimeType ?? mimeTypeForTelegramPath(file.file_path);
|
|
644
|
+
} catch {
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
function mimeTypeForTelegramPath(filePath) {
|
|
648
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
649
|
+
if (ext === ".png") return "image/png";
|
|
650
|
+
if (ext === ".gif") return "image/gif";
|
|
651
|
+
if (ext === ".webp") return "image/webp";
|
|
652
|
+
return "image/jpeg";
|
|
653
|
+
}
|
|
626
654
|
var init_bot = __esm({
|
|
627
655
|
"src/telegram/bot.ts"() {
|
|
628
656
|
"use strict";
|
|
@@ -651,29 +679,46 @@ function debug(message) {
|
|
|
651
679
|
if (process.env.GIRL_AGENT_DEBUG === "1") process.stderr.write(`${message}
|
|
652
680
|
`);
|
|
653
681
|
}
|
|
682
|
+
function clientProxy(cfg) {
|
|
683
|
+
const proxy = cfg.telegram.proxy;
|
|
684
|
+
if (!proxy) return void 0;
|
|
685
|
+
if (proxy.MTProxy && proxy.secret) {
|
|
686
|
+
return {
|
|
687
|
+
ip: proxy.ip,
|
|
688
|
+
port: proxy.port,
|
|
689
|
+
MTProxy: true,
|
|
690
|
+
secret: proxy.secret,
|
|
691
|
+
timeout: proxy.timeout ?? 10
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
if (!proxy.socksType) throw new Error("Invalid Telegram proxy: socksType missing");
|
|
695
|
+
return {
|
|
696
|
+
ip: proxy.ip,
|
|
697
|
+
port: proxy.port,
|
|
698
|
+
socksType: proxy.socksType,
|
|
699
|
+
username: proxy.username,
|
|
700
|
+
password: proxy.password,
|
|
701
|
+
timeout: proxy.timeout ?? 10
|
|
702
|
+
};
|
|
703
|
+
}
|
|
654
704
|
function makeUserbotAdapter(cfg) {
|
|
655
705
|
const apiId = cfg.telegram.apiId;
|
|
656
706
|
const apiHash = cfg.telegram.apiHash;
|
|
657
707
|
const session = cfg.telegram.sessionString ?? "";
|
|
658
|
-
|
|
708
|
+
const effectiveApiId = apiId || OWNER_PROXY_API_ID;
|
|
709
|
+
const effectiveApiHash = apiHash || OWNER_PROXY_API_HASH;
|
|
710
|
+
if (!effectiveApiId || !effectiveApiHash) throw new Error("API_ID/API_HASH missing for userbot: \u0432\u044B\u0431\u0435\u0440\u0438 \xAB\u043F\u0440\u043E\u043A\u0441\u0438 \u0430\u0432\u0442\u043E\u0440\u0430\xBB \u0432 WebUI \u0438\u043B\u0438 \u0443\u043A\u0430\u0436\u0438 \u0441\u0432\u043E\u0438 api_id/api_hash");
|
|
659
711
|
const useWSS = cfg.telegram.useWSS !== false;
|
|
660
|
-
const proxy = cfg
|
|
712
|
+
const proxy = clientProxy(cfg);
|
|
661
713
|
debug(`[userbot] creating TelegramClient (useWSS=${useWSS}${proxy ? ", proxy=on" : ""})\u2026`);
|
|
662
|
-
const client = new TelegramClient(new StringSession(session),
|
|
714
|
+
const client = new TelegramClient(new StringSession(session), effectiveApiId, effectiveApiHash, {
|
|
663
715
|
connectionRetries: 5,
|
|
664
716
|
requestRetries: 5,
|
|
665
717
|
retryDelay: 3e3,
|
|
666
718
|
autoReconnect: true,
|
|
667
719
|
floodSleepThreshold: 120,
|
|
668
720
|
useWSS,
|
|
669
|
-
proxy
|
|
670
|
-
ip: proxy.ip,
|
|
671
|
-
port: proxy.port,
|
|
672
|
-
socksType: proxy.socksType,
|
|
673
|
-
username: proxy.username,
|
|
674
|
-
password: proxy.password,
|
|
675
|
-
timeout: proxy.timeout ?? 10
|
|
676
|
-
} : void 0
|
|
721
|
+
proxy
|
|
677
722
|
});
|
|
678
723
|
client.onError = async () => {
|
|
679
724
|
};
|
|
@@ -979,17 +1024,28 @@ async function detectUserbotMedia(client, message) {
|
|
|
979
1024
|
if (isVideoNote) return { kind: "video_note", caption, mimeType };
|
|
980
1025
|
if (isSticker) {
|
|
981
1026
|
const stickerAttr = attrs.find((a) => a.className === "DocumentAttributeSticker");
|
|
982
|
-
|
|
1027
|
+
const out = { kind: "sticker", caption, mimeType, emoji: stickerAttr?.alt };
|
|
1028
|
+
if (mimeType?.startsWith("image/")) {
|
|
1029
|
+
try {
|
|
1030
|
+
const downloaded = await client.downloadMedia(message, {});
|
|
1031
|
+
if (Buffer.isBuffer(downloaded)) out.base64 = downloaded.toString("base64");
|
|
1032
|
+
} catch {
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
return out;
|
|
983
1036
|
}
|
|
984
1037
|
if (isVideo) return { kind: "video", caption, mimeType };
|
|
985
1038
|
return { kind: "document", caption, mimeType };
|
|
986
1039
|
}
|
|
987
1040
|
return void 0;
|
|
988
1041
|
}
|
|
1042
|
+
var OWNER_PROXY_API_ID, OWNER_PROXY_API_HASH;
|
|
989
1043
|
var init_userbot = __esm({
|
|
990
1044
|
"src/telegram/userbot.ts"() {
|
|
991
1045
|
"use strict";
|
|
992
1046
|
init_esm_shims();
|
|
1047
|
+
OWNER_PROXY_API_ID = Number(process.env.GIRL_AGENT_OWNER_PROXY_API_ID ?? process.env.GIRL_AGENT_TG_API_ID ?? 0);
|
|
1048
|
+
OWNER_PROXY_API_HASH = process.env.GIRL_AGENT_OWNER_PROXY_API_HASH ?? process.env.GIRL_AGENT_TG_API_HASH ?? "";
|
|
993
1049
|
}
|
|
994
1050
|
});
|
|
995
1051
|
|
|
@@ -1113,35 +1169,45 @@ var init_communication = __esm({
|
|
|
1113
1169
|
|
|
1114
1170
|
// src/storage/md.ts
|
|
1115
1171
|
import { promises as fs2 } from "fs";
|
|
1116
|
-
import { existsSync } from "fs";
|
|
1117
|
-
import
|
|
1172
|
+
import { existsSync, mkdirSync, accessSync, constants } from "fs";
|
|
1173
|
+
import path4 from "path";
|
|
1118
1174
|
import os from "os";
|
|
1175
|
+
function canWriteDir(dir) {
|
|
1176
|
+
try {
|
|
1177
|
+
existsSync(dir) || mkdirSync(dir, { recursive: true });
|
|
1178
|
+
accessSync(dir, constants.W_OK);
|
|
1179
|
+
return true;
|
|
1180
|
+
} catch {
|
|
1181
|
+
return false;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1119
1184
|
function defaultDataRoot() {
|
|
1120
1185
|
const cwd = process.cwd();
|
|
1121
|
-
|
|
1186
|
+
const projectData = path4.resolve(cwd, "data");
|
|
1187
|
+
if (looksLikeProjectRoot(cwd) && canWriteDir(path4.dirname(projectData))) return projectData;
|
|
1122
1188
|
if (process.platform === "win32") {
|
|
1123
|
-
const appdata = process.env.APPDATA ?
|
|
1124
|
-
return
|
|
1189
|
+
const appdata = process.env.APPDATA ? path4.resolve(process.env.APPDATA) : path4.join(os.homedir(), "AppData", "Roaming");
|
|
1190
|
+
return path4.join(appdata, "girl-agent", "data");
|
|
1125
1191
|
}
|
|
1126
1192
|
if (process.platform === "darwin" && !process.env.XDG_DATA_HOME) {
|
|
1127
|
-
return
|
|
1193
|
+
return path4.join(os.homedir(), "Library", "Application Support", "girl-agent", "data");
|
|
1128
1194
|
}
|
|
1129
|
-
const xdg = process.env.XDG_DATA_HOME ?
|
|
1130
|
-
return
|
|
1195
|
+
const xdg = process.env.XDG_DATA_HOME ? path4.resolve(process.env.XDG_DATA_HOME) : path4.join(os.homedir(), ".local", "share");
|
|
1196
|
+
return path4.join(xdg, "girl-agent", "data");
|
|
1131
1197
|
}
|
|
1132
1198
|
function looksLikeProjectRoot(dir) {
|
|
1133
|
-
return existsSync(
|
|
1199
|
+
return existsSync(path4.join(dir, "package.json")) && (existsSync(path4.join(dir, "src")) || existsSync(path4.join(dir, "dist")));
|
|
1134
1200
|
}
|
|
1135
1201
|
function profileDir(slug) {
|
|
1136
|
-
return
|
|
1202
|
+
return path4.join(DATA_ROOT, slug);
|
|
1137
1203
|
}
|
|
1138
1204
|
async function ensureProfile(slug) {
|
|
1139
1205
|
const dir = profileDir(slug);
|
|
1140
|
-
await fs2.mkdir(
|
|
1141
|
-
await fs2.mkdir(
|
|
1206
|
+
await fs2.mkdir(path4.join(dir, "memory", "episodes"), { recursive: true });
|
|
1207
|
+
await fs2.mkdir(path4.join(dir, "log"), { recursive: true });
|
|
1142
1208
|
}
|
|
1143
1209
|
async function readMd(slug, name) {
|
|
1144
|
-
const p =
|
|
1210
|
+
const p = path4.join(profileDir(slug), name);
|
|
1145
1211
|
try {
|
|
1146
1212
|
return await fs2.readFile(p, "utf8");
|
|
1147
1213
|
} catch {
|
|
@@ -1149,18 +1215,18 @@ async function readMd(slug, name) {
|
|
|
1149
1215
|
}
|
|
1150
1216
|
}
|
|
1151
1217
|
async function writeMd(slug, name, content) {
|
|
1152
|
-
const p =
|
|
1153
|
-
await fs2.mkdir(
|
|
1218
|
+
const p = path4.join(profileDir(slug), name);
|
|
1219
|
+
await fs2.mkdir(path4.dirname(p), { recursive: true });
|
|
1154
1220
|
await fs2.writeFile(p, content, "utf8");
|
|
1155
1221
|
}
|
|
1156
1222
|
async function appendMd(slug, name, content) {
|
|
1157
|
-
const p =
|
|
1158
|
-
await fs2.mkdir(
|
|
1223
|
+
const p = path4.join(profileDir(slug), name);
|
|
1224
|
+
await fs2.mkdir(path4.dirname(p), { recursive: true });
|
|
1159
1225
|
await fs2.appendFile(p, content, "utf8");
|
|
1160
1226
|
}
|
|
1161
1227
|
async function readConfig(slug) {
|
|
1162
1228
|
try {
|
|
1163
|
-
const raw = await fs2.readFile(
|
|
1229
|
+
const raw = await fs2.readFile(path4.join(profileDir(slug), "config.json"), "utf8");
|
|
1164
1230
|
const parsed = JSON.parse(raw);
|
|
1165
1231
|
const communication = normalizeCommunicationProfile(parsed);
|
|
1166
1232
|
const ownerId = normalizeOwnerId(parsed.ownerId);
|
|
@@ -1185,7 +1251,7 @@ async function writeConfig(cfg) {
|
|
|
1185
1251
|
const ownerId = normalizeOwnerId(cfg.ownerId ?? process.env.GIRL_AGENT_OWNER_ID);
|
|
1186
1252
|
const normalized = ownerId === void 0 ? { ...cfg, ownerId: void 0, ignoreTendency: normalizeIgnoreTendency(cfg.ignoreTendency) } : { ...cfg, ownerId, ignoreTendency: normalizeIgnoreTendency(cfg.ignoreTendency) };
|
|
1187
1253
|
await fs2.writeFile(
|
|
1188
|
-
|
|
1254
|
+
path4.join(profileDir(cfg.slug), "config.json"),
|
|
1189
1255
|
JSON.stringify(normalized, null, 2),
|
|
1190
1256
|
"utf8"
|
|
1191
1257
|
);
|
|
@@ -1210,7 +1276,7 @@ async function listProfiles() {
|
|
|
1210
1276
|
const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1211
1277
|
const valid = await Promise.all(dirs.map(async (name) => {
|
|
1212
1278
|
try {
|
|
1213
|
-
await fs2.access(
|
|
1279
|
+
await fs2.access(path4.join(profileDir(name), "config.json"));
|
|
1214
1280
|
return name;
|
|
1215
1281
|
} catch {
|
|
1216
1282
|
return null;
|
|
@@ -1279,13 +1345,35 @@ function sessionDate(tz, now = /* @__PURE__ */ new Date()) {
|
|
|
1279
1345
|
}
|
|
1280
1346
|
return `${y}-${String(mo).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
|
|
1281
1347
|
}
|
|
1282
|
-
async function appendSessionLog(slug, tz, line) {
|
|
1348
|
+
async function appendSessionLog(slug, tz, line, fromId) {
|
|
1349
|
+
const day = sessionDate(tz);
|
|
1350
|
+
const suffix = fromId ? ` <!--from:${fromId}-->` : "";
|
|
1351
|
+
await appendMd(slug, `log/${day}.md`, line + suffix + "\n");
|
|
1352
|
+
}
|
|
1353
|
+
async function appendSharedMemory(slug, tz, fromId, text) {
|
|
1283
1354
|
const day = sessionDate(tz);
|
|
1284
|
-
|
|
1355
|
+
const safe = text.replace(/\s+/g, " ").trim();
|
|
1356
|
+
if (!safe) return;
|
|
1357
|
+
const line = `- ${(/* @__PURE__ */ new Date()).toISOString()} user:${fromId} day:${day}: ${safe}`;
|
|
1358
|
+
const raw = await readMd(slug, "memory/shared-cross-chat.md");
|
|
1359
|
+
const lines = raw.split(/\r?\n/).filter(Boolean);
|
|
1360
|
+
if (lines.slice(-20).some((existing) => existing.endsWith(`: ${safe}`))) return;
|
|
1361
|
+
await writeMd(slug, "memory/shared-cross-chat.md", [...lines.slice(-500), line].join("\n") + "\n");
|
|
1362
|
+
}
|
|
1363
|
+
async function readSharedMemory(slug, limit = 40) {
|
|
1364
|
+
const raw = await readMd(slug, "memory/shared-cross-chat.md");
|
|
1365
|
+
return raw.split(/\r?\n/).filter(Boolean).slice(-limit).join("\n");
|
|
1366
|
+
}
|
|
1367
|
+
async function searchSharedMemory(slug, query, limit = 8) {
|
|
1368
|
+
const raw = await readMd(slug, "memory/shared-cross-chat.md");
|
|
1369
|
+
const tokens = query.toLowerCase().split(/\s+/).filter((t) => t.length >= 3);
|
|
1370
|
+
const lines = raw.split(/\r?\n/).filter(Boolean);
|
|
1371
|
+
const hits = tokens.length ? lines.filter((line) => tokens.some((t) => line.toLowerCase().includes(t))) : [];
|
|
1372
|
+
return (hits.length ? hits : lines).slice(-limit).join("\n");
|
|
1285
1373
|
}
|
|
1286
1374
|
async function listSessionDays(slug) {
|
|
1287
1375
|
try {
|
|
1288
|
-
const dir =
|
|
1376
|
+
const dir = path4.join(profileDir(slug), "log");
|
|
1289
1377
|
const files = await fs2.readdir(dir);
|
|
1290
1378
|
return files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => f.replace(/\.md$/, "")).sort();
|
|
1291
1379
|
} catch {
|
|
@@ -1300,7 +1388,7 @@ async function writeDailySummary(slug, day, content) {
|
|
|
1300
1388
|
}
|
|
1301
1389
|
async function listDailySummaries(slug) {
|
|
1302
1390
|
try {
|
|
1303
|
-
const dir =
|
|
1391
|
+
const dir = path4.join(profileDir(slug), "memory", "daily");
|
|
1304
1392
|
const files = await fs2.readdir(dir);
|
|
1305
1393
|
return files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => f.replace(/\.md$/, "")).sort();
|
|
1306
1394
|
} catch {
|
|
@@ -1340,7 +1428,7 @@ function parseSessionLogTurns(raw, fromId, limit = 30) {
|
|
|
1340
1428
|
if (user) {
|
|
1341
1429
|
currentChatMatches = fromId == null || Number(user[2]) === fromId;
|
|
1342
1430
|
if (currentChatMatches) {
|
|
1343
|
-
turns.push({ role: "user", content: user[3] ?? "", ts: Date.parse(user[1] ?? "") || void 0 });
|
|
1431
|
+
turns.push({ role: "user", content: user[3] ?? "", ts: Date.parse(user[1] ?? "") || void 0, fromId: Number(user[2]) });
|
|
1344
1432
|
}
|
|
1345
1433
|
continue;
|
|
1346
1434
|
}
|
|
@@ -1359,7 +1447,7 @@ async function readRecentSessionTurns(slug, tz, fromId, limit = 30) {
|
|
|
1359
1447
|
}
|
|
1360
1448
|
async function readAgenda(slug) {
|
|
1361
1449
|
try {
|
|
1362
|
-
const raw = await fs2.readFile(
|
|
1450
|
+
const raw = await fs2.readFile(path4.join(profileDir(slug), "agenda.json"), "utf8");
|
|
1363
1451
|
return JSON.parse(raw);
|
|
1364
1452
|
} catch {
|
|
1365
1453
|
return [];
|
|
@@ -1367,7 +1455,7 @@ async function readAgenda(slug) {
|
|
|
1367
1455
|
}
|
|
1368
1456
|
async function writeAgenda(slug, items) {
|
|
1369
1457
|
await ensureProfile(slug);
|
|
1370
|
-
await fs2.writeFile(
|
|
1458
|
+
await fs2.writeFile(path4.join(profileDir(slug), "agenda.json"), JSON.stringify(items, null, 2), "utf8");
|
|
1371
1459
|
}
|
|
1372
1460
|
var DATA_ROOT, SCORE_RE;
|
|
1373
1461
|
var init_md = __esm({
|
|
@@ -1375,7 +1463,7 @@ var init_md = __esm({
|
|
|
1375
1463
|
"use strict";
|
|
1376
1464
|
init_esm_shims();
|
|
1377
1465
|
init_communication();
|
|
1378
|
-
DATA_ROOT = process.env.GIRL_AGENT_DATA ?
|
|
1466
|
+
DATA_ROOT = process.env.GIRL_AGENT_DATA ? path4.resolve(process.env.GIRL_AGENT_DATA) : defaultDataRoot();
|
|
1379
1467
|
SCORE_RE = /<!--score:(.+?)-->/;
|
|
1380
1468
|
}
|
|
1381
1469
|
});
|
|
@@ -1837,8 +1925,8 @@ phoneAvailable=false \u043A\u043E\u0433\u0434\u0430: \u0441\u043F\u0438\u0442, \
|
|
|
1837
1925
|
}
|
|
1838
1926
|
async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(), conflict = null) {
|
|
1839
1927
|
const dateLocal = localDateStr(cfg.tz, now);
|
|
1840
|
-
const
|
|
1841
|
-
const existing = await readMd(cfg.slug,
|
|
1928
|
+
const path14 = `daily-life/${dateLocal}.md`;
|
|
1929
|
+
const existing = await readMd(cfg.slug, path14);
|
|
1842
1930
|
if (existing) {
|
|
1843
1931
|
try {
|
|
1844
1932
|
const m = existing.match(/<!--daily:(.+?)-->/s);
|
|
@@ -1870,7 +1958,7 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
1870
1958
|
dl = { dateLocal, vibe: "\u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0434\u0435\u043D\u044C", blocks: [], events: [], wants: [] };
|
|
1871
1959
|
}
|
|
1872
1960
|
const human = renderDailyLifeHuman(dl);
|
|
1873
|
-
await writeMd(cfg.slug,
|
|
1961
|
+
await writeMd(cfg.slug, path14, `${human}
|
|
1874
1962
|
|
|
1875
1963
|
<!--daily:${JSON.stringify(dl)}-->
|
|
1876
1964
|
`);
|
|
@@ -1936,10 +2024,10 @@ var init_daily_life = __esm({
|
|
|
1936
2024
|
|
|
1937
2025
|
// src/engine/conflict.ts
|
|
1938
2026
|
import { promises as fs3 } from "fs";
|
|
1939
|
-
import
|
|
2027
|
+
import path5 from "path";
|
|
1940
2028
|
async function readConflict(slug) {
|
|
1941
2029
|
try {
|
|
1942
|
-
const raw = await fs3.readFile(
|
|
2030
|
+
const raw = await fs3.readFile(path5.join(profileDir(slug), "conflict.json"), "utf8");
|
|
1943
2031
|
const parsed = JSON.parse(raw);
|
|
1944
2032
|
return { ...empty, ...parsed, history: parsed.history ?? [] };
|
|
1945
2033
|
} catch {
|
|
@@ -1948,7 +2036,7 @@ async function readConflict(slug) {
|
|
|
1948
2036
|
}
|
|
1949
2037
|
async function writeConflict(slug, c) {
|
|
1950
2038
|
await ensureProfile(slug);
|
|
1951
|
-
await fs3.writeFile(
|
|
2039
|
+
await fs3.writeFile(path5.join(profileDir(slug), "conflict.json"), JSON.stringify(c, null, 2), "utf8");
|
|
1952
2040
|
}
|
|
1953
2041
|
function activeConflict(c, now = /* @__PURE__ */ new Date()) {
|
|
1954
2042
|
const cold = c.coldUntil ? new Date(c.coldUntil).getTime() > now.getTime() : false;
|
|
@@ -2074,7 +2162,7 @@ var init_conflict = __esm({
|
|
|
2074
2162
|
// src/engine/memory-palace.ts
|
|
2075
2163
|
import { promises as fs4 } from "fs";
|
|
2076
2164
|
import { createHash } from "crypto";
|
|
2077
|
-
import
|
|
2165
|
+
import path6 from "path";
|
|
2078
2166
|
function wordsFrom(text) {
|
|
2079
2167
|
return [...text.toLowerCase().matchAll(/[a-zа-яё0-9]{3,}/gi)].map((match) => match[0]).filter((token) => !STOP_WORDS.has(token));
|
|
2080
2168
|
}
|
|
@@ -2204,9 +2292,9 @@ async function ensureDefaults(cfg) {
|
|
|
2204
2292
|
["time/promises.md", "# promises\n"],
|
|
2205
2293
|
["memory/uncertain.md", "# uncertain\n"]
|
|
2206
2294
|
];
|
|
2207
|
-
await Promise.all(defaults.map(async ([
|
|
2208
|
-
const current = await readMd(cfg.slug,
|
|
2209
|
-
if (!current.trim()) await writeMd(cfg.slug,
|
|
2295
|
+
await Promise.all(defaults.map(async ([path14, content]) => {
|
|
2296
|
+
const current = await readMd(cfg.slug, path14);
|
|
2297
|
+
if (!current.trim()) await writeMd(cfg.slug, path14, content + "\n");
|
|
2210
2298
|
}));
|
|
2211
2299
|
}
|
|
2212
2300
|
function scoreDrawer(drawer, tokens, query) {
|
|
@@ -2243,7 +2331,7 @@ async function listPalaceDrawers(cfg) {
|
|
|
2243
2331
|
}
|
|
2244
2332
|
async function listChildDirs(slug, rel) {
|
|
2245
2333
|
try {
|
|
2246
|
-
const entries = await fs4.readdir(
|
|
2334
|
+
const entries = await fs4.readdir(path6.join(profileDir(slug), rel), { withFileTypes: true });
|
|
2247
2335
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
2248
2336
|
} catch {
|
|
2249
2337
|
return [];
|
|
@@ -2251,7 +2339,7 @@ async function listChildDirs(slug, rel) {
|
|
|
2251
2339
|
}
|
|
2252
2340
|
async function listChildFiles(slug, rel) {
|
|
2253
2341
|
try {
|
|
2254
|
-
const entries = await fs4.readdir(
|
|
2342
|
+
const entries = await fs4.readdir(path6.join(profileDir(slug), rel), { withFileTypes: true });
|
|
2255
2343
|
return entries.filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
2256
2344
|
} catch {
|
|
2257
2345
|
return [];
|
|
@@ -2380,13 +2468,13 @@ async function appendCompatibilityMemory(cfg, drawer) {
|
|
|
2380
2468
|
await appendMd(cfg.slug, "relationship/timeline.md", line);
|
|
2381
2469
|
}
|
|
2382
2470
|
}
|
|
2383
|
-
async function recordInteractionMemory(llm, cfg, incoming, reply) {
|
|
2471
|
+
async function recordInteractionMemory(llm, cfg, incoming, reply, fromId, scope = "primary") {
|
|
2384
2472
|
if (!incoming.trim()) return;
|
|
2385
2473
|
await ensureDefaults(cfg);
|
|
2386
2474
|
const raw = await llm.chat([
|
|
2387
2475
|
{
|
|
2388
2476
|
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.`
|
|
2477
|
+
content: scope === "acquaintance" ? `\u0422\u044B \u0438\u0437\u0432\u043B\u0435\u043A\u0430\u0435\u0448\u044C \u043A\u0440\u043E\u0441\u0441-\u0447\u0430\u0442\u043E\u0432\u0443\u044E \u043F\u0430\u043C\u044F\u0442\u044C \u043E \u0441\u0442\u043E\u0440\u043E\u043D\u043D\u0435\u043C Telegram-\u0441\u043E\u0431\u0435\u0441\u0435\u0434\u043D\u0438\u043A\u0435. \u041D\u0443\u0436\u043D\u044B \u0442\u043E\u043B\u044C\u043A\u043E \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u044B\u0435 \u0431\u0430\u0437\u043E\u0432\u044B\u0435 \u0444\u0430\u043A\u0442\u044B: \u043A\u0442\u043E \u043F\u0438\u0441\u0430\u043B, \u043E\u0431\u0449\u0438\u0439 \u0442\u043E\u043D, \u044F\u0432\u043D\u044B\u0435 \u043D\u0435\u0438\u043D\u0442\u0438\u043C\u043D\u044B\u0435 \u0444\u0430\u043A\u0442\u044B, \u0441\u0442\u0440\u0430\u043D\u043D\u043E\u0435/\u043E\u043F\u0430\u0441\u043D\u043E\u0435 \u043F\u043E\u0432\u0435\u0434\u0435\u043D\u0438\u0435. \u041D\u0415\u041B\u042C\u0417\u042F \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C \u0441\u0435\u043A\u0440\u0435\u0442\u044B, \u0430\u0434\u0440\u0435\u0441\u0430, \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B, \u0438\u043D\u0442\u0438\u043C, \u0442\u043E\u043A\u0435\u043D\u044B, \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u044B, \u0434\u043E\u0441\u043B\u043E\u0432\u043D\u044B\u0435 \u0434\u043B\u0438\u043D\u043D\u044B\u0435 \u0446\u0438\u0442\u0430\u0442\u044B. \u041F\u0438\u0448\u0438 \u043A\u0440\u0430\u0442\u043A\u043E \u0438 \u043E\u0431\u043E\u0431\u0449\u0451\u043D\u043D\u043E.` : `\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
2478
|
},
|
|
2391
2479
|
{
|
|
2392
2480
|
role: "user",
|
|
@@ -2416,7 +2504,14 @@ ${reply ?? ""}
|
|
|
2416
2504
|
}
|
|
2417
2505
|
], { temperature: 0.1, maxTokens: 3500, json: true });
|
|
2418
2506
|
const parsed = parseJsonObject(raw);
|
|
2419
|
-
const drawers = parsedDrawers(parsed?.drawers).slice(0, 12);
|
|
2507
|
+
const drawers = parsedDrawers(parsed?.drawers).slice(0, scope === "acquaintance" ? 4 : 12);
|
|
2508
|
+
if (scope === "acquaintance") {
|
|
2509
|
+
if (!fromId) return;
|
|
2510
|
+
for (const drawer of drawers) {
|
|
2511
|
+
await appendSharedMemory(cfg.slug, cfg.tz, fromId, drawer.quote);
|
|
2512
|
+
}
|
|
2513
|
+
return;
|
|
2514
|
+
}
|
|
2420
2515
|
for (const drawer of drawers) {
|
|
2421
2516
|
await appendDrawer(cfg, "interaction", drawer);
|
|
2422
2517
|
}
|
|
@@ -2659,15 +2754,19 @@ function describeIncomingMedia(media) {
|
|
|
2659
2754
|
}
|
|
2660
2755
|
function mediaPromptFragment(media) {
|
|
2661
2756
|
if (!media) return "";
|
|
2662
|
-
if (media.kind === "photo") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0435\u0435 \u0444\u043E\u0442\u043E\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0444\u043E\u0442\u043E. \u0415\u0441\u043B\u0438 \u043C\u043E\u0434\u0435\u043B\u044C \u0432\u0438\u0434\u0438\u0442 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443 \u2014 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0439 \u043D\u0430 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u0438\u043A\u0443 \u0444\u043E\u0442\u043E, \u043A\u043E\u0440\u043E\u0442\u043A\u043E \u0438 \u043F\u043E-\u0447\u0435\u043B\u043E\u0432\u0435\u0447\u0435\u0441\u043A\u0438. \u041D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438, \u0447\u0442\u043E \u0430\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u0443\u0435\u0448\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435. \u0415\u0441\u043B\u0438 \u0444\u043E\u0442\u043E \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E\u0435 \u2014 \u0441\u043A\u0430\u0436\u0438 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u043E.";
|
|
2757
|
+
if (media.kind === "photo") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0435\u0435 \u0444\u043E\u0442\u043E\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0444\u043E\u0442\u043E. \u0415\u0441\u043B\u0438 \u043C\u043E\u0434\u0435\u043B\u044C \u0432\u0438\u0434\u0438\u0442 \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443 \u2014 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0439 \u043D\u0430 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u0438\u043A\u0443 \u0444\u043E\u0442\u043E, \u043A\u043E\u0440\u043E\u0442\u043A\u043E \u0438 \u043F\u043E-\u0447\u0435\u043B\u043E\u0432\u0435\u0447\u0435\u0441\u043A\u0438. \u041D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438, \u0447\u0442\u043E \u0430\u043D\u0430\u043B\u0438\u0437\u0438\u0440\u0443\u0435\u0448\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435. \u0415\u0441\u043B\u0438 \u0444\u043E\u0442\u043E \u043D\u0435\u043F\u043E\u043D\u044F\u0442\u043D\u043E\u0435 \u2014 \u0441\u043A\u0430\u0436\u0438 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u043E.\n\n# \u041E\u0431\u043D\u0430\u0440\u0443\u0436\u0435\u043D\u0438\u0435 \u043C\u0435\u043C\u043E\u0432 \u0431\u0435\u0437 \u043F\u043E\u0438\u0441\u043A\u0430\n\u041F\u0440\u043E\u0432\u0435\u0440\u044C, \u0443\u0437\u043D\u0430\u0451\u0448\u044C \u043B\u0438 \u0442\u044B \u0444\u043E\u0442\u043E \u043A\u0430\u043A \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u0438\u043D\u0442\u0435\u0440\u043D\u0435\u0442-\u043C\u0435\u043C, \u043C\u0435\u043C-\u0448\u0430\u0431\u043B\u043E\u043D, \u0432\u0438\u0440\u0443\u0441\u043D\u0443\u044E \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443 \u0438\u043B\u0438 \u0443\u0441\u0442\u043E\u0439\u0447\u0438\u0432\u0443\u044E \u043F\u043E\u043F-\u043A\u0443\u043B\u044C\u0442\u0443\u0440\u043D\u0443\u044E \u0432\u0438\u0437\u0443\u0430\u043B\u044C\u043D\u0443\u044E \u043E\u0442\u0441\u044B\u043B\u043A\u0443. \u042D\u0442\u043E \u041D\u0415 reverse image search: \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u0442\u043E\u043B\u044C\u043A\u043E \u0441\u0432\u043E\u0438 \u0432\u0438\u0437\u0443\u0430\u043B\u044C\u043D\u044B\u0435 \u0437\u043D\u0430\u043D\u0438\u044F. \u0423\u043F\u043E\u043C\u0438\u043D\u0430\u0439 \u043C\u0435\u043C/\u043E\u0442\u0441\u044B\u043B\u043A\u0443 \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u0438 \u0432\u044B\u0441\u043E\u043A\u043E\u0439 \u0443\u0432\u0435\u0440\u0435\u043D\u043D\u043E\u0441\u0442\u0438. \u0415\u0441\u043B\u0438 \u0435\u0441\u0442\u044C \u0441\u043E\u043C\u043D\u0435\u043D\u0438\u0435 \u2014 \u0441\u0447\u0438\u0442\u0430\u0439 \u044D\u0442\u043E \u043E\u0431\u044B\u0447\u043D\u044B\u043C \u0444\u043E\u0442\u043E \u0438 \u043D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043C\u0435\u043C\u043E\u043C.";
|
|
2663
2758
|
if (media.kind === "voice") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0435\u0435 \u0433\u043E\u043B\u043E\u0441\u043E\u0432\u043E\u0435\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0433\u043E\u043B\u043E\u0441\u043E\u0432\u043E\u0435. \u0415\u0441\u043B\u0438 \u043D\u0435\u0442 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043E\u0432\u043A\u0438, \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0439 \u043A\u0430\u043A \u0447\u0435\u043B\u043E\u0432\u0435\u043A, \u043A\u043E\u0442\u043E\u0440\u043E\u043C\u0443 \u043D\u0435\u0443\u0434\u043E\u0431\u043D\u043E \u0441\u043B\u0443\u0448\u0430\u0442\u044C: \u043F\u043E\u043F\u0440\u043E\u0441\u0438 \u0442\u0435\u043A\u0441\u0442\u043E\u043C \u0438\u043B\u0438 \u043E\u0442\u043C\u0430\u0445\u043D\u0438\u0441\u044C.";
|
|
2664
2759
|
if (media.kind === "video_note") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0438\u0439 \u043A\u0440\u0443\u0436\u043E\u0447\u0435\u043A\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u043A\u0440\u0443\u0436\u043E\u0447\u0435\u043A. \u041D\u0435 \u043E\u0431\u0435\u0449\u0430\u0439 \u043E\u0442\u043F\u0440\u0430\u0432\u0438\u0442\u044C \u043A\u0440\u0443\u0436\u043E\u043A \u0432 \u043E\u0442\u0432\u0435\u0442. \u041C\u043E\u0436\u0435\u0448\u044C \u043B\u0435\u043D\u0438\u0432\u043E/\u0441\u043C\u0443\u0449\u0451\u043D\u043D\u043E \u043E\u0442\u0440\u0435\u0430\u0433\u0438\u0440\u043E\u0432\u0430\u0442\u044C.";
|
|
2665
2760
|
if (media.kind === "video") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0435\u0435 \u0432\u0438\u0434\u0435\u043E\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0432\u0438\u0434\u0435\u043E. \u0420\u0435\u0430\u0433\u0438\u0440\u0443\u0439 \u043E\u0441\u0442\u043E\u0440\u043E\u0436\u043D\u043E; \u043D\u0435 \u043F\u0440\u0438\u0442\u0432\u043E\u0440\u044F\u0439\u0441\u044F, \u0447\u0442\u043E \u0432\u0438\u0434\u0435\u043B\u0430 \u0434\u0435\u0442\u0430\u043B\u0438, \u0435\u0441\u043B\u0438 \u043E\u043D\u0438 \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u044B \u043C\u043E\u0434\u0435\u043B\u0438.";
|
|
2666
|
-
if (media.kind === "sticker") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0438\u0439 \u0441\u0442\u0438\u043A\u0435\u0440\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0441\u0442\u0438\u043A\u0435\u0440. \u041C\u043E\u0436\u043D\u043E \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u0440\u0435\u0430\u043A\u0446\u0438\u0435\u0439/\u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0439 \u0440\u0435\u043F\u043B\u0438\u043A\u043E\u0439 \u0438\u043B\u0438 \u0442\u043E\u0436\u0435 \u0441\u0442\u0438\u043A\u0435\u0440\u043E\u043C, \u0435\u0441\u043B\u0438 \u0443\u043C\u0435\u0441\u0442\u043D\u043E.";
|
|
2761
|
+
if (media.kind === "sticker") return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0438\u0439 \u0441\u0442\u0438\u043A\u0435\u0440\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0441\u0442\u0438\u043A\u0435\u0440. \u0415\u0441\u043B\u0438 \u043C\u043E\u0434\u0435\u043B\u044C \u0432\u0438\u0434\u0438\u0442 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u0441\u0442\u0438\u043A\u0435\u0440\u0430 \u2014 \u0440\u0435\u0430\u0433\u0438\u0440\u0443\u0439 \u043D\u0430 \u043A\u043E\u043D\u043A\u0440\u0435\u0442\u043D\u0443\u044E \u044D\u043C\u043E\u0446\u0438\u044E/\u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443, \u0430 \u043D\u0435 \u0442\u043E\u043B\u044C\u043A\u043E \u043D\u0430 emoji. \u041C\u043E\u0436\u043D\u043E \u043E\u0442\u0432\u0435\u0442\u0438\u0442\u044C \u0440\u0435\u0430\u043A\u0446\u0438\u0435\u0439/\u043A\u043E\u0440\u043E\u0442\u043A\u043E\u0439 \u0440\u0435\u043F\u043B\u0438\u043A\u043E\u0439 \u0438\u043B\u0438 \u0442\u043E\u0436\u0435 \u0441\u0442\u0438\u043A\u0435\u0440\u043E\u043C, \u0435\u0441\u043B\u0438 \u0443\u043C\u0435\u0441\u0442\u043D\u043E. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043C\u0435\u043C\u043D\u044B\u0439 \u0441\u0442\u0438\u043A\u0435\u0440/\u043F\u0435\u0440\u0441\u043E\u043D\u0430\u0436 \u2014 \u0443\u0447\u0438\u0442\u044B\u0432\u0430\u0439 \u044D\u0442\u043E \u0442\u043E\u043B\u044C\u043A\u043E \u043F\u0440\u0438 \u0432\u044B\u0441\u043E\u043A\u043E\u0439 \u0443\u0432\u0435\u0440\u0435\u043D\u043D\u043E\u0441\u0442\u0438, \u0431\u0435\u0437 \u0443\u0433\u0430\u0434\u044B\u0432\u0430\u043D\u0438\u044F.";
|
|
2667
2762
|
return "# \u0412\u0445\u043E\u0434\u044F\u0449\u0438\u0439 \u0444\u0430\u0439\u043B\n\u041E\u043D \u043F\u0440\u0438\u0441\u043B\u0430\u043B \u0444\u0430\u0439\u043B. \u041D\u0435 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0439 \u0438 \u043D\u0435 \u043E\u0431\u0435\u0449\u0430\u0439 \u0441\u043C\u043E\u0442\u0440\u0435\u0442\u044C \u043F\u043E\u0434\u0440\u043E\u0431\u043D\u043E, \u0435\u0441\u043B\u0438 \u0441\u043E\u0434\u0435\u0440\u0436\u0438\u043C\u043E\u0435 \u043D\u0435 \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043E.";
|
|
2668
2763
|
}
|
|
2764
|
+
function memeDetectionInstruction(media) {
|
|
2765
|
+
if (!media || media.kind !== "photo" && media.kind !== "sticker") return "";
|
|
2766
|
+
return "\u041F\u0440\u043E\u0432\u0435\u0440\u044C, \u0443\u0437\u043D\u0430\u0451\u0448\u044C \u043B\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043A\u0430\u043A \u0438\u0437\u0432\u0435\u0441\u0442\u043D\u044B\u0439 \u043C\u0435\u043C/\u043C\u0435\u043C-\u0448\u0430\u0431\u043B\u043E\u043D/\u0432\u0438\u0440\u0443\u0441\u043D\u0443\u044E \u043A\u0430\u0440\u0442\u0438\u043D\u043A\u0443. \u0415\u0441\u043B\u0438 \u0443\u0432\u0435\u0440\u0435\u043D \u2014 \u0443\u0447\u0442\u0438 \u044D\u0442\u043E \u043A\u0430\u043A \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442 \u0434\u043B\u044F \u043E\u0442\u0432\u0435\u0442\u0430. \u0415\u0441\u043B\u0438 \u043D\u0435 \u0443\u0432\u0435\u0440\u0435\u043D \u2014 \u043D\u0435 \u043D\u0430\u0437\u044B\u0432\u0430\u0439 \u043C\u0435\u043C\u043E\u043C \u0438 \u043E\u0442\u0432\u0435\u0447\u0430\u0439 \u043A\u0430\u043A \u043D\u0430 \u043E\u0431\u044B\u0447\u043D\u043E\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435.";
|
|
2767
|
+
}
|
|
2669
2768
|
function imagePartFromMedia(media) {
|
|
2670
|
-
if (!media || media.kind !== "photo" || !media.mimeType || !media.base64) return void 0;
|
|
2769
|
+
if (!media || media.kind !== "photo" && media.kind !== "sticker" || !media.mimeType || !media.base64) return void 0;
|
|
2671
2770
|
return {
|
|
2672
2771
|
type: "image",
|
|
2673
2772
|
mimeType: media.mimeType,
|
|
@@ -2846,6 +2945,7 @@ async function buildSystemPrompt(cfg, ctx = {}) {
|
|
|
2846
2945
|
const effectiveStageId = isAcquaintance ? "tg-given-cold" : cfg.stage;
|
|
2847
2946
|
const rel = isAcquaintance ? { ...relRaw, stage: effectiveStageId, score: { interest: 0, trust: 0, attraction: 0, annoyance: 0, cringe: 0 } } : relRaw;
|
|
2848
2947
|
const longTerm = isAcquaintance ? "" : await readMd(cfg.slug, "memory/long-term.md");
|
|
2948
|
+
const sharedMemory = isAcquaintance ? await readSharedMemory(cfg.slug, 8) : ctx.incoming ? await searchSharedMemory(cfg.slug, ctx.incoming, 12) : await readSharedMemory(cfg.slug, 20);
|
|
2849
2949
|
const stage = findStage(effectiveStageId);
|
|
2850
2950
|
const seed = [...cfg.name].reduce((a, c) => a + c.charCodeAt(0), 0);
|
|
2851
2951
|
const stressLoad = Math.min(
|
|
@@ -2883,7 +2983,7 @@ ${hits.map((h) => `- ${h.day}: ${h.excerpt}`).join("\n")}
|
|
|
2883
2983
|
\u0415\u0441\u043B\u0438 \u043E\u043D \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442 "\u0447\u0442\u043E \u0434\u0435\u043B\u0430\u0435\u0448\u044C", \u0443\u043C\u0435\u0441\u0442\u043D\u043E: "\u043D\u0430 \u0443\u0440\u043E\u043A\u0435 \u0441\u0438\u0436\u0443", "\u0443\u0440\u043E\u043A\u0438", "\u0434\u043E\u043C\u0430\u0448\u043A\u0443 \u0434\u0435\u043B\u0430\u044E", "\u043D\u0430 \u043F\u0435\u0440\u0435\u043C\u0435\u043D\u0435".` : cfg.age < 23 ? `# \u0412\u041E\u0417\u0420\u0410\u0421\u0422\u041D\u041E\u0419 \u041A\u041E\u041D\u0422\u0415\u041A\u0421\u0422 \u0423\u0427\u0401\u0411\u042B
|
|
2884
2984
|
\u0422\u0435\u0431\u0435 ${cfg.age}. \u0415\u0441\u043B\u0438 \u0442\u044B \u0443\u0447\u0438\u0448\u044C\u0441\u044F \u043F\u043E\u0441\u043B\u0435 \u0448\u043A\u043E\u043B\u044B, \u043C\u043E\u0436\u043D\u043E \u0433\u043E\u0432\u043E\u0440\u0438\u0442\u044C "\u043F\u0430\u0440\u0430", "\u043B\u0435\u043A\u0446\u0438\u044F", "\u0443\u043D\u0438\u0432\u0435\u0440/\u043A\u043E\u043B\u043B\u0435\u0434\u0436". \u0415\u0441\u043B\u0438 \u043F\u043E persona \u0442\u044B \u0435\u0449\u0451 \u0448\u043A\u043E\u043B\u044C\u043D\u0438\u0446\u0430 \u2014 \u0433\u043E\u0432\u043E\u0440\u0438 "\u0443\u0440\u043E\u043A\u0438/\u0448\u043A\u043E\u043B\u0430", \u043D\u0435 "\u043F\u0430\u0440\u044B".` : "";
|
|
2885
2985
|
const relationshipBoundary = isAcquaintance ? `# \u042D\u0422\u041E \u041D\u0415 \u041E\u0421\u041D\u041E\u0412\u041D\u041E\u0419 \u041F\u0410\u0420\u0415\u041D\u042C
|
|
2886
|
-
\u0422\u044B \u0441\u0435\u0439\u0447\u0430\u0441 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0448\u044C\u0441\u044F \u043D\u0435 \u0441 \u043E\u0441\u043D\u043E\u0432\u043D\u044B\u043C \u043F\u0430\u0440\u043D\u0435\u043C \u0438\u0437 relationship/memory. \u041D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u043F\u0430\u043C\u044F\u0442\u044C, \u0447\u0443\u0432\u0441\u0442\u0432\u0430, \u0448\u0443\u0442\u043A\u0438, \u043E\u0431\u0435\u0449\u0430\u043D\u0438\u044F \u0438 \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u0439 \u0441 \u043D\u0438\u043C.
|
|
2986
|
+
\u0422\u044B \u0441\u0435\u0439\u0447\u0430\u0441 \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u044B\u0432\u0430\u0435\u0448\u044C\u0441\u044F \u043D\u0435 \u0441 \u043E\u0441\u043D\u043E\u0432\u043D\u044B\u043C \u043F\u0430\u0440\u043D\u0435\u043C \u0438\u0437 relationship/memory. \u041D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 \u043F\u0430\u043C\u044F\u0442\u044C, \u0447\u0443\u0432\u0441\u0442\u0432\u0430, \u0448\u0443\u0442\u043A\u0438, \u043E\u0431\u0435\u0449\u0430\u043D\u0438\u044F \u0438 \u0438\u0441\u0442\u043E\u0440\u0438\u044E \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u0439 \u0441 \u043D\u0438\u043C. \u0415\u0433\u043E \u043E\u0431\u044B\u0447\u043D\u044B\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043C\u043E\u0436\u043D\u043E \u0437\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u0442\u044C \u0442\u043E\u043B\u044C\u043A\u043E \u043A\u0430\u043A \u0431\u0430\u0437\u043E\u0432\u0443\u044E cross-chat \u043F\u0430\u043C\u044F\u0442\u044C: \u043A\u0442\u043E \u043F\u0438\u0441\u0430\u043B, \u043E\u0431\u0449\u0438\u0439 \u0442\u043E\u043D, \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u044B\u0435 \u044F\u0432\u043D\u044B\u0435 \u0444\u0430\u043A\u0442\u044B. \u041D\u0435 \u0437\u0430\u043F\u043E\u043C\u0438\u043D\u0430\u0439 \u0438 \u043D\u0435 \u043F\u0435\u0440\u0435\u0441\u043A\u0430\u0437\u044B\u0432\u0430\u0439 \u0438\u043D\u0442\u0438\u043C\u043D\u043E\u0435/\u0441\u0435\u043A\u0440\u0435\u0442\u043D\u043E\u0435/\u043B\u0438\u0447\u043D\u044B\u0435 \u0434\u0430\u043D\u043D\u044B\u0435.
|
|
2887
2987
|
${ctx.committedPrimary ? `\u0423 \u0442\u0435\u0431\u044F \u0443\u0436\u0435 \u0435\u0441\u0442\u044C \u043F\u0430\u0440\u0435\u043D\u044C. \u041D\u0430 \u0444\u043B\u0438\u0440\u0442, \u043F\u043E\u0434\u043A\u0430\u0442\u044B, \u0440\u0435\u0432\u043D\u043E\u0441\u0442\u044C, "\u0434\u0430\u0432\u0430\u0439 \u0432\u0441\u0442\u0440\u0435\u0447\u0430\u0442\u044C\u0441\u044F", \u0440\u043E\u043C\u0430\u043D\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0435 \u0438\u043B\u0438 \u0438\u043D\u0442\u0438\u043C\u043D\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B \u0441\u0442\u0430\u0432\u044C \u0433\u0440\u0430\u043D\u0438\u0446\u0443 \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u043E: "\u0443 \u043C\u0435\u043D\u044F \u0435\u0441\u0442\u044C \u043F\u0430\u0440\u0435\u043D\u044C", "\u044F \u043D\u0435 \u0437\u043D\u0430\u043A\u043E\u043C\u043B\u044E\u0441\u044C", "\u043D\u0435 \u0444\u043B\u0438\u0440\u0442\u0443\u044E". \u0411\u0435\u0437 \u043B\u0435\u043A\u0446\u0438\u0439.` : `\u0421 \u044D\u0442\u0438\u043C \u0447\u0435\u043B\u043E\u0432\u0435\u043A\u043E\u043C \u043D\u0435\u0442 \u043E\u0431\u0449\u0435\u0439 \u0438\u0441\u0442\u043E\u0440\u0438\u0438. \u041C\u043E\u0436\u043D\u043E \u043E\u0442\u0432\u0435\u0447\u0430\u0442\u044C \u043F\u043E \u043B\u0435\u0433\u0435\u043D\u0434\u0435 \u043D\u0430 \u043E\u0431\u044B\u0447\u043D\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B, \u043D\u043E \u043D\u0435 \u0443\u0441\u043A\u043E\u0440\u044F\u0439 \u0431\u043B\u0438\u0437\u043E\u0441\u0442\u044C \u0438 \u043D\u0435 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0430\u0439 \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044E\u0449\u0438\u0435 \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u044F.`}
|
|
2888
2988
|
${ctx.romanticApproach ? `\u041F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0435 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0435 \u0432\u044B\u0433\u043B\u044F\u0434\u0438\u0442 \u043A\u0430\u043A \u0440\u043E\u043C\u0430\u043D\u0442\u0438\u0447\u0435\u0441\u043A\u0438\u0439/\u0444\u043B\u0438\u0440\u0442\u0443\u044E\u0449\u0438\u0439 \u0437\u0430\u0445\u043E\u0434. \u041E\u0442\u0432\u0435\u0442 \u0434\u043E\u043B\u0436\u0435\u043D \u043F\u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043B\u0438\u0447\u043D\u0443\u044E \u0433\u0440\u0430\u043D\u0438\u0446\u0443, \u043A\u043E\u0440\u043E\u0442\u043A\u043E \u0438 \u043F\u043E-\u0447\u0435\u043B\u043E\u0432\u0435\u0447\u0435\u0441\u043A\u0438.` : `\u0415\u0441\u043B\u0438 \u0432\u043E\u043F\u0440\u043E\u0441 \u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u2014 \u043E\u0442\u0432\u0435\u0442\u044C \u043A\u0430\u043A ${cfg.name} \u043F\u043E \u0441\u0432\u043E\u0435\u0439 \u043B\u0435\u0433\u0435\u043D\u0434\u0435, \u0431\u0435\u0437 \u043F\u0435\u0440\u0435\u043D\u043E\u0441\u0430 \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u0439.`}` : "";
|
|
2889
2989
|
const communicationFragment = communicationPromptFragment(communication);
|
|
@@ -3058,6 +3158,8 @@ var init_prompt = __esm({
|
|
|
3058
3158
|
|
|
3059
3159
|
# \u041F\u0410\u041C\u042F\u0422\u042C
|
|
3060
3160
|
- \u0418\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 long-term memory \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u0444\u0430\u043A\u0442 \u0422\u0410\u041C \u0437\u0430\u043F\u0438\u0441\u0430\u043D. \u0418\u043D\u0430\u0447\u0435 \u2014 \u043D\u0435 \u043F\u043E\u043C\u043D\u0438\u0448\u044C.
|
|
3161
|
+
- \u041A\u0440\u043E\u0441\u0441-\u0447\u0430\u0442\u043E\u0432\u0430\u044F \u043F\u0430\u043C\u044F\u0442\u044C \u2014 \u0442\u043E\u043B\u044C\u043A\u043E \u0434\u043B\u044F \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u044B\u0445 \u0431\u0430\u0437\u043E\u0432\u044B\u0445 \u0444\u0430\u043A\u0442\u043E\u0432 \u043E \u0434\u0440\u0443\u0433\u0438\u0445 \u043B\u044E\u0434\u044F\u0445 \u0438 \u0444\u0430\u043A\u0442\u0430 \u043A\u043E\u043D\u0442\u0430\u043A\u0442\u0430. \u041D\u0435 \u0440\u0430\u0441\u043A\u0440\u044B\u0432\u0430\u0439 \u0438\u043D\u0442\u0438\u043C\u043D\u044B\u0435 \u0434\u0435\u0442\u0430\u043B\u0438, \u0441\u0435\u043A\u0440\u0435\u0442\u044B, \u0442\u043E\u043A\u0435\u043D\u044B, \u0430\u0434\u0440\u0435\u0441\u0430, \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B, \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0441\u043B\u043E\u0432\u043E-\u0432-\u0441\u043B\u043E\u0432\u043E.
|
|
3162
|
+
- \u0415\u0441\u043B\u0438 \u043E\u0441\u043D\u043E\u0432\u043D\u043E\u0439 \u043F\u0430\u0440\u0435\u043D\u044C \u0441\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u0435\u0442, \u043F\u0438\u0441\u0430\u043B \u043B\u0438 \u0442\u0435\u0431\u0435 \u043A\u0442\u043E-\u0442\u043E \u0441\u0442\u0440\u0430\u043D\u043D\u044B\u0439/\u0434\u0440\u0443\u0433\u043E\u0439, \u043C\u043E\u0436\u0435\u0448\u044C \u0432\u0441\u043F\u043E\u043C\u043D\u0438\u0442\u044C \u043E\u0431\u0449\u0438\u0439 \u0444\u0430\u043A\u0442 \u0438\u0437 cross-chat memory \u0431\u0435\u0437 \u0434\u043E\u0441\u043B\u043E\u0432\u043D\u044B\u0445 \u0446\u0438\u0442\u0430\u0442 \u0438 \u0431\u0435\u0437 \u043B\u0438\u0448\u043D\u0435\u0439 \u043F\u0440\u0438\u0432\u0430\u0442\u043D\u043E\u0441\u0442\u0438.
|
|
3061
3163
|
- \u041D\u0430 \u0440\u0430\u043D\u043D\u0435\u043C \u044D\u0442\u0430\u043F\u0435 \u0442\u044B \u0435\u0449\u0451 \u043D\u0438\u0447\u0435\u0433\u043E \u043E \u043D\u0451\u043C \u043D\u0435 \u0437\u043D\u0430\u0435\u0448\u044C. \u041D\u0435 \u0434\u0435\u043B\u0430\u0439 \u0432\u0438\u0434 \u0447\u0442\u043E \u0437\u043D\u0430\u0435\u0448\u044C.
|
|
3062
3164
|
|
|
3063
3165
|
# \u0420\u0418\u0422\u041C \u0418 \u0414\u041B\u0418\u041D\u0410 (\u043A\u0430\u043A \u0440\u0435\u0430\u043B\u044C\u043D\u043E \u043F\u0438\u0448\u0443\u0442 \u0434\u0435\u0432\u0443\u0448\u043A\u0438 \u0432 \u0442\u0433)
|
|
@@ -3707,96 +3809,10 @@ var init_llm2 = __esm({
|
|
|
3707
3809
|
}
|
|
3708
3810
|
});
|
|
3709
3811
|
|
|
3710
|
-
// src/presets/mcp.ts
|
|
3711
|
-
function findMcp(id) {
|
|
3712
|
-
return MCP_PRESETS.find((m) => m.id === id);
|
|
3713
|
-
}
|
|
3714
|
-
var MCP_PRESETS;
|
|
3715
|
-
var init_mcp = __esm({
|
|
3716
|
-
"src/presets/mcp.ts"() {
|
|
3717
|
-
"use strict";
|
|
3718
|
-
init_esm_shims();
|
|
3719
|
-
MCP_PRESETS = [
|
|
3720
|
-
{
|
|
3721
|
-
id: "exa",
|
|
3722
|
-
name: "Exa Search",
|
|
3723
|
-
description: "Web-\u043F\u043E\u0438\u0441\u043A \u0447\u0435\u0440\u0435\u0437 Exa. \u0414\u0435\u0432\u0443\u0448\u043A\u0430 \u043C\u043E\u0436\u0435\u0442 \u043F\u043E\u0433\u0443\u0433\u043B\u0438\u0442\u044C \u043C\u0435\u043C, \u0442\u0440\u0435\u043A, \u0442\u0440\u0435\u043D\u0434.",
|
|
3724
|
-
ready: true,
|
|
3725
|
-
secrets: [{ key: "EXA_API_KEY", label: "Exa API key" }],
|
|
3726
|
-
spawn: (s) => ({
|
|
3727
|
-
command: "npx",
|
|
3728
|
-
args: ["-y", "exa-mcp-server"],
|
|
3729
|
-
env: { EXA_API_KEY: s.EXA_API_KEY ?? "" }
|
|
3730
|
-
})
|
|
3731
|
-
},
|
|
3732
|
-
{
|
|
3733
|
-
id: "spotify",
|
|
3734
|
-
name: "Spotify (soon)",
|
|
3735
|
-
description: "\u041B\u044E\u0431\u0438\u043C\u044B\u0435 \u0442\u0440\u0435\u043A\u0438, \u0447\u0442\u043E \u0441\u043B\u0443\u0448\u0430\u0435\u0442 \u043F\u0440\u044F\u043C\u043E \u0441\u0435\u0439\u0447\u0430\u0441.",
|
|
3736
|
-
ready: false
|
|
3737
|
-
},
|
|
3738
|
-
{
|
|
3739
|
-
id: "instagram",
|
|
3740
|
-
name: "Instagram (soon)",
|
|
3741
|
-
description: "\u041F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u0441\u0442\u043E\u0440\u0438\u0441/\u043F\u043E\u0441\u0442\u043E\u0432 \u0434\u043B\u044F \u043A\u043E\u043D\u0442\u0435\u043A\u0441\u0442\u0430.",
|
|
3742
|
-
ready: false
|
|
3743
|
-
},
|
|
3744
|
-
{
|
|
3745
|
-
id: "weather",
|
|
3746
|
-
name: "Weather (soon)",
|
|
3747
|
-
description: "\u041F\u043E\u0433\u043E\u0434\u0430 \u0432 \u0435\u0451 \u0433\u043E\u0440\u043E\u0434\u0435, \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043D\u0438\u0435.",
|
|
3748
|
-
ready: false
|
|
3749
|
-
},
|
|
3750
|
-
{
|
|
3751
|
-
id: "calendar",
|
|
3752
|
-
name: "Calendar (soon)",
|
|
3753
|
-
description: "\u0417\u0430\u043D\u044F\u0442\u043E\u0441\u0442\u044C, \u0448\u043A\u043E\u043B\u0430/\u0443\u043D\u0438\u0432\u0435\u0440, \u043F\u043B\u0430\u043D\u044B \u043D\u0430 \u0432\u044B\u0445\u043E\u0434\u043D\u044B\u0435.",
|
|
3754
|
-
ready: false
|
|
3755
|
-
}
|
|
3756
|
-
];
|
|
3757
|
-
}
|
|
3758
|
-
});
|
|
3759
|
-
|
|
3760
|
-
// src/mcp/client.ts
|
|
3761
|
-
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3762
|
-
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
|
|
3763
|
-
async function startMcpServers(cfg) {
|
|
3764
|
-
const handles = [];
|
|
3765
|
-
for (const slot of cfg.mcp) {
|
|
3766
|
-
const preset = findMcp(slot.id);
|
|
3767
|
-
if (!preset?.ready || !preset.spawn) continue;
|
|
3768
|
-
try {
|
|
3769
|
-
const spec = preset.spawn(slot.secrets);
|
|
3770
|
-
const transport = new StdioClientTransport({
|
|
3771
|
-
command: spec.command,
|
|
3772
|
-
args: spec.args,
|
|
3773
|
-
env: { ...process.env, ...spec.env }
|
|
3774
|
-
});
|
|
3775
|
-
const client = new Client({ name: "girl-agent", version: "0.1.0" }, { capabilities: {} });
|
|
3776
|
-
await client.connect(transport);
|
|
3777
|
-
const list = await client.listTools();
|
|
3778
|
-
handles.push({
|
|
3779
|
-
id: preset.id,
|
|
3780
|
-
client,
|
|
3781
|
-
tools: list.tools.map((t) => ({ name: t.name, description: t.description })),
|
|
3782
|
-
close: () => client.close().catch(() => {
|
|
3783
|
-
})
|
|
3784
|
-
});
|
|
3785
|
-
} catch (e) {
|
|
3786
|
-
console.error(`[mcp] failed to start ${slot.id}:`, e.message);
|
|
3787
|
-
}
|
|
3788
|
-
}
|
|
3789
|
-
return handles;
|
|
3790
|
-
}
|
|
3791
|
-
var init_client = __esm({
|
|
3792
|
-
"src/mcp/client.ts"() {
|
|
3793
|
-
"use strict";
|
|
3794
|
-
init_esm_shims();
|
|
3795
|
-
init_mcp();
|
|
3796
|
-
}
|
|
3797
|
-
});
|
|
3798
|
-
|
|
3799
3812
|
// src/engine/agenda.ts
|
|
3813
|
+
function agendaById(items) {
|
|
3814
|
+
return new Map(items.map((item) => [item.id, item]));
|
|
3815
|
+
}
|
|
3800
3816
|
function localDateKey(tz, now = /* @__PURE__ */ new Date()) {
|
|
3801
3817
|
try {
|
|
3802
3818
|
return new Intl.DateTimeFormat("en-CA", { timeZone: tz, year: "numeric", month: "2-digit", day: "2-digit" }).format(now);
|
|
@@ -3895,6 +3911,7 @@ ${persona}`;
|
|
|
3895
3911
|
return { created: 0, updated: 0, cancelled: 0 };
|
|
3896
3912
|
}
|
|
3897
3913
|
let created = 0, updated = 0, cancelled = 0;
|
|
3914
|
+
const byId = agendaById(agenda);
|
|
3898
3915
|
for (const a of actions) {
|
|
3899
3916
|
if (a.action === "noop" || !a.action) continue;
|
|
3900
3917
|
if (a.action === "create" && a.about && a.pingAt) {
|
|
@@ -3914,21 +3931,21 @@ ${persona}`;
|
|
|
3914
3931
|
agenda.push(item);
|
|
3915
3932
|
created++;
|
|
3916
3933
|
} else if (a.action === "update" && a.id) {
|
|
3917
|
-
const
|
|
3918
|
-
if (
|
|
3919
|
-
if (a.about)
|
|
3920
|
-
if (a.pingAt)
|
|
3921
|
-
if (a.reason)
|
|
3922
|
-
if (a.userEventTime)
|
|
3923
|
-
if (a.importance)
|
|
3924
|
-
|
|
3934
|
+
const item = byId.get(a.id);
|
|
3935
|
+
if (item) {
|
|
3936
|
+
if (a.about) item.about = a.about;
|
|
3937
|
+
if (a.pingAt) item.pingAt = a.pingAt;
|
|
3938
|
+
if (a.reason) item.reason = a.reason;
|
|
3939
|
+
if (a.userEventTime) item.userEventTime = a.userEventTime;
|
|
3940
|
+
if (a.importance) item.importance = a.importance;
|
|
3941
|
+
item.history = [...item.history ?? [], `updated at ${(/* @__PURE__ */ new Date()).toISOString()}: ${a.reason ?? ""}`];
|
|
3925
3942
|
updated++;
|
|
3926
3943
|
}
|
|
3927
3944
|
} else if (a.action === "cancel" && a.id) {
|
|
3928
|
-
const
|
|
3929
|
-
if (
|
|
3930
|
-
|
|
3931
|
-
|
|
3945
|
+
const item = byId.get(a.id);
|
|
3946
|
+
if (item) {
|
|
3947
|
+
item.state = "cancelled";
|
|
3948
|
+
item.history = [...item.history ?? [], `cancelled at ${(/* @__PURE__ */ new Date()).toISOString()}: ${a.reason ?? ""}`];
|
|
3932
3949
|
cancelled++;
|
|
3933
3950
|
}
|
|
3934
3951
|
}
|
|
@@ -4025,17 +4042,15 @@ async function reconcileAgendaAfterConflict(slug, conflict, prevLevel) {
|
|
|
4025
4042
|
let rescheduled = 0;
|
|
4026
4043
|
const now = Date.now();
|
|
4027
4044
|
for (const item of pending2) {
|
|
4028
|
-
const idx = agenda.findIndex((x) => x.id === item.id);
|
|
4029
|
-
if (idx < 0) continue;
|
|
4030
4045
|
if (conflict.level >= 3 || item.importance === 1) {
|
|
4031
|
-
|
|
4032
|
-
|
|
4046
|
+
item.state = "cancelled";
|
|
4047
|
+
item.history = [...item.history ?? [], `cancelled due to conflict level ${conflict.level} at ${(/* @__PURE__ */ new Date()).toISOString()}`];
|
|
4033
4048
|
cancelled++;
|
|
4034
4049
|
} else if (conflict.level >= 2 && item.importance === 2) {
|
|
4035
4050
|
const delayHours = 12 + Math.random() * 24;
|
|
4036
4051
|
const newPing = new Date(now + delayHours * 36e5).toISOString();
|
|
4037
|
-
|
|
4038
|
-
|
|
4052
|
+
item.pingAt = newPing;
|
|
4053
|
+
item.history = [...item.history ?? [], `rescheduled due to conflict level ${conflict.level} at ${(/* @__PURE__ */ new Date()).toISOString()}`];
|
|
4039
4054
|
rescheduled++;
|
|
4040
4055
|
}
|
|
4041
4056
|
}
|
|
@@ -4051,21 +4066,21 @@ async function dueAgendaItems(slug) {
|
|
|
4051
4066
|
}
|
|
4052
4067
|
async function markAgendaFired(slug, id) {
|
|
4053
4068
|
const agenda = await readAgenda(slug);
|
|
4054
|
-
const
|
|
4055
|
-
if (
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4069
|
+
const item = agendaById(agenda).get(id);
|
|
4070
|
+
if (item) {
|
|
4071
|
+
item.state = "fired";
|
|
4072
|
+
item.attempts += 1;
|
|
4073
|
+
item.history = [...item.history ?? [], `fired at ${(/* @__PURE__ */ new Date()).toISOString()}`];
|
|
4059
4074
|
await writeAgenda(slug, agenda);
|
|
4060
4075
|
}
|
|
4061
4076
|
}
|
|
4062
4077
|
async function rescheduleAgenda(slug, id, newPingAt, note) {
|
|
4063
4078
|
const agenda = await readAgenda(slug);
|
|
4064
|
-
const
|
|
4065
|
-
if (
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4079
|
+
const item = agendaById(agenda).get(id);
|
|
4080
|
+
if (item) {
|
|
4081
|
+
item.pingAt = newPingAt;
|
|
4082
|
+
item.state = "pending";
|
|
4083
|
+
item.history = [...item.history ?? [], `rescheduled to ${newPingAt}: ${note}`];
|
|
4069
4084
|
await writeAgenda(slug, agenda);
|
|
4070
4085
|
}
|
|
4071
4086
|
}
|
|
@@ -4345,12 +4360,12 @@ var init_daily_summarizer = __esm({
|
|
|
4345
4360
|
|
|
4346
4361
|
// src/engine/stickers.ts
|
|
4347
4362
|
import { promises as fs5 } from "fs";
|
|
4348
|
-
import
|
|
4363
|
+
import path7 from "path";
|
|
4349
4364
|
async function libraryPath(cfg) {
|
|
4350
4365
|
const rel = "stickers/library.md";
|
|
4351
4366
|
const current = await readMd(cfg.slug, rel);
|
|
4352
4367
|
if (!current.trim()) await writeMd(cfg.slug, rel, DEFAULT_LIBRARY);
|
|
4353
|
-
return
|
|
4368
|
+
return path7.join(profileDir(cfg.slug), rel);
|
|
4354
4369
|
}
|
|
4355
4370
|
async function listStickers(cfg) {
|
|
4356
4371
|
await libraryPath(cfg);
|
|
@@ -4370,7 +4385,9 @@ async function pickSticker(cfg, mood = "") {
|
|
|
4370
4385
|
}
|
|
4371
4386
|
async function addStickerToLibrary(cfg, fileId, emoji = "", tags = []) {
|
|
4372
4387
|
await libraryPath(cfg);
|
|
4373
|
-
const
|
|
4388
|
+
const existing = await listStickers(cfg);
|
|
4389
|
+
if (existing.some((s) => s.fileId === fileId)) return;
|
|
4390
|
+
const p = path7.join(profileDir(cfg.slug), "stickers/library.md");
|
|
4374
4391
|
await fs5.appendFile(p, `${fileId} | ${emoji} | ${tags.join(",")}
|
|
4375
4392
|
`, "utf8");
|
|
4376
4393
|
}
|
|
@@ -5066,7 +5083,6 @@ var init_runtime = __esm({
|
|
|
5066
5083
|
init_stages();
|
|
5067
5084
|
init_communication();
|
|
5068
5085
|
init_llm2();
|
|
5069
|
-
init_client();
|
|
5070
5086
|
init_agenda();
|
|
5071
5087
|
init_presence();
|
|
5072
5088
|
init_online_tick();
|
|
@@ -5093,7 +5109,6 @@ var init_runtime = __esm({
|
|
|
5093
5109
|
cfg;
|
|
5094
5110
|
llm;
|
|
5095
5111
|
tg;
|
|
5096
|
-
mcps = [];
|
|
5097
5112
|
histories = /* @__PURE__ */ new Map();
|
|
5098
5113
|
paused = false;
|
|
5099
5114
|
agendaTimer;
|
|
@@ -5134,8 +5149,6 @@ var init_runtime = __esm({
|
|
|
5134
5149
|
tgSelf = {};
|
|
5135
5150
|
async start() {
|
|
5136
5151
|
this.presenceProfile = computePresenceProfile(this.cfg);
|
|
5137
|
-
this.mcps = await startMcpServers(this.cfg);
|
|
5138
|
-
this.emit("event", { type: "info", text: `MCP started: ${this.mcps.map((m) => m.id).join(", ") || "none"}` });
|
|
5139
5152
|
this.tg = await makeTgAdapter(this.cfg);
|
|
5140
5153
|
await this.tg.start((m) => this.handleIncoming(m));
|
|
5141
5154
|
if (this.tg.getSelf) this.tgSelf = this.tg.getSelf();
|
|
@@ -5172,7 +5185,6 @@ var init_runtime = __esm({
|
|
|
5172
5185
|
await this.tg?.stop();
|
|
5173
5186
|
} catch {
|
|
5174
5187
|
}
|
|
5175
|
-
for (const h of this.mcps) await h.close();
|
|
5176
5188
|
}
|
|
5177
5189
|
pause() {
|
|
5178
5190
|
this.paused = true;
|
|
@@ -5239,7 +5251,6 @@ var init_runtime = __esm({
|
|
|
5239
5251
|
if (!fromId) return;
|
|
5240
5252
|
if (this.cfg.ownerId === fromId) return;
|
|
5241
5253
|
if (this.cfg.ownerId) {
|
|
5242
|
-
this.emit("event", { type: "info", text: `owner mismatch: config=${this.cfg.ownerId}, incoming=${fromId}. \u0415\u0441\u043B\u0438 \u044D\u0442\u043E \u0442\u044B \u2014 \u0438\u0441\u043F\u0440\u0430\u0432\u044C ownerId \u0432 config.json \u0438\u043B\u0438 \u0437\u0430\u043F\u0443\u0441\u0442\u0438 \u0441 GIRL_AGENT_OWNER_ID=${fromId}` });
|
|
5243
5254
|
return;
|
|
5244
5255
|
}
|
|
5245
5256
|
this.cfg.ownerId = fromId;
|
|
@@ -5318,6 +5329,13 @@ var init_runtime = __esm({
|
|
|
5318
5329
|
return m.text ? `${media}
|
|
5319
5330
|
${m.text}` : media;
|
|
5320
5331
|
}
|
|
5332
|
+
async rememberSharedCrossChat(fromId, incomingText) {
|
|
5333
|
+
const text = incomingText.trim();
|
|
5334
|
+
if (!text || text.length < 3) return;
|
|
5335
|
+
const safe = text.replace(/\s+/g, " ").slice(0, 280);
|
|
5336
|
+
await appendSharedMemory(this.cfg.slug, this.cfg.tz, fromId, safe).catch(() => {
|
|
5337
|
+
});
|
|
5338
|
+
}
|
|
5321
5339
|
requestedOutgoingMedia(text) {
|
|
5322
5340
|
if (/\b(фото|фотку|селфи|скинь себя|покажи себя)\b/i.test(text)) return "photo";
|
|
5323
5341
|
if (/\b(видео|видос|запиши видео)\b/i.test(text)) return "video";
|
|
@@ -5371,10 +5389,8 @@ ${m.text}` : media;
|
|
|
5371
5389
|
try {
|
|
5372
5390
|
await this.tg.editText(chatId, messageId, rawText);
|
|
5373
5391
|
this.emit("event", { type: "info", text: `edit-self: "${text.slice(0, 30)}" \u2192 "${rawText.slice(0, 30)}"`, chatId });
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
});
|
|
5377
|
-
}
|
|
5392
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` ~ edit "${text.slice(0, 40)}" \u2192 "${rawText.slice(0, 40)}"`, typeof chatId === "number" ? chatId : void 0).catch(() => {
|
|
5393
|
+
});
|
|
5378
5394
|
const rec = this.sentMessages.find((s) => s.messageId === messageId);
|
|
5379
5395
|
if (rec) rec.text = rawText;
|
|
5380
5396
|
const histEntry = hist[hist.length - 1];
|
|
@@ -5390,7 +5406,7 @@ ${m.text}` : media;
|
|
|
5390
5406
|
this.lastHerReplyTs.set(this.histKey(chatId), Date.now());
|
|
5391
5407
|
this.bumpStageStats("her");
|
|
5392
5408
|
this.emit("event", { type: "outgoing", text, chatId });
|
|
5393
|
-
|
|
5409
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> \u043E\u043D\u0430: ${text}`, typeof chatId === "number" ? chatId : void 0);
|
|
5394
5410
|
sent.push(text);
|
|
5395
5411
|
}
|
|
5396
5412
|
return sent;
|
|
@@ -5400,7 +5416,7 @@ ${m.text}` : media;
|
|
|
5400
5416
|
});
|
|
5401
5417
|
this.setDecisionStatus(this.histKey(chatId), "fallback", "LLM \u043D\u0435 \u0434\u0430\u043B \u0431\u0435\u0437\u043E\u043F\u0430\u0441\u043D\u044B\u0439 \u043E\u0442\u0432\u0435\u0442");
|
|
5402
5418
|
this.emit("event", { type: "ignored", text: hist[hist.length - 1]?.content ?? "", reason: reasonTag });
|
|
5403
|
-
|
|
5419
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> ignored (${reasonTag})`, typeof chatId === "number" ? chatId : void 0);
|
|
5404
5420
|
}
|
|
5405
5421
|
/**
|
|
5406
5422
|
* Один ретрай с упрощённым system-промптом. Используется когда первый ответ оказался
|
|
@@ -5435,7 +5451,7 @@ ${m.text}` : media;
|
|
|
5435
5451
|
this.lastHerReplyTs.set(this.histKey(chatId), Date.now());
|
|
5436
5452
|
this.emit("event", { type: "outgoing", text: candidate, chatId });
|
|
5437
5453
|
this.emit("event", { type: "info", text: "neutral-filler \u0432\u043C\u0435\u0441\u0442\u043E silent-fallback" });
|
|
5438
|
-
|
|
5454
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> \u043E\u043D\u0430 (filler): ${candidate}`, typeof chatId === "number" ? chatId : void 0);
|
|
5439
5455
|
hist.push({ role: "assistant", content: candidate, ts: Date.now() });
|
|
5440
5456
|
this.setDecisionStatus(this.histKey(chatId), "sent", "neutral-filler");
|
|
5441
5457
|
} catch (e) {
|
|
@@ -5603,11 +5619,15 @@ ${m.text}` : media;
|
|
|
5603
5619
|
this.histories.set(key, hist);
|
|
5604
5620
|
this.emit("event", { type: "incoming", text: incomingText, chatId: m.chatId });
|
|
5605
5621
|
if (isPrimary) {
|
|
5606
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[${(/* @__PURE__ */ new Date()).toISOString()}] \u043E\u043D(${m.fromId}): ${incomingText}
|
|
5622
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[${(/* @__PURE__ */ new Date()).toISOString()}] \u043E\u043D(${m.fromId}): ${incomingText}`, m.fromId);
|
|
5623
|
+
} else {
|
|
5624
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[${(/* @__PURE__ */ new Date()).toISOString()}] \u0434\u0440\u0443\u0433\u043E\u0439(${m.fromId}): ${incomingText}`, m.fromId);
|
|
5625
|
+
await this.rememberSharedCrossChat(m.fromId, incomingText);
|
|
5626
|
+
recordInteractionMemory(this.llm, this.cfg, incomingText, void 0, m.fromId, "acquaintance").catch(() => {
|
|
5627
|
+
});
|
|
5607
5628
|
}
|
|
5608
5629
|
if (m.media?.kind === "sticker" && m.media.fileId && isPrimary) {
|
|
5609
|
-
addStickerToLibrary(this.cfg, m.media.fileId, m.media.emoji ?? "", ["received"])
|
|
5610
|
-
});
|
|
5630
|
+
void addStickerToLibrary(this.cfg, m.media.fileId, m.media.emoji ?? "", ["received"]);
|
|
5611
5631
|
}
|
|
5612
5632
|
const requestedMedia = this.requestedOutgoingMedia(m.text);
|
|
5613
5633
|
if (requestedMedia) {
|
|
@@ -5630,7 +5650,7 @@ ${m.text}` : media;
|
|
|
5630
5650
|
}
|
|
5631
5651
|
if (!bubbles.length) return;
|
|
5632
5652
|
await this.sendBubbles(m.chatId, bubbles, hist, isPrimary ? "primary" : "acquaintance", true);
|
|
5633
|
-
if (isPrimary) recordInteractionMemory(this.llm, this.cfg, incomingText, bubbles.join(" / ")).catch(() => {
|
|
5653
|
+
if (isPrimary) recordInteractionMemory(this.llm, this.cfg, incomingText, bubbles.join(" / "), m.fromId, "primary").catch(() => {
|
|
5634
5654
|
});
|
|
5635
5655
|
return;
|
|
5636
5656
|
}
|
|
@@ -5761,7 +5781,7 @@ ${m.text}` : media;
|
|
|
5761
5781
|
});
|
|
5762
5782
|
const msgTag = target.messageId !== m.messageId ? ` (msgId=${target.messageId})` : "";
|
|
5763
5783
|
this.emit("event", { type: "info", text: `\u0440\u0435\u0430\u043A\u0446\u0438\u044F ${tick.reaction}${msgTag} \u043D\u0430 "${target.text.slice(0, 40)}"` });
|
|
5764
|
-
appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> reaction ${tick.reaction}${msgTag}
|
|
5784
|
+
appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> reaction ${tick.reaction}${msgTag}`, m.fromId).catch(() => {
|
|
5765
5785
|
});
|
|
5766
5786
|
}, reactDelay).unref?.();
|
|
5767
5787
|
}
|
|
@@ -5777,8 +5797,8 @@ ${m.text}` : media;
|
|
|
5777
5797
|
});
|
|
5778
5798
|
}
|
|
5779
5799
|
this.emit("event", { type: "ignored", text: incomingText, reason: tick.ignoreReason ?? tick.intent });
|
|
5780
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> ignored (${tick.intent}: ${tick.ignoreReason ?? ""})
|
|
5781
|
-
recordInteractionMemory(this.llm, this.cfg, incomingText).catch(() => {
|
|
5800
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> ignored (${tick.intent}: ${tick.ignoreReason ?? ""})`, m.fromId);
|
|
5801
|
+
recordInteractionMemory(this.llm, this.cfg, incomingText, void 0, m.fromId, "primary").catch(() => {
|
|
5782
5802
|
});
|
|
5783
5803
|
return;
|
|
5784
5804
|
}
|
|
@@ -5823,10 +5843,12 @@ ${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u
|
|
|
5823
5843
|
];
|
|
5824
5844
|
const image = imagePartFromMedia(incoming?.media);
|
|
5825
5845
|
if (image) {
|
|
5846
|
+
const memeHint = memeDetectionInstruction(incoming?.media);
|
|
5826
5847
|
messages.push({
|
|
5827
5848
|
role: "user",
|
|
5828
5849
|
content: [
|
|
5829
|
-
{ type: "text", text: "\u044D\u0442\u043E \u0444\u043E\u0442\u043E \u0438\u0437 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F. \u043E\u0442\u0432\u0435\u0442\u044C \u043D\u0430 \u043D\u0435\u0433\u043E \u043A\u0430\u043A \u0432 \u0442\u0433, \u043A\u043E\u0440\u043E\u0442\u043A\u043E."
|
|
5850
|
+
{ type: "text", text: `${incoming?.media?.kind === "sticker" ? "\u044D\u0442\u043E \u0441\u0442\u0438\u043A\u0435\u0440 \u0438\u0437 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F. \u043E\u0442\u0432\u0435\u0442\u044C \u043D\u0430 \u043D\u0435\u0433\u043E \u043A\u0430\u043A \u0432 \u0442\u0433, \u043A\u043E\u0440\u043E\u0442\u043A\u043E." : "\u044D\u0442\u043E \u0444\u043E\u0442\u043E \u0438\u0437 \u043F\u043E\u0441\u043B\u0435\u0434\u043D\u0435\u0433\u043E \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F. \u043E\u0442\u0432\u0435\u0442\u044C \u043D\u0430 \u043D\u0435\u0433\u043E \u043A\u0430\u043A \u0432 \u0442\u0433, \u043A\u043E\u0440\u043E\u0442\u043A\u043E."}${memeHint ? `
|
|
5851
|
+
${memeHint}` : ""}` },
|
|
5830
5852
|
image
|
|
5831
5853
|
]
|
|
5832
5854
|
});
|
|
@@ -5856,7 +5878,7 @@ ${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u
|
|
|
5856
5878
|
const sent = await this.sendBubbles(chatId, bubbles, hist, scope, tick.typing);
|
|
5857
5879
|
this.setDecisionStatus(this.histKey(chatId), sent.length ? "sent" : "fallback", sent.length ? void 0 : "\u0432\u0441\u0435 \u043F\u0443\u0437\u044B\u0440\u0438 \u0431\u044B\u043B\u0438 \u043F\u0443\u0441\u0442\u044B\u043C\u0438/\u0434\u0443\u0431\u043B\u044F\u043C\u0438");
|
|
5858
5880
|
if (scope === "primary") {
|
|
5859
|
-
recordInteractionMemory(this.llm, this.cfg, lastUser ?? "", sent.join(" / ")).catch(() => {
|
|
5881
|
+
recordInteractionMemory(this.llm, this.cfg, lastUser ?? "", sent.join(" / "), typeof chatId === "number" ? chatId : void 0, "primary").catch(() => {
|
|
5860
5882
|
});
|
|
5861
5883
|
}
|
|
5862
5884
|
if (this.tg.sendSticker && Math.random() < 0.08) {
|
|
@@ -5935,7 +5957,7 @@ ${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u
|
|
|
5935
5957
|
}
|
|
5936
5958
|
hist.push({ role: "assistant", content: piece, ts: now });
|
|
5937
5959
|
this.emit("event", { type: "outgoing", text: piece, chatId: item.chatId });
|
|
5938
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> [proactive] \u043E\u043D\u0430: ${piece}
|
|
5960
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> [proactive] \u043E\u043D\u0430: ${piece}`, typeof item.chatId === "number" ? item.chatId : void 0);
|
|
5939
5961
|
}
|
|
5940
5962
|
this.histories.set(key, hist);
|
|
5941
5963
|
await markAgendaFired(this.cfg.slug, item.id);
|
|
@@ -5997,7 +6019,6 @@ ${herLastMessages.map((m) => `- "${m}"`).join("\n")}
|
|
|
5997
6019
|
`communication: ${communicationProfileLabel(communication)}`,
|
|
5998
6020
|
`config: ${profileDir(this.cfg.slug)}/config.json`,
|
|
5999
6021
|
`score: ${JSON.stringify(rel.score)}`,
|
|
6000
|
-
`mcp: ${this.mcps.map((m) => m.id).join(", ") || "\u2014"}`,
|
|
6001
6022
|
`paused: ${this.paused}`
|
|
6002
6023
|
].join("\n");
|
|
6003
6024
|
}
|
|
@@ -6451,7 +6472,7 @@ ${describeLLM(this.cfg)}`;
|
|
|
6451
6472
|
await maybeAdvanceRelationshipTimeline(this.cfg, oldStage, decision.next);
|
|
6452
6473
|
this.stageStats.set(decision.next, { herMsgs: 0, hisMsgs: 0, ignoresInStage: 0, lastCheckAt: 0, stageEnteredAt: Date.now() });
|
|
6453
6474
|
this.emit("event", { type: "info", text: `stage ${oldStage} \u2192 ${decision.next} (${decision.reason})` });
|
|
6454
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[stage-transition] ${oldStage} \u2192 ${decision.next} (${decision.reason})
|
|
6475
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[stage-transition] ${oldStage} \u2192 ${decision.next} (${decision.reason})`, this.cfg.ownerId);
|
|
6455
6476
|
} catch {
|
|
6456
6477
|
}
|
|
6457
6478
|
}
|
|
@@ -6482,7 +6503,7 @@ ${describeLLM(this.cfg)}`;
|
|
|
6482
6503
|
};
|
|
6483
6504
|
this.emit("event", { type: "info", text: `delete: ${awareness}${m.deletion.text ? ` "${m.deletion.text.slice(0, 40)}"` : ""}` });
|
|
6484
6505
|
if (this.isPrimaryFrom(m.fromId)) {
|
|
6485
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[deletion ${awareness}] \u043E\u043D \u0443\u0434\u0430\u043B\u0438\u043B: "${m.deletion.text.slice(0, 80)}"
|
|
6506
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[deletion ${awareness}] \u043E\u043D \u0443\u0434\u0430\u043B\u0438\u043B: "${m.deletion.text.slice(0, 80)}"`, m.fromId);
|
|
6486
6507
|
}
|
|
6487
6508
|
if (!shouldRespondToDeletion(ctx)) return;
|
|
6488
6509
|
if (!inHistory && awareness === "saw-and-read") {
|
|
@@ -6568,7 +6589,7 @@ ${buildDeletionPromptContext(this.cfg, ctx)}` },
|
|
|
6568
6589
|
}
|
|
6569
6590
|
this.emit("event", { type: "info", text: `emoji-react ${m.emojiReaction.emoji} (${decision.category}/${decision.intent}): ${decision.reason}` });
|
|
6570
6591
|
if (isPrimary) {
|
|
6571
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[emoji-react] \u043E\u043D(${m.fromId}): ${m.emojiReaction.emoji} \u2192 ${decision.intent} (${decision.reason})
|
|
6592
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[emoji-react] \u043E\u043D(${m.fromId}): ${m.emojiReaction.emoji} \u2192 ${decision.intent} (${decision.reason})`, m.fromId);
|
|
6572
6593
|
}
|
|
6573
6594
|
if (decision.moodDelta && Object.keys(decision.moodDelta).length > 0) {
|
|
6574
6595
|
const newScore = applyMoodDelta(rel.score, decision.moodDelta);
|
|
@@ -6708,7 +6729,7 @@ var init_memory_palace2 = __esm({
|
|
|
6708
6729
|
|
|
6709
6730
|
// src/migrations/index.ts
|
|
6710
6731
|
import { promises as fs6 } from "fs";
|
|
6711
|
-
import
|
|
6732
|
+
import path8 from "path";
|
|
6712
6733
|
import { readFileSync } from "fs";
|
|
6713
6734
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6714
6735
|
async function readMigrationState() {
|
|
@@ -6814,15 +6835,15 @@ function formatUpdateWarnings(warnings) {
|
|
|
6814
6835
|
function currentVersion() {
|
|
6815
6836
|
try {
|
|
6816
6837
|
const here = fileURLToPath3(import.meta.url);
|
|
6817
|
-
let dir =
|
|
6838
|
+
let dir = path8.dirname(here);
|
|
6818
6839
|
for (let i = 0; i < 5; i++) {
|
|
6819
|
-
const candidate =
|
|
6840
|
+
const candidate = path8.join(dir, "package.json");
|
|
6820
6841
|
try {
|
|
6821
6842
|
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
6822
6843
|
if (pkg.name === "@thesashadev/girl-agent" && pkg.version) return pkg.version;
|
|
6823
6844
|
} catch {
|
|
6824
6845
|
}
|
|
6825
|
-
dir =
|
|
6846
|
+
dir = path8.dirname(dir);
|
|
6826
6847
|
}
|
|
6827
6848
|
return "unknown";
|
|
6828
6849
|
} catch {
|
|
@@ -6838,7 +6859,7 @@ var init_migrations = __esm({
|
|
|
6838
6859
|
init_add_use_wss_default();
|
|
6839
6860
|
init_ensure_communication_md();
|
|
6840
6861
|
init_memory_palace2();
|
|
6841
|
-
MIGRATIONS_FILE = () =>
|
|
6862
|
+
MIGRATIONS_FILE = () => path8.join(DATA_ROOT, ".migrations.json");
|
|
6842
6863
|
ALL_MIGRATIONS = [
|
|
6843
6864
|
migration0112,
|
|
6844
6865
|
migration0113,
|
|
@@ -7001,13 +7022,13 @@ __export(addons_exports, {
|
|
|
7001
7022
|
validateManifest: () => validateManifest
|
|
7002
7023
|
});
|
|
7003
7024
|
import { promises as fs9 } from "fs";
|
|
7004
|
-
import
|
|
7025
|
+
import path11 from "path";
|
|
7005
7026
|
import os3 from "os";
|
|
7006
7027
|
import { execFile } from "child_process";
|
|
7007
7028
|
import { promisify } from "util";
|
|
7008
7029
|
function addonsDir() {
|
|
7009
|
-
const root = process.env.GIRL_AGENT_DATA ?
|
|
7010
|
-
return
|
|
7030
|
+
const root = process.env.GIRL_AGENT_DATA ? path11.resolve(process.env.GIRL_AGENT_DATA, "..") : path11.join(os3.homedir(), ".local", "share", "girl-agent");
|
|
7031
|
+
return path11.join(root, "addons");
|
|
7011
7032
|
}
|
|
7012
7033
|
async function ensureDir() {
|
|
7013
7034
|
const dir = addonsDir();
|
|
@@ -7024,12 +7045,12 @@ async function readJsonOrEmpty(p, fallback) {
|
|
|
7024
7045
|
}
|
|
7025
7046
|
async function listInstalled() {
|
|
7026
7047
|
const dir = await ensureDir();
|
|
7027
|
-
const indexPath =
|
|
7048
|
+
const indexPath = path11.join(dir, "installed.json");
|
|
7028
7049
|
return await readJsonOrEmpty(indexPath, []);
|
|
7029
7050
|
}
|
|
7030
7051
|
async function writeInstalled(list) {
|
|
7031
7052
|
const dir = await ensureDir();
|
|
7032
|
-
await fs9.writeFile(
|
|
7053
|
+
await fs9.writeFile(path11.join(dir, "installed.json"), JSON.stringify(list, null, 2), "utf8");
|
|
7033
7054
|
}
|
|
7034
7055
|
async function fetchRegistry() {
|
|
7035
7056
|
try {
|
|
@@ -7043,15 +7064,15 @@ async function fetchRegistry() {
|
|
|
7043
7064
|
}
|
|
7044
7065
|
}
|
|
7045
7066
|
async function unpackGaa(gaaPath) {
|
|
7046
|
-
const tmpDir =
|
|
7067
|
+
const tmpDir = path11.join(os3.tmpdir(), `gaa-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
7047
7068
|
await fs9.mkdir(tmpDir, { recursive: true });
|
|
7048
7069
|
await execFileAsync("unzip", ["-o", "-q", gaaPath, "-d", tmpDir]);
|
|
7049
7070
|
const entries = await fs9.readdir(tmpDir);
|
|
7050
7071
|
if (entries.length === 1) {
|
|
7051
|
-
const sub =
|
|
7072
|
+
const sub = path11.join(tmpDir, entries[0]);
|
|
7052
7073
|
const st = await fs9.stat(sub);
|
|
7053
7074
|
if (st.isDirectory()) {
|
|
7054
|
-
const innerManifest =
|
|
7075
|
+
const innerManifest = path11.join(sub, "manifest.json");
|
|
7055
7076
|
try {
|
|
7056
7077
|
await fs9.access(innerManifest);
|
|
7057
7078
|
return sub;
|
|
@@ -7062,34 +7083,34 @@ async function unpackGaa(gaaPath) {
|
|
|
7062
7083
|
return tmpDir;
|
|
7063
7084
|
}
|
|
7064
7085
|
async function packGaa(addonDir, outputPath) {
|
|
7065
|
-
const manifestPath =
|
|
7086
|
+
const manifestPath = path11.join(addonDir, "manifest.json");
|
|
7066
7087
|
const manifestRaw = await fs9.readFile(manifestPath, "utf8");
|
|
7067
7088
|
const manifest = JSON.parse(manifestRaw);
|
|
7068
7089
|
validateManifest(manifest);
|
|
7069
|
-
const out = outputPath ??
|
|
7090
|
+
const out = outputPath ?? path11.join(process.cwd(), `${manifest.id}.gaa`);
|
|
7070
7091
|
try {
|
|
7071
7092
|
await fs9.unlink(out);
|
|
7072
7093
|
} catch {
|
|
7073
7094
|
}
|
|
7074
|
-
const dirName =
|
|
7075
|
-
const parentDir =
|
|
7095
|
+
const dirName = path11.basename(addonDir);
|
|
7096
|
+
const parentDir = path11.dirname(addonDir);
|
|
7076
7097
|
await execFileAsync("zip", ["-r", "-q", out, dirName], { cwd: parentDir });
|
|
7077
7098
|
return out;
|
|
7078
7099
|
}
|
|
7079
7100
|
async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
7080
|
-
const manifestPath =
|
|
7101
|
+
const manifestPath = path11.join(addonDir, "manifest.json");
|
|
7081
7102
|
const manifestRaw = await fs9.readFile(manifestPath, "utf8");
|
|
7082
7103
|
const manifest = JSON.parse(manifestRaw);
|
|
7083
7104
|
validateManifest(manifest);
|
|
7084
7105
|
const applied = [];
|
|
7085
7106
|
const installedFiles = [];
|
|
7086
|
-
const filesDir =
|
|
7107
|
+
const filesDir = path11.join(addonDir, "files");
|
|
7087
7108
|
try {
|
|
7088
7109
|
const fileStat = await fs9.stat(filesDir);
|
|
7089
7110
|
if (fileStat.isDirectory() && profileSlug) {
|
|
7090
7111
|
const fileEntries = await walkDir(filesDir);
|
|
7091
7112
|
for (const relPath of fileEntries) {
|
|
7092
|
-
const content = await fs9.readFile(
|
|
7113
|
+
const content = await fs9.readFile(path11.join(filesDir, relPath), "utf8");
|
|
7093
7114
|
await writeMd(profileSlug, relPath, content);
|
|
7094
7115
|
installedFiles.push(relPath);
|
|
7095
7116
|
}
|
|
@@ -7097,7 +7118,7 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
7097
7118
|
}
|
|
7098
7119
|
} catch {
|
|
7099
7120
|
}
|
|
7100
|
-
const patchPath =
|
|
7121
|
+
const patchPath = path11.join(addonDir, "config.patch.json");
|
|
7101
7122
|
try {
|
|
7102
7123
|
const patchRaw = await fs9.readFile(patchPath, "utf8");
|
|
7103
7124
|
const patch = JSON.parse(patchRaw);
|
|
@@ -7111,11 +7132,11 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
7111
7132
|
}
|
|
7112
7133
|
} catch {
|
|
7113
7134
|
}
|
|
7114
|
-
const codePatchPath =
|
|
7135
|
+
const codePatchPath = path11.join(addonDir, "code.patch");
|
|
7115
7136
|
try {
|
|
7116
7137
|
const patchContent = await fs9.readFile(codePatchPath, "utf8");
|
|
7117
7138
|
if (patchContent.trim()) {
|
|
7118
|
-
const projectRoot =
|
|
7139
|
+
const projectRoot = path11.resolve(import.meta.url.replace("file://", ""), "../../../");
|
|
7119
7140
|
try {
|
|
7120
7141
|
await execFileAsync("git", ["apply", "--check", codePatchPath], { cwd: projectRoot });
|
|
7121
7142
|
await execFileAsync("git", ["apply", codePatchPath], { cwd: projectRoot });
|
|
@@ -7126,24 +7147,24 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
7126
7147
|
}
|
|
7127
7148
|
} catch {
|
|
7128
7149
|
}
|
|
7129
|
-
const themePath =
|
|
7150
|
+
const themePath = path11.join(addonDir, "theme.css");
|
|
7130
7151
|
try {
|
|
7131
7152
|
const css = await fs9.readFile(themePath, "utf8");
|
|
7132
7153
|
const dir2 = await ensureDir();
|
|
7133
|
-
await fs9.writeFile(
|
|
7154
|
+
await fs9.writeFile(path11.join(dir2, `theme-${manifest.id}.css`), css, "utf8");
|
|
7134
7155
|
applied.push("\u0442\u0435\u043C\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430");
|
|
7135
7156
|
} catch {
|
|
7136
7157
|
}
|
|
7137
7158
|
const dir = await ensureDir();
|
|
7138
|
-
const addonStorePath =
|
|
7159
|
+
const addonStorePath = path11.join(dir, manifest.id);
|
|
7139
7160
|
await fs9.mkdir(addonStorePath, { recursive: true });
|
|
7140
|
-
await fs9.copyFile(manifestPath,
|
|
7161
|
+
await fs9.copyFile(manifestPath, path11.join(addonStorePath, "manifest.json"));
|
|
7141
7162
|
const allFiles = await walkDir(addonDir);
|
|
7142
7163
|
for (const f of allFiles) {
|
|
7143
7164
|
if (f === "manifest.json") continue;
|
|
7144
|
-
const src =
|
|
7145
|
-
const dst =
|
|
7146
|
-
await fs9.mkdir(
|
|
7165
|
+
const src = path11.join(addonDir, f);
|
|
7166
|
+
const dst = path11.join(addonStorePath, f);
|
|
7167
|
+
await fs9.mkdir(path11.dirname(dst), { recursive: true });
|
|
7147
7168
|
await fs9.copyFile(src, dst);
|
|
7148
7169
|
}
|
|
7149
7170
|
const list = await listInstalled();
|
|
@@ -7188,7 +7209,7 @@ async function installFromRegistry(id, registryManifest, profileSlug) {
|
|
|
7188
7209
|
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
7189
7210
|
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}`);
|
|
7190
7211
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
7191
|
-
const tmpGaa =
|
|
7212
|
+
const tmpGaa = path11.join(os3.tmpdir(), `${id}-${Date.now()}.gaa`);
|
|
7192
7213
|
await fs9.writeFile(tmpGaa, buf);
|
|
7193
7214
|
try {
|
|
7194
7215
|
return await installFromGaa(tmpGaa, profileSlug);
|
|
@@ -7202,10 +7223,10 @@ async function uninstall(id) {
|
|
|
7202
7223
|
const next = list.filter((a) => a.manifest.id !== id);
|
|
7203
7224
|
if (next.length === list.length) return false;
|
|
7204
7225
|
const dir = addonsDir();
|
|
7205
|
-
const addonStore =
|
|
7226
|
+
const addonStore = path11.join(dir, id);
|
|
7206
7227
|
await fs9.rm(addonStore, { recursive: true, force: true }).catch(() => {
|
|
7207
7228
|
});
|
|
7208
|
-
const themePath =
|
|
7229
|
+
const themePath = path11.join(dir, `theme-${id}.css`);
|
|
7209
7230
|
await fs9.unlink(themePath).catch(() => {
|
|
7210
7231
|
});
|
|
7211
7232
|
await writeInstalled(next);
|
|
@@ -7241,7 +7262,7 @@ async function walkDir(dir, prefix = "") {
|
|
|
7241
7262
|
for (const e of entries) {
|
|
7242
7263
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
7243
7264
|
if (e.isDirectory()) {
|
|
7244
|
-
result.push(...await walkDir(
|
|
7265
|
+
result.push(...await walkDir(path11.join(dir, e.name), rel));
|
|
7245
7266
|
} else {
|
|
7246
7267
|
result.push(rel);
|
|
7247
7268
|
}
|
|
@@ -7261,7 +7282,7 @@ function deepMerge(target, source) {
|
|
|
7261
7282
|
}
|
|
7262
7283
|
async function getAddonReadme(id) {
|
|
7263
7284
|
const dir = addonsDir();
|
|
7264
|
-
const readmePath =
|
|
7285
|
+
const readmePath = path11.join(dir, id, "README.md");
|
|
7265
7286
|
try {
|
|
7266
7287
|
return await fs9.readFile(readmePath, "utf8");
|
|
7267
7288
|
} catch {
|
|
@@ -7270,7 +7291,7 @@ async function getAddonReadme(id) {
|
|
|
7270
7291
|
}
|
|
7271
7292
|
async function getAddonFiles(id) {
|
|
7272
7293
|
const dir = addonsDir();
|
|
7273
|
-
const addonDir =
|
|
7294
|
+
const addonDir = path11.join(dir, id);
|
|
7274
7295
|
try {
|
|
7275
7296
|
return await walkDir(addonDir);
|
|
7276
7297
|
} catch {
|
|
@@ -7299,6 +7320,7 @@ init_esm_shims();
|
|
|
7299
7320
|
import http2 from "http";
|
|
7300
7321
|
import { URL as URL2 } from "url";
|
|
7301
7322
|
import os5 from "os";
|
|
7323
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
7302
7324
|
|
|
7303
7325
|
// src/webui/http.ts
|
|
7304
7326
|
init_esm_shims();
|
|
@@ -7313,9 +7335,9 @@ var HttpError = class extends Error {
|
|
|
7313
7335
|
};
|
|
7314
7336
|
var Router = class {
|
|
7315
7337
|
routes = [];
|
|
7316
|
-
add(method,
|
|
7338
|
+
add(method, path14, handler) {
|
|
7317
7339
|
const paramNames = [];
|
|
7318
|
-
const parts =
|
|
7340
|
+
const parts = path14.split("/").map((part) => {
|
|
7319
7341
|
if (part.startsWith(":")) {
|
|
7320
7342
|
paramNames.push(part.slice(1));
|
|
7321
7343
|
return "([^/]+)";
|
|
@@ -7330,20 +7352,20 @@ var Router = class {
|
|
|
7330
7352
|
handler
|
|
7331
7353
|
});
|
|
7332
7354
|
}
|
|
7333
|
-
get(
|
|
7334
|
-
this.add("GET",
|
|
7355
|
+
get(path14, h) {
|
|
7356
|
+
this.add("GET", path14, h);
|
|
7335
7357
|
}
|
|
7336
|
-
post(
|
|
7337
|
-
this.add("POST",
|
|
7358
|
+
post(path14, h) {
|
|
7359
|
+
this.add("POST", path14, h);
|
|
7338
7360
|
}
|
|
7339
|
-
put(
|
|
7340
|
-
this.add("PUT",
|
|
7361
|
+
put(path14, h) {
|
|
7362
|
+
this.add("PUT", path14, h);
|
|
7341
7363
|
}
|
|
7342
|
-
delete(
|
|
7343
|
-
this.add("DELETE",
|
|
7364
|
+
delete(path14, h) {
|
|
7365
|
+
this.add("DELETE", path14, h);
|
|
7344
7366
|
}
|
|
7345
|
-
patch(
|
|
7346
|
-
this.add("PATCH",
|
|
7367
|
+
patch(path14, h) {
|
|
7368
|
+
this.add("PATCH", path14, h);
|
|
7347
7369
|
}
|
|
7348
7370
|
match(method, pathname) {
|
|
7349
7371
|
for (const r of this.routes) {
|
|
@@ -7444,14 +7466,13 @@ async function findWebUIRoot() {
|
|
|
7444
7466
|
}
|
|
7445
7467
|
})();
|
|
7446
7468
|
const candidates = [
|
|
7469
|
+
path2.resolve(process.cwd(), "dist", "webui"),
|
|
7470
|
+
path2.resolve(process.cwd(), "webui", "dist"),
|
|
7447
7471
|
path2.resolve(here, "webui"),
|
|
7448
|
-
// dist/cli.js -> dist/webui/
|
|
7449
7472
|
path2.resolve(here, "..", "dist", "webui"),
|
|
7450
|
-
// src/webui/static.ts -> dist/webui/
|
|
7451
7473
|
path2.resolve(here, "..", "..", "dist", "webui"),
|
|
7452
|
-
// src/webui/static.ts -> dist/webui/
|
|
7453
7474
|
path2.resolve(here, "..", "..", "..", "dist", "webui"),
|
|
7454
|
-
path2.resolve(
|
|
7475
|
+
path2.resolve(here, "..", "..", "webui", "dist")
|
|
7455
7476
|
];
|
|
7456
7477
|
for (const c of candidates) {
|
|
7457
7478
|
try {
|
|
@@ -7527,10 +7548,62 @@ init_esm_shims();
|
|
|
7527
7548
|
init_runtime_bus();
|
|
7528
7549
|
init_md();
|
|
7529
7550
|
import { WebSocketServer } from "ws";
|
|
7551
|
+
|
|
7552
|
+
// src/webui/auth.ts
|
|
7553
|
+
init_esm_shims();
|
|
7554
|
+
import crypto2 from "crypto";
|
|
7555
|
+
var COOKIE = "girl_agent_auth";
|
|
7556
|
+
var TOKEN_BYTES = 24;
|
|
7557
|
+
var authSecret = process.env.GIRL_AGENT_WEBUI_PASSWORD?.trim() || process.env.GIRL_AGENT_WEBUI_TOKEN?.trim() || "";
|
|
7558
|
+
var sessions = /* @__PURE__ */ new Set();
|
|
7559
|
+
function authEnabled() {
|
|
7560
|
+
return !!authSecret;
|
|
7561
|
+
}
|
|
7562
|
+
function authStatus() {
|
|
7563
|
+
return { enabled: authEnabled() };
|
|
7564
|
+
}
|
|
7565
|
+
function verifyPassword(password) {
|
|
7566
|
+
if (!authSecret) return true;
|
|
7567
|
+
const a = Buffer.from(password);
|
|
7568
|
+
const b = Buffer.from(authSecret);
|
|
7569
|
+
return a.length === b.length && crypto2.timingSafeEqual(a, b);
|
|
7570
|
+
}
|
|
7571
|
+
function createSession(res) {
|
|
7572
|
+
const token = crypto2.randomBytes(TOKEN_BYTES).toString("base64url");
|
|
7573
|
+
sessions.add(token);
|
|
7574
|
+
res.setHeader("Set-Cookie", `${COOKIE}=${token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=2592000`);
|
|
7575
|
+
}
|
|
7576
|
+
function clearSession(req, res) {
|
|
7577
|
+
const token = readCookie(req);
|
|
7578
|
+
if (token) sessions.delete(token);
|
|
7579
|
+
res.setHeader("Set-Cookie", `${COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
|
|
7580
|
+
}
|
|
7581
|
+
function isAuthorized(req) {
|
|
7582
|
+
if (!authSecret) return true;
|
|
7583
|
+
const bearer = String(req.headers.authorization ?? "").replace(/^Bearer\s+/i, "");
|
|
7584
|
+
if (bearer && verifyPassword(bearer)) return true;
|
|
7585
|
+
const token = readCookie(req);
|
|
7586
|
+
return !!token && sessions.has(token);
|
|
7587
|
+
}
|
|
7588
|
+
function readCookie(req) {
|
|
7589
|
+
const raw = req.headers.cookie;
|
|
7590
|
+
if (!raw) return void 0;
|
|
7591
|
+
for (const part of raw.split(";")) {
|
|
7592
|
+
const [key, ...rest] = part.trim().split("=");
|
|
7593
|
+
if (key === COOKIE) return rest.join("=");
|
|
7594
|
+
}
|
|
7595
|
+
return void 0;
|
|
7596
|
+
}
|
|
7597
|
+
|
|
7598
|
+
// src/webui/websocket.ts
|
|
7530
7599
|
function attachWebSockets(server) {
|
|
7531
7600
|
const wssLogs = new WebSocketServer({ noServer: true });
|
|
7532
7601
|
const wssStatus = new WebSocketServer({ noServer: true });
|
|
7533
7602
|
server.on("upgrade", (req, socket, head) => {
|
|
7603
|
+
if (!isAuthorized(req)) {
|
|
7604
|
+
socket.destroy();
|
|
7605
|
+
return;
|
|
7606
|
+
}
|
|
7534
7607
|
const url = req.url ?? "";
|
|
7535
7608
|
const logsMatch = url.match(/^\/ws\/logs\/([^/?#]+)/);
|
|
7536
7609
|
if (logsMatch) {
|
|
@@ -7656,6 +7729,8 @@ var BUSY_SCHEDULE_SCHEMA = {
|
|
|
7656
7729
|
}
|
|
7657
7730
|
};
|
|
7658
7731
|
async function generatePersonaPack(llm, slug, name, age, nationality = "RU", personaNotes = "", onProgress) {
|
|
7732
|
+
const existing = await readExistingPersona(slug);
|
|
7733
|
+
if (existing) return existing;
|
|
7659
7734
|
const country = nationality === "UA" ? "\u0423\u043A\u0440\u0430\u0438\u043D\u0430" : "\u0420\u043E\u0441\u0441\u0438\u044F / \u0421\u041D\u0413";
|
|
7660
7735
|
const langHint = nationality === "UA" ? "\u041F\u0438\u0448\u0435\u0442 \u043D\u0430 \u0420\u0423\u0421\u0421\u041A\u041E\u041C (\u043A\u0430\u043A \u0440\u0435\u0430\u043B\u044C\u043D\u043E \u043F\u0438\u0448\u0435\u0442 \u0431\u043E\u043B\u044C\u0448\u0438\u043D\u0441\u0442\u0432\u043E \u0434\u0435\u0432\u0443\u0448\u0435\u043A \u0432 \u0423\u043A\u0440\u0430\u0438\u043D\u0435 \u0432 \u0442\u0433). \u0414\u043E\u043F\u0443\u0441\u0442\u0438\u043C \u043B\u0451\u0433\u043A\u0438\u0439 \u0441\u0443\u0440\u0436\u0438\u043A: ~90% \u0440\u0443\u0441\u0441\u043A\u0438\u0439 + ~10% \u0443\u043A\u0440\u0430\u0438\u043D\u0441\u043A\u0438\u0445 \u0432\u0441\u0442\u0430\u0432\u043E\u043A (\u043E\u0442\u0434\u0435\u043B\u044C\u043D\u044B\u0435 \u0441\u043B\u043E\u0432\u0430: '\u0448\u043E', '\u043C\u0430\u0431\u0443\u0442\u044C', '\u0442\u0440\u043E\u0445\u0438', '\u044F\u043A', '\u043D\u0443 \u0448\u043E', '\u0442\u0430 \u0439\u0434\u0438', '\u0434\u044F\u043A\u0443\u044E'), \u043D\u043E \u0431\u0435\u0437 \u043F\u043E\u043B\u043D\u043E\u0433\u043E \u043F\u0435\u0440\u0435\u0445\u043E\u0434\u0430 \u043D\u0430 \u0443\u043A\u0440\u0430\u0438\u043D\u0441\u043A\u0438\u0439. \u0427\u0438\u0441\u0442\u043E-\u0443\u043A\u0440\u0430\u0438\u043D\u0441\u043A\u0438\u0439 \u0442\u0435\u043A\u0441\u0442 \u041D\u0415 \u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439 \u2014 \u044D\u0442\u043E \u043D\u0435\u0440\u0435\u0430\u043B\u0438\u0441\u0442\u0438\u0447\u043D\u043E \u0434\u043B\u044F \u0442\u0433-\u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438." : "\u0420\u0443\u0441\u0441\u043A\u043E\u044F\u0437\u044B\u0447\u043D\u0430\u044F \u0431\u0435\u0437 \u0443\u043A\u0440\u0430\u0438\u043D\u0438\u0437\u043C\u043E\u0432.";
|
|
7661
7736
|
const notes = personaNotes.trim() ? `
|
|
@@ -7772,10 +7847,93 @@ ${personaNotes.trim()}
|
|
|
7772
7847
|
await writeMd(slug, "communication.md", boundaries);
|
|
7773
7848
|
return { persona, speech, boundaries, busySchedule };
|
|
7774
7849
|
}
|
|
7850
|
+
async function ensurePersonaPack(slug, name, age) {
|
|
7851
|
+
const existing = await readExistingPersona(slug);
|
|
7852
|
+
if (existing) return existing;
|
|
7853
|
+
const persona = fallbackPersona(name, age);
|
|
7854
|
+
const speech = fallbackSpeech(name, age);
|
|
7855
|
+
const boundaries = fallbackCommunication(name, age);
|
|
7856
|
+
const busySchedule = fallbackBusySchedule(name, age);
|
|
7857
|
+
await writeMd(slug, "persona.md", persona);
|
|
7858
|
+
await writeMd(slug, "speech.md", speech);
|
|
7859
|
+
await writeMd(slug, "communication.md", boundaries);
|
|
7860
|
+
return { persona, speech, boundaries, busySchedule };
|
|
7861
|
+
}
|
|
7862
|
+
async function readExistingPersona(slug) {
|
|
7863
|
+
try {
|
|
7864
|
+
const [persona, speech, boundaries] = await Promise.all([
|
|
7865
|
+
readMd(slug, "persona.md"),
|
|
7866
|
+
readMd(slug, "speech.md"),
|
|
7867
|
+
readMd(slug, "communication.md")
|
|
7868
|
+
]);
|
|
7869
|
+
if (persona.trim() && speech.trim() && boundaries.trim()) {
|
|
7870
|
+
return { persona, speech, boundaries, busySchedule: [] };
|
|
7871
|
+
}
|
|
7872
|
+
} catch {
|
|
7873
|
+
}
|
|
7874
|
+
return null;
|
|
7875
|
+
}
|
|
7775
7876
|
function sanitizeProfileText(text) {
|
|
7776
7877
|
const cleaned = sanitizeModelReply(text).replace(/[^\S\r\n]{2,}/g, " ").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
7777
7878
|
return cleaned || text.trim();
|
|
7778
7879
|
}
|
|
7880
|
+
function fallbackPersona(name, age) {
|
|
7881
|
+
const occupation = age <= 18 ? "\u0443\u0447\u0438\u0442\u0441\u044F \u0432 \u0448\u043A\u043E\u043B\u0435" : age <= 22 ? "\u0443\u0447\u0438\u0442\u0441\u044F \u0438 \u0438\u043D\u043E\u0433\u0434\u0430 \u043F\u043E\u0434\u0440\u0430\u0431\u0430\u0442\u044B\u0432\u0430\u0435\u0442" : "\u0440\u0430\u0431\u043E\u0442\u0430\u0435\u0442 \u0438 \u0436\u0438\u0432\u0451\u0442 \u043E\u0431\u044B\u0447\u043D\u043E\u0439 \u0433\u043E\u0440\u043E\u0434\u0441\u043A\u043E\u0439 \u0436\u0438\u0437\u043D\u044C\u044E";
|
|
7882
|
+
return `# ${name}, ${age}
|
|
7883
|
+
## \u0411\u044D\u043A\u0433\u0440\u0430\u0443\u043D\u0434
|
|
7884
|
+
\u041E\u0431\u044B\u0447\u043D\u0430\u044F \u0440\u0443\u0441\u0441\u043A\u043E\u044F\u0437\u044B\u0447\u043D\u0430\u044F \u0434\u0435\u0432\u0443\u0448\u043A\u0430, ${occupation}. \u0416\u0438\u0432\u0451\u0442 \u0431\u0435\u0437 \u0434\u0440\u0430\u043C\u0430\u0442\u0438\u0447\u043D\u043E\u0433\u043E \u043A\u0438\u043D\u043E\u0448\u043D\u043E\u0433\u043E \u043F\u0440\u043E\u0448\u043B\u043E\u0433\u043E, \u0443\u0441\u0442\u0430\u0451\u0442 \u043E\u0442 \u0431\u044B\u0442\u0430, \u0438\u043D\u043E\u0433\u0434\u0430 \u0437\u0430\u043B\u0438\u043F\u0430\u0435\u0442 \u0432 \u0442\u0435\u043B\u0435\u0444\u043E\u043D \u0438 \u043E\u0442\u043A\u043B\u0430\u0434\u044B\u0432\u0430\u0435\u0442 \u0434\u0435\u043B\u0430.
|
|
7885
|
+
|
|
7886
|
+
## \u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440
|
|
7887
|
+
- \u043E\u0441\u0442\u043E\u0440\u043E\u0436\u043D\u0430\u044F \u0441 \u043D\u0435\u0437\u043D\u0430\u043A\u043E\u043C\u044B\u043C\u0438 \u043B\u044E\u0434\u044C\u043C\u0438
|
|
7888
|
+
- \u043C\u043E\u0436\u0435\u0442 \u0431\u044B\u0442\u044C \u0442\u0451\u043F\u043B\u043E\u0439, \u0435\u0441\u043B\u0438 \u043A \u043D\u0435\u0439 \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u043E \u043E\u0442\u043D\u043E\u0441\u044F\u0442\u0441\u044F
|
|
7889
|
+
- \u043D\u0435 \u043B\u044E\u0431\u0438\u0442 \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0438 \u0434\u043E\u043F\u0440\u043E\u0441\u044B
|
|
7890
|
+
- \u0438\u043D\u043E\u0433\u0434\u0430 \u043E\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0441\u0443\u0445\u043E \u043F\u0440\u043E\u0441\u0442\u043E \u043F\u043E\u0442\u043E\u043C\u0443 \u0447\u0442\u043E \u043D\u0435\u0442 \u0441\u0438\u043B
|
|
7891
|
+
- \u0446\u0435\u043D\u0438\u0442 \u0447\u0443\u0432\u0441\u0442\u0432\u043E \u0442\u0430\u043A\u0442\u0430 \u0431\u043E\u043B\u044C\u0448\u0435 \u043A\u0440\u0430\u0441\u0438\u0432\u044B\u0445 \u0441\u043B\u043E\u0432
|
|
7892
|
+
|
|
7893
|
+
## \u0427\u0442\u043E \u0435\u0451 \u0431\u0435\u0441\u0438\u0442
|
|
7894
|
+
- \u043D\u0430\u0432\u044F\u0437\u0447\u0438\u0432\u043E\u0441\u0442\u044C
|
|
7895
|
+
- \u043F\u0430\u0441\u0441\u0438\u0432\u043D\u0430\u044F \u0430\u0433\u0440\u0435\u0441\u0441\u0438\u044F
|
|
7896
|
+
- \u043A\u043E\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u044E\u0442 \u0431\u044B\u0441\u0442\u0440\u044B\u0439 \u043E\u0442\u0432\u0435\u0442
|
|
7897
|
+
- \u0442\u0443\u043F\u044B\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 "\u0430 \u0442\u044B \u043D\u0430\u0441\u0442\u043E\u044F\u0449\u0430\u044F?"
|
|
7898
|
+
- \u0440\u0430\u0437\u0433\u043E\u0432\u043E\u0440\u044B \u043A\u0430\u043A \u043D\u0430 \u0441\u043E\u0431\u0435\u0441\u0435\u0434\u043E\u0432\u0430\u043D\u0438\u0438
|
|
7899
|
+
|
|
7900
|
+
## \u0427\u0442\u043E \u0435\u0439 \u043D\u0440\u0430\u0432\u0438\u0442\u0441\u044F
|
|
7901
|
+
\u041C\u0443\u0437\u044B\u043A\u0430 \u0444\u043E\u043D\u043E\u043C, \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0435 \u0432\u0438\u0434\u0435\u043E, \u043F\u0440\u043E\u0433\u0443\u043B\u043A\u0438, \u043F\u0435\u0440\u0435\u043F\u0438\u0441\u043A\u0438 \u0431\u0435\u0437 \u043D\u0430\u043F\u0440\u044F\u0433\u0430, \u0431\u044B\u0442\u043E\u0432\u044B\u0435 \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u0438\u0435 \u043F\u043B\u0430\u043D\u044B.`;
|
|
7902
|
+
}
|
|
7903
|
+
function fallbackSpeech(name, age) {
|
|
7904
|
+
return `# \u041C\u0430\u043D\u0435\u0440\u0430 \u0440\u0435\u0447\u0438
|
|
7905
|
+
${name} \u043F\u0438\u0448\u0435\u0442 \u043A\u043E\u0440\u043E\u0442\u043A\u043E, \u0431\u0435\u0437 \u043A\u0430\u043D\u0446\u0435\u043B\u044F\u0440\u0438\u0442\u0430 \u0438 \u0431\u0435\u0437 \u043E\u0449\u0443\u0449\u0435\u043D\u0438\u044F "\u043F\u043E\u043C\u043E\u0449\u043D\u0438\u043A\u0430". \u041E\u0431\u044B\u0447\u043D\u043E 1-2 \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u044F \u043F\u043E\u0434\u0440\u044F\u0434.
|
|
7906
|
+
|
|
7907
|
+
## \u0420\u0435\u0433\u0438\u0441\u0442\u0440 \u0438 \u043F\u0443\u043D\u043A\u0442\u0443\u0430\u0446\u0438\u044F
|
|
7908
|
+
\u0427\u0430\u0441\u0442\u043E \u043F\u0438\u0448\u0435\u0442 \u0441 \u043C\u0430\u043B\u0435\u043D\u044C\u043A\u043E\u0439 \u0431\u0443\u043A\u0432\u044B. \u0422\u043E\u0447\u043A\u0438 \u0432 \u043A\u043E\u043D\u0446\u0435 \u043A\u043E\u0440\u043E\u0442\u043A\u0438\u0445 \u0441\u043E\u043E\u0431\u0449\u0435\u043D\u0438\u0439 \u043F\u043E\u0447\u0442\u0438 \u043D\u0435 \u0441\u0442\u0430\u0432\u0438\u0442. \u0421\u043A\u043E\u0431\u043A\u0438 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442 \u0440\u0435\u0434\u043A\u043E, \u0435\u0441\u043B\u0438 \u0445\u043E\u0447\u0435\u0442 \u0441\u043C\u044F\u0433\u0447\u0438\u0442\u044C \u0442\u043E\u043D.
|
|
7909
|
+
|
|
7910
|
+
## \u0421\u043B\u0435\u043D\u0433
|
|
7911
|
+
\u0421\u043B\u0435\u043D\u0433\u0430 \u043D\u0435\u043C\u043D\u043E\u0433\u043E, \u0442\u043E\u043B\u044C\u043A\u043E \u0435\u0441\u043B\u0438 \u043E\u043D \u0435\u0441\u0442\u0435\u0441\u0442\u0432\u0435\u043D\u043D\u043E \u043F\u043E\u0434\u0445\u043E\u0434\u0438\u0442 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0438. \u041D\u0435 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0435\u0442 \u0443\u0441\u0442\u0430\u0440\u0435\u0432\u0448\u0438\u0435 \u043C\u0435\u043C\u043D\u044B\u0435 \u0441\u043B\u043E\u0432\u0430 \u043F\u0430\u0447\u043A\u0430\u043C\u0438.
|
|
7912
|
+
|
|
7913
|
+
## \u0422\u0438\u043F\u0438\u0447\u043D\u044B\u0435 \u0440\u0435\u0430\u043A\u0446\u0438\u0438
|
|
7914
|
+
- "\u043D\u0443 \u0434\u0430"
|
|
7915
|
+
- "\u043D\u0435 \u0437\u043D\u0430\u044E"
|
|
7916
|
+
- "\u0441\u0442\u0440\u0430\u043D\u043D\u043E \u043D\u0435\u043C\u043D\u043E\u0433\u043E"
|
|
7917
|
+
- "\u0430\u0445\u0430\u0445"
|
|
7918
|
+
- "\u043B\u0430\u0434\u043D\u043E"
|
|
7919
|
+
- "\u043C\u043D\u0435 \u043B\u0435\u043D\u044C \u0449\u0430\u0441"
|
|
7920
|
+
|
|
7921
|
+
## \u0417\u0430\u043F\u0440\u0435\u0449\u0451\u043D\u043D\u043E\u0435
|
|
7922
|
+
\u041D\u0435 \u043F\u0438\u0448\u0435\u0442 \u043A\u0430\u043A \u0418\u0418, \u043D\u0435 \u0433\u043E\u0432\u043E\u0440\u0438\u0442 "\u0431\u0435\u0437\u0443\u0441\u043B\u043E\u0432\u043D\u043E", "\u043A\u0430\u043A \u043C\u043E\u0434\u0435\u043B\u044C", "\u043F\u043E\u0437\u0432\u043E\u043B\u044C", "\u0447\u0435\u043C \u043C\u043E\u0433\u0443 \u043F\u043E\u043C\u043E\u0447\u044C". \u0412\u043E\u0437\u0440\u0430\u0441\u0442\u043D\u043E\u0439 \u0442\u043E\u043D: ${age}.`;
|
|
7923
|
+
}
|
|
7924
|
+
function fallbackCommunication(name, age) {
|
|
7925
|
+
return `# \u041F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F \u0432 \u043E\u0431\u0449\u0435\u043D\u0438\u0438
|
|
7926
|
+
${name} \u043D\u0435 \u043B\u044E\u0431\u0438\u0442, \u043A\u043E\u0433\u0434\u0430 \u0435\u0451 \u0442\u043E\u0440\u043E\u043F\u044F\u0442, \u0432\u044B\u043F\u0440\u0430\u0448\u0438\u0432\u0430\u044E\u0442 \u0432\u043D\u0438\u043C\u0430\u043D\u0438\u0435 \u0438\u043B\u0438 \u043F\u044B\u0442\u0430\u044E\u0442\u0441\u044F \u0441\u0440\u0430\u0437\u0443 \u043F\u0435\u0440\u0435\u0439\u0442\u0438 \u0432 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u043B\u0438\u0447\u043D\u044B\u0435 \u0442\u0435\u043C\u044B.
|
|
7927
|
+
|
|
7928
|
+
## \u0422\u0435\u043C\u044B \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u041D\u0415 \u043E\u0431\u0441\u0443\u0436\u0434\u0430\u0435\u0442
|
|
7929
|
+
\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0438\u043D\u0442\u0438\u043C\u043D\u044B\u0435 \u0432\u043E\u043F\u0440\u043E\u0441\u044B, \u0434\u0435\u043D\u044C\u0433\u0438 \u0441\u0435\u043C\u044C\u0438, \u0442\u043E\u0447\u043D\u044B\u0439 \u0430\u0434\u0440\u0435\u0441, \u0434\u043E\u043A\u0443\u043C\u0435\u043D\u0442\u044B, \u0434\u043E\u0441\u0442\u0443\u043F\u044B \u0438 \u0432\u0441\u0451, \u0447\u0442\u043E \u043F\u043E\u0445\u043E\u0436\u0435 \u043D\u0430 \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u0435.
|
|
7930
|
+
|
|
7931
|
+
## \u0417\u0435\u043B\u0451\u043D\u044B\u0435 \u0444\u043B\u0430\u0433\u0438
|
|
7932
|
+
\u0421\u043F\u043E\u043A\u043E\u0439\u043D\u044B\u0439 \u0442\u043E\u043D, \u043D\u043E\u0440\u043C\u0430\u043B\u044C\u043D\u044B\u0439 \u044E\u043C\u043E\u0440, \u0443\u0432\u0430\u0436\u0435\u043D\u0438\u0435 \u043A \u043F\u0430\u0443\u0437\u0430\u043C \u0432 \u043E\u0442\u0432\u0435\u0442\u0430\u0445, \u0438\u043D\u0442\u0435\u0440\u0435\u0441 \u0431\u0435\u0437 \u0434\u043E\u043F\u0440\u043E\u0441\u0430.
|
|
7933
|
+
|
|
7934
|
+
## \u041A\u043E\u0433\u0434\u0430 \u0443\u0445\u043E\u0434\u0438\u0442 \u0432 \u0438\u0433\u043D\u043E\u0440
|
|
7935
|
+
\u0415\u0441\u043B\u0438 \u0441\u043E\u0431\u0435\u0441\u0435\u0434\u043D\u0438\u043A \u0434\u0430\u0432\u0438\u0442, \u0441\u043F\u043E\u0440\u0438\u0442 \u0440\u0430\u0434\u0438 \u0441\u043F\u043E\u0440\u0430 \u0438\u043B\u0438 \u043F\u0438\u0448\u0435\u0442 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\u043E\u0433\u043E \u043F\u043E\u0434\u0440\u044F\u0434.`;
|
|
7936
|
+
}
|
|
7779
7937
|
function parseBusySchedule(raw, name, age) {
|
|
7780
7938
|
try {
|
|
7781
7939
|
const start = raw.indexOf("{");
|
|
@@ -7836,7 +7994,7 @@ init_llm();
|
|
|
7836
7994
|
init_llm_update();
|
|
7837
7995
|
init_llm2();
|
|
7838
7996
|
import { promises as fs7 } from "fs";
|
|
7839
|
-
import
|
|
7997
|
+
import path9 from "path";
|
|
7840
7998
|
var MEMORY_FILES = [
|
|
7841
7999
|
"persona.md",
|
|
7842
8000
|
"speech.md",
|
|
@@ -7853,7 +8011,7 @@ var MEMORY_FILES = [
|
|
|
7853
8011
|
function isAllowedMemoryPath(p) {
|
|
7854
8012
|
if (!p || typeof p !== "string") return false;
|
|
7855
8013
|
if (p.includes("..")) return false;
|
|
7856
|
-
if (
|
|
8014
|
+
if (path9.isAbsolute(p)) return false;
|
|
7857
8015
|
if (p.startsWith("config.json")) return false;
|
|
7858
8016
|
if (p.startsWith("agenda.json")) return false;
|
|
7859
8017
|
if (MEMORY_FILES.includes(p)) return true;
|
|
@@ -7917,7 +8075,6 @@ function registerProfileRoutes(r) {
|
|
|
7917
8075
|
stage: data.stage ?? "tg-given-cold",
|
|
7918
8076
|
llm: data.llm ?? { presetId: "claudehub", proto: "anthropic", apiKey: "", model: "claude-sonnet-4.6" },
|
|
7919
8077
|
telegram: data.telegram ?? {},
|
|
7920
|
-
mcp: data.mcp ?? [],
|
|
7921
8078
|
privacy: data.privacy ?? "owner-only",
|
|
7922
8079
|
ownerId: normalizeOwnerId(data.ownerId),
|
|
7923
8080
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8029,29 +8186,29 @@ function registerProfileRoutes(r) {
|
|
|
8029
8186
|
const entries = [];
|
|
8030
8187
|
for (const f of MEMORY_FILES) entries.push({ rel: f });
|
|
8031
8188
|
try {
|
|
8032
|
-
const dailyDir =
|
|
8189
|
+
const dailyDir = path9.join(dir, "memory", "daily");
|
|
8033
8190
|
const list = await fs7.readdir(dailyDir);
|
|
8034
8191
|
for (const f of list) if (/^\d{4}-\d{2}-\d{2}\.md$/.test(f)) entries.push({ rel: `memory/daily/${f}` });
|
|
8035
8192
|
} catch {
|
|
8036
8193
|
}
|
|
8037
8194
|
try {
|
|
8038
|
-
const epDir =
|
|
8195
|
+
const epDir = path9.join(dir, "memory", "episodes");
|
|
8039
8196
|
const list = await fs7.readdir(epDir);
|
|
8040
8197
|
for (const f of list) if (/^[\w\-]{1,80}\.md$/.test(f)) entries.push({ rel: `memory/episodes/${f}` });
|
|
8041
8198
|
} catch {
|
|
8042
8199
|
}
|
|
8043
8200
|
try {
|
|
8044
|
-
const palaceDir =
|
|
8201
|
+
const palaceDir = path9.join(dir, "memory", "palace");
|
|
8045
8202
|
const wings = await fs7.readdir(palaceDir, { withFileTypes: true });
|
|
8046
8203
|
for (const wing of wings) {
|
|
8047
8204
|
if (!wing.isDirectory() || !/^[\w\-]{1,80}$/.test(wing.name)) continue;
|
|
8048
|
-
const halls = await fs7.readdir(
|
|
8205
|
+
const halls = await fs7.readdir(path9.join(palaceDir, wing.name), { withFileTypes: true });
|
|
8049
8206
|
for (const hall of halls) {
|
|
8050
8207
|
if (!hall.isDirectory() || !/^[\w\-]{1,80}$/.test(hall.name)) continue;
|
|
8051
|
-
const rooms = await fs7.readdir(
|
|
8208
|
+
const rooms = await fs7.readdir(path9.join(palaceDir, wing.name, hall.name), { withFileTypes: true });
|
|
8052
8209
|
for (const room of rooms) {
|
|
8053
8210
|
if (!room.isDirectory() || !/^[\w\-]{1,80}$/.test(room.name)) continue;
|
|
8054
|
-
const drawers = await fs7.readdir(
|
|
8211
|
+
const drawers = await fs7.readdir(path9.join(palaceDir, wing.name, hall.name, room.name));
|
|
8055
8212
|
for (const drawer of drawers) {
|
|
8056
8213
|
if (/^[\w\-]{1,120}\.md$/.test(drawer)) entries.push({ rel: `memory/palace/${wing.name}/${hall.name}/${room.name}/${drawer}` });
|
|
8057
8214
|
}
|
|
@@ -8062,7 +8219,7 @@ function registerProfileRoutes(r) {
|
|
|
8062
8219
|
}
|
|
8063
8220
|
for (const e of entries) {
|
|
8064
8221
|
try {
|
|
8065
|
-
const stat = await fs7.stat(
|
|
8222
|
+
const stat = await fs7.stat(path9.join(dir, e.rel));
|
|
8066
8223
|
items.push({ path: e.rel, size: stat.size, mtime: stat.mtimeMs });
|
|
8067
8224
|
} catch {
|
|
8068
8225
|
}
|
|
@@ -8135,15 +8292,20 @@ function registerProfileRoutes(r) {
|
|
|
8135
8292
|
const cfg = await readConfig(slug);
|
|
8136
8293
|
if (!cfg) throw new HttpError(404, "profile not found");
|
|
8137
8294
|
const data = body ?? {};
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
llm
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8295
|
+
let generated;
|
|
8296
|
+
try {
|
|
8297
|
+
const llm = makeLLM(cfg.llm);
|
|
8298
|
+
generated = await generatePersonaPack(
|
|
8299
|
+
llm,
|
|
8300
|
+
cfg.slug,
|
|
8301
|
+
data.name ?? cfg.name,
|
|
8302
|
+
data.age ?? cfg.age,
|
|
8303
|
+
data.nationality ?? cfg.nationality,
|
|
8304
|
+
data.notes ?? cfg.personaNotes
|
|
8305
|
+
);
|
|
8306
|
+
} catch {
|
|
8307
|
+
generated = await ensurePersonaPack(cfg.slug, data.name ?? cfg.name, data.age ?? cfg.age);
|
|
8308
|
+
}
|
|
8147
8309
|
cfg.busySchedule = generated.busySchedule;
|
|
8148
8310
|
await writeConfig(cfg);
|
|
8149
8311
|
return { ok: true, busySchedule: generated.busySchedule };
|
|
@@ -8160,7 +8322,6 @@ init_esm_shims();
|
|
|
8160
8322
|
init_llm2();
|
|
8161
8323
|
init_stages();
|
|
8162
8324
|
init_communication();
|
|
8163
|
-
init_mcp();
|
|
8164
8325
|
|
|
8165
8326
|
// src/data/timezones.ts
|
|
8166
8327
|
init_esm_shims();
|
|
@@ -8407,15 +8568,6 @@ function registerPresetRoutes(r) {
|
|
|
8407
8568
|
profile: p.profile
|
|
8408
8569
|
}))
|
|
8409
8570
|
}));
|
|
8410
|
-
r.get("/api/presets/mcp", () => ({
|
|
8411
|
-
presets: MCP_PRESETS.map((p) => ({
|
|
8412
|
-
id: p.id,
|
|
8413
|
-
name: p.name,
|
|
8414
|
-
description: p.description,
|
|
8415
|
-
ready: p.ready,
|
|
8416
|
-
secrets: p.secrets ?? []
|
|
8417
|
-
}))
|
|
8418
|
-
}));
|
|
8419
8571
|
r.get("/api/presets/timezones", ({ searchParams }) => {
|
|
8420
8572
|
const q = searchParams.get("q") ?? "";
|
|
8421
8573
|
const all = q ? findTzByQuery(q, 200) : TIMEZONES;
|
|
@@ -8433,7 +8585,7 @@ init_esm_shims();
|
|
|
8433
8585
|
init_md();
|
|
8434
8586
|
import { promises as fs8 } from "fs";
|
|
8435
8587
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8436
|
-
import
|
|
8588
|
+
import path10 from "path";
|
|
8437
8589
|
import os2 from "os";
|
|
8438
8590
|
var cachedVersion = null;
|
|
8439
8591
|
async function readPackageVersion() {
|
|
@@ -8441,12 +8593,12 @@ async function readPackageVersion() {
|
|
|
8441
8593
|
const candidates = [];
|
|
8442
8594
|
try {
|
|
8443
8595
|
const here = fileURLToPath4(import.meta.url);
|
|
8444
|
-
candidates.push(
|
|
8445
|
-
candidates.push(
|
|
8446
|
-
candidates.push(
|
|
8596
|
+
candidates.push(path10.resolve(path10.dirname(here), "..", "package.json"));
|
|
8597
|
+
candidates.push(path10.resolve(path10.dirname(here), "..", "..", "package.json"));
|
|
8598
|
+
candidates.push(path10.resolve(path10.dirname(here), "..", "..", "..", "package.json"));
|
|
8447
8599
|
} catch {
|
|
8448
8600
|
}
|
|
8449
|
-
candidates.push(
|
|
8601
|
+
candidates.push(path10.resolve(process.cwd(), "package.json"));
|
|
8450
8602
|
for (const c of candidates) {
|
|
8451
8603
|
try {
|
|
8452
8604
|
const raw = await fs8.readFile(c, "utf8");
|
|
@@ -8501,7 +8653,7 @@ function registerSystemRoutes(r) {
|
|
|
8501
8653
|
init_esm_shims();
|
|
8502
8654
|
init_addons();
|
|
8503
8655
|
import { promises as fs10 } from "fs";
|
|
8504
|
-
import
|
|
8656
|
+
import path12 from "path";
|
|
8505
8657
|
import os4 from "os";
|
|
8506
8658
|
function registerAddonRoutes(r) {
|
|
8507
8659
|
r.get("/api/addons", async () => {
|
|
@@ -8528,7 +8680,7 @@ function registerAddonRoutes(r) {
|
|
|
8528
8680
|
const data = body;
|
|
8529
8681
|
if (!data?.gaaBase64) throw new HttpError(400, "gaaBase64 required");
|
|
8530
8682
|
const buf = Buffer.from(data.gaaBase64, "base64");
|
|
8531
|
-
const tmpPath =
|
|
8683
|
+
const tmpPath = path12.join(os4.tmpdir(), `upload-${Date.now()}.gaa`);
|
|
8532
8684
|
await fs10.writeFile(tmpPath, buf);
|
|
8533
8685
|
try {
|
|
8534
8686
|
const result = await installFromGaa(tmpPath, data.profileSlug);
|
|
@@ -8546,7 +8698,7 @@ function registerAddonRoutes(r) {
|
|
|
8546
8698
|
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
8547
8699
|
if (!res.ok) throw new HttpError(502, `fetch failed: HTTP ${res.status}`);
|
|
8548
8700
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
8549
|
-
const tmpPath =
|
|
8701
|
+
const tmpPath = path12.join(os4.tmpdir(), `url-${Date.now()}.gaa`);
|
|
8550
8702
|
await fs10.writeFile(tmpPath, buf);
|
|
8551
8703
|
try {
|
|
8552
8704
|
const result = await installFromGaa(tmpPath, data.profileSlug);
|
|
@@ -8606,7 +8758,6 @@ init_runtime_bus();
|
|
|
8606
8758
|
init_esm_shims();
|
|
8607
8759
|
init_communication();
|
|
8608
8760
|
init_llm2();
|
|
8609
|
-
init_mcp();
|
|
8610
8761
|
init_stages();
|
|
8611
8762
|
var CORE_KNOWLEDGE_BASE = [
|
|
8612
8763
|
{
|
|
@@ -8635,7 +8786,7 @@ var CORE_KNOWLEDGE_BASE = [
|
|
|
8635
8786
|
subcategory: "project-structure",
|
|
8636
8787
|
title: "\u041A\u0430\u0440\u0442\u0430 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u0439",
|
|
8637
8788
|
keywords: ["\u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u0438", "\u0444\u0430\u0439\u043B\u044B", "\u0441\u0442\u0440\u0443\u043A\u0442\u0443\u0440\u0430", "src", "engine", "webui", "telegram", "storage"],
|
|
8638
|
-
body: "src/engine \u2014 \u044F\u0434\u0440\u043E \u043F\u043E\u0432\u0435\u0434\u0435\u043D\u0438\u044F: runtime, presence, behavior-tick, prompt, memory-palace, conflict, agenda, daily-life. src/telegram \u2014 bot/userbot adapters. src/llm \u2014 \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u043E\u0432. src/storage/md.ts \u2014 \u0444\u0430\u0439\u043B\u043E\u0432\u043E\u0435 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439. src/webui \u2014 HTTP API, runtime bus, routes. webui/src \u2014 React \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B. src/presets \u2014 stages, llm, communication
|
|
8789
|
+
body: "src/engine \u2014 \u044F\u0434\u0440\u043E \u043F\u043E\u0432\u0435\u0434\u0435\u043D\u0438\u044F: runtime, presence, behavior-tick, prompt, memory-palace, conflict, agenda, daily-life. src/telegram \u2014 bot/userbot adapters. src/llm \u2014 \u043A\u043B\u0438\u0435\u043D\u0442\u044B \u043F\u0440\u043E\u0432\u0430\u0439\u0434\u0435\u0440\u043E\u0432. src/storage/md.ts \u2014 \u0444\u0430\u0439\u043B\u043E\u0432\u043E\u0435 \u0445\u0440\u0430\u043D\u0438\u043B\u0438\u0449\u0435 \u043F\u0440\u043E\u0444\u0438\u043B\u0435\u0439. src/webui \u2014 HTTP API, runtime bus, routes. webui/src \u2014 React \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B. src/presets \u2014 stages, llm, communication."
|
|
8639
8790
|
},
|
|
8640
8791
|
{
|
|
8641
8792
|
category: "overview",
|
|
@@ -8677,7 +8828,7 @@ var CORE_KNOWLEDGE_BASE = [
|
|
|
8677
8828
|
subcategory: "profile-config",
|
|
8678
8829
|
title: "ProfileConfig",
|
|
8679
8830
|
keywords: ["ProfileConfig", "config", "slug", "name", "age", "nationality", "tz", "mode"],
|
|
8680
|
-
body: "ProfileConfig \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 slug, name, age, nationality RU/UA, timezone, mode bot/userbot, stage, llm, telegram,
|
|
8831
|
+
body: "ProfileConfig \u0432\u043A\u043B\u044E\u0447\u0430\u0435\u0442 slug, name, age, nationality RU/UA, timezone, mode bot/userbot, stage, llm, telegram, ownerId, privacy, sleepFrom/sleepTo, nightWakeChance, ignoreTendency, vibe, communication, personaNotes, addons \u0438 busySchedule. \u041F\u0440\u0438 \u0447\u0442\u0435\u043D\u0438\u0438 storage \u043D\u043E\u0440\u043C\u0430\u043B\u0438\u0437\u0443\u0435\u0442 ownerId, communication \u0438 ignoreTendency."
|
|
8681
8832
|
},
|
|
8682
8833
|
{
|
|
8683
8834
|
category: "config",
|
|
@@ -9036,13 +9187,6 @@ var CORE_KNOWLEDGE_BASE = [
|
|
|
9036
9187
|
keywords: ["manifest", "addon", "id", "version", "compatibility", "settings"],
|
|
9037
9188
|
body: "Manifest \u0442\u0440\u0435\u0431\u0443\u0435\u0442 id/name/description/version. \u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u043E: author, compatibility semver range, tags, dependencies, settings, icon, homepage. Settings \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u044E\u0442 string/number/boolean/select \u0441 default/options/required."
|
|
9038
9189
|
},
|
|
9039
|
-
{
|
|
9040
|
-
category: "mcp",
|
|
9041
|
-
subcategory: "client",
|
|
9042
|
-
title: "MCP servers",
|
|
9043
|
-
keywords: ["mcp", "tools", "stdio", "exa", "spotify", "instagram", "weather", "calendar"],
|
|
9044
|
-
body: "startMcpServers \u0447\u0438\u0442\u0430\u0435\u0442 cfg.mcp, \u043D\u0430\u0445\u043E\u0434\u0438\u0442 preset, \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0435\u0442 stdio transport, \u043F\u043E\u0434\u043A\u043B\u044E\u0447\u0430\u0435\u0442 MCP Client \u0438 \u043F\u043E\u043B\u0443\u0447\u0430\u0435\u0442 listTools. \u0421\u0435\u0439\u0447\u0430\u0441 \u0433\u043E\u0442\u043E\u0432 Exa Search \u0447\u0435\u0440\u0435\u0437 npx -y exa-mcp-server \u0438 EXA_API_KEY; spotify/instagram/weather/calendar \u043F\u043E\u043C\u0435\u0447\u0435\u043D\u044B soon."
|
|
9045
|
-
},
|
|
9046
9190
|
{
|
|
9047
9191
|
category: "migrations",
|
|
9048
9192
|
subcategory: "data-migrations",
|
|
@@ -9089,11 +9233,11 @@ function generatedKnowledge() {
|
|
|
9089
9233
|
body: LLM_PRESETS.map((p) => `${p.id}: ${p.name}, proto=${p.proto}, default=${p.defaultModel || "custom"}${p.baseURL ? `, baseURL=${p.baseURL}` : ""}${p.disabled ? `, disabled=${p.disabledReason ?? "yes"}` : ""}${p.hint ? `, hint=${p.hint}` : ""}`).join("\n")
|
|
9090
9234
|
},
|
|
9091
9235
|
{
|
|
9092
|
-
category: "
|
|
9093
|
-
subcategory: "
|
|
9094
|
-
title: "\
|
|
9095
|
-
keywords: ["
|
|
9096
|
-
body:
|
|
9236
|
+
category: "addons",
|
|
9237
|
+
subcategory: "integration-index",
|
|
9238
|
+
title: "\u0410\u0434\u0434\u043E\u043D\u044B \u0432\u043C\u0435\u0441\u0442\u043E MCP",
|
|
9239
|
+
keywords: ["addons", "\u0430\u0434\u0434\u043E\u043D\u044B", "\u0438\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438", "gaa", "mcp"],
|
|
9240
|
+
body: "\u0412\u043D\u0435\u0448\u043D\u0438\u0435 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043D\u0438\u044F \u0442\u0435\u043F\u0435\u0440\u044C \u043F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u044E\u0442\u0441\u044F \u043A\u0430\u043A \u0430\u0434\u0434\u043E\u043D\u044B. MCP-\u043F\u0440\u0435\u0441\u0435\u0442\u044B \u043D\u0435 \u0432\u044B\u0432\u043E\u0434\u044F\u0442\u0441\u044F \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0439 \u0441\u0438\u0441\u0442\u0435\u043C\u043E\u0439 \u0432 WebUI; \u0438\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438 \u0441\u0442\u0430\u0432\u044F\u0442\u0441\u044F \u0447\u0435\u0440\u0435\u0437 Marketplace/.gaa \u0438 \u043C\u043E\u0433\u0443\u0442 \u043C\u0435\u043D\u044F\u0442\u044C config.patch.json, \u0444\u0430\u0439\u043B\u044B \u043F\u0440\u043E\u0444\u0438\u043B\u044F, \u0442\u0435\u043C\u0443 \u0438\u043B\u0438 code.patch."
|
|
9097
9241
|
}
|
|
9098
9242
|
];
|
|
9099
9243
|
}
|
|
@@ -9563,8 +9707,8 @@ function tail(text, limit) {
|
|
|
9563
9707
|
if (text.length <= limit) return text;
|
|
9564
9708
|
return text.slice(-limit);
|
|
9565
9709
|
}
|
|
9566
|
-
function setNested(obj,
|
|
9567
|
-
const parts =
|
|
9710
|
+
function setNested(obj, path14, value) {
|
|
9711
|
+
const parts = path14.split(".");
|
|
9568
9712
|
let cur = obj;
|
|
9569
9713
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9570
9714
|
const p = parts[i];
|
|
@@ -9583,14 +9727,14 @@ var DEFAULT_PROXY = "https://tgproxy.girl-agent.com";
|
|
|
9583
9727
|
function proxyUrl() {
|
|
9584
9728
|
return process.env.GIRL_AGENT_AUTH_PROXY ?? DEFAULT_PROXY;
|
|
9585
9729
|
}
|
|
9586
|
-
async function post(
|
|
9587
|
-
const res = await fetch(`${proxyUrl()}${
|
|
9730
|
+
async function post(path14, body) {
|
|
9731
|
+
const res = await fetch(`${proxyUrl()}${path14}`, {
|
|
9588
9732
|
method: "POST",
|
|
9589
9733
|
headers: { "Content-Type": "application/json" },
|
|
9590
9734
|
body: JSON.stringify(body)
|
|
9591
9735
|
});
|
|
9592
9736
|
const data = await res.json();
|
|
9593
|
-
if (!res.ok) throw new Error(data.error ?? `proxy ${
|
|
9737
|
+
if (!res.ok) throw new Error(data.error ?? `proxy ${path14} failed (${res.status})`);
|
|
9594
9738
|
return data;
|
|
9595
9739
|
}
|
|
9596
9740
|
function remoteSendCode(phone) {
|
|
@@ -9701,12 +9845,59 @@ function registerTgAuthRoutes(r) {
|
|
|
9701
9845
|
});
|
|
9702
9846
|
}
|
|
9703
9847
|
|
|
9848
|
+
// src/webui/routes/auth.ts
|
|
9849
|
+
init_esm_shims();
|
|
9850
|
+
function registerAuthRoutes(r) {
|
|
9851
|
+
r.get("/api/auth/status", () => authStatus());
|
|
9852
|
+
r.post("/api/auth/login", ({ body, res }) => {
|
|
9853
|
+
const { password } = body ?? {};
|
|
9854
|
+
if (!verifyPassword(password ?? "")) throw new HttpError(401, "\u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C");
|
|
9855
|
+
createSession(res);
|
|
9856
|
+
return { ok: true };
|
|
9857
|
+
});
|
|
9858
|
+
r.post("/api/auth/logout", ({ req, res }) => {
|
|
9859
|
+
clearSession(req, res);
|
|
9860
|
+
return { ok: true };
|
|
9861
|
+
});
|
|
9862
|
+
}
|
|
9863
|
+
|
|
9704
9864
|
// src/webui/server.ts
|
|
9705
9865
|
init_md();
|
|
9706
9866
|
var DEFAULT_PORT = Number(process.env.GIRL_AGENT_PORT ?? 3e3);
|
|
9707
|
-
|
|
9867
|
+
function isLikelyDocker() {
|
|
9868
|
+
if (process.env.GIRL_AGENT_DOCKER || process.env.DOCKER_CONTAINER) return true;
|
|
9869
|
+
try {
|
|
9870
|
+
return os5.release().toLowerCase().includes("docker") || existsSync2("/.dockerenv") || readFileSync2("/proc/1/cgroup", "utf8").toLowerCase().includes("docker");
|
|
9871
|
+
} catch {
|
|
9872
|
+
return false;
|
|
9873
|
+
}
|
|
9874
|
+
}
|
|
9875
|
+
function firstExternalIPv4() {
|
|
9876
|
+
for (const items of Object.values(os5.networkInterfaces())) {
|
|
9877
|
+
for (const item of items ?? []) {
|
|
9878
|
+
if (item.family === "IPv4" && !item.internal) return item.address;
|
|
9879
|
+
}
|
|
9880
|
+
}
|
|
9881
|
+
return void 0;
|
|
9882
|
+
}
|
|
9883
|
+
function publicUrlForPort(port) {
|
|
9884
|
+
const explicit = process.env.GIRL_AGENT_PUBLIC_URL?.trim();
|
|
9885
|
+
if (explicit) {
|
|
9886
|
+
try {
|
|
9887
|
+
const url = new URL2(explicit);
|
|
9888
|
+
if (!url.port) url.port = String(port);
|
|
9889
|
+
return url.toString().replace(/\/$/, "");
|
|
9890
|
+
} catch {
|
|
9891
|
+
const clean = explicit.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
9892
|
+
return `http://${clean.includes(":") ? clean : `${clean}:${port}`}`;
|
|
9893
|
+
}
|
|
9894
|
+
}
|
|
9895
|
+
return `http://${firstExternalIPv4() ?? "0.0.0.0"}:${port}`;
|
|
9896
|
+
}
|
|
9897
|
+
var DEFAULT_HOST = process.env.GIRL_AGENT_HOST ?? (isLikelyDocker() ? "0.0.0.0" : "127.0.0.1");
|
|
9708
9898
|
function buildRouter() {
|
|
9709
9899
|
const r = new Router();
|
|
9900
|
+
registerAuthRoutes(r);
|
|
9710
9901
|
registerProfileRoutes(r);
|
|
9711
9902
|
registerPresetRoutes(r);
|
|
9712
9903
|
registerSystemRoutes(r);
|
|
@@ -9730,6 +9921,10 @@ async function startWebUIServer(opts = {}) {
|
|
|
9730
9921
|
const url2 = new URL2(req.url ?? "/", `http://${req.headers.host ?? host}`);
|
|
9731
9922
|
const pathname = url2.pathname;
|
|
9732
9923
|
if (pathname.startsWith("/api/")) {
|
|
9924
|
+
if (!pathname.startsWith("/api/auth/") && !isAuthorized(req)) {
|
|
9925
|
+
sendJson(res, 401, { error: "auth required" });
|
|
9926
|
+
return;
|
|
9927
|
+
}
|
|
9733
9928
|
const matched = router.match(req.method ?? "GET", pathname);
|
|
9734
9929
|
if (!matched) {
|
|
9735
9930
|
sendJson(res, 404, { error: "not found", path: pathname });
|
|
@@ -9789,20 +9984,12 @@ async function startWebUIServer(opts = {}) {
|
|
|
9789
9984
|
resolve();
|
|
9790
9985
|
});
|
|
9791
9986
|
});
|
|
9792
|
-
const
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
displayHost = i.address;
|
|
9799
|
-
break;
|
|
9800
|
-
}
|
|
9801
|
-
}
|
|
9802
|
-
if (displayHost !== "0.0.0.0") break;
|
|
9803
|
-
}
|
|
9804
|
-
}
|
|
9805
|
-
const url = `http://${displayHost === "0.0.0.0" ? "127.0.0.1" : displayHost}:${port}`;
|
|
9987
|
+
const urls = {
|
|
9988
|
+
loopback: `http://127.0.0.1:${port}`,
|
|
9989
|
+
localhost: `http://localhost:${port}`,
|
|
9990
|
+
public: publicUrlForPort(port)
|
|
9991
|
+
};
|
|
9992
|
+
const url = urls.localhost;
|
|
9806
9993
|
if (opts.autoStart) {
|
|
9807
9994
|
try {
|
|
9808
9995
|
const slugs = await listProfiles();
|
|
@@ -9820,6 +10007,7 @@ async function startWebUIServer(opts = {}) {
|
|
|
9820
10007
|
port,
|
|
9821
10008
|
host,
|
|
9822
10009
|
url,
|
|
10010
|
+
urls,
|
|
9823
10011
|
async stop() {
|
|
9824
10012
|
await bus.stopAll();
|
|
9825
10013
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
@@ -9978,7 +10166,7 @@ init_llm2();
|
|
|
9978
10166
|
init_stages();
|
|
9979
10167
|
init_communication();
|
|
9980
10168
|
import fs11 from "fs/promises";
|
|
9981
|
-
import
|
|
10169
|
+
import path13 from "path";
|
|
9982
10170
|
import os6 from "os";
|
|
9983
10171
|
init_md();
|
|
9984
10172
|
init_runtime();
|
|
@@ -10010,7 +10198,7 @@ env-vars (\u0434\u043B\u044F CI / docker secrets / k8s):
|
|
|
10010
10198
|
GIRL_AGENT_MODEL, _NAME, _AGE, _NATIONALITY, _TZ, _STAGE (id \u0438\u043B\u0438 \u043D\u043E\u043C\u0435\u0440 1-8), _COMM_PRESET, _IGNORE_TENDENCY, _OWNER_ID
|
|
10011
10199
|
|
|
10012
10200
|
\u0434\u043B\u044F \u0438\u043D\u0442\u0435\u0440\u0430\u043A\u0442\u0438\u0432\u043D\u043E\u0439 \u043F\u0435\u0440\u0432\u0438\u0447\u043D\u043E\u0439 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0438 \u0437\u0430\u043F\u0443\u0441\u043A\u0430\u0439 \u0431\u0435\u0437 \u0444\u043B\u0430\u0433\u043E\u0432 \u2014
|
|
10013
|
-
\u043E\u0442\u043A\u0440\u043E\u0435\u0442\u0441\u044F WebUI \u043D\u0430 http://localhost:3000.
|
|
10201
|
+
\u043E\u0442\u043A\u0440\u043E\u0435\u0442\u0441\u044F WebUI \u043D\u0430 http://localhost:3000 (\u0432 docker \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 -p 3000:3000).
|
|
10014
10202
|
`;
|
|
10015
10203
|
function parseServerArgs(argv) {
|
|
10016
10204
|
return {
|
|
@@ -10061,7 +10249,7 @@ async function runServer(rawArgv) {
|
|
|
10061
10249
|
}
|
|
10062
10250
|
if (!args.yes) {
|
|
10063
10251
|
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.
|
|
10064
|
-
\u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${
|
|
10252
|
+
\u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${path13.join(DATA_ROOT, args.profile)}
|
|
10065
10253
|
`);
|
|
10066
10254
|
process.exit(1);
|
|
10067
10255
|
}
|
|
@@ -10123,7 +10311,7 @@ data dir: ${DATA_ROOT}
|
|
|
10123
10311
|
}
|
|
10124
10312
|
async function persistAndMaybeStart(cfg, args) {
|
|
10125
10313
|
await writeConfig(cfg);
|
|
10126
|
-
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${
|
|
10314
|
+
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${path13.join(DATA_ROOT, cfg.slug)}
|
|
10127
10315
|
`);
|
|
10128
10316
|
if (cfg.llm.apiKey || findPreset(cfg.llm.presetId)?.apiKeyRequired === false) {
|
|
10129
10317
|
try {
|
|
@@ -10226,7 +10414,6 @@ function configFromEnv() {
|
|
|
10226
10414
|
phone: e.GIRL_AGENT_TG_PHONE ?? "",
|
|
10227
10415
|
proxy: parseTelegramProxy(e.GIRL_AGENT_TG_PROXY)
|
|
10228
10416
|
},
|
|
10229
|
-
mcp: [],
|
|
10230
10417
|
ownerId: normalizeOwnerId(e.GIRL_AGENT_OWNER_ID),
|
|
10231
10418
|
privacy: "owner-only",
|
|
10232
10419
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10240,7 +10427,7 @@ function configFromEnv() {
|
|
|
10240
10427
|
};
|
|
10241
10428
|
}
|
|
10242
10429
|
async function loadConfigFile(file) {
|
|
10243
|
-
const abs =
|
|
10430
|
+
const abs = path13.isAbsolute(file) ? file : path13.join(process.cwd(), file);
|
|
10244
10431
|
let raw;
|
|
10245
10432
|
try {
|
|
10246
10433
|
raw = await fs11.readFile(abs, "utf-8");
|
|
@@ -10294,7 +10481,6 @@ function validateConfig(raw) {
|
|
|
10294
10481
|
model: c.llm.model
|
|
10295
10482
|
},
|
|
10296
10483
|
telegram: c.telegram ?? {},
|
|
10297
|
-
mcp: c.mcp ?? [],
|
|
10298
10484
|
ownerId: normalizeOwnerId(c.ownerId ?? process.env.GIRL_AGENT_OWNER_ID),
|
|
10299
10485
|
privacy: c.privacy ?? "owner-only",
|
|
10300
10486
|
createdAt: c.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10313,6 +10499,14 @@ function parseTelegramProxy(raw) {
|
|
|
10313
10499
|
if (!raw?.trim()) return void 0;
|
|
10314
10500
|
try {
|
|
10315
10501
|
const url = new URL(raw);
|
|
10502
|
+
if (url.protocol === "tg:" && url.hostname === "proxy") {
|
|
10503
|
+
const ip = url.searchParams.get("server")?.trim();
|
|
10504
|
+
const port2 = Number(url.searchParams.get("port"));
|
|
10505
|
+
const secret = url.searchParams.get("secret")?.trim();
|
|
10506
|
+
if (!ip || !Number.isInteger(port2) || port2 <= 0 || !secret) return void 0;
|
|
10507
|
+
return { ip, port: port2, MTProxy: true, secret };
|
|
10508
|
+
}
|
|
10509
|
+
if (url.protocol !== "socks4:" && url.protocol !== "socks5:") return void 0;
|
|
10316
10510
|
const socksType = url.protocol === "socks4:" ? 4 : 5;
|
|
10317
10511
|
const port = Number(url.port);
|
|
10318
10512
|
if (!url.hostname || !Number.isInteger(port) || port <= 0) return void 0;
|
|
@@ -10347,7 +10541,6 @@ function buildConfigTemplate() {
|
|
|
10347
10541
|
model: "claude-sonnet-4.6"
|
|
10348
10542
|
},
|
|
10349
10543
|
telegram: { botToken: "REPLACE_ME" },
|
|
10350
|
-
mcp: [],
|
|
10351
10544
|
ownerId: void 0,
|
|
10352
10545
|
privacy: "owner-only",
|
|
10353
10546
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10426,9 +10619,11 @@ docker run -d --name girl-agent --restart=unless-stopped \\
|
|
|
10426
10619
|
# services:
|
|
10427
10620
|
# girl-agent:
|
|
10428
10621
|
# image: ghcr.io/thesashadev/girl-agent:latest
|
|
10622
|
+
# # interactive WebUI: command: [] and ports: ["3000:3000"]
|
|
10429
10623
|
# command: ["server", "--config", "/config/bot.json", "--headless"]
|
|
10430
10624
|
# environment:
|
|
10431
10625
|
# GIRL_AGENT_DATA: /data
|
|
10626
|
+
# GIRL_AGENT_HOST: 0.0.0.0
|
|
10432
10627
|
# volumes:
|
|
10433
10628
|
# - girl-agent-data:/data
|
|
10434
10629
|
# - ./bot.json:/config/bot.json:ro
|
|
@@ -10447,6 +10642,16 @@ init_llm();
|
|
|
10447
10642
|
init_llm2();
|
|
10448
10643
|
init_stages();
|
|
10449
10644
|
init_communication();
|
|
10645
|
+
var nodeMajor = Number(process.versions.node.split(".")[0] ?? 0);
|
|
10646
|
+
if (nodeMajor < 18) {
|
|
10647
|
+
process.stderr.write(`[girl-agent] Node.js ${process.version} \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F. \u041D\u0443\u0436\u0435\u043D Node.js 18.18+; \u0432 Termux: pkg install nodejs
|
|
10648
|
+
`);
|
|
10649
|
+
process.exit(1);
|
|
10650
|
+
}
|
|
10651
|
+
if (nodeMajor < 20) {
|
|
10652
|
+
process.stderr.write(`[girl-agent] \u043F\u0440\u0435\u0434\u0443\u043F\u0440\u0435\u0436\u0434\u0435\u043D\u0438\u0435: Node.js ${process.version}; \u0440\u0435\u043A\u043E\u043C\u0435\u043D\u0434\u0443\u0435\u0442\u0441\u044F 20/22, \u043D\u043E \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0430\u044E \u0437\u0430\u043F\u0443\u0441\u043A.
|
|
10653
|
+
`);
|
|
10654
|
+
}
|
|
10450
10655
|
var HELP = `
|
|
10451
10656
|
girl-agent \u2014 AI girl for Telegram (WebUI)
|
|
10452
10657
|
|
|
@@ -10454,6 +10659,7 @@ usage:
|
|
|
10454
10659
|
npx girl-agent # \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C WebUI \u0438 \u043E\u0442\u043A\u0440\u044B\u0442\u044C http://localhost:3000
|
|
10455
10660
|
npx girl-agent --port=8080 # \u043A\u0430\u0441\u0442\u043E\u043C\u043D\u044B\u0439 \u043F\u043E\u0440\u0442
|
|
10456
10661
|
npx girl-agent --host=0.0.0.0 # \u0441\u043B\u0443\u0448\u0430\u0442\u044C \u043D\u0430 \u0432\u0441\u0435\u0445 \u0438\u043D\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430\u0445
|
|
10662
|
+
GIRL_AGENT_PUBLIC_URL=https://example.com npx girl-agent # URL \u0434\u043B\u044F reverse proxy/docker
|
|
10457
10663
|
npx girl-agent --no-browser # \u043D\u0435 \u043E\u0442\u043A\u0440\u044B\u0432\u0430\u0442\u044C \u0431\u0440\u0430\u0443\u0437\u0435\u0440 \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438
|
|
10458
10664
|
npx girl-agent --profile=<slug> # \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C WebUI \u0438 \u0441\u0440\u0430\u0437\u0443 \u0437\u0430\u043F\u0443\u0441\u0442\u0438\u0442\u044C \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u044B\u0439 \u043F\u0440\u043E\u0444\u0438\u043B\u044C
|
|
10459
10665
|
|
|
@@ -10492,7 +10698,6 @@ async function main() {
|
|
|
10492
10698
|
"proto",
|
|
10493
10699
|
"name",
|
|
10494
10700
|
"stage",
|
|
10495
|
-
"mcp",
|
|
10496
10701
|
"nationality",
|
|
10497
10702
|
"tz",
|
|
10498
10703
|
"vibe",
|
|
@@ -10651,20 +10856,19 @@ async function main() {
|
|
|
10651
10856
|
autoStart: !argv.profile,
|
|
10652
10857
|
noBrowser: !!argv["no-browser"]
|
|
10653
10858
|
});
|
|
10654
|
-
const showHost = host === "0.0.0.0" ? "<public-ip>" : host === "127.0.0.1" ? "localhost" : host;
|
|
10655
|
-
const localUrl = `http://${host === "0.0.0.0" ? "127.0.0.1" : host}:${port}`;
|
|
10656
10859
|
process.stdout.write(`
|
|
10657
10860
|
\u{1F310} girl-agent WebUI \u0437\u0430\u043F\u0443\u0449\u0435\u043D
|
|
10658
|
-
${instance.url}
|
|
10659
10861
|
`);
|
|
10660
|
-
|
|
10661
|
-
|
|
10862
|
+
process.stdout.write(` 1) ${instance.urls.loopback}
|
|
10863
|
+
`);
|
|
10864
|
+
process.stdout.write(` 2) ${instance.urls.localhost}
|
|
10865
|
+
`);
|
|
10866
|
+
process.stdout.write(` 3) ${instance.urls.public}
|
|
10662
10867
|
`);
|
|
10663
|
-
}
|
|
10664
10868
|
process.stdout.write(`
|
|
10665
|
-
REST API: ${
|
|
10869
|
+
REST API: ${instance.urls.loopback}/api/system/health
|
|
10666
10870
|
`);
|
|
10667
|
-
process.stdout.write(` WebSocket logs: ws
|
|
10871
|
+
process.stdout.write(` WebSocket logs: ws://127.0.0.1:${port}/ws/logs/<slug>
|
|
10668
10872
|
`);
|
|
10669
10873
|
process.stdout.write(` Ctrl+C \u0434\u043B\u044F \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438
|
|
10670
10874
|
|
|
@@ -10734,17 +10938,11 @@ async function buildConfigFromFlags(argv) {
|
|
|
10734
10938
|
const slug = String(argv.profile ?? slugifyLocal(name));
|
|
10735
10939
|
const mode = argv.mode === "userbot" ? "userbot" : "bot";
|
|
10736
10940
|
const tz = (argv.tz ? parseTzFlag(String(argv.tz)) : void 0) ?? defaultTzForNationality(nationality);
|
|
10737
|
-
const mcpFlags = [].concat(argv.mcp ?? []);
|
|
10738
10941
|
const communication = (() => {
|
|
10739
10942
|
const preset2 = findCommunicationPreset(typeof argv["communication-preset"] === "string" ? argv["communication-preset"] : void 0);
|
|
10740
10943
|
return preset2?.profile ?? normalizeCommunicationProfile({});
|
|
10741
10944
|
})();
|
|
10742
10945
|
const privacy = argv.privacy === "allow-strangers" ? "allow-strangers" : "owner-only";
|
|
10743
|
-
const mcps = mcpFlags.map((entry) => {
|
|
10744
|
-
const [id, key] = entry.split(":");
|
|
10745
|
-
const secrets = id === "exa" ? { EXA_API_KEY: key ?? "" } : { value: key ?? "" };
|
|
10746
|
-
return { id: id ?? "", secrets };
|
|
10747
|
-
});
|
|
10748
10946
|
return {
|
|
10749
10947
|
slug,
|
|
10750
10948
|
name,
|
|
@@ -10759,7 +10957,6 @@ async function buildConfigFromFlags(argv) {
|
|
|
10759
10957
|
apiHash: String(argv["api-hash"] ?? ""),
|
|
10760
10958
|
phone: String(argv.phone ?? "")
|
|
10761
10959
|
},
|
|
10762
|
-
mcp: mcps,
|
|
10763
10960
|
privacy,
|
|
10764
10961
|
ownerId: normalizeOwnerId(argv["owner-id"] ?? process.env.GIRL_AGENT_OWNER_ID),
|
|
10765
10962
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|