@thesashadev/girl-agent 0.3.2 → 0.4.2
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 +76 -0
- package/README.md +159 -118
- package/dist/cli.js +875 -436
- 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
|
@@ -497,12 +497,168 @@ var init_markdown = __esm({
|
|
|
497
497
|
}
|
|
498
498
|
});
|
|
499
499
|
|
|
500
|
+
// src/telegram/reactions.ts
|
|
501
|
+
function normalizeBotReactionEmoji(emoji) {
|
|
502
|
+
if (!emoji) return void 0;
|
|
503
|
+
const trimmed = emoji.trim();
|
|
504
|
+
if (!trimmed) return void 0;
|
|
505
|
+
if (BOT_REACTION_ALLOWED.has(trimmed)) return trimmed;
|
|
506
|
+
const stripped = trimmed.replace(/\uFE0F/g, "");
|
|
507
|
+
if (BOT_REACTION_ALLOWED.has(stripped)) return stripped;
|
|
508
|
+
const mapped = FALLBACK[trimmed] ?? FALLBACK[stripped];
|
|
509
|
+
if (mapped && BOT_REACTION_ALLOWED.has(mapped)) return mapped;
|
|
510
|
+
return void 0;
|
|
511
|
+
}
|
|
512
|
+
var BOT_REACTION_ALLOWED, FALLBACK;
|
|
513
|
+
var init_reactions = __esm({
|
|
514
|
+
"src/telegram/reactions.ts"() {
|
|
515
|
+
"use strict";
|
|
516
|
+
init_esm_shims();
|
|
517
|
+
BOT_REACTION_ALLOWED = /* @__PURE__ */ new Set([
|
|
518
|
+
"\u{1F44D}",
|
|
519
|
+
"\u{1F44E}",
|
|
520
|
+
"\u2764",
|
|
521
|
+
"\u{1F525}",
|
|
522
|
+
"\u{1F970}",
|
|
523
|
+
"\u{1F44F}",
|
|
524
|
+
"\u{1F601}",
|
|
525
|
+
"\u{1F914}",
|
|
526
|
+
"\u{1F92F}",
|
|
527
|
+
"\u{1F631}",
|
|
528
|
+
"\u{1F92C}",
|
|
529
|
+
"\u{1F622}",
|
|
530
|
+
"\u{1F389}",
|
|
531
|
+
"\u{1F929}",
|
|
532
|
+
"\u{1F92E}",
|
|
533
|
+
"\u{1F4A9}",
|
|
534
|
+
"\u{1F64F}",
|
|
535
|
+
"\u{1F44C}",
|
|
536
|
+
"\u{1F54A}",
|
|
537
|
+
"\u{1F921}",
|
|
538
|
+
"\u{1F971}",
|
|
539
|
+
"\u{1F974}",
|
|
540
|
+
"\u{1F60D}",
|
|
541
|
+
"\u{1F433}",
|
|
542
|
+
"\u2764\u200D\u{1F525}",
|
|
543
|
+
"\u{1F31A}",
|
|
544
|
+
"\u{1F32D}",
|
|
545
|
+
"\u{1F4AF}",
|
|
546
|
+
"\u{1F923}",
|
|
547
|
+
"\u26A1",
|
|
548
|
+
"\u{1F34C}",
|
|
549
|
+
"\u{1F3C6}",
|
|
550
|
+
"\u{1F494}",
|
|
551
|
+
"\u{1F928}",
|
|
552
|
+
"\u{1F610}",
|
|
553
|
+
"\u{1F353}",
|
|
554
|
+
"\u{1F37E}",
|
|
555
|
+
"\u{1F48B}",
|
|
556
|
+
"\u{1F595}",
|
|
557
|
+
"\u{1F608}",
|
|
558
|
+
"\u{1F634}",
|
|
559
|
+
"\u{1F62D}",
|
|
560
|
+
"\u{1F913}",
|
|
561
|
+
"\u{1F47B}",
|
|
562
|
+
"\u{1F468}\u200D\u{1F4BB}",
|
|
563
|
+
"\u{1F440}",
|
|
564
|
+
"\u{1F383}",
|
|
565
|
+
"\u{1F648}",
|
|
566
|
+
"\u{1F607}",
|
|
567
|
+
"\u{1F628}",
|
|
568
|
+
"\u{1F91D}",
|
|
569
|
+
"\u270D",
|
|
570
|
+
"\u{1F917}",
|
|
571
|
+
"\u{1FAE1}",
|
|
572
|
+
"\u{1F385}",
|
|
573
|
+
"\u{1F384}",
|
|
574
|
+
"\u2603",
|
|
575
|
+
"\u{1F485}",
|
|
576
|
+
"\u{1F92A}",
|
|
577
|
+
"\u{1F5FF}",
|
|
578
|
+
"\u{1F192}",
|
|
579
|
+
"\u{1F498}",
|
|
580
|
+
"\u{1F649}",
|
|
581
|
+
"\u{1F984}",
|
|
582
|
+
"\u{1F618}",
|
|
583
|
+
"\u{1F48A}",
|
|
584
|
+
"\u{1F64A}",
|
|
585
|
+
"\u{1F60E}",
|
|
586
|
+
"\u{1F47E}",
|
|
587
|
+
"\u{1F937}\u200D\u2642",
|
|
588
|
+
"\u{1F937}",
|
|
589
|
+
"\u{1F937}\u200D\u2640",
|
|
590
|
+
"\u{1F621}"
|
|
591
|
+
]);
|
|
592
|
+
FALLBACK = {
|
|
593
|
+
"\u2764\uFE0F": "\u2764",
|
|
594
|
+
"\u{1F496}": "\u2764",
|
|
595
|
+
"\u{1F497}": "\u2764",
|
|
596
|
+
"\u{1F495}": "\u2764",
|
|
597
|
+
"\u{1F493}": "\u2764",
|
|
598
|
+
"\u{1F49E}": "\u2764",
|
|
599
|
+
"\u{1FA77}": "\u2764",
|
|
600
|
+
"\u{1F49C}": "\u2764",
|
|
601
|
+
"\u{1F499}": "\u2764",
|
|
602
|
+
"\u{1F49A}": "\u2764",
|
|
603
|
+
"\u{1F9E1}": "\u2764",
|
|
604
|
+
"\u{1F49B}": "\u2764",
|
|
605
|
+
"\u{1F90D}": "\u2764",
|
|
606
|
+
"\u{1F5A4}": "\u2764",
|
|
607
|
+
"\u{1F90E}": "\u2764",
|
|
608
|
+
"\u{1F60F}": "\u{1F60E}",
|
|
609
|
+
"\u{1F644}": "\u{1F928}",
|
|
610
|
+
"\u{1F97A}": "\u{1F979}",
|
|
611
|
+
"\u{1F979}": "\u{1F62D}",
|
|
612
|
+
"\u{1F480}": "\u{1F5FF}",
|
|
613
|
+
"\u{1F602}": "\u{1F923}",
|
|
614
|
+
"\u{1F92D}": "\u{1F917}",
|
|
615
|
+
"\u{1F92B}": "\u{1FAE1}",
|
|
616
|
+
"\u{1F910}": "\u{1FAE1}",
|
|
617
|
+
"\u{1F643}": "\u{1F970}",
|
|
618
|
+
"\u{1F642}": "\u{1F970}",
|
|
619
|
+
"\u{1F60A}": "\u{1F970}",
|
|
620
|
+
"\u{1F605}": "\u{1F601}",
|
|
621
|
+
"\u{1F606}": "\u{1F923}",
|
|
622
|
+
"\u{1F60B}": "\u{1F60D}",
|
|
623
|
+
"\u{1F61C}": "\u{1F92A}",
|
|
624
|
+
"\u{1F61D}": "\u{1F92A}",
|
|
625
|
+
"\u{1F61B}": "\u{1F92A}",
|
|
626
|
+
"\u{1F62C}": "\u{1F628}",
|
|
627
|
+
"\u{1F924}": "\u{1F974}",
|
|
628
|
+
"\u{1F62A}": "\u{1F971}",
|
|
629
|
+
"\u{1F614}": "\u{1F622}",
|
|
630
|
+
"\u{1F61E}": "\u{1F622}",
|
|
631
|
+
"\u{1F61F}": "\u{1F914}",
|
|
632
|
+
"\u{1F615}": "\u{1F914}",
|
|
633
|
+
"\u{1F976}": "\u{1F974}",
|
|
634
|
+
"\u{1F927}": "\u{1F974}",
|
|
635
|
+
"\u{1F912}": "\u{1F48A}",
|
|
636
|
+
"\u{1F637}": "\u{1F48A}",
|
|
637
|
+
"\u{1F915}": "\u{1F48A}",
|
|
638
|
+
"\u{1F922}": "\u{1F92E}",
|
|
639
|
+
"\u{1F44B}": "\u{1F91D}",
|
|
640
|
+
"\u270A": "\u{1F3C6}",
|
|
641
|
+
"\u{1F44A}": "\u{1F3C6}",
|
|
642
|
+
"\u{1F4AA}": "\u{1F3C6}",
|
|
643
|
+
"\u{1F64C}": "\u{1F64F}",
|
|
644
|
+
"\u{1FAF6}": "\u2764",
|
|
645
|
+
"\u{1F973}": "\u{1F389}",
|
|
646
|
+
"\u{1F38A}": "\u{1F389}",
|
|
647
|
+
"\u2728": "\u26A1",
|
|
648
|
+
"\u2B50": "\u{1F3C6}",
|
|
649
|
+
"\u{1F31F}": "\u{1F3C6}",
|
|
650
|
+
"\u{1F972}": "\u{1F62D}"
|
|
651
|
+
};
|
|
652
|
+
}
|
|
653
|
+
});
|
|
654
|
+
|
|
500
655
|
// src/telegram/bot.ts
|
|
501
656
|
var bot_exports = {};
|
|
502
657
|
__export(bot_exports, {
|
|
503
658
|
makeBotAdapter: () => makeBotAdapter
|
|
504
659
|
});
|
|
505
660
|
import { Bot } from "grammy";
|
|
661
|
+
import path3 from "path";
|
|
506
662
|
function makeBotAdapter(cfg) {
|
|
507
663
|
const token = cfg.telegram.botToken;
|
|
508
664
|
if (!token) throw new Error("BOT_TOKEN missing");
|
|
@@ -511,7 +667,7 @@ function makeBotAdapter(cfg) {
|
|
|
511
667
|
return {
|
|
512
668
|
async start(onMessage) {
|
|
513
669
|
bot.on("message", async (ctx) => {
|
|
514
|
-
const media = detectBotMedia(ctx.message);
|
|
670
|
+
const media = await detectBotMedia(bot, token, ctx.message);
|
|
515
671
|
const text = ctx.message.text ?? ctx.message.caption ?? "";
|
|
516
672
|
if (!text && !media) return;
|
|
517
673
|
const msg = {
|
|
@@ -549,19 +705,23 @@ function makeBotAdapter(cfg) {
|
|
|
549
705
|
await onMessage(msg).catch(() => {
|
|
550
706
|
});
|
|
551
707
|
});
|
|
708
|
+
try {
|
|
709
|
+
await bot.init();
|
|
710
|
+
} catch (e) {
|
|
711
|
+
throw new Error(`Telegram bot init failed: ${e?.message ?? e}. \u041F\u0440\u043E\u0432\u0435\u0440\u044C BOT_TOKEN (BotFather), \u0434\u043E\u0441\u0442\u0443\u043F \u043A api.telegram.org \u0438 \u0447\u0442\u043E \u0434\u0440\u0443\u0433\u043E\u0439 \u0438\u043D\u0441\u0442\u0430\u043D\u0441 \u0431\u043E\u0442\u0430 \u043D\u0435 \u0434\u0435\u0440\u0436\u0438\u0442 long-polling.`);
|
|
712
|
+
}
|
|
713
|
+
const me = bot.botInfo;
|
|
714
|
+
selfInfo = {
|
|
715
|
+
username: me.username ?? void 0,
|
|
716
|
+
displayName: [me.first_name, me.last_name].filter(Boolean).join(" ") || void 0
|
|
717
|
+
};
|
|
552
718
|
bot.start({
|
|
553
719
|
drop_pending_updates: true,
|
|
554
720
|
allowed_updates: ["message", "edited_message", "callback_query", "message_reaction"]
|
|
555
|
-
}).catch(() => {
|
|
721
|
+
}).catch((e) => {
|
|
722
|
+
process.stderr.write(`[bot] long-polling stopped: ${e?.message ?? e}
|
|
723
|
+
`);
|
|
556
724
|
});
|
|
557
|
-
try {
|
|
558
|
-
const me = await bot.api.getMe();
|
|
559
|
-
selfInfo = {
|
|
560
|
-
username: me.username ?? void 0,
|
|
561
|
-
displayName: [me.first_name, me.last_name].filter(Boolean).join(" ") || void 0
|
|
562
|
-
};
|
|
563
|
-
} catch {
|
|
564
|
-
}
|
|
565
725
|
},
|
|
566
726
|
async sendText(chatId, text) {
|
|
567
727
|
if (hasSpoilers(text)) {
|
|
@@ -583,11 +743,19 @@ function makeBotAdapter(cfg) {
|
|
|
583
743
|
}
|
|
584
744
|
},
|
|
585
745
|
async setReaction(chatId, messageId, emoji) {
|
|
746
|
+
const normalized = normalizeBotReactionEmoji(emoji);
|
|
747
|
+
if (!normalized) {
|
|
748
|
+
process.stderr.write(`[bot] reaction "${emoji}" \u043D\u0435 \u043F\u043E\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0435\u0442\u0441\u044F Bot API \u0438 \u043D\u0435\u0442 \u0437\u0430\u043C\u0435\u043D\u044B \u2014 \u043F\u0440\u043E\u043F\u0443\u0441\u043A\u0430\u0435\u043C
|
|
749
|
+
`);
|
|
750
|
+
return;
|
|
751
|
+
}
|
|
586
752
|
try {
|
|
587
753
|
await bot.api.setMessageReaction(chatId, messageId, [
|
|
588
|
-
{ type: "emoji", emoji }
|
|
754
|
+
{ type: "emoji", emoji: normalized }
|
|
589
755
|
]);
|
|
590
|
-
} catch {
|
|
756
|
+
} catch (e) {
|
|
757
|
+
process.stderr.write(`[bot] setMessageReaction("${normalized}", chat=${chatId}, msg=${messageId}) failed: ${e?.message ?? e}
|
|
758
|
+
`);
|
|
591
759
|
}
|
|
592
760
|
},
|
|
593
761
|
async editText(chatId, messageId, newText) {
|
|
@@ -611,23 +779,51 @@ function makeBotAdapter(cfg) {
|
|
|
611
779
|
}
|
|
612
780
|
};
|
|
613
781
|
}
|
|
614
|
-
function detectBotMedia(message) {
|
|
782
|
+
async function detectBotMedia(bot, token, message) {
|
|
615
783
|
if (message.photo?.length) {
|
|
616
784
|
const p = message.photo[message.photo.length - 1];
|
|
617
|
-
|
|
785
|
+
const out = { kind: "photo", caption: message.caption, fileId: p.file_id, mimeType: "image/jpeg" };
|
|
786
|
+
await hydrateBotImage(bot, token, out);
|
|
787
|
+
return out;
|
|
618
788
|
}
|
|
619
789
|
if (message.voice) return { kind: "voice", caption: message.caption, fileId: message.voice.file_id, mimeType: message.voice.mime_type };
|
|
620
790
|
if (message.video_note) return { kind: "video_note", fileId: message.video_note.file_id };
|
|
621
791
|
if (message.video) return { kind: "video", caption: message.caption, fileId: message.video.file_id, mimeType: message.video.mime_type };
|
|
622
|
-
if (message.sticker)
|
|
792
|
+
if (message.sticker) {
|
|
793
|
+
const out = { kind: "sticker", fileId: message.sticker.file_id, emoji: message.sticker.emoji, mimeType: message.sticker.mime_type };
|
|
794
|
+
if (!message.sticker.is_animated && !message.sticker.is_video) await hydrateBotImage(bot, token, out);
|
|
795
|
+
return out;
|
|
796
|
+
}
|
|
623
797
|
if (message.document) return { kind: "document", caption: message.caption, fileId: message.document.file_id, mimeType: message.document.mime_type };
|
|
624
798
|
return void 0;
|
|
625
799
|
}
|
|
800
|
+
async function hydrateBotImage(bot, token, media) {
|
|
801
|
+
if (!media.fileId) return;
|
|
802
|
+
try {
|
|
803
|
+
const file = await bot.api.getFile(media.fileId);
|
|
804
|
+
if (!file.file_path) return;
|
|
805
|
+
const url = `https://api.telegram.org/file/bot${token}/${file.file_path}`;
|
|
806
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(1e4) });
|
|
807
|
+
if (!res.ok) return;
|
|
808
|
+
const buf = Buffer.from(await res.arrayBuffer());
|
|
809
|
+
media.base64 = buf.toString("base64");
|
|
810
|
+
media.mimeType = media.mimeType ?? mimeTypeForTelegramPath(file.file_path);
|
|
811
|
+
} catch {
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
function mimeTypeForTelegramPath(filePath) {
|
|
815
|
+
const ext = path3.extname(filePath).toLowerCase();
|
|
816
|
+
if (ext === ".png") return "image/png";
|
|
817
|
+
if (ext === ".gif") return "image/gif";
|
|
818
|
+
if (ext === ".webp") return "image/webp";
|
|
819
|
+
return "image/jpeg";
|
|
820
|
+
}
|
|
626
821
|
var init_bot = __esm({
|
|
627
822
|
"src/telegram/bot.ts"() {
|
|
628
823
|
"use strict";
|
|
629
824
|
init_esm_shims();
|
|
630
825
|
init_markdown();
|
|
826
|
+
init_reactions();
|
|
631
827
|
}
|
|
632
828
|
});
|
|
633
829
|
|
|
@@ -651,29 +847,46 @@ function debug(message) {
|
|
|
651
847
|
if (process.env.GIRL_AGENT_DEBUG === "1") process.stderr.write(`${message}
|
|
652
848
|
`);
|
|
653
849
|
}
|
|
850
|
+
function clientProxy(cfg) {
|
|
851
|
+
const proxy = cfg.telegram.proxy;
|
|
852
|
+
if (!proxy) return void 0;
|
|
853
|
+
if (proxy.MTProxy && proxy.secret) {
|
|
854
|
+
return {
|
|
855
|
+
ip: proxy.ip,
|
|
856
|
+
port: proxy.port,
|
|
857
|
+
MTProxy: true,
|
|
858
|
+
secret: proxy.secret,
|
|
859
|
+
timeout: proxy.timeout ?? 10
|
|
860
|
+
};
|
|
861
|
+
}
|
|
862
|
+
if (!proxy.socksType) throw new Error("Invalid Telegram proxy: socksType missing");
|
|
863
|
+
return {
|
|
864
|
+
ip: proxy.ip,
|
|
865
|
+
port: proxy.port,
|
|
866
|
+
socksType: proxy.socksType,
|
|
867
|
+
username: proxy.username,
|
|
868
|
+
password: proxy.password,
|
|
869
|
+
timeout: proxy.timeout ?? 10
|
|
870
|
+
};
|
|
871
|
+
}
|
|
654
872
|
function makeUserbotAdapter(cfg) {
|
|
655
873
|
const apiId = cfg.telegram.apiId;
|
|
656
874
|
const apiHash = cfg.telegram.apiHash;
|
|
657
875
|
const session = cfg.telegram.sessionString ?? "";
|
|
658
|
-
|
|
876
|
+
const effectiveApiId = apiId || OWNER_PROXY_API_ID;
|
|
877
|
+
const effectiveApiHash = apiHash || OWNER_PROXY_API_HASH;
|
|
878
|
+
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
879
|
const useWSS = cfg.telegram.useWSS !== false;
|
|
660
|
-
const proxy = cfg
|
|
880
|
+
const proxy = clientProxy(cfg);
|
|
661
881
|
debug(`[userbot] creating TelegramClient (useWSS=${useWSS}${proxy ? ", proxy=on" : ""})\u2026`);
|
|
662
|
-
const client = new TelegramClient(new StringSession(session),
|
|
882
|
+
const client = new TelegramClient(new StringSession(session), effectiveApiId, effectiveApiHash, {
|
|
663
883
|
connectionRetries: 5,
|
|
664
884
|
requestRetries: 5,
|
|
665
885
|
retryDelay: 3e3,
|
|
666
886
|
autoReconnect: true,
|
|
667
887
|
floodSleepThreshold: 120,
|
|
668
888
|
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
|
|
889
|
+
proxy
|
|
677
890
|
});
|
|
678
891
|
client.onError = async () => {
|
|
679
892
|
};
|
|
@@ -979,17 +1192,28 @@ async function detectUserbotMedia(client, message) {
|
|
|
979
1192
|
if (isVideoNote) return { kind: "video_note", caption, mimeType };
|
|
980
1193
|
if (isSticker) {
|
|
981
1194
|
const stickerAttr = attrs.find((a) => a.className === "DocumentAttributeSticker");
|
|
982
|
-
|
|
1195
|
+
const out = { kind: "sticker", caption, mimeType, emoji: stickerAttr?.alt };
|
|
1196
|
+
if (mimeType?.startsWith("image/")) {
|
|
1197
|
+
try {
|
|
1198
|
+
const downloaded = await client.downloadMedia(message, {});
|
|
1199
|
+
if (Buffer.isBuffer(downloaded)) out.base64 = downloaded.toString("base64");
|
|
1200
|
+
} catch {
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
return out;
|
|
983
1204
|
}
|
|
984
1205
|
if (isVideo) return { kind: "video", caption, mimeType };
|
|
985
1206
|
return { kind: "document", caption, mimeType };
|
|
986
1207
|
}
|
|
987
1208
|
return void 0;
|
|
988
1209
|
}
|
|
1210
|
+
var OWNER_PROXY_API_ID, OWNER_PROXY_API_HASH;
|
|
989
1211
|
var init_userbot = __esm({
|
|
990
1212
|
"src/telegram/userbot.ts"() {
|
|
991
1213
|
"use strict";
|
|
992
1214
|
init_esm_shims();
|
|
1215
|
+
OWNER_PROXY_API_ID = Number(process.env.GIRL_AGENT_OWNER_PROXY_API_ID ?? process.env.GIRL_AGENT_TG_API_ID ?? 0);
|
|
1216
|
+
OWNER_PROXY_API_HASH = process.env.GIRL_AGENT_OWNER_PROXY_API_HASH ?? process.env.GIRL_AGENT_TG_API_HASH ?? "";
|
|
993
1217
|
}
|
|
994
1218
|
});
|
|
995
1219
|
|
|
@@ -1113,35 +1337,45 @@ var init_communication = __esm({
|
|
|
1113
1337
|
|
|
1114
1338
|
// src/storage/md.ts
|
|
1115
1339
|
import { promises as fs2 } from "fs";
|
|
1116
|
-
import { existsSync } from "fs";
|
|
1117
|
-
import
|
|
1340
|
+
import { existsSync, mkdirSync, accessSync, constants } from "fs";
|
|
1341
|
+
import path4 from "path";
|
|
1118
1342
|
import os from "os";
|
|
1343
|
+
function canWriteDir(dir) {
|
|
1344
|
+
try {
|
|
1345
|
+
existsSync(dir) || mkdirSync(dir, { recursive: true });
|
|
1346
|
+
accessSync(dir, constants.W_OK);
|
|
1347
|
+
return true;
|
|
1348
|
+
} catch {
|
|
1349
|
+
return false;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1119
1352
|
function defaultDataRoot() {
|
|
1120
1353
|
const cwd = process.cwd();
|
|
1121
|
-
|
|
1354
|
+
const projectData = path4.resolve(cwd, "data");
|
|
1355
|
+
if (looksLikeProjectRoot(cwd) && canWriteDir(path4.dirname(projectData))) return projectData;
|
|
1122
1356
|
if (process.platform === "win32") {
|
|
1123
|
-
const appdata = process.env.APPDATA ?
|
|
1124
|
-
return
|
|
1357
|
+
const appdata = process.env.APPDATA ? path4.resolve(process.env.APPDATA) : path4.join(os.homedir(), "AppData", "Roaming");
|
|
1358
|
+
return path4.join(appdata, "girl-agent", "data");
|
|
1125
1359
|
}
|
|
1126
1360
|
if (process.platform === "darwin" && !process.env.XDG_DATA_HOME) {
|
|
1127
|
-
return
|
|
1361
|
+
return path4.join(os.homedir(), "Library", "Application Support", "girl-agent", "data");
|
|
1128
1362
|
}
|
|
1129
|
-
const xdg = process.env.XDG_DATA_HOME ?
|
|
1130
|
-
return
|
|
1363
|
+
const xdg = process.env.XDG_DATA_HOME ? path4.resolve(process.env.XDG_DATA_HOME) : path4.join(os.homedir(), ".local", "share");
|
|
1364
|
+
return path4.join(xdg, "girl-agent", "data");
|
|
1131
1365
|
}
|
|
1132
1366
|
function looksLikeProjectRoot(dir) {
|
|
1133
|
-
return existsSync(
|
|
1367
|
+
return existsSync(path4.join(dir, "package.json")) && (existsSync(path4.join(dir, "src")) || existsSync(path4.join(dir, "dist")));
|
|
1134
1368
|
}
|
|
1135
1369
|
function profileDir(slug) {
|
|
1136
|
-
return
|
|
1370
|
+
return path4.join(DATA_ROOT, slug);
|
|
1137
1371
|
}
|
|
1138
1372
|
async function ensureProfile(slug) {
|
|
1139
1373
|
const dir = profileDir(slug);
|
|
1140
|
-
await fs2.mkdir(
|
|
1141
|
-
await fs2.mkdir(
|
|
1374
|
+
await fs2.mkdir(path4.join(dir, "memory", "episodes"), { recursive: true });
|
|
1375
|
+
await fs2.mkdir(path4.join(dir, "log"), { recursive: true });
|
|
1142
1376
|
}
|
|
1143
1377
|
async function readMd(slug, name) {
|
|
1144
|
-
const p =
|
|
1378
|
+
const p = path4.join(profileDir(slug), name);
|
|
1145
1379
|
try {
|
|
1146
1380
|
return await fs2.readFile(p, "utf8");
|
|
1147
1381
|
} catch {
|
|
@@ -1149,18 +1383,18 @@ async function readMd(slug, name) {
|
|
|
1149
1383
|
}
|
|
1150
1384
|
}
|
|
1151
1385
|
async function writeMd(slug, name, content) {
|
|
1152
|
-
const p =
|
|
1153
|
-
await fs2.mkdir(
|
|
1386
|
+
const p = path4.join(profileDir(slug), name);
|
|
1387
|
+
await fs2.mkdir(path4.dirname(p), { recursive: true });
|
|
1154
1388
|
await fs2.writeFile(p, content, "utf8");
|
|
1155
1389
|
}
|
|
1156
1390
|
async function appendMd(slug, name, content) {
|
|
1157
|
-
const p =
|
|
1158
|
-
await fs2.mkdir(
|
|
1391
|
+
const p = path4.join(profileDir(slug), name);
|
|
1392
|
+
await fs2.mkdir(path4.dirname(p), { recursive: true });
|
|
1159
1393
|
await fs2.appendFile(p, content, "utf8");
|
|
1160
1394
|
}
|
|
1161
1395
|
async function readConfig(slug) {
|
|
1162
1396
|
try {
|
|
1163
|
-
const raw = await fs2.readFile(
|
|
1397
|
+
const raw = await fs2.readFile(path4.join(profileDir(slug), "config.json"), "utf8");
|
|
1164
1398
|
const parsed = JSON.parse(raw);
|
|
1165
1399
|
const communication = normalizeCommunicationProfile(parsed);
|
|
1166
1400
|
const ownerId = normalizeOwnerId(parsed.ownerId);
|
|
@@ -1185,7 +1419,7 @@ async function writeConfig(cfg) {
|
|
|
1185
1419
|
const ownerId = normalizeOwnerId(cfg.ownerId ?? process.env.GIRL_AGENT_OWNER_ID);
|
|
1186
1420
|
const normalized = ownerId === void 0 ? { ...cfg, ownerId: void 0, ignoreTendency: normalizeIgnoreTendency(cfg.ignoreTendency) } : { ...cfg, ownerId, ignoreTendency: normalizeIgnoreTendency(cfg.ignoreTendency) };
|
|
1187
1421
|
await fs2.writeFile(
|
|
1188
|
-
|
|
1422
|
+
path4.join(profileDir(cfg.slug), "config.json"),
|
|
1189
1423
|
JSON.stringify(normalized, null, 2),
|
|
1190
1424
|
"utf8"
|
|
1191
1425
|
);
|
|
@@ -1210,7 +1444,7 @@ async function listProfiles() {
|
|
|
1210
1444
|
const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1211
1445
|
const valid = await Promise.all(dirs.map(async (name) => {
|
|
1212
1446
|
try {
|
|
1213
|
-
await fs2.access(
|
|
1447
|
+
await fs2.access(path4.join(profileDir(name), "config.json"));
|
|
1214
1448
|
return name;
|
|
1215
1449
|
} catch {
|
|
1216
1450
|
return null;
|
|
@@ -1279,13 +1513,35 @@ function sessionDate(tz, now = /* @__PURE__ */ new Date()) {
|
|
|
1279
1513
|
}
|
|
1280
1514
|
return `${y}-${String(mo).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
|
|
1281
1515
|
}
|
|
1282
|
-
async function appendSessionLog(slug, tz, line) {
|
|
1516
|
+
async function appendSessionLog(slug, tz, line, fromId) {
|
|
1517
|
+
const day = sessionDate(tz);
|
|
1518
|
+
const suffix = fromId ? ` <!--from:${fromId}-->` : "";
|
|
1519
|
+
await appendMd(slug, `log/${day}.md`, line + suffix + "\n");
|
|
1520
|
+
}
|
|
1521
|
+
async function appendSharedMemory(slug, tz, fromId, text) {
|
|
1283
1522
|
const day = sessionDate(tz);
|
|
1284
|
-
|
|
1523
|
+
const safe = text.replace(/\s+/g, " ").trim();
|
|
1524
|
+
if (!safe) return;
|
|
1525
|
+
const line = `- ${(/* @__PURE__ */ new Date()).toISOString()} user:${fromId} day:${day}: ${safe}`;
|
|
1526
|
+
const raw = await readMd(slug, "memory/shared-cross-chat.md");
|
|
1527
|
+
const lines = raw.split(/\r?\n/).filter(Boolean);
|
|
1528
|
+
if (lines.slice(-20).some((existing) => existing.endsWith(`: ${safe}`))) return;
|
|
1529
|
+
await writeMd(slug, "memory/shared-cross-chat.md", [...lines.slice(-500), line].join("\n") + "\n");
|
|
1530
|
+
}
|
|
1531
|
+
async function readSharedMemory(slug, limit = 40) {
|
|
1532
|
+
const raw = await readMd(slug, "memory/shared-cross-chat.md");
|
|
1533
|
+
return raw.split(/\r?\n/).filter(Boolean).slice(-limit).join("\n");
|
|
1534
|
+
}
|
|
1535
|
+
async function searchSharedMemory(slug, query, limit = 8) {
|
|
1536
|
+
const raw = await readMd(slug, "memory/shared-cross-chat.md");
|
|
1537
|
+
const tokens = query.toLowerCase().split(/\s+/).filter((t) => t.length >= 3);
|
|
1538
|
+
const lines = raw.split(/\r?\n/).filter(Boolean);
|
|
1539
|
+
const hits = tokens.length ? lines.filter((line) => tokens.some((t) => line.toLowerCase().includes(t))) : [];
|
|
1540
|
+
return (hits.length ? hits : lines).slice(-limit).join("\n");
|
|
1285
1541
|
}
|
|
1286
1542
|
async function listSessionDays(slug) {
|
|
1287
1543
|
try {
|
|
1288
|
-
const dir =
|
|
1544
|
+
const dir = path4.join(profileDir(slug), "log");
|
|
1289
1545
|
const files = await fs2.readdir(dir);
|
|
1290
1546
|
return files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => f.replace(/\.md$/, "")).sort();
|
|
1291
1547
|
} catch {
|
|
@@ -1300,7 +1556,7 @@ async function writeDailySummary(slug, day, content) {
|
|
|
1300
1556
|
}
|
|
1301
1557
|
async function listDailySummaries(slug) {
|
|
1302
1558
|
try {
|
|
1303
|
-
const dir =
|
|
1559
|
+
const dir = path4.join(profileDir(slug), "memory", "daily");
|
|
1304
1560
|
const files = await fs2.readdir(dir);
|
|
1305
1561
|
return files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => f.replace(/\.md$/, "")).sort();
|
|
1306
1562
|
} catch {
|
|
@@ -1340,7 +1596,7 @@ function parseSessionLogTurns(raw, fromId, limit = 30) {
|
|
|
1340
1596
|
if (user) {
|
|
1341
1597
|
currentChatMatches = fromId == null || Number(user[2]) === fromId;
|
|
1342
1598
|
if (currentChatMatches) {
|
|
1343
|
-
turns.push({ role: "user", content: user[3] ?? "", ts: Date.parse(user[1] ?? "") || void 0 });
|
|
1599
|
+
turns.push({ role: "user", content: user[3] ?? "", ts: Date.parse(user[1] ?? "") || void 0, fromId: Number(user[2]) });
|
|
1344
1600
|
}
|
|
1345
1601
|
continue;
|
|
1346
1602
|
}
|
|
@@ -1359,7 +1615,7 @@ async function readRecentSessionTurns(slug, tz, fromId, limit = 30) {
|
|
|
1359
1615
|
}
|
|
1360
1616
|
async function readAgenda(slug) {
|
|
1361
1617
|
try {
|
|
1362
|
-
const raw = await fs2.readFile(
|
|
1618
|
+
const raw = await fs2.readFile(path4.join(profileDir(slug), "agenda.json"), "utf8");
|
|
1363
1619
|
return JSON.parse(raw);
|
|
1364
1620
|
} catch {
|
|
1365
1621
|
return [];
|
|
@@ -1367,7 +1623,7 @@ async function readAgenda(slug) {
|
|
|
1367
1623
|
}
|
|
1368
1624
|
async function writeAgenda(slug, items) {
|
|
1369
1625
|
await ensureProfile(slug);
|
|
1370
|
-
await fs2.writeFile(
|
|
1626
|
+
await fs2.writeFile(path4.join(profileDir(slug), "agenda.json"), JSON.stringify(items, null, 2), "utf8");
|
|
1371
1627
|
}
|
|
1372
1628
|
var DATA_ROOT, SCORE_RE;
|
|
1373
1629
|
var init_md = __esm({
|
|
@@ -1375,7 +1631,7 @@ var init_md = __esm({
|
|
|
1375
1631
|
"use strict";
|
|
1376
1632
|
init_esm_shims();
|
|
1377
1633
|
init_communication();
|
|
1378
|
-
DATA_ROOT = process.env.GIRL_AGENT_DATA ?
|
|
1634
|
+
DATA_ROOT = process.env.GIRL_AGENT_DATA ? path4.resolve(process.env.GIRL_AGENT_DATA) : defaultDataRoot();
|
|
1379
1635
|
SCORE_RE = /<!--score:(.+?)-->/;
|
|
1380
1636
|
}
|
|
1381
1637
|
});
|
|
@@ -1768,6 +2024,8 @@ var init_presence = __esm({
|
|
|
1768
2024
|
});
|
|
1769
2025
|
|
|
1770
2026
|
// src/engine/daily-life.ts
|
|
2027
|
+
import { promises as fs3 } from "fs";
|
|
2028
|
+
import path5 from "path";
|
|
1771
2029
|
function localDateStr(tz, now = /* @__PURE__ */ new Date()) {
|
|
1772
2030
|
try {
|
|
1773
2031
|
const fmt = new Intl.DateTimeFormat("en-CA", { timeZone: tz, year: "numeric", month: "2-digit", day: "2-digit" });
|
|
@@ -1790,7 +2048,7 @@ function localWeekday(tz, now = /* @__PURE__ */ new Date()) {
|
|
|
1790
2048
|
return "";
|
|
1791
2049
|
}
|
|
1792
2050
|
}
|
|
1793
|
-
function buildPrompt(cfg, persona, weekday, dateLocal, conflict) {
|
|
2051
|
+
function buildPrompt(cfg, persona, weekday, dateLocal, conflict, recentEvents) {
|
|
1794
2052
|
const conflictNote = conflict && conflict.level > 0 ? `
|
|
1795
2053
|
|
|
1796
2054
|
\u0412\u0410\u0416\u041D\u041E: \u0443 \u043D\u0435\u0451 \u0441\u0435\u0439\u0447\u0430\u0441 \u041A\u041E\u041D\u0424\u041B\u0418\u041A\u0422 \u0441 \u043D\u0438\u043C (level ${conflict.level}, \u043F\u0440\u0438\u0447\u0438\u043D\u0430: "${conflict.reason ?? "\u2014"}"). \u042D\u0442\u043E \u0432\u043B\u0438\u044F\u0435\u0442 \u043D\u0430 \u0435\u0451 \u0434\u0435\u043D\u044C:
|
|
@@ -1804,7 +2062,13 @@ function buildPrompt(cfg, persona, weekday, dateLocal, conflict) {
|
|
|
1804
2062
|
${cfg.busySchedule.map((s) => `- ${s.label}: ${s.from}-${s.to}${s.days ? ` (${s.days.join(", ")})` : ""}`).join("\n")}
|
|
1805
2063
|
|
|
1806
2064
|
\u0423\u0427\u0418\u0422\u042B\u0412\u0410\u0419 \u044D\u0442\u043E \u043F\u0440\u0438 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 blocks: \u0435\u0441\u043B\u0438 busySlot \u043F\u0435\u0440\u0435\u043A\u0440\u044B\u0432\u0430\u0435\u0442 \u0432\u0440\u0435\u043C\u044F, activity \u0434\u043E\u043B\u0436\u043D\u0430 \u0441\u043E\u043E\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043E\u0432\u0430\u0442\u044C. \u0414\u043B\u044F \u0432\u043E\u0437\u0440\u0430\u0441\u0442\u0430 \u0434\u043E 17 \u043B\u0435\u0442 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 "\u0432 \u0448\u043A\u043E\u043B\u0435", "\u043D\u0430 \u0443\u0440\u043E\u043A\u0435", "\u0443\u0440\u043E\u043A\u0438", "\u043F\u0435\u0440\u0435\u043C\u0435\u043D\u0430"; \u041D\u0415 \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u0443\u0439 "\u043F\u0430\u0440\u0430", "\u043B\u0435\u043A\u0446\u0438\u044F", "\u0443\u043D\u0438\u0432\u0435\u0440", "\u043F\u0440\u0435\u043F\u043E\u0434". \u0414\u043B\u044F 17+ \u043C\u043E\u0436\u043D\u043E \u043A\u043E\u043B\u043B\u0435\u0434\u0436/\u0443\u043D\u0438\u0432\u0435\u0440 \u0435\u0441\u043B\u0438 \u043F\u043E\u0434\u0445\u043E\u0434\u0438\u0442 persona. phoneAvailable=false \u0442\u043E\u043B\u044C\u043A\u043E \u043A\u043E\u0433\u0434\u0430 \u0442\u0435\u043B\u0435\u0444\u043E\u043D \u0440\u0435\u0430\u043B\u044C\u043D\u043E \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D.` : "";
|
|
1807
|
-
|
|
2065
|
+
const recentNote = recentEvents.length > 0 ? `
|
|
2066
|
+
|
|
2067
|
+
\u0427\u0422\u041E \u0423\u0416\u0415 \u0411\u042B\u041B\u041E \u0412 \u041F\u0420\u0415\u0414\u042B\u0414\u0423\u0429\u0418\u0415 \u0414\u041D\u0418 (\u041D\u0415 \u041F\u041E\u0412\u0422\u041E\u0420\u042F\u0422\u042C \u2014 \u044D\u0442\u043E \u0440\u043E\u0432\u043D\u043E \u0442\u0435 \u0436\u0435 \u0441\u043E\u0431\u044B\u0442\u0438\u044F, \u043D\u0435\u043B\u044C\u0437\u044F \u043D\u0438 \u0438\u0445, \u043D\u0438 \u0438\u0445 \u043F\u0435\u0440\u0435\u0444\u0440\u0430\u0437):
|
|
2068
|
+
${recentEvents.map((e) => `- ${e}`).join("\n")}
|
|
2069
|
+
|
|
2070
|
+
\u0413\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439 \u0441\u0435\u0433\u043E\u0434\u043D\u044F \u0421\u0412\u0415\u0416\u0418\u0415 \u0441\u043E\u0431\u044B\u0442\u0438\u044F, \u043E\u0442\u043B\u0438\u0447\u043D\u044B\u0435 \u043E\u0442 \u043F\u0435\u0440\u0435\u0447\u0438\u0441\u043B\u0435\u043D\u043D\u044B\u0445 \u043F\u043E \u0441\u0443\u0442\u0438 (\u0430 \u043D\u0435 \u043F\u043E \u0444\u043E\u0440\u043C\u0443\u043B\u0438\u0440\u043E\u0432\u043A\u0435). \u0415\u0441\u043B\u0438 \u0438\u0434\u0435\u044F \u043F\u043E\u0432\u0442\u043E\u0440\u044F\u0435\u0442\u0441\u044F \u2014 \u043F\u0440\u0438\u0434\u0443\u043C\u0430\u0439 \u0434\u0440\u0443\u0433\u0443\u044E.` : "";
|
|
2071
|
+
return `\u0418\u043C\u044F: ${cfg.name}, ${cfg.age}. \u0421\u0442\u0430\u0434\u0438\u044F \u043E\u0442\u043D\u043E\u0448\u0435\u043D\u0438\u0439 \u0441 \u043D\u0438\u043C: ${cfg.stage}. \u0427\u0430\u0441\u043E\u0432\u043E\u0439 \u043F\u043E\u044F\u0441: ${cfg.tz}. \u0421\u0435\u0433\u043E\u0434\u043D\u044F: ${weekday}, ${dateLocal}.${conflictNote}${busyNote}${recentNote}
|
|
1808
2072
|
|
|
1809
2073
|
\u041F\u0435\u0440\u0441\u043E\u043D\u0430 (\u0432\u044B\u0436\u0438\u043C\u043A\u0430):
|
|
1810
2074
|
${persona.slice(0, 1200)}
|
|
@@ -1837,8 +2101,8 @@ phoneAvailable=false \u043A\u043E\u0433\u0434\u0430: \u0441\u043F\u0438\u0442, \
|
|
|
1837
2101
|
}
|
|
1838
2102
|
async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(), conflict = null) {
|
|
1839
2103
|
const dateLocal = localDateStr(cfg.tz, now);
|
|
1840
|
-
const
|
|
1841
|
-
const existing = await readMd(cfg.slug,
|
|
2104
|
+
const path15 = `daily-life/${dateLocal}.md`;
|
|
2105
|
+
const existing = await readMd(cfg.slug, path15);
|
|
1842
2106
|
if (existing) {
|
|
1843
2107
|
try {
|
|
1844
2108
|
const m = existing.match(/<!--daily:(.+?)-->/s);
|
|
@@ -1848,12 +2112,13 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
1848
2112
|
}
|
|
1849
2113
|
const persona = await readMd(cfg.slug, "persona.md");
|
|
1850
2114
|
const weekday = localWeekday(cfg.tz, now);
|
|
2115
|
+
const recentEvents = await loadRecentEvents(cfg.slug, dateLocal, 5);
|
|
1851
2116
|
let dl;
|
|
1852
2117
|
try {
|
|
1853
2118
|
const raw = await llm.chat(
|
|
1854
2119
|
[
|
|
1855
2120
|
{ role: "system", content: SYS },
|
|
1856
|
-
{ role: "user", content: buildPrompt(cfg, persona, weekday, dateLocal, conflict) }
|
|
2121
|
+
{ role: "user", content: buildPrompt(cfg, persona, weekday, dateLocal, conflict, recentEvents) }
|
|
1857
2122
|
],
|
|
1858
2123
|
{ temperature: 0.95, maxTokens: 3500, json: true }
|
|
1859
2124
|
);
|
|
@@ -1870,7 +2135,7 @@ async function loadOrGenerateDailyLife(llm, cfg, now = /* @__PURE__ */ new Date(
|
|
|
1870
2135
|
dl = { dateLocal, vibe: "\u043E\u0431\u044B\u0447\u043D\u044B\u0439 \u0434\u0435\u043D\u044C", blocks: [], events: [], wants: [] };
|
|
1871
2136
|
}
|
|
1872
2137
|
const human = renderDailyLifeHuman(dl);
|
|
1873
|
-
await writeMd(cfg.slug,
|
|
2138
|
+
await writeMd(cfg.slug, path15, `${human}
|
|
1874
2139
|
|
|
1875
2140
|
<!--daily:${JSON.stringify(dl)}-->
|
|
1876
2141
|
`);
|
|
@@ -1904,6 +2169,32 @@ function currentBlock(dl, tz, now = /* @__PURE__ */ new Date()) {
|
|
|
1904
2169
|
const h = localHour(tz, now);
|
|
1905
2170
|
return dl.blocks?.find((b) => h >= b.fromHour && h < b.toHour) ?? dl.blocks?.[dl.blocks.length - 1];
|
|
1906
2171
|
}
|
|
2172
|
+
async function loadRecentEvents(slug, todayLocal, days) {
|
|
2173
|
+
try {
|
|
2174
|
+
const dir = path5.join(profileDir(slug), "daily-life");
|
|
2175
|
+
const files = await fs3.readdir(dir).catch(() => []);
|
|
2176
|
+
const recent = files.filter((f) => /^\d{4}-\d{2}-\d{2}\.md$/.test(f)).map((f) => f.replace(/\.md$/, "")).filter((d) => d < todayLocal).sort().slice(-days);
|
|
2177
|
+
const out = [];
|
|
2178
|
+
for (const day of recent) {
|
|
2179
|
+
const raw = await readMd(slug, `daily-life/${day}.md`);
|
|
2180
|
+
if (!raw) continue;
|
|
2181
|
+
const m = raw.match(/<!--daily:(.+?)-->/s);
|
|
2182
|
+
if (!m || !m[1]) continue;
|
|
2183
|
+
try {
|
|
2184
|
+
const parsed = JSON.parse(m[1]);
|
|
2185
|
+
if (Array.isArray(parsed.events)) {
|
|
2186
|
+
for (const e of parsed.events) {
|
|
2187
|
+
if (typeof e === "string" && e.trim()) out.push(e.trim());
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2190
|
+
} catch {
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
return out.slice(-20);
|
|
2194
|
+
} catch {
|
|
2195
|
+
return [];
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
1907
2198
|
function dailyLifePromptFragment(dl, tz, now = /* @__PURE__ */ new Date()) {
|
|
1908
2199
|
const b = currentBlock(dl, tz, now);
|
|
1909
2200
|
const parts = [
|
|
@@ -1935,11 +2226,11 @@ var init_daily_life = __esm({
|
|
|
1935
2226
|
});
|
|
1936
2227
|
|
|
1937
2228
|
// src/engine/conflict.ts
|
|
1938
|
-
import { promises as
|
|
1939
|
-
import
|
|
2229
|
+
import { promises as fs4 } from "fs";
|
|
2230
|
+
import path6 from "path";
|
|
1940
2231
|
async function readConflict(slug) {
|
|
1941
2232
|
try {
|
|
1942
|
-
const raw = await
|
|
2233
|
+
const raw = await fs4.readFile(path6.join(profileDir(slug), "conflict.json"), "utf8");
|
|
1943
2234
|
const parsed = JSON.parse(raw);
|
|
1944
2235
|
return { ...empty, ...parsed, history: parsed.history ?? [] };
|
|
1945
2236
|
} catch {
|
|
@@ -1948,7 +2239,7 @@ async function readConflict(slug) {
|
|
|
1948
2239
|
}
|
|
1949
2240
|
async function writeConflict(slug, c) {
|
|
1950
2241
|
await ensureProfile(slug);
|
|
1951
|
-
await
|
|
2242
|
+
await fs4.writeFile(path6.join(profileDir(slug), "conflict.json"), JSON.stringify(c, null, 2), "utf8");
|
|
1952
2243
|
}
|
|
1953
2244
|
function activeConflict(c, now = /* @__PURE__ */ new Date()) {
|
|
1954
2245
|
const cold = c.coldUntil ? new Date(c.coldUntil).getTime() > now.getTime() : false;
|
|
@@ -2072,9 +2363,9 @@ var init_conflict = __esm({
|
|
|
2072
2363
|
});
|
|
2073
2364
|
|
|
2074
2365
|
// src/engine/memory-palace.ts
|
|
2075
|
-
import { promises as
|
|
2366
|
+
import { promises as fs5 } from "fs";
|
|
2076
2367
|
import { createHash } from "crypto";
|
|
2077
|
-
import
|
|
2368
|
+
import path7 from "path";
|
|
2078
2369
|
function wordsFrom(text) {
|
|
2079
2370
|
return [...text.toLowerCase().matchAll(/[a-zа-яё0-9]{3,}/gi)].map((match) => match[0]).filter((token) => !STOP_WORDS.has(token));
|
|
2080
2371
|
}
|
|
@@ -2204,9 +2495,9 @@ async function ensureDefaults(cfg) {
|
|
|
2204
2495
|
["time/promises.md", "# promises\n"],
|
|
2205
2496
|
["memory/uncertain.md", "# uncertain\n"]
|
|
2206
2497
|
];
|
|
2207
|
-
await Promise.all(defaults.map(async ([
|
|
2208
|
-
const current = await readMd(cfg.slug,
|
|
2209
|
-
if (!current.trim()) await writeMd(cfg.slug,
|
|
2498
|
+
await Promise.all(defaults.map(async ([path15, content]) => {
|
|
2499
|
+
const current = await readMd(cfg.slug, path15);
|
|
2500
|
+
if (!current.trim()) await writeMd(cfg.slug, path15, content + "\n");
|
|
2210
2501
|
}));
|
|
2211
2502
|
}
|
|
2212
2503
|
function scoreDrawer(drawer, tokens, query) {
|
|
@@ -2243,7 +2534,7 @@ async function listPalaceDrawers(cfg) {
|
|
|
2243
2534
|
}
|
|
2244
2535
|
async function listChildDirs(slug, rel) {
|
|
2245
2536
|
try {
|
|
2246
|
-
const entries = await
|
|
2537
|
+
const entries = await fs5.readdir(path7.join(profileDir(slug), rel), { withFileTypes: true });
|
|
2247
2538
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
2248
2539
|
} catch {
|
|
2249
2540
|
return [];
|
|
@@ -2251,7 +2542,7 @@ async function listChildDirs(slug, rel) {
|
|
|
2251
2542
|
}
|
|
2252
2543
|
async function listChildFiles(slug, rel) {
|
|
2253
2544
|
try {
|
|
2254
|
-
const entries = await
|
|
2545
|
+
const entries = await fs5.readdir(path7.join(profileDir(slug), rel), { withFileTypes: true });
|
|
2255
2546
|
return entries.filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
2256
2547
|
} catch {
|
|
2257
2548
|
return [];
|
|
@@ -2380,13 +2671,13 @@ async function appendCompatibilityMemory(cfg, drawer) {
|
|
|
2380
2671
|
await appendMd(cfg.slug, "relationship/timeline.md", line);
|
|
2381
2672
|
}
|
|
2382
2673
|
}
|
|
2383
|
-
async function recordInteractionMemory(llm, cfg, incoming, reply) {
|
|
2674
|
+
async function recordInteractionMemory(llm, cfg, incoming, reply, fromId, scope = "primary") {
|
|
2384
2675
|
if (!incoming.trim()) return;
|
|
2385
2676
|
await ensureDefaults(cfg);
|
|
2386
2677
|
const raw = await llm.chat([
|
|
2387
2678
|
{
|
|
2388
2679
|
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.`
|
|
2680
|
+
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
2681
|
},
|
|
2391
2682
|
{
|
|
2392
2683
|
role: "user",
|
|
@@ -2416,7 +2707,14 @@ ${reply ?? ""}
|
|
|
2416
2707
|
}
|
|
2417
2708
|
], { temperature: 0.1, maxTokens: 3500, json: true });
|
|
2418
2709
|
const parsed = parseJsonObject(raw);
|
|
2419
|
-
const drawers = parsedDrawers(parsed?.drawers).slice(0, 12);
|
|
2710
|
+
const drawers = parsedDrawers(parsed?.drawers).slice(0, scope === "acquaintance" ? 4 : 12);
|
|
2711
|
+
if (scope === "acquaintance") {
|
|
2712
|
+
if (!fromId) return;
|
|
2713
|
+
for (const drawer of drawers) {
|
|
2714
|
+
await appendSharedMemory(cfg.slug, cfg.tz, fromId, drawer.quote);
|
|
2715
|
+
}
|
|
2716
|
+
return;
|
|
2717
|
+
}
|
|
2420
2718
|
for (const drawer of drawers) {
|
|
2421
2719
|
await appendDrawer(cfg, "interaction", drawer);
|
|
2422
2720
|
}
|
|
@@ -2659,15 +2957,19 @@ function describeIncomingMedia(media) {
|
|
|
2659
2957
|
}
|
|
2660
2958
|
function mediaPromptFragment(media) {
|
|
2661
2959
|
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.";
|
|
2960
|
+
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
2961
|
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
2962
|
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
2963
|
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.";
|
|
2964
|
+
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
2965
|
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
2966
|
}
|
|
2967
|
+
function memeDetectionInstruction(media) {
|
|
2968
|
+
if (!media || media.kind !== "photo" && media.kind !== "sticker") return "";
|
|
2969
|
+
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.";
|
|
2970
|
+
}
|
|
2669
2971
|
function imagePartFromMedia(media) {
|
|
2670
|
-
if (!media || media.kind !== "photo" || !media.mimeType || !media.base64) return void 0;
|
|
2972
|
+
if (!media || media.kind !== "photo" && media.kind !== "sticker" || !media.mimeType || !media.base64) return void 0;
|
|
2671
2973
|
return {
|
|
2672
2974
|
type: "image",
|
|
2673
2975
|
mimeType: media.mimeType,
|
|
@@ -2846,6 +3148,7 @@ async function buildSystemPrompt(cfg, ctx = {}) {
|
|
|
2846
3148
|
const effectiveStageId = isAcquaintance ? "tg-given-cold" : cfg.stage;
|
|
2847
3149
|
const rel = isAcquaintance ? { ...relRaw, stage: effectiveStageId, score: { interest: 0, trust: 0, attraction: 0, annoyance: 0, cringe: 0 } } : relRaw;
|
|
2848
3150
|
const longTerm = isAcquaintance ? "" : await readMd(cfg.slug, "memory/long-term.md");
|
|
3151
|
+
const sharedMemory = isAcquaintance ? await readSharedMemory(cfg.slug, 8) : ctx.incoming ? await searchSharedMemory(cfg.slug, ctx.incoming, 12) : await readSharedMemory(cfg.slug, 20);
|
|
2849
3152
|
const stage = findStage(effectiveStageId);
|
|
2850
3153
|
const seed = [...cfg.name].reduce((a, c) => a + c.charCodeAt(0), 0);
|
|
2851
3154
|
const stressLoad = Math.min(
|
|
@@ -2883,7 +3186,7 @@ ${hits.map((h) => `- ${h.day}: ${h.excerpt}`).join("\n")}
|
|
|
2883
3186
|
\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
3187
|
\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
3188
|
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.
|
|
3189
|
+
\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
3190
|
${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
3191
|
${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
3192
|
const communicationFragment = communicationPromptFragment(communication);
|
|
@@ -3058,6 +3361,8 @@ var init_prompt = __esm({
|
|
|
3058
3361
|
|
|
3059
3362
|
# \u041F\u0410\u041C\u042F\u0422\u042C
|
|
3060
3363
|
- \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.
|
|
3364
|
+
- \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.
|
|
3365
|
+
- \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
3366
|
- \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
3367
|
|
|
3063
3368
|
# \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 +4012,10 @@ var init_llm2 = __esm({
|
|
|
3707
4012
|
}
|
|
3708
4013
|
});
|
|
3709
4014
|
|
|
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
4015
|
// src/engine/agenda.ts
|
|
4016
|
+
function agendaById(items) {
|
|
4017
|
+
return new Map(items.map((item) => [item.id, item]));
|
|
4018
|
+
}
|
|
3800
4019
|
function localDateKey(tz, now = /* @__PURE__ */ new Date()) {
|
|
3801
4020
|
try {
|
|
3802
4021
|
return new Intl.DateTimeFormat("en-CA", { timeZone: tz, year: "numeric", month: "2-digit", day: "2-digit" }).format(now);
|
|
@@ -3895,6 +4114,7 @@ ${persona}`;
|
|
|
3895
4114
|
return { created: 0, updated: 0, cancelled: 0 };
|
|
3896
4115
|
}
|
|
3897
4116
|
let created = 0, updated = 0, cancelled = 0;
|
|
4117
|
+
const byId = agendaById(agenda);
|
|
3898
4118
|
for (const a of actions) {
|
|
3899
4119
|
if (a.action === "noop" || !a.action) continue;
|
|
3900
4120
|
if (a.action === "create" && a.about && a.pingAt) {
|
|
@@ -3914,21 +4134,21 @@ ${persona}`;
|
|
|
3914
4134
|
agenda.push(item);
|
|
3915
4135
|
created++;
|
|
3916
4136
|
} 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
|
-
|
|
4137
|
+
const item = byId.get(a.id);
|
|
4138
|
+
if (item) {
|
|
4139
|
+
if (a.about) item.about = a.about;
|
|
4140
|
+
if (a.pingAt) item.pingAt = a.pingAt;
|
|
4141
|
+
if (a.reason) item.reason = a.reason;
|
|
4142
|
+
if (a.userEventTime) item.userEventTime = a.userEventTime;
|
|
4143
|
+
if (a.importance) item.importance = a.importance;
|
|
4144
|
+
item.history = [...item.history ?? [], `updated at ${(/* @__PURE__ */ new Date()).toISOString()}: ${a.reason ?? ""}`];
|
|
3925
4145
|
updated++;
|
|
3926
4146
|
}
|
|
3927
4147
|
} else if (a.action === "cancel" && a.id) {
|
|
3928
|
-
const
|
|
3929
|
-
if (
|
|
3930
|
-
|
|
3931
|
-
|
|
4148
|
+
const item = byId.get(a.id);
|
|
4149
|
+
if (item) {
|
|
4150
|
+
item.state = "cancelled";
|
|
4151
|
+
item.history = [...item.history ?? [], `cancelled at ${(/* @__PURE__ */ new Date()).toISOString()}: ${a.reason ?? ""}`];
|
|
3932
4152
|
cancelled++;
|
|
3933
4153
|
}
|
|
3934
4154
|
}
|
|
@@ -4025,17 +4245,15 @@ async function reconcileAgendaAfterConflict(slug, conflict, prevLevel) {
|
|
|
4025
4245
|
let rescheduled = 0;
|
|
4026
4246
|
const now = Date.now();
|
|
4027
4247
|
for (const item of pending2) {
|
|
4028
|
-
const idx = agenda.findIndex((x) => x.id === item.id);
|
|
4029
|
-
if (idx < 0) continue;
|
|
4030
4248
|
if (conflict.level >= 3 || item.importance === 1) {
|
|
4031
|
-
|
|
4032
|
-
|
|
4249
|
+
item.state = "cancelled";
|
|
4250
|
+
item.history = [...item.history ?? [], `cancelled due to conflict level ${conflict.level} at ${(/* @__PURE__ */ new Date()).toISOString()}`];
|
|
4033
4251
|
cancelled++;
|
|
4034
4252
|
} else if (conflict.level >= 2 && item.importance === 2) {
|
|
4035
4253
|
const delayHours = 12 + Math.random() * 24;
|
|
4036
4254
|
const newPing = new Date(now + delayHours * 36e5).toISOString();
|
|
4037
|
-
|
|
4038
|
-
|
|
4255
|
+
item.pingAt = newPing;
|
|
4256
|
+
item.history = [...item.history ?? [], `rescheduled due to conflict level ${conflict.level} at ${(/* @__PURE__ */ new Date()).toISOString()}`];
|
|
4039
4257
|
rescheduled++;
|
|
4040
4258
|
}
|
|
4041
4259
|
}
|
|
@@ -4051,21 +4269,21 @@ async function dueAgendaItems(slug) {
|
|
|
4051
4269
|
}
|
|
4052
4270
|
async function markAgendaFired(slug, id) {
|
|
4053
4271
|
const agenda = await readAgenda(slug);
|
|
4054
|
-
const
|
|
4055
|
-
if (
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4272
|
+
const item = agendaById(agenda).get(id);
|
|
4273
|
+
if (item) {
|
|
4274
|
+
item.state = "fired";
|
|
4275
|
+
item.attempts += 1;
|
|
4276
|
+
item.history = [...item.history ?? [], `fired at ${(/* @__PURE__ */ new Date()).toISOString()}`];
|
|
4059
4277
|
await writeAgenda(slug, agenda);
|
|
4060
4278
|
}
|
|
4061
4279
|
}
|
|
4062
4280
|
async function rescheduleAgenda(slug, id, newPingAt, note) {
|
|
4063
4281
|
const agenda = await readAgenda(slug);
|
|
4064
|
-
const
|
|
4065
|
-
if (
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4282
|
+
const item = agendaById(agenda).get(id);
|
|
4283
|
+
if (item) {
|
|
4284
|
+
item.pingAt = newPingAt;
|
|
4285
|
+
item.state = "pending";
|
|
4286
|
+
item.history = [...item.history ?? [], `rescheduled to ${newPingAt}: ${note}`];
|
|
4069
4287
|
await writeAgenda(slug, agenda);
|
|
4070
4288
|
}
|
|
4071
4289
|
}
|
|
@@ -4344,13 +4562,13 @@ var init_daily_summarizer = __esm({
|
|
|
4344
4562
|
});
|
|
4345
4563
|
|
|
4346
4564
|
// src/engine/stickers.ts
|
|
4347
|
-
import { promises as
|
|
4348
|
-
import
|
|
4565
|
+
import { promises as fs6 } from "fs";
|
|
4566
|
+
import path8 from "path";
|
|
4349
4567
|
async function libraryPath(cfg) {
|
|
4350
4568
|
const rel = "stickers/library.md";
|
|
4351
4569
|
const current = await readMd(cfg.slug, rel);
|
|
4352
4570
|
if (!current.trim()) await writeMd(cfg.slug, rel, DEFAULT_LIBRARY);
|
|
4353
|
-
return
|
|
4571
|
+
return path8.join(profileDir(cfg.slug), rel);
|
|
4354
4572
|
}
|
|
4355
4573
|
async function listStickers(cfg) {
|
|
4356
4574
|
await libraryPath(cfg);
|
|
@@ -4370,8 +4588,10 @@ async function pickSticker(cfg, mood = "") {
|
|
|
4370
4588
|
}
|
|
4371
4589
|
async function addStickerToLibrary(cfg, fileId, emoji = "", tags = []) {
|
|
4372
4590
|
await libraryPath(cfg);
|
|
4373
|
-
const
|
|
4374
|
-
|
|
4591
|
+
const existing = await listStickers(cfg);
|
|
4592
|
+
if (existing.some((s) => s.fileId === fileId)) return;
|
|
4593
|
+
const p = path8.join(profileDir(cfg.slug), "stickers/library.md");
|
|
4594
|
+
await fs6.appendFile(p, `${fileId} | ${emoji} | ${tags.join(",")}
|
|
4375
4595
|
`, "utf8");
|
|
4376
4596
|
}
|
|
4377
4597
|
var DEFAULT_LIBRARY;
|
|
@@ -5066,7 +5286,6 @@ var init_runtime = __esm({
|
|
|
5066
5286
|
init_stages();
|
|
5067
5287
|
init_communication();
|
|
5068
5288
|
init_llm2();
|
|
5069
|
-
init_client();
|
|
5070
5289
|
init_agenda();
|
|
5071
5290
|
init_presence();
|
|
5072
5291
|
init_online_tick();
|
|
@@ -5093,7 +5312,6 @@ var init_runtime = __esm({
|
|
|
5093
5312
|
cfg;
|
|
5094
5313
|
llm;
|
|
5095
5314
|
tg;
|
|
5096
|
-
mcps = [];
|
|
5097
5315
|
histories = /* @__PURE__ */ new Map();
|
|
5098
5316
|
paused = false;
|
|
5099
5317
|
agendaTimer;
|
|
@@ -5134,8 +5352,6 @@ var init_runtime = __esm({
|
|
|
5134
5352
|
tgSelf = {};
|
|
5135
5353
|
async start() {
|
|
5136
5354
|
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
5355
|
this.tg = await makeTgAdapter(this.cfg);
|
|
5140
5356
|
await this.tg.start((m) => this.handleIncoming(m));
|
|
5141
5357
|
if (this.tg.getSelf) this.tgSelf = this.tg.getSelf();
|
|
@@ -5172,7 +5388,6 @@ var init_runtime = __esm({
|
|
|
5172
5388
|
await this.tg?.stop();
|
|
5173
5389
|
} catch {
|
|
5174
5390
|
}
|
|
5175
|
-
for (const h of this.mcps) await h.close();
|
|
5176
5391
|
}
|
|
5177
5392
|
pause() {
|
|
5178
5393
|
this.paused = true;
|
|
@@ -5239,7 +5454,6 @@ var init_runtime = __esm({
|
|
|
5239
5454
|
if (!fromId) return;
|
|
5240
5455
|
if (this.cfg.ownerId === fromId) return;
|
|
5241
5456
|
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
5457
|
return;
|
|
5244
5458
|
}
|
|
5245
5459
|
this.cfg.ownerId = fromId;
|
|
@@ -5318,6 +5532,13 @@ var init_runtime = __esm({
|
|
|
5318
5532
|
return m.text ? `${media}
|
|
5319
5533
|
${m.text}` : media;
|
|
5320
5534
|
}
|
|
5535
|
+
async rememberSharedCrossChat(fromId, incomingText) {
|
|
5536
|
+
const text = incomingText.trim();
|
|
5537
|
+
if (!text || text.length < 3) return;
|
|
5538
|
+
const safe = text.replace(/\s+/g, " ").slice(0, 280);
|
|
5539
|
+
await appendSharedMemory(this.cfg.slug, this.cfg.tz, fromId, safe).catch(() => {
|
|
5540
|
+
});
|
|
5541
|
+
}
|
|
5321
5542
|
requestedOutgoingMedia(text) {
|
|
5322
5543
|
if (/\b(фото|фотку|селфи|скинь себя|покажи себя)\b/i.test(text)) return "photo";
|
|
5323
5544
|
if (/\b(видео|видос|запиши видео)\b/i.test(text)) return "video";
|
|
@@ -5371,10 +5592,8 @@ ${m.text}` : media;
|
|
|
5371
5592
|
try {
|
|
5372
5593
|
await this.tg.editText(chatId, messageId, rawText);
|
|
5373
5594
|
this.emit("event", { type: "info", text: `edit-self: "${text.slice(0, 30)}" \u2192 "${rawText.slice(0, 30)}"`, chatId });
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
});
|
|
5377
|
-
}
|
|
5595
|
+
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(() => {
|
|
5596
|
+
});
|
|
5378
5597
|
const rec = this.sentMessages.find((s) => s.messageId === messageId);
|
|
5379
5598
|
if (rec) rec.text = rawText;
|
|
5380
5599
|
const histEntry = hist[hist.length - 1];
|
|
@@ -5390,7 +5609,7 @@ ${m.text}` : media;
|
|
|
5390
5609
|
this.lastHerReplyTs.set(this.histKey(chatId), Date.now());
|
|
5391
5610
|
this.bumpStageStats("her");
|
|
5392
5611
|
this.emit("event", { type: "outgoing", text, chatId });
|
|
5393
|
-
|
|
5612
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> \u043E\u043D\u0430: ${text}`, typeof chatId === "number" ? chatId : void 0);
|
|
5394
5613
|
sent.push(text);
|
|
5395
5614
|
}
|
|
5396
5615
|
return sent;
|
|
@@ -5400,7 +5619,7 @@ ${m.text}` : media;
|
|
|
5400
5619
|
});
|
|
5401
5620
|
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
5621
|
this.emit("event", { type: "ignored", text: hist[hist.length - 1]?.content ?? "", reason: reasonTag });
|
|
5403
|
-
|
|
5622
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> ignored (${reasonTag})`, typeof chatId === "number" ? chatId : void 0);
|
|
5404
5623
|
}
|
|
5405
5624
|
/**
|
|
5406
5625
|
* Один ретрай с упрощённым system-промптом. Используется когда первый ответ оказался
|
|
@@ -5435,7 +5654,7 @@ ${m.text}` : media;
|
|
|
5435
5654
|
this.lastHerReplyTs.set(this.histKey(chatId), Date.now());
|
|
5436
5655
|
this.emit("event", { type: "outgoing", text: candidate, chatId });
|
|
5437
5656
|
this.emit("event", { type: "info", text: "neutral-filler \u0432\u043C\u0435\u0441\u0442\u043E silent-fallback" });
|
|
5438
|
-
|
|
5657
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> \u043E\u043D\u0430 (filler): ${candidate}`, typeof chatId === "number" ? chatId : void 0);
|
|
5439
5658
|
hist.push({ role: "assistant", content: candidate, ts: Date.now() });
|
|
5440
5659
|
this.setDecisionStatus(this.histKey(chatId), "sent", "neutral-filler");
|
|
5441
5660
|
} catch (e) {
|
|
@@ -5603,11 +5822,15 @@ ${m.text}` : media;
|
|
|
5603
5822
|
this.histories.set(key, hist);
|
|
5604
5823
|
this.emit("event", { type: "incoming", text: incomingText, chatId: m.chatId });
|
|
5605
5824
|
if (isPrimary) {
|
|
5606
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[${(/* @__PURE__ */ new Date()).toISOString()}] \u043E\u043D(${m.fromId}): ${incomingText}
|
|
5825
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[${(/* @__PURE__ */ new Date()).toISOString()}] \u043E\u043D(${m.fromId}): ${incomingText}`, m.fromId);
|
|
5826
|
+
} else {
|
|
5827
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[${(/* @__PURE__ */ new Date()).toISOString()}] \u0434\u0440\u0443\u0433\u043E\u0439(${m.fromId}): ${incomingText}`, m.fromId);
|
|
5828
|
+
await this.rememberSharedCrossChat(m.fromId, incomingText);
|
|
5829
|
+
recordInteractionMemory(this.llm, this.cfg, incomingText, void 0, m.fromId, "acquaintance").catch(() => {
|
|
5830
|
+
});
|
|
5607
5831
|
}
|
|
5608
5832
|
if (m.media?.kind === "sticker" && m.media.fileId && isPrimary) {
|
|
5609
|
-
addStickerToLibrary(this.cfg, m.media.fileId, m.media.emoji ?? "", ["received"])
|
|
5610
|
-
});
|
|
5833
|
+
void addStickerToLibrary(this.cfg, m.media.fileId, m.media.emoji ?? "", ["received"]);
|
|
5611
5834
|
}
|
|
5612
5835
|
const requestedMedia = this.requestedOutgoingMedia(m.text);
|
|
5613
5836
|
if (requestedMedia) {
|
|
@@ -5630,7 +5853,7 @@ ${m.text}` : media;
|
|
|
5630
5853
|
}
|
|
5631
5854
|
if (!bubbles.length) return;
|
|
5632
5855
|
await this.sendBubbles(m.chatId, bubbles, hist, isPrimary ? "primary" : "acquaintance", true);
|
|
5633
|
-
if (isPrimary) recordInteractionMemory(this.llm, this.cfg, incomingText, bubbles.join(" / ")).catch(() => {
|
|
5856
|
+
if (isPrimary) recordInteractionMemory(this.llm, this.cfg, incomingText, bubbles.join(" / "), m.fromId, "primary").catch(() => {
|
|
5634
5857
|
});
|
|
5635
5858
|
return;
|
|
5636
5859
|
}
|
|
@@ -5761,7 +5984,7 @@ ${m.text}` : media;
|
|
|
5761
5984
|
});
|
|
5762
5985
|
const msgTag = target.messageId !== m.messageId ? ` (msgId=${target.messageId})` : "";
|
|
5763
5986
|
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}
|
|
5987
|
+
appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> reaction ${tick.reaction}${msgTag}`, m.fromId).catch(() => {
|
|
5765
5988
|
});
|
|
5766
5989
|
}, reactDelay).unref?.();
|
|
5767
5990
|
}
|
|
@@ -5777,8 +6000,8 @@ ${m.text}` : media;
|
|
|
5777
6000
|
});
|
|
5778
6001
|
}
|
|
5779
6002
|
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(() => {
|
|
6003
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> ignored (${tick.intent}: ${tick.ignoreReason ?? ""})`, m.fromId);
|
|
6004
|
+
recordInteractionMemory(this.llm, this.cfg, incomingText, void 0, m.fromId, "primary").catch(() => {
|
|
5782
6005
|
});
|
|
5783
6006
|
return;
|
|
5784
6007
|
}
|
|
@@ -5823,10 +6046,12 @@ ${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u
|
|
|
5823
6046
|
];
|
|
5824
6047
|
const image = imagePartFromMedia(incoming?.media);
|
|
5825
6048
|
if (image) {
|
|
6049
|
+
const memeHint = memeDetectionInstruction(incoming?.media);
|
|
5826
6050
|
messages.push({
|
|
5827
6051
|
role: "user",
|
|
5828
6052
|
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."
|
|
6053
|
+
{ 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 ? `
|
|
6054
|
+
${memeHint}` : ""}` },
|
|
5830
6055
|
image
|
|
5831
6056
|
]
|
|
5832
6057
|
});
|
|
@@ -5856,7 +6081,7 @@ ${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u
|
|
|
5856
6081
|
const sent = await this.sendBubbles(chatId, bubbles, hist, scope, tick.typing);
|
|
5857
6082
|
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
6083
|
if (scope === "primary") {
|
|
5859
|
-
recordInteractionMemory(this.llm, this.cfg, lastUser ?? "", sent.join(" / ")).catch(() => {
|
|
6084
|
+
recordInteractionMemory(this.llm, this.cfg, lastUser ?? "", sent.join(" / "), typeof chatId === "number" ? chatId : void 0, "primary").catch(() => {
|
|
5860
6085
|
});
|
|
5861
6086
|
}
|
|
5862
6087
|
if (this.tg.sendSticker && Math.random() < 0.08) {
|
|
@@ -5935,7 +6160,7 @@ ${tick.intent === "short" ? "\u041E\u0442\u0432\u0435\u0447\u0430\u0439 \u043E\u
|
|
|
5935
6160
|
}
|
|
5936
6161
|
hist.push({ role: "assistant", content: piece, ts: now });
|
|
5937
6162
|
this.emit("event", { type: "outgoing", text: piece, chatId: item.chatId });
|
|
5938
|
-
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> [proactive] \u043E\u043D\u0430: ${piece}
|
|
6163
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, ` -> [proactive] \u043E\u043D\u0430: ${piece}`, typeof item.chatId === "number" ? item.chatId : void 0);
|
|
5939
6164
|
}
|
|
5940
6165
|
this.histories.set(key, hist);
|
|
5941
6166
|
await markAgendaFired(this.cfg.slug, item.id);
|
|
@@ -5997,7 +6222,6 @@ ${herLastMessages.map((m) => `- "${m}"`).join("\n")}
|
|
|
5997
6222
|
`communication: ${communicationProfileLabel(communication)}`,
|
|
5998
6223
|
`config: ${profileDir(this.cfg.slug)}/config.json`,
|
|
5999
6224
|
`score: ${JSON.stringify(rel.score)}`,
|
|
6000
|
-
`mcp: ${this.mcps.map((m) => m.id).join(", ") || "\u2014"}`,
|
|
6001
6225
|
`paused: ${this.paused}`
|
|
6002
6226
|
].join("\n");
|
|
6003
6227
|
}
|
|
@@ -6451,7 +6675,7 @@ ${describeLLM(this.cfg)}`;
|
|
|
6451
6675
|
await maybeAdvanceRelationshipTimeline(this.cfg, oldStage, decision.next);
|
|
6452
6676
|
this.stageStats.set(decision.next, { herMsgs: 0, hisMsgs: 0, ignoresInStage: 0, lastCheckAt: 0, stageEnteredAt: Date.now() });
|
|
6453
6677
|
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})
|
|
6678
|
+
await appendSessionLog(this.cfg.slug, this.cfg.tz, `[stage-transition] ${oldStage} \u2192 ${decision.next} (${decision.reason})`, this.cfg.ownerId);
|
|
6455
6679
|
} catch {
|
|
6456
6680
|
}
|
|
6457
6681
|
}
|
|
@@ -6482,7 +6706,7 @@ ${describeLLM(this.cfg)}`;
|
|
|
6482
6706
|
};
|
|
6483
6707
|
this.emit("event", { type: "info", text: `delete: ${awareness}${m.deletion.text ? ` "${m.deletion.text.slice(0, 40)}"` : ""}` });
|
|
6484
6708
|
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)}"
|
|
6709
|
+
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
6710
|
}
|
|
6487
6711
|
if (!shouldRespondToDeletion(ctx)) return;
|
|
6488
6712
|
if (!inHistory && awareness === "saw-and-read") {
|
|
@@ -6568,7 +6792,7 @@ ${buildDeletionPromptContext(this.cfg, ctx)}` },
|
|
|
6568
6792
|
}
|
|
6569
6793
|
this.emit("event", { type: "info", text: `emoji-react ${m.emojiReaction.emoji} (${decision.category}/${decision.intent}): ${decision.reason}` });
|
|
6570
6794
|
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})
|
|
6795
|
+
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
6796
|
}
|
|
6573
6797
|
if (decision.moodDelta && Object.keys(decision.moodDelta).length > 0) {
|
|
6574
6798
|
const newScore = applyMoodDelta(rel.score, decision.moodDelta);
|
|
@@ -6707,21 +6931,21 @@ var init_memory_palace2 = __esm({
|
|
|
6707
6931
|
});
|
|
6708
6932
|
|
|
6709
6933
|
// src/migrations/index.ts
|
|
6710
|
-
import { promises as
|
|
6711
|
-
import
|
|
6934
|
+
import { promises as fs7 } from "fs";
|
|
6935
|
+
import path9 from "path";
|
|
6712
6936
|
import { readFileSync } from "fs";
|
|
6713
6937
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6714
6938
|
async function readMigrationState() {
|
|
6715
6939
|
try {
|
|
6716
|
-
const raw = await
|
|
6940
|
+
const raw = await fs7.readFile(MIGRATIONS_FILE(), "utf8");
|
|
6717
6941
|
return JSON.parse(raw);
|
|
6718
6942
|
} catch {
|
|
6719
6943
|
return { appliedMigrations: [], lastRunVersion: "0.0.0", lastRunAt: "" };
|
|
6720
6944
|
}
|
|
6721
6945
|
}
|
|
6722
6946
|
async function writeMigrationState(state) {
|
|
6723
|
-
await
|
|
6724
|
-
await
|
|
6947
|
+
await fs7.mkdir(DATA_ROOT, { recursive: true });
|
|
6948
|
+
await fs7.writeFile(MIGRATIONS_FILE(), JSON.stringify(state, null, 2), "utf8");
|
|
6725
6949
|
}
|
|
6726
6950
|
async function pendingMigrations() {
|
|
6727
6951
|
const state = await readMigrationState();
|
|
@@ -6814,15 +7038,15 @@ function formatUpdateWarnings(warnings) {
|
|
|
6814
7038
|
function currentVersion() {
|
|
6815
7039
|
try {
|
|
6816
7040
|
const here = fileURLToPath3(import.meta.url);
|
|
6817
|
-
let dir =
|
|
7041
|
+
let dir = path9.dirname(here);
|
|
6818
7042
|
for (let i = 0; i < 5; i++) {
|
|
6819
|
-
const candidate =
|
|
7043
|
+
const candidate = path9.join(dir, "package.json");
|
|
6820
7044
|
try {
|
|
6821
7045
|
const pkg = JSON.parse(readFileSync(candidate, "utf8"));
|
|
6822
7046
|
if (pkg.name === "@thesashadev/girl-agent" && pkg.version) return pkg.version;
|
|
6823
7047
|
} catch {
|
|
6824
7048
|
}
|
|
6825
|
-
dir =
|
|
7049
|
+
dir = path9.dirname(dir);
|
|
6826
7050
|
}
|
|
6827
7051
|
return "unknown";
|
|
6828
7052
|
} catch {
|
|
@@ -6838,7 +7062,7 @@ var init_migrations = __esm({
|
|
|
6838
7062
|
init_add_use_wss_default();
|
|
6839
7063
|
init_ensure_communication_md();
|
|
6840
7064
|
init_memory_palace2();
|
|
6841
|
-
MIGRATIONS_FILE = () =>
|
|
7065
|
+
MIGRATIONS_FILE = () => path9.join(DATA_ROOT, ".migrations.json");
|
|
6842
7066
|
ALL_MIGRATIONS = [
|
|
6843
7067
|
migration0112,
|
|
6844
7068
|
migration0113,
|
|
@@ -7000,23 +7224,23 @@ __export(addons_exports, {
|
|
|
7000
7224
|
updateSettings: () => updateSettings,
|
|
7001
7225
|
validateManifest: () => validateManifest
|
|
7002
7226
|
});
|
|
7003
|
-
import { promises as
|
|
7004
|
-
import
|
|
7227
|
+
import { promises as fs10 } from "fs";
|
|
7228
|
+
import path12 from "path";
|
|
7005
7229
|
import os3 from "os";
|
|
7006
7230
|
import { execFile } from "child_process";
|
|
7007
7231
|
import { promisify } from "util";
|
|
7008
7232
|
function addonsDir() {
|
|
7009
|
-
const root = process.env.GIRL_AGENT_DATA ?
|
|
7010
|
-
return
|
|
7233
|
+
const root = process.env.GIRL_AGENT_DATA ? path12.resolve(process.env.GIRL_AGENT_DATA, "..") : path12.join(os3.homedir(), ".local", "share", "girl-agent");
|
|
7234
|
+
return path12.join(root, "addons");
|
|
7011
7235
|
}
|
|
7012
7236
|
async function ensureDir() {
|
|
7013
7237
|
const dir = addonsDir();
|
|
7014
|
-
await
|
|
7238
|
+
await fs10.mkdir(dir, { recursive: true });
|
|
7015
7239
|
return dir;
|
|
7016
7240
|
}
|
|
7017
7241
|
async function readJsonOrEmpty(p, fallback) {
|
|
7018
7242
|
try {
|
|
7019
|
-
const raw = await
|
|
7243
|
+
const raw = await fs10.readFile(p, "utf8");
|
|
7020
7244
|
return JSON.parse(raw);
|
|
7021
7245
|
} catch {
|
|
7022
7246
|
return fallback;
|
|
@@ -7024,12 +7248,12 @@ async function readJsonOrEmpty(p, fallback) {
|
|
|
7024
7248
|
}
|
|
7025
7249
|
async function listInstalled() {
|
|
7026
7250
|
const dir = await ensureDir();
|
|
7027
|
-
const indexPath =
|
|
7251
|
+
const indexPath = path12.join(dir, "installed.json");
|
|
7028
7252
|
return await readJsonOrEmpty(indexPath, []);
|
|
7029
7253
|
}
|
|
7030
7254
|
async function writeInstalled(list) {
|
|
7031
7255
|
const dir = await ensureDir();
|
|
7032
|
-
await
|
|
7256
|
+
await fs10.writeFile(path12.join(dir, "installed.json"), JSON.stringify(list, null, 2), "utf8");
|
|
7033
7257
|
}
|
|
7034
7258
|
async function fetchRegistry() {
|
|
7035
7259
|
try {
|
|
@@ -7043,17 +7267,17 @@ async function fetchRegistry() {
|
|
|
7043
7267
|
}
|
|
7044
7268
|
}
|
|
7045
7269
|
async function unpackGaa(gaaPath) {
|
|
7046
|
-
const tmpDir =
|
|
7047
|
-
await
|
|
7270
|
+
const tmpDir = path12.join(os3.tmpdir(), `gaa-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
7271
|
+
await fs10.mkdir(tmpDir, { recursive: true });
|
|
7048
7272
|
await execFileAsync("unzip", ["-o", "-q", gaaPath, "-d", tmpDir]);
|
|
7049
|
-
const entries = await
|
|
7273
|
+
const entries = await fs10.readdir(tmpDir);
|
|
7050
7274
|
if (entries.length === 1) {
|
|
7051
|
-
const sub =
|
|
7052
|
-
const st = await
|
|
7275
|
+
const sub = path12.join(tmpDir, entries[0]);
|
|
7276
|
+
const st = await fs10.stat(sub);
|
|
7053
7277
|
if (st.isDirectory()) {
|
|
7054
|
-
const innerManifest =
|
|
7278
|
+
const innerManifest = path12.join(sub, "manifest.json");
|
|
7055
7279
|
try {
|
|
7056
|
-
await
|
|
7280
|
+
await fs10.access(innerManifest);
|
|
7057
7281
|
return sub;
|
|
7058
7282
|
} catch {
|
|
7059
7283
|
}
|
|
@@ -7062,34 +7286,34 @@ async function unpackGaa(gaaPath) {
|
|
|
7062
7286
|
return tmpDir;
|
|
7063
7287
|
}
|
|
7064
7288
|
async function packGaa(addonDir, outputPath) {
|
|
7065
|
-
const manifestPath =
|
|
7066
|
-
const manifestRaw = await
|
|
7289
|
+
const manifestPath = path12.join(addonDir, "manifest.json");
|
|
7290
|
+
const manifestRaw = await fs10.readFile(manifestPath, "utf8");
|
|
7067
7291
|
const manifest = JSON.parse(manifestRaw);
|
|
7068
7292
|
validateManifest(manifest);
|
|
7069
|
-
const out = outputPath ??
|
|
7293
|
+
const out = outputPath ?? path12.join(process.cwd(), `${manifest.id}.gaa`);
|
|
7070
7294
|
try {
|
|
7071
|
-
await
|
|
7295
|
+
await fs10.unlink(out);
|
|
7072
7296
|
} catch {
|
|
7073
7297
|
}
|
|
7074
|
-
const dirName =
|
|
7075
|
-
const parentDir =
|
|
7298
|
+
const dirName = path12.basename(addonDir);
|
|
7299
|
+
const parentDir = path12.dirname(addonDir);
|
|
7076
7300
|
await execFileAsync("zip", ["-r", "-q", out, dirName], { cwd: parentDir });
|
|
7077
7301
|
return out;
|
|
7078
7302
|
}
|
|
7079
7303
|
async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
7080
|
-
const manifestPath =
|
|
7081
|
-
const manifestRaw = await
|
|
7304
|
+
const manifestPath = path12.join(addonDir, "manifest.json");
|
|
7305
|
+
const manifestRaw = await fs10.readFile(manifestPath, "utf8");
|
|
7082
7306
|
const manifest = JSON.parse(manifestRaw);
|
|
7083
7307
|
validateManifest(manifest);
|
|
7084
7308
|
const applied = [];
|
|
7085
7309
|
const installedFiles = [];
|
|
7086
|
-
const filesDir =
|
|
7310
|
+
const filesDir = path12.join(addonDir, "files");
|
|
7087
7311
|
try {
|
|
7088
|
-
const fileStat = await
|
|
7312
|
+
const fileStat = await fs10.stat(filesDir);
|
|
7089
7313
|
if (fileStat.isDirectory() && profileSlug) {
|
|
7090
7314
|
const fileEntries = await walkDir(filesDir);
|
|
7091
7315
|
for (const relPath of fileEntries) {
|
|
7092
|
-
const content = await
|
|
7316
|
+
const content = await fs10.readFile(path12.join(filesDir, relPath), "utf8");
|
|
7093
7317
|
await writeMd(profileSlug, relPath, content);
|
|
7094
7318
|
installedFiles.push(relPath);
|
|
7095
7319
|
}
|
|
@@ -7097,9 +7321,9 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
7097
7321
|
}
|
|
7098
7322
|
} catch {
|
|
7099
7323
|
}
|
|
7100
|
-
const patchPath =
|
|
7324
|
+
const patchPath = path12.join(addonDir, "config.patch.json");
|
|
7101
7325
|
try {
|
|
7102
|
-
const patchRaw = await
|
|
7326
|
+
const patchRaw = await fs10.readFile(patchPath, "utf8");
|
|
7103
7327
|
const patch = JSON.parse(patchRaw);
|
|
7104
7328
|
if (profileSlug) {
|
|
7105
7329
|
const cfg = await readConfig(profileSlug);
|
|
@@ -7111,11 +7335,11 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
7111
7335
|
}
|
|
7112
7336
|
} catch {
|
|
7113
7337
|
}
|
|
7114
|
-
const codePatchPath =
|
|
7338
|
+
const codePatchPath = path12.join(addonDir, "code.patch");
|
|
7115
7339
|
try {
|
|
7116
|
-
const patchContent = await
|
|
7340
|
+
const patchContent = await fs10.readFile(codePatchPath, "utf8");
|
|
7117
7341
|
if (patchContent.trim()) {
|
|
7118
|
-
const projectRoot =
|
|
7342
|
+
const projectRoot = path12.resolve(import.meta.url.replace("file://", ""), "../../../");
|
|
7119
7343
|
try {
|
|
7120
7344
|
await execFileAsync("git", ["apply", "--check", codePatchPath], { cwd: projectRoot });
|
|
7121
7345
|
await execFileAsync("git", ["apply", codePatchPath], { cwd: projectRoot });
|
|
@@ -7126,25 +7350,25 @@ async function installFromDir(addonDir, profileSlug, source = "local") {
|
|
|
7126
7350
|
}
|
|
7127
7351
|
} catch {
|
|
7128
7352
|
}
|
|
7129
|
-
const themePath =
|
|
7353
|
+
const themePath = path12.join(addonDir, "theme.css");
|
|
7130
7354
|
try {
|
|
7131
|
-
const css = await
|
|
7355
|
+
const css = await fs10.readFile(themePath, "utf8");
|
|
7132
7356
|
const dir2 = await ensureDir();
|
|
7133
|
-
await
|
|
7357
|
+
await fs10.writeFile(path12.join(dir2, `theme-${manifest.id}.css`), css, "utf8");
|
|
7134
7358
|
applied.push("\u0442\u0435\u043C\u0430 \u0443\u0441\u0442\u0430\u043D\u043E\u0432\u043B\u0435\u043D\u0430");
|
|
7135
7359
|
} catch {
|
|
7136
7360
|
}
|
|
7137
7361
|
const dir = await ensureDir();
|
|
7138
|
-
const addonStorePath =
|
|
7139
|
-
await
|
|
7140
|
-
await
|
|
7362
|
+
const addonStorePath = path12.join(dir, manifest.id);
|
|
7363
|
+
await fs10.mkdir(addonStorePath, { recursive: true });
|
|
7364
|
+
await fs10.copyFile(manifestPath, path12.join(addonStorePath, "manifest.json"));
|
|
7141
7365
|
const allFiles = await walkDir(addonDir);
|
|
7142
7366
|
for (const f of allFiles) {
|
|
7143
7367
|
if (f === "manifest.json") continue;
|
|
7144
|
-
const src =
|
|
7145
|
-
const dst =
|
|
7146
|
-
await
|
|
7147
|
-
await
|
|
7368
|
+
const src = path12.join(addonDir, f);
|
|
7369
|
+
const dst = path12.join(addonStorePath, f);
|
|
7370
|
+
await fs10.mkdir(path12.dirname(dst), { recursive: true });
|
|
7371
|
+
await fs10.copyFile(src, dst);
|
|
7148
7372
|
}
|
|
7149
7373
|
const list = await listInstalled();
|
|
7150
7374
|
const item = {
|
|
@@ -7165,7 +7389,7 @@ async function installFromGaa(gaaPath, profileSlug) {
|
|
|
7165
7389
|
try {
|
|
7166
7390
|
return await installFromDir(dir, profileSlug, "file");
|
|
7167
7391
|
} finally {
|
|
7168
|
-
await
|
|
7392
|
+
await fs10.rm(dir, { recursive: true, force: true }).catch(() => {
|
|
7169
7393
|
});
|
|
7170
7394
|
}
|
|
7171
7395
|
}
|
|
@@ -7188,12 +7412,12 @@ async function installFromRegistry(id, registryManifest, profileSlug) {
|
|
|
7188
7412
|
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
7189
7413
|
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
7414
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
7191
|
-
const tmpGaa =
|
|
7192
|
-
await
|
|
7415
|
+
const tmpGaa = path12.join(os3.tmpdir(), `${id}-${Date.now()}.gaa`);
|
|
7416
|
+
await fs10.writeFile(tmpGaa, buf);
|
|
7193
7417
|
try {
|
|
7194
7418
|
return await installFromGaa(tmpGaa, profileSlug);
|
|
7195
7419
|
} finally {
|
|
7196
|
-
await
|
|
7420
|
+
await fs10.unlink(tmpGaa).catch(() => {
|
|
7197
7421
|
});
|
|
7198
7422
|
}
|
|
7199
7423
|
}
|
|
@@ -7202,11 +7426,11 @@ async function uninstall(id) {
|
|
|
7202
7426
|
const next = list.filter((a) => a.manifest.id !== id);
|
|
7203
7427
|
if (next.length === list.length) return false;
|
|
7204
7428
|
const dir = addonsDir();
|
|
7205
|
-
const addonStore =
|
|
7206
|
-
await
|
|
7429
|
+
const addonStore = path12.join(dir, id);
|
|
7430
|
+
await fs10.rm(addonStore, { recursive: true, force: true }).catch(() => {
|
|
7207
7431
|
});
|
|
7208
|
-
const themePath =
|
|
7209
|
-
await
|
|
7432
|
+
const themePath = path12.join(dir, `theme-${id}.css`);
|
|
7433
|
+
await fs10.unlink(themePath).catch(() => {
|
|
7210
7434
|
});
|
|
7211
7435
|
await writeInstalled(next);
|
|
7212
7436
|
return true;
|
|
@@ -7237,11 +7461,11 @@ function validateManifest(m) {
|
|
|
7237
7461
|
}
|
|
7238
7462
|
async function walkDir(dir, prefix = "") {
|
|
7239
7463
|
const result = [];
|
|
7240
|
-
const entries = await
|
|
7464
|
+
const entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
7241
7465
|
for (const e of entries) {
|
|
7242
7466
|
const rel = prefix ? `${prefix}/${e.name}` : e.name;
|
|
7243
7467
|
if (e.isDirectory()) {
|
|
7244
|
-
result.push(...await walkDir(
|
|
7468
|
+
result.push(...await walkDir(path12.join(dir, e.name), rel));
|
|
7245
7469
|
} else {
|
|
7246
7470
|
result.push(rel);
|
|
7247
7471
|
}
|
|
@@ -7261,16 +7485,16 @@ function deepMerge(target, source) {
|
|
|
7261
7485
|
}
|
|
7262
7486
|
async function getAddonReadme(id) {
|
|
7263
7487
|
const dir = addonsDir();
|
|
7264
|
-
const readmePath =
|
|
7488
|
+
const readmePath = path12.join(dir, id, "README.md");
|
|
7265
7489
|
try {
|
|
7266
|
-
return await
|
|
7490
|
+
return await fs10.readFile(readmePath, "utf8");
|
|
7267
7491
|
} catch {
|
|
7268
7492
|
return null;
|
|
7269
7493
|
}
|
|
7270
7494
|
}
|
|
7271
7495
|
async function getAddonFiles(id) {
|
|
7272
7496
|
const dir = addonsDir();
|
|
7273
|
-
const addonDir =
|
|
7497
|
+
const addonDir = path12.join(dir, id);
|
|
7274
7498
|
try {
|
|
7275
7499
|
return await walkDir(addonDir);
|
|
7276
7500
|
} catch {
|
|
@@ -7299,6 +7523,7 @@ init_esm_shims();
|
|
|
7299
7523
|
import http2 from "http";
|
|
7300
7524
|
import { URL as URL2 } from "url";
|
|
7301
7525
|
import os5 from "os";
|
|
7526
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
7302
7527
|
|
|
7303
7528
|
// src/webui/http.ts
|
|
7304
7529
|
init_esm_shims();
|
|
@@ -7313,9 +7538,9 @@ var HttpError = class extends Error {
|
|
|
7313
7538
|
};
|
|
7314
7539
|
var Router = class {
|
|
7315
7540
|
routes = [];
|
|
7316
|
-
add(method,
|
|
7541
|
+
add(method, path15, handler) {
|
|
7317
7542
|
const paramNames = [];
|
|
7318
|
-
const parts =
|
|
7543
|
+
const parts = path15.split("/").map((part) => {
|
|
7319
7544
|
if (part.startsWith(":")) {
|
|
7320
7545
|
paramNames.push(part.slice(1));
|
|
7321
7546
|
return "([^/]+)";
|
|
@@ -7330,20 +7555,20 @@ var Router = class {
|
|
|
7330
7555
|
handler
|
|
7331
7556
|
});
|
|
7332
7557
|
}
|
|
7333
|
-
get(
|
|
7334
|
-
this.add("GET",
|
|
7558
|
+
get(path15, h) {
|
|
7559
|
+
this.add("GET", path15, h);
|
|
7335
7560
|
}
|
|
7336
|
-
post(
|
|
7337
|
-
this.add("POST",
|
|
7561
|
+
post(path15, h) {
|
|
7562
|
+
this.add("POST", path15, h);
|
|
7338
7563
|
}
|
|
7339
|
-
put(
|
|
7340
|
-
this.add("PUT",
|
|
7564
|
+
put(path15, h) {
|
|
7565
|
+
this.add("PUT", path15, h);
|
|
7341
7566
|
}
|
|
7342
|
-
delete(
|
|
7343
|
-
this.add("DELETE",
|
|
7567
|
+
delete(path15, h) {
|
|
7568
|
+
this.add("DELETE", path15, h);
|
|
7344
7569
|
}
|
|
7345
|
-
patch(
|
|
7346
|
-
this.add("PATCH",
|
|
7570
|
+
patch(path15, h) {
|
|
7571
|
+
this.add("PATCH", path15, h);
|
|
7347
7572
|
}
|
|
7348
7573
|
match(method, pathname) {
|
|
7349
7574
|
for (const r of this.routes) {
|
|
@@ -7444,14 +7669,13 @@ async function findWebUIRoot() {
|
|
|
7444
7669
|
}
|
|
7445
7670
|
})();
|
|
7446
7671
|
const candidates = [
|
|
7672
|
+
path2.resolve(process.cwd(), "dist", "webui"),
|
|
7673
|
+
path2.resolve(process.cwd(), "webui", "dist"),
|
|
7447
7674
|
path2.resolve(here, "webui"),
|
|
7448
|
-
// dist/cli.js -> dist/webui/
|
|
7449
7675
|
path2.resolve(here, "..", "dist", "webui"),
|
|
7450
|
-
// src/webui/static.ts -> dist/webui/
|
|
7451
7676
|
path2.resolve(here, "..", "..", "dist", "webui"),
|
|
7452
|
-
// src/webui/static.ts -> dist/webui/
|
|
7453
7677
|
path2.resolve(here, "..", "..", "..", "dist", "webui"),
|
|
7454
|
-
path2.resolve(
|
|
7678
|
+
path2.resolve(here, "..", "..", "webui", "dist")
|
|
7455
7679
|
];
|
|
7456
7680
|
for (const c of candidates) {
|
|
7457
7681
|
try {
|
|
@@ -7527,10 +7751,62 @@ init_esm_shims();
|
|
|
7527
7751
|
init_runtime_bus();
|
|
7528
7752
|
init_md();
|
|
7529
7753
|
import { WebSocketServer } from "ws";
|
|
7754
|
+
|
|
7755
|
+
// src/webui/auth.ts
|
|
7756
|
+
init_esm_shims();
|
|
7757
|
+
import crypto2 from "crypto";
|
|
7758
|
+
var COOKIE = "girl_agent_auth";
|
|
7759
|
+
var TOKEN_BYTES = 24;
|
|
7760
|
+
var authSecret = process.env.GIRL_AGENT_WEBUI_PASSWORD?.trim() || process.env.GIRL_AGENT_WEBUI_TOKEN?.trim() || "";
|
|
7761
|
+
var sessions = /* @__PURE__ */ new Set();
|
|
7762
|
+
function authEnabled() {
|
|
7763
|
+
return !!authSecret;
|
|
7764
|
+
}
|
|
7765
|
+
function authStatus() {
|
|
7766
|
+
return { enabled: authEnabled() };
|
|
7767
|
+
}
|
|
7768
|
+
function verifyPassword(password) {
|
|
7769
|
+
if (!authSecret) return true;
|
|
7770
|
+
const a = Buffer.from(password);
|
|
7771
|
+
const b = Buffer.from(authSecret);
|
|
7772
|
+
return a.length === b.length && crypto2.timingSafeEqual(a, b);
|
|
7773
|
+
}
|
|
7774
|
+
function createSession(res) {
|
|
7775
|
+
const token = crypto2.randomBytes(TOKEN_BYTES).toString("base64url");
|
|
7776
|
+
sessions.add(token);
|
|
7777
|
+
res.setHeader("Set-Cookie", `${COOKIE}=${token}; Path=/; HttpOnly; SameSite=Lax; Max-Age=2592000`);
|
|
7778
|
+
}
|
|
7779
|
+
function clearSession(req, res) {
|
|
7780
|
+
const token = readCookie(req);
|
|
7781
|
+
if (token) sessions.delete(token);
|
|
7782
|
+
res.setHeader("Set-Cookie", `${COOKIE}=; Path=/; HttpOnly; SameSite=Lax; Max-Age=0`);
|
|
7783
|
+
}
|
|
7784
|
+
function isAuthorized(req) {
|
|
7785
|
+
if (!authSecret) return true;
|
|
7786
|
+
const bearer = String(req.headers.authorization ?? "").replace(/^Bearer\s+/i, "");
|
|
7787
|
+
if (bearer && verifyPassword(bearer)) return true;
|
|
7788
|
+
const token = readCookie(req);
|
|
7789
|
+
return !!token && sessions.has(token);
|
|
7790
|
+
}
|
|
7791
|
+
function readCookie(req) {
|
|
7792
|
+
const raw = req.headers.cookie;
|
|
7793
|
+
if (!raw) return void 0;
|
|
7794
|
+
for (const part of raw.split(";")) {
|
|
7795
|
+
const [key, ...rest] = part.trim().split("=");
|
|
7796
|
+
if (key === COOKIE) return rest.join("=");
|
|
7797
|
+
}
|
|
7798
|
+
return void 0;
|
|
7799
|
+
}
|
|
7800
|
+
|
|
7801
|
+
// src/webui/websocket.ts
|
|
7530
7802
|
function attachWebSockets(server) {
|
|
7531
7803
|
const wssLogs = new WebSocketServer({ noServer: true });
|
|
7532
7804
|
const wssStatus = new WebSocketServer({ noServer: true });
|
|
7533
7805
|
server.on("upgrade", (req, socket, head) => {
|
|
7806
|
+
if (!isAuthorized(req)) {
|
|
7807
|
+
socket.destroy();
|
|
7808
|
+
return;
|
|
7809
|
+
}
|
|
7534
7810
|
const url = req.url ?? "";
|
|
7535
7811
|
const logsMatch = url.match(/^\/ws\/logs\/([^/?#]+)/);
|
|
7536
7812
|
if (logsMatch) {
|
|
@@ -7612,6 +7888,60 @@ init_runtime_bus();
|
|
|
7612
7888
|
// src/webui/routes/profiles.ts
|
|
7613
7889
|
init_esm_shims();
|
|
7614
7890
|
init_md();
|
|
7891
|
+
|
|
7892
|
+
// src/telegram/proxy-parse.ts
|
|
7893
|
+
init_esm_shims();
|
|
7894
|
+
function parseTelegramProxyInput(raw) {
|
|
7895
|
+
if (raw == null) return void 0;
|
|
7896
|
+
if (typeof raw === "object") {
|
|
7897
|
+
if (!raw.ip || !raw.port) return void 0;
|
|
7898
|
+
if (raw.MTProxy && raw.secret) {
|
|
7899
|
+
return { ip: raw.ip, port: raw.port, MTProxy: true, secret: raw.secret, timeout: raw.timeout };
|
|
7900
|
+
}
|
|
7901
|
+
const socksType = raw.socksType === 4 ? 4 : 5;
|
|
7902
|
+
return {
|
|
7903
|
+
ip: raw.ip,
|
|
7904
|
+
port: raw.port,
|
|
7905
|
+
socksType,
|
|
7906
|
+
username: raw.username,
|
|
7907
|
+
password: raw.password,
|
|
7908
|
+
timeout: raw.timeout
|
|
7909
|
+
};
|
|
7910
|
+
}
|
|
7911
|
+
const trimmed = raw.trim();
|
|
7912
|
+
if (!trimmed) return void 0;
|
|
7913
|
+
try {
|
|
7914
|
+
const url = new URL(trimmed);
|
|
7915
|
+
const isMtproxy = url.protocol === "tg:" && url.hostname === "proxy" || /^https?:$/.test(url.protocol) && url.hostname === "t.me" && url.pathname.replace(/^\//, "") === "proxy";
|
|
7916
|
+
if (isMtproxy) {
|
|
7917
|
+
const ip = url.searchParams.get("server")?.trim();
|
|
7918
|
+
const port2 = Number(url.searchParams.get("port"));
|
|
7919
|
+
const secret = url.searchParams.get("secret")?.trim();
|
|
7920
|
+
if (!ip || !Number.isInteger(port2) || port2 <= 0 || !secret) return void 0;
|
|
7921
|
+
return { ip, port: port2, MTProxy: true, secret };
|
|
7922
|
+
}
|
|
7923
|
+
if (url.protocol === "socks4:" || url.protocol === "socks5:") {
|
|
7924
|
+
const socksType = url.protocol === "socks4:" ? 4 : 5;
|
|
7925
|
+
const port2 = Number(url.port);
|
|
7926
|
+
if (!url.hostname || !Number.isInteger(port2) || port2 <= 0) return void 0;
|
|
7927
|
+
return {
|
|
7928
|
+
ip: url.hostname,
|
|
7929
|
+
port: port2,
|
|
7930
|
+
socksType,
|
|
7931
|
+
username: url.username ? decodeURIComponent(url.username) : void 0,
|
|
7932
|
+
password: url.password ? decodeURIComponent(url.password) : void 0
|
|
7933
|
+
};
|
|
7934
|
+
}
|
|
7935
|
+
return void 0;
|
|
7936
|
+
} catch {
|
|
7937
|
+
}
|
|
7938
|
+
const [host, portRaw] = trimmed.split(":");
|
|
7939
|
+
const port = Number(portRaw);
|
|
7940
|
+
if (!host || !Number.isInteger(port) || port <= 0) return void 0;
|
|
7941
|
+
return { ip: host, port, socksType: 5 };
|
|
7942
|
+
}
|
|
7943
|
+
|
|
7944
|
+
// src/webui/routes/profiles.ts
|
|
7615
7945
|
init_runtime_bus();
|
|
7616
7946
|
init_stages();
|
|
7617
7947
|
|
|
@@ -7656,6 +7986,8 @@ var BUSY_SCHEDULE_SCHEMA = {
|
|
|
7656
7986
|
}
|
|
7657
7987
|
};
|
|
7658
7988
|
async function generatePersonaPack(llm, slug, name, age, nationality = "RU", personaNotes = "", onProgress) {
|
|
7989
|
+
const existing = await readExistingPersona(slug);
|
|
7990
|
+
if (existing) return existing;
|
|
7659
7991
|
const country = nationality === "UA" ? "\u0423\u043A\u0440\u0430\u0438\u043D\u0430" : "\u0420\u043E\u0441\u0441\u0438\u044F / \u0421\u041D\u0413";
|
|
7660
7992
|
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
7993
|
const notes = personaNotes.trim() ? `
|
|
@@ -7772,10 +8104,93 @@ ${personaNotes.trim()}
|
|
|
7772
8104
|
await writeMd(slug, "communication.md", boundaries);
|
|
7773
8105
|
return { persona, speech, boundaries, busySchedule };
|
|
7774
8106
|
}
|
|
8107
|
+
async function ensurePersonaPack(slug, name, age) {
|
|
8108
|
+
const existing = await readExistingPersona(slug);
|
|
8109
|
+
if (existing) return existing;
|
|
8110
|
+
const persona = fallbackPersona(name, age);
|
|
8111
|
+
const speech = fallbackSpeech(name, age);
|
|
8112
|
+
const boundaries = fallbackCommunication(name, age);
|
|
8113
|
+
const busySchedule = fallbackBusySchedule(name, age);
|
|
8114
|
+
await writeMd(slug, "persona.md", persona);
|
|
8115
|
+
await writeMd(slug, "speech.md", speech);
|
|
8116
|
+
await writeMd(slug, "communication.md", boundaries);
|
|
8117
|
+
return { persona, speech, boundaries, busySchedule };
|
|
8118
|
+
}
|
|
8119
|
+
async function readExistingPersona(slug) {
|
|
8120
|
+
try {
|
|
8121
|
+
const [persona, speech, boundaries] = await Promise.all([
|
|
8122
|
+
readMd(slug, "persona.md"),
|
|
8123
|
+
readMd(slug, "speech.md"),
|
|
8124
|
+
readMd(slug, "communication.md")
|
|
8125
|
+
]);
|
|
8126
|
+
if (persona.trim() && speech.trim() && boundaries.trim()) {
|
|
8127
|
+
return { persona, speech, boundaries, busySchedule: [] };
|
|
8128
|
+
}
|
|
8129
|
+
} catch {
|
|
8130
|
+
}
|
|
8131
|
+
return null;
|
|
8132
|
+
}
|
|
7775
8133
|
function sanitizeProfileText(text) {
|
|
7776
8134
|
const cleaned = sanitizeModelReply(text).replace(/[^\S\r\n]{2,}/g, " ").replace(/\n{4,}/g, "\n\n\n").trim();
|
|
7777
8135
|
return cleaned || text.trim();
|
|
7778
8136
|
}
|
|
8137
|
+
function fallbackPersona(name, age) {
|
|
8138
|
+
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";
|
|
8139
|
+
return `# ${name}, ${age}
|
|
8140
|
+
## \u0411\u044D\u043A\u0433\u0440\u0430\u0443\u043D\u0434
|
|
8141
|
+
\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.
|
|
8142
|
+
|
|
8143
|
+
## \u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440
|
|
8144
|
+
- \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
|
|
8145
|
+
- \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
|
|
8146
|
+
- \u043D\u0435 \u043B\u044E\u0431\u0438\u0442 \u0434\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u0438 \u0434\u043E\u043F\u0440\u043E\u0441\u044B
|
|
8147
|
+
- \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
|
|
8148
|
+
- \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
|
|
8149
|
+
|
|
8150
|
+
## \u0427\u0442\u043E \u0435\u0451 \u0431\u0435\u0441\u0438\u0442
|
|
8151
|
+
- \u043D\u0430\u0432\u044F\u0437\u0447\u0438\u0432\u043E\u0441\u0442\u044C
|
|
8152
|
+
- \u043F\u0430\u0441\u0441\u0438\u0432\u043D\u0430\u044F \u0430\u0433\u0440\u0435\u0441\u0441\u0438\u044F
|
|
8153
|
+
- \u043A\u043E\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u044E\u0442 \u0431\u044B\u0441\u0442\u0440\u044B\u0439 \u043E\u0442\u0432\u0435\u0442
|
|
8154
|
+
- \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?"
|
|
8155
|
+
- \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
|
|
8156
|
+
|
|
8157
|
+
## \u0427\u0442\u043E \u0435\u0439 \u043D\u0440\u0430\u0432\u0438\u0442\u0441\u044F
|
|
8158
|
+
\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.`;
|
|
8159
|
+
}
|
|
8160
|
+
function fallbackSpeech(name, age) {
|
|
8161
|
+
return `# \u041C\u0430\u043D\u0435\u0440\u0430 \u0440\u0435\u0447\u0438
|
|
8162
|
+
${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.
|
|
8163
|
+
|
|
8164
|
+
## \u0420\u0435\u0433\u0438\u0441\u0442\u0440 \u0438 \u043F\u0443\u043D\u043A\u0442\u0443\u0430\u0446\u0438\u044F
|
|
8165
|
+
\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.
|
|
8166
|
+
|
|
8167
|
+
## \u0421\u043B\u0435\u043D\u0433
|
|
8168
|
+
\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.
|
|
8169
|
+
|
|
8170
|
+
## \u0422\u0438\u043F\u0438\u0447\u043D\u044B\u0435 \u0440\u0435\u0430\u043A\u0446\u0438\u0438
|
|
8171
|
+
- "\u043D\u0443 \u0434\u0430"
|
|
8172
|
+
- "\u043D\u0435 \u0437\u043D\u0430\u044E"
|
|
8173
|
+
- "\u0441\u0442\u0440\u0430\u043D\u043D\u043E \u043D\u0435\u043C\u043D\u043E\u0433\u043E"
|
|
8174
|
+
- "\u0430\u0445\u0430\u0445"
|
|
8175
|
+
- "\u043B\u0430\u0434\u043D\u043E"
|
|
8176
|
+
- "\u043C\u043D\u0435 \u043B\u0435\u043D\u044C \u0449\u0430\u0441"
|
|
8177
|
+
|
|
8178
|
+
## \u0417\u0430\u043F\u0440\u0435\u0449\u0451\u043D\u043D\u043E\u0435
|
|
8179
|
+
\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}.`;
|
|
8180
|
+
}
|
|
8181
|
+
function fallbackCommunication(name, age) {
|
|
8182
|
+
return `# \u041F\u0440\u0435\u0434\u043F\u043E\u0447\u0442\u0435\u043D\u0438\u044F \u0432 \u043E\u0431\u0449\u0435\u043D\u0438\u0438
|
|
8183
|
+
${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.
|
|
8184
|
+
|
|
8185
|
+
## \u0422\u0435\u043C\u044B \u043A\u043E\u0442\u043E\u0440\u044B\u0435 \u041D\u0415 \u043E\u0431\u0441\u0443\u0436\u0434\u0430\u0435\u0442
|
|
8186
|
+
\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.
|
|
8187
|
+
|
|
8188
|
+
## \u0417\u0435\u043B\u0451\u043D\u044B\u0435 \u0444\u043B\u0430\u0433\u0438
|
|
8189
|
+
\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.
|
|
8190
|
+
|
|
8191
|
+
## \u041A\u043E\u0433\u0434\u0430 \u0443\u0445\u043E\u0434\u0438\u0442 \u0432 \u0438\u0433\u043D\u043E\u0440
|
|
8192
|
+
\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.`;
|
|
8193
|
+
}
|
|
7779
8194
|
function parseBusySchedule(raw, name, age) {
|
|
7780
8195
|
try {
|
|
7781
8196
|
const start = raw.indexOf("{");
|
|
@@ -7835,8 +8250,8 @@ function fallbackBusySchedule(name, age) {
|
|
|
7835
8250
|
init_llm();
|
|
7836
8251
|
init_llm_update();
|
|
7837
8252
|
init_llm2();
|
|
7838
|
-
import { promises as
|
|
7839
|
-
import
|
|
8253
|
+
import { promises as fs8 } from "fs";
|
|
8254
|
+
import path10 from "path";
|
|
7840
8255
|
var MEMORY_FILES = [
|
|
7841
8256
|
"persona.md",
|
|
7842
8257
|
"speech.md",
|
|
@@ -7853,7 +8268,7 @@ var MEMORY_FILES = [
|
|
|
7853
8268
|
function isAllowedMemoryPath(p) {
|
|
7854
8269
|
if (!p || typeof p !== "string") return false;
|
|
7855
8270
|
if (p.includes("..")) return false;
|
|
7856
|
-
if (
|
|
8271
|
+
if (path10.isAbsolute(p)) return false;
|
|
7857
8272
|
if (p.startsWith("config.json")) return false;
|
|
7858
8273
|
if (p.startsWith("agenda.json")) return false;
|
|
7859
8274
|
if (MEMORY_FILES.includes(p)) return true;
|
|
@@ -7898,6 +8313,13 @@ function registerProfileRoutes(r) {
|
|
|
7898
8313
|
if (!incoming || typeof incoming !== "object") throw new HttpError(400, "invalid body");
|
|
7899
8314
|
const merged = { ...cur, ...incoming, slug: cur.slug };
|
|
7900
8315
|
if (incoming.ownerId !== void 0) merged.ownerId = normalizeOwnerId(incoming.ownerId);
|
|
8316
|
+
if (incoming.telegram) {
|
|
8317
|
+
merged.telegram = {
|
|
8318
|
+
...cur.telegram,
|
|
8319
|
+
...incoming.telegram,
|
|
8320
|
+
proxy: parseTelegramProxyInput(incoming.telegram.proxy)
|
|
8321
|
+
};
|
|
8322
|
+
}
|
|
7901
8323
|
await writeConfig(merged);
|
|
7902
8324
|
return { config: merged };
|
|
7903
8325
|
});
|
|
@@ -7907,6 +8329,7 @@ function registerProfileRoutes(r) {
|
|
|
7907
8329
|
const slug = data.slug || slugify(data.name);
|
|
7908
8330
|
const existing = await readConfig(slug);
|
|
7909
8331
|
if (existing) throw new HttpError(409, `profile already exists: ${slug}`);
|
|
8332
|
+
const incomingTg = data.telegram ?? {};
|
|
7910
8333
|
const cfg = {
|
|
7911
8334
|
slug,
|
|
7912
8335
|
name: data.name,
|
|
@@ -7916,8 +8339,10 @@ function registerProfileRoutes(r) {
|
|
|
7916
8339
|
mode: data.mode ?? "bot",
|
|
7917
8340
|
stage: data.stage ?? "tg-given-cold",
|
|
7918
8341
|
llm: data.llm ?? { presetId: "claudehub", proto: "anthropic", apiKey: "", model: "claude-sonnet-4.6" },
|
|
7919
|
-
telegram:
|
|
7920
|
-
|
|
8342
|
+
telegram: {
|
|
8343
|
+
...incomingTg,
|
|
8344
|
+
proxy: parseTelegramProxyInput(incomingTg.proxy)
|
|
8345
|
+
},
|
|
7921
8346
|
privacy: data.privacy ?? "owner-only",
|
|
7922
8347
|
ownerId: normalizeOwnerId(data.ownerId),
|
|
7923
8348
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -8029,29 +8454,29 @@ function registerProfileRoutes(r) {
|
|
|
8029
8454
|
const entries = [];
|
|
8030
8455
|
for (const f of MEMORY_FILES) entries.push({ rel: f });
|
|
8031
8456
|
try {
|
|
8032
|
-
const dailyDir =
|
|
8033
|
-
const list = await
|
|
8457
|
+
const dailyDir = path10.join(dir, "memory", "daily");
|
|
8458
|
+
const list = await fs8.readdir(dailyDir);
|
|
8034
8459
|
for (const f of list) if (/^\d{4}-\d{2}-\d{2}\.md$/.test(f)) entries.push({ rel: `memory/daily/${f}` });
|
|
8035
8460
|
} catch {
|
|
8036
8461
|
}
|
|
8037
8462
|
try {
|
|
8038
|
-
const epDir =
|
|
8039
|
-
const list = await
|
|
8463
|
+
const epDir = path10.join(dir, "memory", "episodes");
|
|
8464
|
+
const list = await fs8.readdir(epDir);
|
|
8040
8465
|
for (const f of list) if (/^[\w\-]{1,80}\.md$/.test(f)) entries.push({ rel: `memory/episodes/${f}` });
|
|
8041
8466
|
} catch {
|
|
8042
8467
|
}
|
|
8043
8468
|
try {
|
|
8044
|
-
const palaceDir =
|
|
8045
|
-
const wings = await
|
|
8469
|
+
const palaceDir = path10.join(dir, "memory", "palace");
|
|
8470
|
+
const wings = await fs8.readdir(palaceDir, { withFileTypes: true });
|
|
8046
8471
|
for (const wing of wings) {
|
|
8047
8472
|
if (!wing.isDirectory() || !/^[\w\-]{1,80}$/.test(wing.name)) continue;
|
|
8048
|
-
const halls = await
|
|
8473
|
+
const halls = await fs8.readdir(path10.join(palaceDir, wing.name), { withFileTypes: true });
|
|
8049
8474
|
for (const hall of halls) {
|
|
8050
8475
|
if (!hall.isDirectory() || !/^[\w\-]{1,80}$/.test(hall.name)) continue;
|
|
8051
|
-
const rooms = await
|
|
8476
|
+
const rooms = await fs8.readdir(path10.join(palaceDir, wing.name, hall.name), { withFileTypes: true });
|
|
8052
8477
|
for (const room of rooms) {
|
|
8053
8478
|
if (!room.isDirectory() || !/^[\w\-]{1,80}$/.test(room.name)) continue;
|
|
8054
|
-
const drawers = await
|
|
8479
|
+
const drawers = await fs8.readdir(path10.join(palaceDir, wing.name, hall.name, room.name));
|
|
8055
8480
|
for (const drawer of drawers) {
|
|
8056
8481
|
if (/^[\w\-]{1,120}\.md$/.test(drawer)) entries.push({ rel: `memory/palace/${wing.name}/${hall.name}/${room.name}/${drawer}` });
|
|
8057
8482
|
}
|
|
@@ -8062,7 +8487,7 @@ function registerProfileRoutes(r) {
|
|
|
8062
8487
|
}
|
|
8063
8488
|
for (const e of entries) {
|
|
8064
8489
|
try {
|
|
8065
|
-
const stat = await
|
|
8490
|
+
const stat = await fs8.stat(path10.join(dir, e.rel));
|
|
8066
8491
|
items.push({ path: e.rel, size: stat.size, mtime: stat.mtimeMs });
|
|
8067
8492
|
} catch {
|
|
8068
8493
|
}
|
|
@@ -8135,15 +8560,20 @@ function registerProfileRoutes(r) {
|
|
|
8135
8560
|
const cfg = await readConfig(slug);
|
|
8136
8561
|
if (!cfg) throw new HttpError(404, "profile not found");
|
|
8137
8562
|
const data = body ?? {};
|
|
8138
|
-
|
|
8139
|
-
|
|
8140
|
-
llm
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8145
|
-
|
|
8146
|
-
|
|
8563
|
+
let generated;
|
|
8564
|
+
try {
|
|
8565
|
+
const llm = makeLLM(cfg.llm);
|
|
8566
|
+
generated = await generatePersonaPack(
|
|
8567
|
+
llm,
|
|
8568
|
+
cfg.slug,
|
|
8569
|
+
data.name ?? cfg.name,
|
|
8570
|
+
data.age ?? cfg.age,
|
|
8571
|
+
data.nationality ?? cfg.nationality,
|
|
8572
|
+
data.notes ?? cfg.personaNotes
|
|
8573
|
+
);
|
|
8574
|
+
} catch {
|
|
8575
|
+
generated = await ensurePersonaPack(cfg.slug, data.name ?? cfg.name, data.age ?? cfg.age);
|
|
8576
|
+
}
|
|
8147
8577
|
cfg.busySchedule = generated.busySchedule;
|
|
8148
8578
|
await writeConfig(cfg);
|
|
8149
8579
|
return { ok: true, busySchedule: generated.busySchedule };
|
|
@@ -8160,7 +8590,6 @@ init_esm_shims();
|
|
|
8160
8590
|
init_llm2();
|
|
8161
8591
|
init_stages();
|
|
8162
8592
|
init_communication();
|
|
8163
|
-
init_mcp();
|
|
8164
8593
|
|
|
8165
8594
|
// src/data/timezones.ts
|
|
8166
8595
|
init_esm_shims();
|
|
@@ -8407,15 +8836,6 @@ function registerPresetRoutes(r) {
|
|
|
8407
8836
|
profile: p.profile
|
|
8408
8837
|
}))
|
|
8409
8838
|
}));
|
|
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
8839
|
r.get("/api/presets/timezones", ({ searchParams }) => {
|
|
8420
8840
|
const q = searchParams.get("q") ?? "";
|
|
8421
8841
|
const all = q ? findTzByQuery(q, 200) : TIMEZONES;
|
|
@@ -8431,9 +8851,9 @@ function registerPresetRoutes(r) {
|
|
|
8431
8851
|
// src/webui/routes/system.ts
|
|
8432
8852
|
init_esm_shims();
|
|
8433
8853
|
init_md();
|
|
8434
|
-
import { promises as
|
|
8854
|
+
import { promises as fs9 } from "fs";
|
|
8435
8855
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
8436
|
-
import
|
|
8856
|
+
import path11 from "path";
|
|
8437
8857
|
import os2 from "os";
|
|
8438
8858
|
var cachedVersion = null;
|
|
8439
8859
|
async function readPackageVersion() {
|
|
@@ -8441,15 +8861,15 @@ async function readPackageVersion() {
|
|
|
8441
8861
|
const candidates = [];
|
|
8442
8862
|
try {
|
|
8443
8863
|
const here = fileURLToPath4(import.meta.url);
|
|
8444
|
-
candidates.push(
|
|
8445
|
-
candidates.push(
|
|
8446
|
-
candidates.push(
|
|
8864
|
+
candidates.push(path11.resolve(path11.dirname(here), "..", "package.json"));
|
|
8865
|
+
candidates.push(path11.resolve(path11.dirname(here), "..", "..", "package.json"));
|
|
8866
|
+
candidates.push(path11.resolve(path11.dirname(here), "..", "..", "..", "package.json"));
|
|
8447
8867
|
} catch {
|
|
8448
8868
|
}
|
|
8449
|
-
candidates.push(
|
|
8869
|
+
candidates.push(path11.resolve(process.cwd(), "package.json"));
|
|
8450
8870
|
for (const c of candidates) {
|
|
8451
8871
|
try {
|
|
8452
|
-
const raw = await
|
|
8872
|
+
const raw = await fs9.readFile(c, "utf8");
|
|
8453
8873
|
const parsed = JSON.parse(raw);
|
|
8454
8874
|
if (parsed.name === "@thesashadev/girl-agent" && parsed.version) {
|
|
8455
8875
|
cachedVersion = parsed.version;
|
|
@@ -8500,8 +8920,8 @@ function registerSystemRoutes(r) {
|
|
|
8500
8920
|
// src/webui/routes/addons.ts
|
|
8501
8921
|
init_esm_shims();
|
|
8502
8922
|
init_addons();
|
|
8503
|
-
import { promises as
|
|
8504
|
-
import
|
|
8923
|
+
import { promises as fs11 } from "fs";
|
|
8924
|
+
import path13 from "path";
|
|
8505
8925
|
import os4 from "os";
|
|
8506
8926
|
function registerAddonRoutes(r) {
|
|
8507
8927
|
r.get("/api/addons", async () => {
|
|
@@ -8528,13 +8948,13 @@ function registerAddonRoutes(r) {
|
|
|
8528
8948
|
const data = body;
|
|
8529
8949
|
if (!data?.gaaBase64) throw new HttpError(400, "gaaBase64 required");
|
|
8530
8950
|
const buf = Buffer.from(data.gaaBase64, "base64");
|
|
8531
|
-
const tmpPath =
|
|
8532
|
-
await
|
|
8951
|
+
const tmpPath = path13.join(os4.tmpdir(), `upload-${Date.now()}.gaa`);
|
|
8952
|
+
await fs11.writeFile(tmpPath, buf);
|
|
8533
8953
|
try {
|
|
8534
8954
|
const result = await installFromGaa(tmpPath, data.profileSlug);
|
|
8535
8955
|
return { ok: true, installed: result.addon, applied: result.applied };
|
|
8536
8956
|
} finally {
|
|
8537
|
-
await
|
|
8957
|
+
await fs11.unlink(tmpPath).catch(() => {
|
|
8538
8958
|
});
|
|
8539
8959
|
}
|
|
8540
8960
|
});
|
|
@@ -8546,13 +8966,13 @@ function registerAddonRoutes(r) {
|
|
|
8546
8966
|
const res = await fetch(url, { signal: AbortSignal.timeout(3e4) });
|
|
8547
8967
|
if (!res.ok) throw new HttpError(502, `fetch failed: HTTP ${res.status}`);
|
|
8548
8968
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
8549
|
-
const tmpPath =
|
|
8550
|
-
await
|
|
8969
|
+
const tmpPath = path13.join(os4.tmpdir(), `url-${Date.now()}.gaa`);
|
|
8970
|
+
await fs11.writeFile(tmpPath, buf);
|
|
8551
8971
|
try {
|
|
8552
8972
|
const result = await installFromGaa(tmpPath, data.profileSlug);
|
|
8553
8973
|
return { ok: true, installed: result.addon, applied: result.applied };
|
|
8554
8974
|
} finally {
|
|
8555
|
-
await
|
|
8975
|
+
await fs11.unlink(tmpPath).catch(() => {
|
|
8556
8976
|
});
|
|
8557
8977
|
}
|
|
8558
8978
|
} else {
|
|
@@ -8606,7 +9026,6 @@ init_runtime_bus();
|
|
|
8606
9026
|
init_esm_shims();
|
|
8607
9027
|
init_communication();
|
|
8608
9028
|
init_llm2();
|
|
8609
|
-
init_mcp();
|
|
8610
9029
|
init_stages();
|
|
8611
9030
|
var CORE_KNOWLEDGE_BASE = [
|
|
8612
9031
|
{
|
|
@@ -8635,7 +9054,7 @@ var CORE_KNOWLEDGE_BASE = [
|
|
|
8635
9054
|
subcategory: "project-structure",
|
|
8636
9055
|
title: "\u041A\u0430\u0440\u0442\u0430 \u0434\u0438\u0440\u0435\u043A\u0442\u043E\u0440\u0438\u0439",
|
|
8637
9056
|
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
|
|
9057
|
+
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
9058
|
},
|
|
8640
9059
|
{
|
|
8641
9060
|
category: "overview",
|
|
@@ -8677,7 +9096,7 @@ var CORE_KNOWLEDGE_BASE = [
|
|
|
8677
9096
|
subcategory: "profile-config",
|
|
8678
9097
|
title: "ProfileConfig",
|
|
8679
9098
|
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,
|
|
9099
|
+
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
9100
|
},
|
|
8682
9101
|
{
|
|
8683
9102
|
category: "config",
|
|
@@ -9036,13 +9455,6 @@ var CORE_KNOWLEDGE_BASE = [
|
|
|
9036
9455
|
keywords: ["manifest", "addon", "id", "version", "compatibility", "settings"],
|
|
9037
9456
|
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
9457
|
},
|
|
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
9458
|
{
|
|
9047
9459
|
category: "migrations",
|
|
9048
9460
|
subcategory: "data-migrations",
|
|
@@ -9089,11 +9501,11 @@ function generatedKnowledge() {
|
|
|
9089
9501
|
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
9502
|
},
|
|
9091
9503
|
{
|
|
9092
|
-
category: "
|
|
9093
|
-
subcategory: "
|
|
9094
|
-
title: "\
|
|
9095
|
-
keywords: ["
|
|
9096
|
-
body:
|
|
9504
|
+
category: "addons",
|
|
9505
|
+
subcategory: "integration-index",
|
|
9506
|
+
title: "\u0410\u0434\u0434\u043E\u043D\u044B \u0432\u043C\u0435\u0441\u0442\u043E MCP",
|
|
9507
|
+
keywords: ["addons", "\u0430\u0434\u0434\u043E\u043D\u044B", "\u0438\u043D\u0442\u0435\u0433\u0440\u0430\u0446\u0438\u0438", "gaa", "mcp"],
|
|
9508
|
+
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
9509
|
}
|
|
9098
9510
|
];
|
|
9099
9511
|
}
|
|
@@ -9563,8 +9975,8 @@ function tail(text, limit) {
|
|
|
9563
9975
|
if (text.length <= limit) return text;
|
|
9564
9976
|
return text.slice(-limit);
|
|
9565
9977
|
}
|
|
9566
|
-
function setNested(obj,
|
|
9567
|
-
const parts =
|
|
9978
|
+
function setNested(obj, path15, value) {
|
|
9979
|
+
const parts = path15.split(".");
|
|
9568
9980
|
let cur = obj;
|
|
9569
9981
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
9570
9982
|
const p = parts[i];
|
|
@@ -9583,14 +9995,14 @@ var DEFAULT_PROXY = "https://tgproxy.girl-agent.com";
|
|
|
9583
9995
|
function proxyUrl() {
|
|
9584
9996
|
return process.env.GIRL_AGENT_AUTH_PROXY ?? DEFAULT_PROXY;
|
|
9585
9997
|
}
|
|
9586
|
-
async function post(
|
|
9587
|
-
const res = await fetch(`${proxyUrl()}${
|
|
9998
|
+
async function post(path15, body) {
|
|
9999
|
+
const res = await fetch(`${proxyUrl()}${path15}`, {
|
|
9588
10000
|
method: "POST",
|
|
9589
10001
|
headers: { "Content-Type": "application/json" },
|
|
9590
10002
|
body: JSON.stringify(body)
|
|
9591
10003
|
});
|
|
9592
10004
|
const data = await res.json();
|
|
9593
|
-
if (!res.ok) throw new Error(data.error ?? `proxy ${
|
|
10005
|
+
if (!res.ok) throw new Error(data.error ?? `proxy ${path15} failed (${res.status})`);
|
|
9594
10006
|
return data;
|
|
9595
10007
|
}
|
|
9596
10008
|
function remoteSendCode(phone) {
|
|
@@ -9701,12 +10113,59 @@ function registerTgAuthRoutes(r) {
|
|
|
9701
10113
|
});
|
|
9702
10114
|
}
|
|
9703
10115
|
|
|
10116
|
+
// src/webui/routes/auth.ts
|
|
10117
|
+
init_esm_shims();
|
|
10118
|
+
function registerAuthRoutes(r) {
|
|
10119
|
+
r.get("/api/auth/status", () => authStatus());
|
|
10120
|
+
r.post("/api/auth/login", ({ body, res }) => {
|
|
10121
|
+
const { password } = body ?? {};
|
|
10122
|
+
if (!verifyPassword(password ?? "")) throw new HttpError(401, "\u043D\u0435\u0432\u0435\u0440\u043D\u044B\u0439 \u043F\u0430\u0440\u043E\u043B\u044C");
|
|
10123
|
+
createSession(res);
|
|
10124
|
+
return { ok: true };
|
|
10125
|
+
});
|
|
10126
|
+
r.post("/api/auth/logout", ({ req, res }) => {
|
|
10127
|
+
clearSession(req, res);
|
|
10128
|
+
return { ok: true };
|
|
10129
|
+
});
|
|
10130
|
+
}
|
|
10131
|
+
|
|
9704
10132
|
// src/webui/server.ts
|
|
9705
10133
|
init_md();
|
|
9706
10134
|
var DEFAULT_PORT = Number(process.env.GIRL_AGENT_PORT ?? 3e3);
|
|
9707
|
-
|
|
10135
|
+
function isLikelyDocker() {
|
|
10136
|
+
if (process.env.GIRL_AGENT_DOCKER || process.env.DOCKER_CONTAINER) return true;
|
|
10137
|
+
try {
|
|
10138
|
+
return os5.release().toLowerCase().includes("docker") || existsSync2("/.dockerenv") || readFileSync2("/proc/1/cgroup", "utf8").toLowerCase().includes("docker");
|
|
10139
|
+
} catch {
|
|
10140
|
+
return false;
|
|
10141
|
+
}
|
|
10142
|
+
}
|
|
10143
|
+
function firstExternalIPv4() {
|
|
10144
|
+
for (const items of Object.values(os5.networkInterfaces())) {
|
|
10145
|
+
for (const item of items ?? []) {
|
|
10146
|
+
if (item.family === "IPv4" && !item.internal) return item.address;
|
|
10147
|
+
}
|
|
10148
|
+
}
|
|
10149
|
+
return void 0;
|
|
10150
|
+
}
|
|
10151
|
+
function publicUrlForPort(port) {
|
|
10152
|
+
const explicit = process.env.GIRL_AGENT_PUBLIC_URL?.trim();
|
|
10153
|
+
if (explicit) {
|
|
10154
|
+
try {
|
|
10155
|
+
const url = new URL2(explicit);
|
|
10156
|
+
if (!url.port) url.port = String(port);
|
|
10157
|
+
return url.toString().replace(/\/$/, "");
|
|
10158
|
+
} catch {
|
|
10159
|
+
const clean = explicit.replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
10160
|
+
return `http://${clean.includes(":") ? clean : `${clean}:${port}`}`;
|
|
10161
|
+
}
|
|
10162
|
+
}
|
|
10163
|
+
return `http://${firstExternalIPv4() ?? "0.0.0.0"}:${port}`;
|
|
10164
|
+
}
|
|
10165
|
+
var DEFAULT_HOST = process.env.GIRL_AGENT_HOST ?? (isLikelyDocker() ? "0.0.0.0" : "127.0.0.1");
|
|
9708
10166
|
function buildRouter() {
|
|
9709
10167
|
const r = new Router();
|
|
10168
|
+
registerAuthRoutes(r);
|
|
9710
10169
|
registerProfileRoutes(r);
|
|
9711
10170
|
registerPresetRoutes(r);
|
|
9712
10171
|
registerSystemRoutes(r);
|
|
@@ -9730,6 +10189,10 @@ async function startWebUIServer(opts = {}) {
|
|
|
9730
10189
|
const url2 = new URL2(req.url ?? "/", `http://${req.headers.host ?? host}`);
|
|
9731
10190
|
const pathname = url2.pathname;
|
|
9732
10191
|
if (pathname.startsWith("/api/")) {
|
|
10192
|
+
if (!pathname.startsWith("/api/auth/") && !isAuthorized(req)) {
|
|
10193
|
+
sendJson(res, 401, { error: "auth required" });
|
|
10194
|
+
return;
|
|
10195
|
+
}
|
|
9733
10196
|
const matched = router.match(req.method ?? "GET", pathname);
|
|
9734
10197
|
if (!matched) {
|
|
9735
10198
|
sendJson(res, 404, { error: "not found", path: pathname });
|
|
@@ -9789,20 +10252,12 @@ async function startWebUIServer(opts = {}) {
|
|
|
9789
10252
|
resolve();
|
|
9790
10253
|
});
|
|
9791
10254
|
});
|
|
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}`;
|
|
10255
|
+
const urls = {
|
|
10256
|
+
loopback: `http://127.0.0.1:${port}`,
|
|
10257
|
+
localhost: `http://localhost:${port}`,
|
|
10258
|
+
public: publicUrlForPort(port)
|
|
10259
|
+
};
|
|
10260
|
+
const url = urls.localhost;
|
|
9806
10261
|
if (opts.autoStart) {
|
|
9807
10262
|
try {
|
|
9808
10263
|
const slugs = await listProfiles();
|
|
@@ -9820,6 +10275,7 @@ async function startWebUIServer(opts = {}) {
|
|
|
9820
10275
|
port,
|
|
9821
10276
|
host,
|
|
9822
10277
|
url,
|
|
10278
|
+
urls,
|
|
9823
10279
|
async stop() {
|
|
9824
10280
|
await bus.stopAll();
|
|
9825
10281
|
await new Promise((resolve) => server.close(() => resolve()));
|
|
@@ -9977,8 +10433,8 @@ init_esm_shims();
|
|
|
9977
10433
|
init_llm2();
|
|
9978
10434
|
init_stages();
|
|
9979
10435
|
init_communication();
|
|
9980
|
-
import
|
|
9981
|
-
import
|
|
10436
|
+
import fs12 from "fs/promises";
|
|
10437
|
+
import path14 from "path";
|
|
9982
10438
|
import os6 from "os";
|
|
9983
10439
|
init_md();
|
|
9984
10440
|
init_runtime();
|
|
@@ -10010,7 +10466,7 @@ env-vars (\u0434\u043B\u044F CI / docker secrets / k8s):
|
|
|
10010
10466
|
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
10467
|
|
|
10012
10468
|
\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.
|
|
10469
|
+
\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
10470
|
`;
|
|
10015
10471
|
function parseServerArgs(argv) {
|
|
10016
10472
|
return {
|
|
@@ -10061,7 +10517,7 @@ async function runServer(rawArgv) {
|
|
|
10061
10517
|
}
|
|
10062
10518
|
if (!args.yes) {
|
|
10063
10519
|
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: ${
|
|
10520
|
+
\u0431\u0443\u0434\u0435\u0442 \u0443\u0434\u0430\u043B\u0435\u043D\u043E: ${path14.join(DATA_ROOT, args.profile)}
|
|
10065
10521
|
`);
|
|
10066
10522
|
process.exit(1);
|
|
10067
10523
|
}
|
|
@@ -10123,7 +10579,7 @@ data dir: ${DATA_ROOT}
|
|
|
10123
10579
|
}
|
|
10124
10580
|
async function persistAndMaybeStart(cfg, args) {
|
|
10125
10581
|
await writeConfig(cfg);
|
|
10126
|
-
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${
|
|
10582
|
+
process.stderr.write(`[server] \u043F\u0440\u043E\u0444\u0438\u043B\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D: ${path14.join(DATA_ROOT, cfg.slug)}
|
|
10127
10583
|
`);
|
|
10128
10584
|
if (cfg.llm.apiKey || findPreset(cfg.llm.presetId)?.apiKeyRequired === false) {
|
|
10129
10585
|
try {
|
|
@@ -10226,7 +10682,6 @@ function configFromEnv() {
|
|
|
10226
10682
|
phone: e.GIRL_AGENT_TG_PHONE ?? "",
|
|
10227
10683
|
proxy: parseTelegramProxy(e.GIRL_AGENT_TG_PROXY)
|
|
10228
10684
|
},
|
|
10229
|
-
mcp: [],
|
|
10230
10685
|
ownerId: normalizeOwnerId(e.GIRL_AGENT_OWNER_ID),
|
|
10231
10686
|
privacy: "owner-only",
|
|
10232
10687
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10240,10 +10695,10 @@ function configFromEnv() {
|
|
|
10240
10695
|
};
|
|
10241
10696
|
}
|
|
10242
10697
|
async function loadConfigFile(file) {
|
|
10243
|
-
const abs =
|
|
10698
|
+
const abs = path14.isAbsolute(file) ? file : path14.join(process.cwd(), file);
|
|
10244
10699
|
let raw;
|
|
10245
10700
|
try {
|
|
10246
|
-
raw = await
|
|
10701
|
+
raw = await fs12.readFile(abs, "utf-8");
|
|
10247
10702
|
} catch (e) {
|
|
10248
10703
|
process.stderr.write(`[server] \u043D\u0435 \u043C\u043E\u0433\u0443 \u043F\u0440\u043E\u0447\u0438\u0442\u0430\u0442\u044C ${abs}: ${e?.message ?? e}
|
|
10249
10704
|
`);
|
|
@@ -10294,7 +10749,6 @@ function validateConfig(raw) {
|
|
|
10294
10749
|
model: c.llm.model
|
|
10295
10750
|
},
|
|
10296
10751
|
telegram: c.telegram ?? {},
|
|
10297
|
-
mcp: c.mcp ?? [],
|
|
10298
10752
|
ownerId: normalizeOwnerId(c.ownerId ?? process.env.GIRL_AGENT_OWNER_ID),
|
|
10299
10753
|
privacy: c.privacy ?? "owner-only",
|
|
10300
10754
|
createdAt: c.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10310,25 +10764,7 @@ function validateConfig(raw) {
|
|
|
10310
10764
|
return filled;
|
|
10311
10765
|
}
|
|
10312
10766
|
function parseTelegramProxy(raw) {
|
|
10313
|
-
|
|
10314
|
-
try {
|
|
10315
|
-
const url = new URL(raw);
|
|
10316
|
-
const socksType = url.protocol === "socks4:" ? 4 : 5;
|
|
10317
|
-
const port = Number(url.port);
|
|
10318
|
-
if (!url.hostname || !Number.isInteger(port) || port <= 0) return void 0;
|
|
10319
|
-
return {
|
|
10320
|
-
ip: url.hostname,
|
|
10321
|
-
port,
|
|
10322
|
-
socksType,
|
|
10323
|
-
username: url.username ? decodeURIComponent(url.username) : void 0,
|
|
10324
|
-
password: url.password ? decodeURIComponent(url.password) : void 0
|
|
10325
|
-
};
|
|
10326
|
-
} catch {
|
|
10327
|
-
const [host, portRaw] = raw.split(":");
|
|
10328
|
-
const port = Number(portRaw);
|
|
10329
|
-
if (!host || !Number.isInteger(port) || port <= 0) return void 0;
|
|
10330
|
-
return { ip: host, port, socksType: 5 };
|
|
10331
|
-
}
|
|
10767
|
+
return parseTelegramProxyInput(raw);
|
|
10332
10768
|
}
|
|
10333
10769
|
function buildConfigTemplate() {
|
|
10334
10770
|
const sample = {
|
|
@@ -10347,7 +10783,6 @@ function buildConfigTemplate() {
|
|
|
10347
10783
|
model: "claude-sonnet-4.6"
|
|
10348
10784
|
},
|
|
10349
10785
|
telegram: { botToken: "REPLACE_ME" },
|
|
10350
|
-
mcp: [],
|
|
10351
10786
|
ownerId: void 0,
|
|
10352
10787
|
privacy: "owner-only",
|
|
10353
10788
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10426,9 +10861,11 @@ docker run -d --name girl-agent --restart=unless-stopped \\
|
|
|
10426
10861
|
# services:
|
|
10427
10862
|
# girl-agent:
|
|
10428
10863
|
# image: ghcr.io/thesashadev/girl-agent:latest
|
|
10864
|
+
# # interactive WebUI: command: [] and ports: ["3000:3000"]
|
|
10429
10865
|
# command: ["server", "--config", "/config/bot.json", "--headless"]
|
|
10430
10866
|
# environment:
|
|
10431
10867
|
# GIRL_AGENT_DATA: /data
|
|
10868
|
+
# GIRL_AGENT_HOST: 0.0.0.0
|
|
10432
10869
|
# volumes:
|
|
10433
10870
|
# - girl-agent-data:/data
|
|
10434
10871
|
# - ./bot.json:/config/bot.json:ro
|
|
@@ -10447,6 +10884,16 @@ init_llm();
|
|
|
10447
10884
|
init_llm2();
|
|
10448
10885
|
init_stages();
|
|
10449
10886
|
init_communication();
|
|
10887
|
+
var nodeMajor = Number(process.versions.node.split(".")[0] ?? 0);
|
|
10888
|
+
if (nodeMajor < 18) {
|
|
10889
|
+
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
|
|
10890
|
+
`);
|
|
10891
|
+
process.exit(1);
|
|
10892
|
+
}
|
|
10893
|
+
if (nodeMajor < 20) {
|
|
10894
|
+
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.
|
|
10895
|
+
`);
|
|
10896
|
+
}
|
|
10450
10897
|
var HELP = `
|
|
10451
10898
|
girl-agent \u2014 AI girl for Telegram (WebUI)
|
|
10452
10899
|
|
|
@@ -10454,6 +10901,7 @@ usage:
|
|
|
10454
10901
|
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
10902
|
npx girl-agent --port=8080 # \u043A\u0430\u0441\u0442\u043E\u043C\u043D\u044B\u0439 \u043F\u043E\u0440\u0442
|
|
10456
10903
|
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
|
|
10904
|
+
GIRL_AGENT_PUBLIC_URL=https://example.com npx girl-agent # URL \u0434\u043B\u044F reverse proxy/docker
|
|
10457
10905
|
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
10906
|
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
10907
|
|
|
@@ -10492,7 +10940,6 @@ async function main() {
|
|
|
10492
10940
|
"proto",
|
|
10493
10941
|
"name",
|
|
10494
10942
|
"stage",
|
|
10495
|
-
"mcp",
|
|
10496
10943
|
"nationality",
|
|
10497
10944
|
"tz",
|
|
10498
10945
|
"vibe",
|
|
@@ -10651,20 +11098,19 @@ async function main() {
|
|
|
10651
11098
|
autoStart: !argv.profile,
|
|
10652
11099
|
noBrowser: !!argv["no-browser"]
|
|
10653
11100
|
});
|
|
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
11101
|
process.stdout.write(`
|
|
10657
11102
|
\u{1F310} girl-agent WebUI \u0437\u0430\u043F\u0443\u0449\u0435\u043D
|
|
10658
|
-
${instance.url}
|
|
10659
11103
|
`);
|
|
10660
|
-
|
|
10661
|
-
|
|
11104
|
+
process.stdout.write(` 1) ${instance.urls.loopback}
|
|
11105
|
+
`);
|
|
11106
|
+
process.stdout.write(` 2) ${instance.urls.localhost}
|
|
11107
|
+
`);
|
|
11108
|
+
process.stdout.write(` 3) ${instance.urls.public}
|
|
10662
11109
|
`);
|
|
10663
|
-
}
|
|
10664
11110
|
process.stdout.write(`
|
|
10665
|
-
REST API: ${
|
|
11111
|
+
REST API: ${instance.urls.loopback}/api/system/health
|
|
10666
11112
|
`);
|
|
10667
|
-
process.stdout.write(` WebSocket logs: ws
|
|
11113
|
+
process.stdout.write(` WebSocket logs: ws://127.0.0.1:${port}/ws/logs/<slug>
|
|
10668
11114
|
`);
|
|
10669
11115
|
process.stdout.write(` Ctrl+C \u0434\u043B\u044F \u043E\u0441\u0442\u0430\u043D\u043E\u0432\u043A\u0438
|
|
10670
11116
|
|
|
@@ -10734,17 +11180,11 @@ async function buildConfigFromFlags(argv) {
|
|
|
10734
11180
|
const slug = String(argv.profile ?? slugifyLocal(name));
|
|
10735
11181
|
const mode = argv.mode === "userbot" ? "userbot" : "bot";
|
|
10736
11182
|
const tz = (argv.tz ? parseTzFlag(String(argv.tz)) : void 0) ?? defaultTzForNationality(nationality);
|
|
10737
|
-
const mcpFlags = [].concat(argv.mcp ?? []);
|
|
10738
11183
|
const communication = (() => {
|
|
10739
11184
|
const preset2 = findCommunicationPreset(typeof argv["communication-preset"] === "string" ? argv["communication-preset"] : void 0);
|
|
10740
11185
|
return preset2?.profile ?? normalizeCommunicationProfile({});
|
|
10741
11186
|
})();
|
|
10742
11187
|
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
11188
|
return {
|
|
10749
11189
|
slug,
|
|
10750
11190
|
name,
|
|
@@ -10759,7 +11199,6 @@ async function buildConfigFromFlags(argv) {
|
|
|
10759
11199
|
apiHash: String(argv["api-hash"] ?? ""),
|
|
10760
11200
|
phone: String(argv.phone ?? "")
|
|
10761
11201
|
},
|
|
10762
|
-
mcp: mcps,
|
|
10763
11202
|
privacy,
|
|
10764
11203
|
ownerId: normalizeOwnerId(argv["owner-id"] ?? process.env.GIRL_AGENT_OWNER_ID),
|
|
10765
11204
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|