luckytri 1.0.0
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/.github/SECURITY.md +71 -0
- package/LICENSE +21 -0
- package/README.en.md +250 -0
- package/README.md +250 -0
- package/bin/luckytri.js +107 -0
- package/docs/brand/banner.png +0 -0
- package/docs/brand/palette.png +0 -0
- package/docs/brand/portrait.png +0 -0
- package/docs/en/CHANGELOG.md +113 -0
- package/docs/en/architecture.md +152 -0
- package/docs/en/chat-style.md +62 -0
- package/docs/en/connect.md +63 -0
- package/docs/en/guide.md +216 -0
- package/docs/en/her-life.md +189 -0
- package/docs/en/npm-release.md +25 -0
- package/docs/en/plugins.md +82 -0
- package/docs/en/recovery.md +28 -0
- package/docs/en/time.md +71 -0
- package/docs/en/webui.md +73 -0
- package/docs/zh/CHANGELOG.md +113 -0
- package/docs/zh/architecture.md +152 -0
- package/docs/zh/chat-style.md +62 -0
- package/docs/zh/connect.md +63 -0
- package/docs/zh/guide.md +216 -0
- package/docs/zh/her-life.md +189 -0
- package/docs/zh/npm-release.md +33 -0
- package/docs/zh/plugins.md +82 -0
- package/docs/zh/recovery.md +28 -0
- package/docs/zh/time.md +71 -0
- package/docs/zh/webui.md +73 -0
- package/package.json +108 -0
- package/plugins/sdk/index.d.ts +155 -0
- package/plugins/sdk/testing.js +58 -0
- package/plugins/weather/index.js +82 -0
- package/plugins/weather/luckytri-plugin.json +29 -0
- package/public/app/assets/ChatsPage-C-FcRapR.js +3 -0
- package/public/app/assets/ChatsPage-DfyPCS9N.css +1 -0
- package/public/app/assets/Empty-CpP5kQHH.js +2 -0
- package/public/app/assets/Empty-DmUB2-Bk.css +1 -0
- package/public/app/assets/Field-D4gY-INU.js +1 -0
- package/public/app/assets/HeartPage-Bft9wZp5.css +1 -0
- package/public/app/assets/HeartPage-CPy_thQd.js +1 -0
- package/public/app/assets/LifePage-BUi5euBF.css +1 -0
- package/public/app/assets/LifePage-CxWvwmSf.js +1 -0
- package/public/app/assets/MemoryPage-DC4rhQ68.js +1 -0
- package/public/app/assets/MemoryPage-cZvXfkXb.css +1 -0
- package/public/app/assets/NaturePage-CTXHCE2D.css +1 -0
- package/public/app/assets/NaturePage-IvYw04Zq.js +3 -0
- package/public/app/assets/PeoplePage-BmUxkrOU.css +1 -0
- package/public/app/assets/PeoplePage-Cqefm9-q.js +1 -0
- package/public/app/assets/PluginsPage-DKSaKvXb.js +2 -0
- package/public/app/assets/PluginsPage-HyBe5D8w.css +1 -0
- package/public/app/assets/SystemPage-CAMPoYqM.css +1 -0
- package/public/app/assets/SystemPage-CJmtJkrK.js +1 -0
- package/public/app/assets/TimePage-BOms_n4I.css +1 -0
- package/public/app/assets/TimePage-Cw44inM4.js +3 -0
- package/public/app/assets/formatters-ZmW_xFHw.js +1 -0
- package/public/app/assets/index-BheRW-1t.js +4 -0
- package/public/app/assets/index-YDz1ree1.css +1 -0
- package/public/app/assets/knowledge-DG0e0uKw.js +1 -0
- package/public/app/assets/liquid-garden-IMoHBwzc.png +0 -0
- package/public/app/assets/luckytri-home-95QKeMtc.png +0 -0
- package/public/app/assets/media-BzPDBm7e.js +1 -0
- package/public/app/index.html +27 -0
- package/public/guide.en.html +1053 -0
- package/public/guide.html +893 -0
- package/public/plugin-kit/v1/bridge.js +30 -0
- package/public/plugin-kit/v1/kit.css +14 -0
- package/public/tutorial.en.md +214 -0
- package/public/tutorial.md +214 -0
- package/scripts/backup.js +311 -0
- package/scripts/browser.js +41 -0
- package/scripts/launch.js +94 -0
- package/scripts/plugin.js +150 -0
- package/scripts/proxy-config.js +167 -0
- package/scripts/recover.js +26 -0
- package/scripts/runtime.js +25 -0
- package/scripts/service.js +47 -0
- package/scripts/setup.js +50 -0
- package/scripts/start-server.js +41 -0
- package/scripts/stop.js +36 -0
- package/server/app.js +96 -0
- package/server/channels/adapters.js +27 -0
- package/server/channels/contract.js +57 -0
- package/server/channels/hub.js +165 -0
- package/server/channels/index.js +25 -0
- package/server/channels/onebot/adapter.js +288 -0
- package/server/channels/onebot/index.js +336 -0
- package/server/channels/onebot/token.js +3 -0
- package/server/channels/qqbot/adapter.js +253 -0
- package/server/channels/qqbot/api.js +199 -0
- package/server/channels/qqbot/credentials.js +11 -0
- package/server/channels/qqbot/gateway.js +274 -0
- package/server/channels/qqbot/index.js +389 -0
- package/server/channels/segments.js +40 -0
- package/server/channels/session-key.js +153 -0
- package/server/channels/state.js +42 -0
- package/server/core/api.js +564 -0
- package/server/core/capabilities.js +208 -0
- package/server/core/context-builder.js +288 -0
- package/server/core/context-compactor.js +454 -0
- package/server/core/conversation-cues.js +325 -0
- package/server/core/conversation-manager.js +87 -0
- package/server/core/events.js +60 -0
- package/server/core/feedback.js +8 -0
- package/server/core/group-style.js +72 -0
- package/server/core/image-preprocessor.js +208 -0
- package/server/core/initiative-context.js +66 -0
- package/server/core/input-budget.js +32 -0
- package/server/core/local-demo.js +98 -0
- package/server/core/message-manager.js +118 -0
- package/server/core/message-scheduler.js +78 -0
- package/server/core/model-json.js +190 -0
- package/server/core/model-manager.js +1213 -0
- package/server/core/model-presets.js +900 -0
- package/server/core/name-call.js +29 -0
- package/server/core/net-guard.js +49 -0
- package/server/core/network.js +157 -0
- package/server/core/orchestrator.js +569 -0
- package/server/core/perceivers.js +91 -0
- package/server/core/person-name.js +22 -0
- package/server/core/persona-manager.js +243 -0
- package/server/core/reply-delivery.js +393 -0
- package/server/core/reply-target-resolver.js +50 -0
- package/server/core/repository.js +293 -0
- package/server/core/response-generator.js +50 -0
- package/server/core/response-validator.js +508 -0
- package/server/core/retired-prompts.js +51 -0
- package/server/core/sessions.js +109 -0
- package/server/core/speaker-names.js +92 -0
- package/server/core/topic-tracker.js +65 -0
- package/server/core/turn-processor.js +630 -0
- package/server/core/turn.js +236 -0
- package/server/core/vision-manager.js +633 -0
- package/server/http.js +18 -0
- package/server/i18n/decisions.js +206 -0
- package/server/i18n/errors.js +497 -0
- package/server/i18n/index.js +144 -0
- package/server/i18n/labels.js +653 -0
- package/server/i18n/models.js +111 -0
- package/server/index.js +102 -0
- package/server/knowledge/api.js +342 -0
- package/server/knowledge/embedding-profile.js +114 -0
- package/server/knowledge/index.js +13 -0
- package/server/knowledge/manager.js +386 -0
- package/server/knowledge/retrieval.js +93 -0
- package/server/knowledge/schema.js +154 -0
- package/server/knowledge/vector-index.js +90 -0
- package/server/mind/affect.js +265 -0
- package/server/mind/anticipations.js +507 -0
- package/server/mind/api.js +703 -0
- package/server/mind/attention.js +200 -0
- package/server/mind/bonds.js +558 -0
- package/server/mind/budget.js +152 -0
- package/server/mind/clock.js +83 -0
- package/server/mind/context-selection.js +61 -0
- package/server/mind/continuity.js +562 -0
- package/server/mind/conversation-origin.js +175 -0
- package/server/mind/day-planner.js +324 -0
- package/server/mind/days.js +210 -0
- package/server/mind/evidence-read.js +45 -0
- package/server/mind/evidence.js +148 -0
- package/server/mind/faces.js +138 -0
- package/server/mind/guard.js +60 -0
- package/server/mind/index.js +445 -0
- package/server/mind/initiative.js +333 -0
- package/server/mind/life/activities.js +21 -0
- package/server/mind/life/context.js +309 -0
- package/server/mind/life/diary.js +786 -0
- package/server/mind/life/growth.js +252 -0
- package/server/mind/life/index.js +1049 -0
- package/server/mind/life/presence.js +305 -0
- package/server/mind/meetings.js +1069 -0
- package/server/mind/memory-policy.js +48 -0
- package/server/mind/memory.js +888 -0
- package/server/mind/nature.js +262 -0
- package/server/mind/novelty.js +19 -0
- package/server/mind/observations.js +84 -0
- package/server/mind/own-day.js +324 -0
- package/server/mind/own-voice.js +318 -0
- package/server/mind/periods.js +118 -0
- package/server/mind/reading.js +120 -0
- package/server/mind/salience.js +201 -0
- package/server/mind/schema.js +562 -0
- package/server/mind/self.js +484 -0
- package/server/mind/senses.js +53 -0
- package/server/mind/thoughts.js +274 -0
- package/server/mind/time/activity-clock.js +196 -0
- package/server/mind/time/agenda.js +242 -0
- package/server/mind/time/api.js +200 -0
- package/server/mind/time/attention.js +34 -0
- package/server/mind/time/availability.js +69 -0
- package/server/mind/time/commitment-review.js +198 -0
- package/server/mind/time/delivery-links.js +130 -0
- package/server/mind/time/executor.js +512 -0
- package/server/mind/time/experiences.js +128 -0
- package/server/mind/time/games.js +562 -0
- package/server/mind/time/index.js +739 -0
- package/server/mind/time/intent.js +166 -0
- package/server/mind/time/kinds.js +171 -0
- package/server/mind/time/model-material.js +77 -0
- package/server/mind/time/plugin-activity.js +207 -0
- package/server/mind/time/presentation.js +51 -0
- package/server/mind/time/schedule.js +83 -0
- package/server/mind/time/schema.js +84 -0
- package/server/mind/time/search.js +383 -0
- package/server/mind/time/sharing.js +472 -0
- package/server/mind/time/task-links.js +311 -0
- package/server/mind/time/tasks.js +587 -0
- package/server/mind/time/works.js +432 -0
- package/server/mind/traits.js +191 -0
- package/server/mind/util.js +110 -0
- package/server/mind/view.js +273 -0
- package/server/paths.js +102 -0
- package/server/plugins/api.js +204 -0
- package/server/plugins/host.js +967 -0
- package/server/plugins/install.js +295 -0
- package/server/plugins/manifest.js +201 -0
- package/server/plugins/permissions.js +42 -0
- package/server/plugins/runner/guard.mjs +36 -0
- package/server/plugins/runner/worker.mjs +250 -0
- package/server/plugins/schema.js +91 -0
- package/server/plugins/zip.js +112 -0
- package/server/startup-lock.js +118 -0
- package/server/storage/archive.js +241 -0
- package/server/storage/backup-cleanup-worker.js +8 -0
- package/server/storage/backup-cleanup.js +414 -0
- package/server/storage/backup-lock.js +76 -0
- package/server/storage/backup-scheduler.js +131 -0
- package/server/storage/store.js +199 -0
- package/server/studio/display-names.js +138 -0
- package/server/studio/management.js +102 -0
- package/server/studio/readiness.js +190 -0
- package/server/studio/settings.js +236 -0
- package/server/version.js +10 -0
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { crisisSignal } from "./guard.js";
|
|
2
|
+
|
|
3
|
+
const MINUTE = 60000;
|
|
4
|
+
const OPEN_QUESTION =
|
|
5
|
+
/有没有人|有人知道|谁知道|求问|请问|大家(?:觉得|说|看)|你们(?:觉得|说)|[??]\s*$/;
|
|
6
|
+
const MEDIA_ONLY = /^(?:\[(?:图片|表情|媒体|提及成员)\]\s*)+$/;
|
|
7
|
+
// Pairs that appear in almost any sentence say nothing about a topic.
|
|
8
|
+
const COMMON = new Set(
|
|
9
|
+
"一起 大家 我们 你们 他们 她们 自己 什么 怎么 这个 那个 真的 就是 可以 没有 不是 知道 觉得 现在 今天 明天 昨天 喜欢 感觉 一下 有点 还是 然后 因为 所以 但是 如果 已经 时候 东西 事情 有人 没人 一个 这样 那样 这么 那么 好像 可能 应该 想要 我想 我的 你的 他的 的话 了吗 是不 最近 很想 其实 一直 总是 以后 之前 开始 起来 出来 一点 一些 很多 非常 特别 比较 不会 不要 不想 不用 只是 而且 这里 那里 我也 你也 也是 还有 想学 想看 想去".split(
|
|
10
|
+
" ",
|
|
11
|
+
),
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
// Overlapping bigrams for Chinese and whole words for Latin text, so a
|
|
15
|
+
// topic is found wherever it sits in a sentence.
|
|
16
|
+
export function interestTerms(values) {
|
|
17
|
+
const terms = new Set();
|
|
18
|
+
for (const value of values || []) {
|
|
19
|
+
const lower = String(value || "").toLowerCase();
|
|
20
|
+
for (const word of lower.match(/[a-z0-9]{2,}/g) || []) terms.add(word);
|
|
21
|
+
for (const run of lower.match(/[\u4e00-\u9fff]+/g) || [])
|
|
22
|
+
for (let i = 0; i + 1 < run.length; i++) {
|
|
23
|
+
const pair = run.slice(i, i + 2);
|
|
24
|
+
if (!COMMON.has(pair)) terms.add(pair);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return terms;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// A Latin or numeric token long enough to be a title, a name, or a work.
|
|
31
|
+
// One Chinese pair is still just a pair; saying the name is meeting it.
|
|
32
|
+
export function projectTerms(terms) {
|
|
33
|
+
const named = new Set();
|
|
34
|
+
for (const term of terms || [])
|
|
35
|
+
if (/^[a-z0-9]{3,}$/.test(term)) named.add(term);
|
|
36
|
+
return named;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// "gal" and "galgame", or "rewrite" and "rewriting": one name contains the other.
|
|
40
|
+
export function namesProject(wish, said) {
|
|
41
|
+
const left = [...projectTerms(wish)];
|
|
42
|
+
const right = [...projectTerms(said)];
|
|
43
|
+
for (const a of left)
|
|
44
|
+
for (const b of right)
|
|
45
|
+
if (a === b || a.startsWith(b) || b.startsWith(a)) return true;
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Whether she actually reads this batch or lets it go by. No dice: the
|
|
50
|
+
// same situation always gets the same attention, and every skipped message
|
|
51
|
+
// stays unread so the next real look still sees it.
|
|
52
|
+
export function attend({
|
|
53
|
+
batch,
|
|
54
|
+
unread = batch.length,
|
|
55
|
+
lastLookAt = null,
|
|
56
|
+
lastSpokeAt = null,
|
|
57
|
+
phase = "awake",
|
|
58
|
+
energy = 0.7,
|
|
59
|
+
interests = new Set(),
|
|
60
|
+
curiosities = new Set(),
|
|
61
|
+
living = new Set(),
|
|
62
|
+
wishes = [],
|
|
63
|
+
held = new Set(),
|
|
64
|
+
closeness = new Map(),
|
|
65
|
+
pressure = 0,
|
|
66
|
+
initiative = 25,
|
|
67
|
+
belongs = false,
|
|
68
|
+
now = Date.now(),
|
|
69
|
+
}) {
|
|
70
|
+
const direct = batch.some((m) => m.relation === "direct");
|
|
71
|
+
const crisis = batch.some(
|
|
72
|
+
(m) => m.role !== "assistant" && crisisSignal(m.text),
|
|
73
|
+
);
|
|
74
|
+
if (crisis)
|
|
75
|
+
return {
|
|
76
|
+
look: true,
|
|
77
|
+
direct,
|
|
78
|
+
crisis,
|
|
79
|
+
score: 99,
|
|
80
|
+
reason: "看到有人好像很难受",
|
|
81
|
+
};
|
|
82
|
+
if (phase === "asleep")
|
|
83
|
+
return {
|
|
84
|
+
look: false,
|
|
85
|
+
defer: direct,
|
|
86
|
+
direct,
|
|
87
|
+
score: 0,
|
|
88
|
+
reason: direct ? "睡着了,醒来再看" : "睡着了",
|
|
89
|
+
};
|
|
90
|
+
if (direct) return { look: true, direct, score: 10, reason: "有人在叫我" };
|
|
91
|
+
if (pressure >= 1)
|
|
92
|
+
return {
|
|
93
|
+
look: false,
|
|
94
|
+
direct,
|
|
95
|
+
score: 0,
|
|
96
|
+
reason: "今天的话已经说得够多了,先只听",
|
|
97
|
+
};
|
|
98
|
+
const reasons = [];
|
|
99
|
+
let score = 0;
|
|
100
|
+
const add = (value, reason) => {
|
|
101
|
+
score += value;
|
|
102
|
+
if (reason && value > 0) reasons.push(reason);
|
|
103
|
+
};
|
|
104
|
+
if (lastSpokeAt && now - lastSpokeAt < 3 * MINUTE) add(3, "刚才还在聊");
|
|
105
|
+
else if (lastSpokeAt && now - lastSpokeAt < 10 * MINUTE)
|
|
106
|
+
add(1.5, "不久前说过话");
|
|
107
|
+
const texts = batch.map((m) => String(m.text || ""));
|
|
108
|
+
if (
|
|
109
|
+
batch.some(
|
|
110
|
+
(m) =>
|
|
111
|
+
m.relation !== "other" &&
|
|
112
|
+
!(m.mentions || []).length &&
|
|
113
|
+
OPEN_QUESTION.test(m.text || ""),
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
add(1.5, "有人在问大家");
|
|
117
|
+
// One person's own words, including several messages from that person.
|
|
118
|
+
// Two people cannot be added together, and her own line does not count.
|
|
119
|
+
// A wish or a curiosity needs two distinctive pairs, or one when that
|
|
120
|
+
// set only has one. An interest needs one.
|
|
121
|
+
const lives = [];
|
|
122
|
+
for (const set of wishes || []) if (set?.size) lives.push(set);
|
|
123
|
+
if (living?.size && !lives.includes(living)) lives.push(living);
|
|
124
|
+
const meets = (terms, need, { named = false } = {}) => {
|
|
125
|
+
if (!terms?.size) return false;
|
|
126
|
+
const required = terms.size < need ? 1 : need;
|
|
127
|
+
const groups = new Map();
|
|
128
|
+
let anon = 0;
|
|
129
|
+
for (const m of batch) {
|
|
130
|
+
if (m.role === "assistant") continue;
|
|
131
|
+
const id = String(m.userId || "");
|
|
132
|
+
const key = id || `\0${anon++}`;
|
|
133
|
+
const texts = groups.get(key) || [];
|
|
134
|
+
texts.push(m.text || "");
|
|
135
|
+
groups.set(key, texts);
|
|
136
|
+
}
|
|
137
|
+
for (const texts of groups.values()) {
|
|
138
|
+
const said = interestTerms(texts);
|
|
139
|
+
if (named && namesProject(terms, said)) return true;
|
|
140
|
+
let shared = 0;
|
|
141
|
+
for (const term of said)
|
|
142
|
+
if (terms.has(term) && ++shared >= required) return true;
|
|
143
|
+
}
|
|
144
|
+
return false;
|
|
145
|
+
};
|
|
146
|
+
if (lives.some((terms) => meets(terms, 2, { named: true })))
|
|
147
|
+
add(2, "聊到了我正在过的事");
|
|
148
|
+
else if (meets(interests, 1) || meets(curiosities, 2))
|
|
149
|
+
add(2, "聊到了我在意的东西");
|
|
150
|
+
if (batch.some((m) => (closeness.get(String(m.userId)) || 0) >= 0.45))
|
|
151
|
+
add(1.5, "熟悉的人在说话");
|
|
152
|
+
if (unread >= 15) add(2.5, "攒了不少消息");
|
|
153
|
+
else if (unread >= 8) add(1.5, "攒了一些消息");
|
|
154
|
+
if (lastLookAt && now - lastLookAt >= 10 * MINUTE && unread >= 3)
|
|
155
|
+
add(1.5, "有一阵没看群了");
|
|
156
|
+
const mediaOnly = texts.every((t) => MEDIA_ONLY.test(t.trim()));
|
|
157
|
+
const sideTalk =
|
|
158
|
+
batch.length > 0 && batch.every((m) => m.relation === "other");
|
|
159
|
+
if (mediaOnly) add(-2);
|
|
160
|
+
if (sideTalk) add(-1.5);
|
|
161
|
+
const threshold =
|
|
162
|
+
3 +
|
|
163
|
+
(pressure > 0.7 ? 1.5 : 0) +
|
|
164
|
+
(energy < 0.3 ? 1 : 0) +
|
|
165
|
+
(phase === "sleepy" || phase === "waking" ? 0.5 : 0) -
|
|
166
|
+
(Number(initiative) - 25) / 25;
|
|
167
|
+
// Someone whose words already met a wish she is still living is worth
|
|
168
|
+
// reading again, even when this sentence does not repeat the wish. A
|
|
169
|
+
// private meeting does not follow her into another room; the caller
|
|
170
|
+
// only passes people visible here. Talking past each other, pictures,
|
|
171
|
+
// and an empty day still pass by.
|
|
172
|
+
const heldHere =
|
|
173
|
+
!mediaOnly &&
|
|
174
|
+
!sideTalk &&
|
|
175
|
+
batch.some(
|
|
176
|
+
(m) => m.role !== "assistant" && held.has(String(m.userId || "")),
|
|
177
|
+
);
|
|
178
|
+
if (heldHere) {
|
|
179
|
+
reasons.push("上次的话碰到了我正在过的事");
|
|
180
|
+
if (pressure < 1 && score < threshold) score = threshold;
|
|
181
|
+
}
|
|
182
|
+
// A room she already lives in is worth a real look, unless people are
|
|
183
|
+
// talking only to each other or the day is out of words.
|
|
184
|
+
if (belongs && !sideTalk && !mediaOnly && pressure < 1 && score < threshold) {
|
|
185
|
+
score = threshold;
|
|
186
|
+
reasons.push("这是我在的地方");
|
|
187
|
+
}
|
|
188
|
+
const look = score >= threshold;
|
|
189
|
+
return {
|
|
190
|
+
look,
|
|
191
|
+
direct,
|
|
192
|
+
score: Math.round(score * 10) / 10,
|
|
193
|
+
threshold: Math.round(threshold * 10) / 10,
|
|
194
|
+
reason: look
|
|
195
|
+
? reasons.join(",") || "看了一眼"
|
|
196
|
+
: reasons.length
|
|
197
|
+
? `扫了一眼(${reasons.join(",")}),没细看`
|
|
198
|
+
: "扫了一眼,群友在聊别的",
|
|
199
|
+
};
|
|
200
|
+
}
|