luckytri 1.0.0 → 1.0.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/.github/SECURITY.md +4 -4
- package/README.en.md +252 -250
- package/README.md +252 -250
- package/bin/luckytri.js +5 -1
- package/docs/en/CHANGELOG.md +8 -0
- package/docs/en/connect.md +18 -18
- package/docs/en/guide.md +202 -216
- package/docs/en/npm-release.md +25 -25
- package/docs/zh/CHANGELOG.md +8 -0
- package/docs/zh/connect.md +17 -17
- package/docs/zh/guide.md +202 -216
- package/docs/zh/npm-release.md +33 -33
- package/package.json +110 -108
- package/plugins/sdk/index.d.ts +155 -155
- package/plugins/sdk/testing.js +58 -58
- package/plugins/weather/index.js +82 -82
- package/plugins/weather/luckytri-plugin.json +29 -29
- package/public/app/assets/ChatsPage-BhlJHseG.js +3 -0
- package/public/app/assets/Empty-DP6WMGHi.js +2 -0
- package/public/app/assets/Field-CtbdqaiB.js +1 -0
- package/public/app/assets/HeartPage-32BeTPn2.js +1 -0
- package/public/app/assets/LifePage-CxSm0XKI.js +1 -0
- package/public/app/assets/MemoryPage-BeKBcPCY.js +1 -0
- package/public/app/assets/NaturePage-NEPYl2HS.js +3 -0
- package/public/app/assets/PeoplePage-DxtpekwM.js +1 -0
- package/public/app/assets/PluginsPage-CVVQwEBI.css +1 -0
- package/public/app/assets/PluginsPage-DksEZbUU.js +2 -0
- package/public/app/assets/{SystemPage-CAMPoYqM.css → SystemPage-BkRu0Rvx.css} +1 -1
- package/public/app/assets/SystemPage-BvzJlHuY.js +1 -0
- package/public/app/assets/TimePage-7-awH5XL.js +3 -0
- package/public/app/assets/index-4rItIkD-.js +4 -0
- package/public/app/assets/{index-YDz1ree1.css → index-DY4e15Kh.css} +1 -1
- package/public/app/assets/{knowledge-DG0e0uKw.js → knowledge-C6_HvoyB.js} +1 -1
- package/public/app/assets/media-SMfTT-yc.js +1 -0
- package/public/app/index.html +3 -3
- package/public/guide.en.html +72 -99
- package/public/guide.html +44 -86
- package/public/tutorial.en.md +25 -39
- package/public/tutorial.md +25 -39
- package/scripts/backup.js +311 -311
- package/scripts/browser.js +41 -41
- package/scripts/import-data.js +128 -0
- package/scripts/launch.js +101 -94
- package/scripts/plugin.js +150 -150
- package/scripts/reset-password.js +22 -0
- package/scripts/runtime.js +25 -25
- package/scripts/service.js +56 -47
- package/scripts/setup.js +50 -50
- package/scripts/start-server.js +41 -41
- package/scripts/stop.js +36 -36
- package/server/app.js +112 -96
- package/server/auth.js +217 -0
- package/server/channels/contract.js +57 -57
- package/server/channels/hub.js +165 -165
- package/server/channels/index.js +28 -25
- package/server/channels/onebot/index.js +335 -336
- package/server/channels/onebot/token.js +22 -3
- package/server/core/capabilities.js +208 -208
- package/server/core/events.js +64 -60
- package/server/core/image-preprocessor.js +208 -208
- package/server/core/model-manager.js +1213 -1213
- package/server/core/net-guard.js +49 -49
- package/server/core/orchestrator.js +569 -569
- package/server/core/perceivers.js +91 -91
- package/server/core/persona-manager.js +243 -243
- package/server/core/repository.js +293 -293
- package/server/core/response-validator.js +508 -508
- package/server/core/turn-processor.js +630 -630
- package/server/core/turn.js +236 -236
- package/server/core/vision-manager.js +633 -633
- package/server/i18n/errors.js +548 -497
- package/server/i18n/labels.js +649 -653
- package/server/index.js +151 -102
- package/server/knowledge/manager.js +386 -386
- package/server/knowledge/schema.js +12 -8
- package/server/local-access.js +32 -0
- package/server/mind/anticipations.js +507 -507
- package/server/mind/api.js +703 -703
- package/server/mind/budget.js +152 -152
- package/server/mind/context-selection.js +61 -61
- package/server/mind/day-planner.js +324 -324
- package/server/mind/evidence.js +148 -148
- package/server/mind/index.js +445 -445
- package/server/mind/life/diary.js +786 -786
- package/server/mind/life/index.js +1049 -1049
- package/server/mind/observations.js +84 -84
- package/server/mind/own-day.js +324 -324
- package/server/mind/own-voice.js +318 -318
- package/server/mind/senses.js +53 -53
- package/server/mind/time/activity-clock.js +196 -196
- package/server/mind/time/availability.js +69 -69
- package/server/mind/time/commitment-review.js +198 -198
- package/server/mind/time/executor.js +512 -512
- package/server/mind/time/experiences.js +128 -128
- package/server/mind/time/games.js +562 -562
- package/server/mind/time/index.js +739 -739
- package/server/mind/time/intent.js +166 -166
- package/server/mind/time/kinds.js +171 -171
- package/server/mind/time/plugin-activity.js +207 -207
- package/server/mind/time/tasks.js +587 -587
- package/server/mind/util.js +110 -110
- package/server/mind/view.js +273 -273
- package/server/paths.js +102 -102
- package/server/plugins/api.js +204 -204
- package/server/plugins/host.js +967 -967
- package/server/plugins/install.js +295 -295
- package/server/plugins/manifest.js +201 -201
- package/server/plugins/permissions.js +42 -42
- package/server/plugins/runner/guard.mjs +36 -36
- package/server/plugins/runner/worker.mjs +250 -250
- package/server/plugins/schema.js +91 -91
- package/server/plugins/zip.js +112 -112
- package/server/startup-lock.js +118 -118
- package/server/storage/archive.js +242 -241
- package/server/storage/backup-cleanup-worker.js +8 -8
- package/server/storage/backup-cleanup.js +415 -414
- package/server/storage/backup-lock.js +76 -76
- package/server/storage/backup-scheduler.js +131 -131
- package/server/storage/data-package.js +298 -0
- package/server/storage/data-transfer-api.js +50 -0
- package/server/storage/data-transfer-worker.js +18 -0
- package/server/storage/data-transfer.js +415 -0
- package/server/storage/store.js +202 -199
- package/server/studio/readiness.js +181 -190
- package/server/studio/settings.js +236 -236
- package/public/app/assets/ChatsPage-C-FcRapR.js +0 -3
- package/public/app/assets/Empty-CpP5kQHH.js +0 -2
- package/public/app/assets/Field-D4gY-INU.js +0 -1
- package/public/app/assets/HeartPage-CPy_thQd.js +0 -1
- package/public/app/assets/LifePage-CxWvwmSf.js +0 -1
- package/public/app/assets/MemoryPage-DC4rhQ68.js +0 -1
- package/public/app/assets/NaturePage-IvYw04Zq.js +0 -3
- package/public/app/assets/PeoplePage-Cqefm9-q.js +0 -1
- package/public/app/assets/PluginsPage-DKSaKvXb.js +0 -2
- package/public/app/assets/PluginsPage-HyBe5D8w.css +0 -1
- package/public/app/assets/SystemPage-CJmtJkrK.js +0 -1
- package/public/app/assets/TimePage-Cw44inM4.js +0 -3
- package/public/app/assets/index-BheRW-1t.js +0 -4
- package/public/app/assets/media-BzPDBm7e.js +0 -1
package/server/mind/budget.js
CHANGED
|
@@ -1,152 +1,152 @@
|
|
|
1
|
-
import { DAY, clamp } from "./util.js";
|
|
2
|
-
|
|
3
|
-
// Talking to people always comes first; thinking alone and bookkeeping live
|
|
4
|
-
// on a share of the same daily allowance.
|
|
5
|
-
export const STAGE_CATEGORY = {
|
|
6
|
-
turn: "conversation",
|
|
7
|
-
rewrite: "conversation",
|
|
8
|
-
generation: "conversation",
|
|
9
|
-
validation: "conversation",
|
|
10
|
-
vision: "conversation",
|
|
11
|
-
decision: "conversation",
|
|
12
|
-
reflection: "inner",
|
|
13
|
-
expression: "inner",
|
|
14
|
-
daily: "inner",
|
|
15
|
-
weekly: "inner",
|
|
16
|
-
memory: "upkeep",
|
|
17
|
-
summary: "upkeep",
|
|
18
|
-
plugin: "plugins",
|
|
19
|
-
};
|
|
20
|
-
export const BUDGET_DEFAULTS = {
|
|
21
|
-
dailyTokens: 0,
|
|
22
|
-
innerShare: 0.25,
|
|
23
|
-
upkeepShare: 0.15,
|
|
24
|
-
pluginShare: 0.1,
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const estimate = (value) =>
|
|
28
|
-
Math.ceil(Buffer.byteLength(String(value || ""), "utf8") / 2);
|
|
29
|
-
|
|
30
|
-
export function recordUsage(db, trace) {
|
|
31
|
-
const insert = db.prepare(
|
|
32
|
-
"INSERT INTO mind_usage(time,category,stage,session_id,input,cached,output,estimated) VALUES (?,?,?,?,?,?,?,?)",
|
|
33
|
-
);
|
|
34
|
-
for (const call of trace?.calls || []) {
|
|
35
|
-
if (call.ledgered || !STAGE_CATEGORY[call.stage]) continue;
|
|
36
|
-
call.ledgered = true;
|
|
37
|
-
const tokens = call.tokens;
|
|
38
|
-
insert.run(
|
|
39
|
-
call.started || Date.now(),
|
|
40
|
-
STAGE_CATEGORY[call.stage],
|
|
41
|
-
call.stage,
|
|
42
|
-
trace.sessionId || null,
|
|
43
|
-
tokens ? tokens.input : Number(call.inputEstimate) || 0,
|
|
44
|
-
tokens ? tokens.cachedRead : 0,
|
|
45
|
-
tokens ? tokens.output : estimate(call.raw),
|
|
46
|
-
tokens ? 0 : 1,
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export class Budget {
|
|
52
|
-
constructor(repo) {
|
|
53
|
-
this.repo = repo;
|
|
54
|
-
this.db = repo.db;
|
|
55
|
-
}
|
|
56
|
-
settings() {
|
|
57
|
-
return { ...BUDGET_DEFAULTS, ...this.repo.config("budget", {}) };
|
|
58
|
-
}
|
|
59
|
-
save(value) {
|
|
60
|
-
const next = { ...this.settings(), ...value };
|
|
61
|
-
if (
|
|
62
|
-
!Number.isInteger(next.dailyTokens) ||
|
|
63
|
-
next.dailyTokens < 0 ||
|
|
64
|
-
next.dailyTokens > 1e10
|
|
65
|
-
)
|
|
66
|
-
throw Error("每日 Token 上限无效");
|
|
67
|
-
for (const key of ["innerShare", "upkeepShare", "pluginShare"])
|
|
68
|
-
if (!Number.isFinite(next[key]) || next[key] < 0 || next[key] > 0.9)
|
|
69
|
-
throw Error("预算份额应在 0–0.9");
|
|
70
|
-
if (next.innerShare + next.upkeepShare + next.pluginShare > 0.95)
|
|
71
|
-
throw Error("后台份额之和不能超过 95%");
|
|
72
|
-
this.repo.saveConfig(
|
|
73
|
-
"budget",
|
|
74
|
-
Object.fromEntries(Object.keys(BUDGET_DEFAULTS).map((k) => [k, next[k]])),
|
|
75
|
-
);
|
|
76
|
-
return this.settings();
|
|
77
|
-
}
|
|
78
|
-
usage(now = Date.now()) {
|
|
79
|
-
const rows = this.db
|
|
80
|
-
.prepare(
|
|
81
|
-
"SELECT category,stage,COUNT(*) calls,SUM(input) input,SUM(cached) cached,SUM(output) output FROM mind_usage WHERE time>? AND time<=? GROUP BY category,stage",
|
|
82
|
-
)
|
|
83
|
-
.all(now - DAY, now);
|
|
84
|
-
const out = {
|
|
85
|
-
total: 0,
|
|
86
|
-
calls: 0,
|
|
87
|
-
cached: 0,
|
|
88
|
-
conversation: 0,
|
|
89
|
-
inner: 0,
|
|
90
|
-
upkeep: 0,
|
|
91
|
-
plugins: 0,
|
|
92
|
-
stages: {},
|
|
93
|
-
};
|
|
94
|
-
for (const row of rows) {
|
|
95
|
-
const tokens = Number(row.input || 0) + Number(row.output || 0);
|
|
96
|
-
out.total += tokens;
|
|
97
|
-
out.calls += row.calls;
|
|
98
|
-
out.cached += Number(row.cached || 0);
|
|
99
|
-
out[row.category] = (out[row.category] || 0) + tokens;
|
|
100
|
-
out.stages[row.stage] = {
|
|
101
|
-
calls: row.calls,
|
|
102
|
-
input: Number(row.input || 0),
|
|
103
|
-
cached: Number(row.cached || 0),
|
|
104
|
-
output: Number(row.output || 0),
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
return out;
|
|
108
|
-
}
|
|
109
|
-
limits() {
|
|
110
|
-
const s = this.settings();
|
|
111
|
-
if (!s.dailyTokens)
|
|
112
|
-
return { total: 0, conversation: 0, inner: 0, upkeep: 0, plugins: 0 };
|
|
113
|
-
return {
|
|
114
|
-
total: s.dailyTokens,
|
|
115
|
-
conversation: s.dailyTokens,
|
|
116
|
-
inner: Math.floor(s.dailyTokens * s.innerShare),
|
|
117
|
-
upkeep: Math.floor(s.dailyTokens * s.upkeepShare),
|
|
118
|
-
plugins: Math.floor(s.dailyTokens * s.pluginShare),
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
// 0 means unlimited or idle; 1 means the allowance is spent.
|
|
122
|
-
pressure(category = "conversation", now = Date.now()) {
|
|
123
|
-
const limit = this.limits()[category];
|
|
124
|
-
if (!limit) return 0;
|
|
125
|
-
const used =
|
|
126
|
-
category === "conversation"
|
|
127
|
-
? this.usage(now).total
|
|
128
|
-
: this.usage(now)[category];
|
|
129
|
-
return clamp(used / limit, 0, 2);
|
|
130
|
-
}
|
|
131
|
-
// The daily cap bounds everything; each background share bounds itself.
|
|
132
|
-
allows(category, now = Date.now()) {
|
|
133
|
-
return (
|
|
134
|
-
this.pressure(category, now) < 1 && this.pressure("conversation", now) < 1
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
report(now = Date.now()) {
|
|
138
|
-
const usage = this.usage(now);
|
|
139
|
-
const limits = this.limits();
|
|
140
|
-
return {
|
|
141
|
-
settings: this.settings(),
|
|
142
|
-
usage,
|
|
143
|
-
limits,
|
|
144
|
-
pressure: {
|
|
145
|
-
conversation: this.pressure("conversation", now),
|
|
146
|
-
inner: this.pressure("inner", now),
|
|
147
|
-
upkeep: this.pressure("upkeep", now),
|
|
148
|
-
plugins: this.pressure("plugins", now),
|
|
149
|
-
},
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
}
|
|
1
|
+
import { DAY, clamp } from "./util.js";
|
|
2
|
+
|
|
3
|
+
// Talking to people always comes first; thinking alone and bookkeeping live
|
|
4
|
+
// on a share of the same daily allowance.
|
|
5
|
+
export const STAGE_CATEGORY = {
|
|
6
|
+
turn: "conversation",
|
|
7
|
+
rewrite: "conversation",
|
|
8
|
+
generation: "conversation",
|
|
9
|
+
validation: "conversation",
|
|
10
|
+
vision: "conversation",
|
|
11
|
+
decision: "conversation",
|
|
12
|
+
reflection: "inner",
|
|
13
|
+
expression: "inner",
|
|
14
|
+
daily: "inner",
|
|
15
|
+
weekly: "inner",
|
|
16
|
+
memory: "upkeep",
|
|
17
|
+
summary: "upkeep",
|
|
18
|
+
plugin: "plugins",
|
|
19
|
+
};
|
|
20
|
+
export const BUDGET_DEFAULTS = {
|
|
21
|
+
dailyTokens: 0,
|
|
22
|
+
innerShare: 0.25,
|
|
23
|
+
upkeepShare: 0.15,
|
|
24
|
+
pluginShare: 0.1,
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const estimate = (value) =>
|
|
28
|
+
Math.ceil(Buffer.byteLength(String(value || ""), "utf8") / 2);
|
|
29
|
+
|
|
30
|
+
export function recordUsage(db, trace) {
|
|
31
|
+
const insert = db.prepare(
|
|
32
|
+
"INSERT INTO mind_usage(time,category,stage,session_id,input,cached,output,estimated) VALUES (?,?,?,?,?,?,?,?)",
|
|
33
|
+
);
|
|
34
|
+
for (const call of trace?.calls || []) {
|
|
35
|
+
if (call.ledgered || !STAGE_CATEGORY[call.stage]) continue;
|
|
36
|
+
call.ledgered = true;
|
|
37
|
+
const tokens = call.tokens;
|
|
38
|
+
insert.run(
|
|
39
|
+
call.started || Date.now(),
|
|
40
|
+
STAGE_CATEGORY[call.stage],
|
|
41
|
+
call.stage,
|
|
42
|
+
trace.sessionId || null,
|
|
43
|
+
tokens ? tokens.input : Number(call.inputEstimate) || 0,
|
|
44
|
+
tokens ? tokens.cachedRead : 0,
|
|
45
|
+
tokens ? tokens.output : estimate(call.raw),
|
|
46
|
+
tokens ? 0 : 1,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class Budget {
|
|
52
|
+
constructor(repo) {
|
|
53
|
+
this.repo = repo;
|
|
54
|
+
this.db = repo.db;
|
|
55
|
+
}
|
|
56
|
+
settings() {
|
|
57
|
+
return { ...BUDGET_DEFAULTS, ...this.repo.config("budget", {}) };
|
|
58
|
+
}
|
|
59
|
+
save(value) {
|
|
60
|
+
const next = { ...this.settings(), ...value };
|
|
61
|
+
if (
|
|
62
|
+
!Number.isInteger(next.dailyTokens) ||
|
|
63
|
+
next.dailyTokens < 0 ||
|
|
64
|
+
next.dailyTokens > 1e10
|
|
65
|
+
)
|
|
66
|
+
throw Error("每日 Token 上限无效");
|
|
67
|
+
for (const key of ["innerShare", "upkeepShare", "pluginShare"])
|
|
68
|
+
if (!Number.isFinite(next[key]) || next[key] < 0 || next[key] > 0.9)
|
|
69
|
+
throw Error("预算份额应在 0–0.9");
|
|
70
|
+
if (next.innerShare + next.upkeepShare + next.pluginShare > 0.95)
|
|
71
|
+
throw Error("后台份额之和不能超过 95%");
|
|
72
|
+
this.repo.saveConfig(
|
|
73
|
+
"budget",
|
|
74
|
+
Object.fromEntries(Object.keys(BUDGET_DEFAULTS).map((k) => [k, next[k]])),
|
|
75
|
+
);
|
|
76
|
+
return this.settings();
|
|
77
|
+
}
|
|
78
|
+
usage(now = Date.now()) {
|
|
79
|
+
const rows = this.db
|
|
80
|
+
.prepare(
|
|
81
|
+
"SELECT category,stage,COUNT(*) calls,SUM(input) input,SUM(cached) cached,SUM(output) output FROM mind_usage WHERE time>? AND time<=? GROUP BY category,stage",
|
|
82
|
+
)
|
|
83
|
+
.all(now - DAY, now);
|
|
84
|
+
const out = {
|
|
85
|
+
total: 0,
|
|
86
|
+
calls: 0,
|
|
87
|
+
cached: 0,
|
|
88
|
+
conversation: 0,
|
|
89
|
+
inner: 0,
|
|
90
|
+
upkeep: 0,
|
|
91
|
+
plugins: 0,
|
|
92
|
+
stages: {},
|
|
93
|
+
};
|
|
94
|
+
for (const row of rows) {
|
|
95
|
+
const tokens = Number(row.input || 0) + Number(row.output || 0);
|
|
96
|
+
out.total += tokens;
|
|
97
|
+
out.calls += row.calls;
|
|
98
|
+
out.cached += Number(row.cached || 0);
|
|
99
|
+
out[row.category] = (out[row.category] || 0) + tokens;
|
|
100
|
+
out.stages[row.stage] = {
|
|
101
|
+
calls: row.calls,
|
|
102
|
+
input: Number(row.input || 0),
|
|
103
|
+
cached: Number(row.cached || 0),
|
|
104
|
+
output: Number(row.output || 0),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
return out;
|
|
108
|
+
}
|
|
109
|
+
limits() {
|
|
110
|
+
const s = this.settings();
|
|
111
|
+
if (!s.dailyTokens)
|
|
112
|
+
return { total: 0, conversation: 0, inner: 0, upkeep: 0, plugins: 0 };
|
|
113
|
+
return {
|
|
114
|
+
total: s.dailyTokens,
|
|
115
|
+
conversation: s.dailyTokens,
|
|
116
|
+
inner: Math.floor(s.dailyTokens * s.innerShare),
|
|
117
|
+
upkeep: Math.floor(s.dailyTokens * s.upkeepShare),
|
|
118
|
+
plugins: Math.floor(s.dailyTokens * s.pluginShare),
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// 0 means unlimited or idle; 1 means the allowance is spent.
|
|
122
|
+
pressure(category = "conversation", now = Date.now()) {
|
|
123
|
+
const limit = this.limits()[category];
|
|
124
|
+
if (!limit) return 0;
|
|
125
|
+
const used =
|
|
126
|
+
category === "conversation"
|
|
127
|
+
? this.usage(now).total
|
|
128
|
+
: this.usage(now)[category];
|
|
129
|
+
return clamp(used / limit, 0, 2);
|
|
130
|
+
}
|
|
131
|
+
// The daily cap bounds everything; each background share bounds itself.
|
|
132
|
+
allows(category, now = Date.now()) {
|
|
133
|
+
return (
|
|
134
|
+
this.pressure(category, now) < 1 && this.pressure("conversation", now) < 1
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
report(now = Date.now()) {
|
|
138
|
+
const usage = this.usage(now);
|
|
139
|
+
const limits = this.limits();
|
|
140
|
+
return {
|
|
141
|
+
settings: this.settings(),
|
|
142
|
+
usage,
|
|
143
|
+
limits,
|
|
144
|
+
pressure: {
|
|
145
|
+
conversation: this.pressure("conversation", now),
|
|
146
|
+
inner: this.pressure("inner", now),
|
|
147
|
+
upkeep: this.pressure("upkeep", now),
|
|
148
|
+
plugins: this.pressure("plugins", now),
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
}
|
|
@@ -1,61 +1,61 @@
|
|
|
1
|
-
import { estimateTokens } from "../core/model-manager.js";
|
|
2
|
-
import { interestTerms } from "./attention.js";
|
|
3
|
-
|
|
4
|
-
export const MIND_CONTEXT_TOKEN_CAP = 6000;
|
|
5
|
-
|
|
6
|
-
// One speaker must provide the cue. Shared relevance across two unrelated
|
|
7
|
-
// speakers is not invented by concatenating the room's words.
|
|
8
|
-
export function relevantContext(
|
|
9
|
-
rows,
|
|
10
|
-
{ cues = [], limit, pinned = () => false } = {},
|
|
11
|
-
) {
|
|
12
|
-
const score = (row) => {
|
|
13
|
-
const terms = interestTerms([row.content]);
|
|
14
|
-
const overlap = Math.max(
|
|
15
|
-
0,
|
|
16
|
-
...cues.map((cue) => [...terms].filter((term) => cue.has(term)).length),
|
|
17
|
-
);
|
|
18
|
-
return (
|
|
19
|
-
overlap * 4 + Number(row.salience ?? row.importance ?? row.strength ?? 0)
|
|
20
|
-
);
|
|
21
|
-
};
|
|
22
|
-
const fixed = rows.filter(pinned).slice(0, limit);
|
|
23
|
-
return [
|
|
24
|
-
...fixed,
|
|
25
|
-
...rows
|
|
26
|
-
.filter((row) => !fixed.includes(row))
|
|
27
|
-
.map((row, order) => ({ row, order, score: score(row) }))
|
|
28
|
-
.sort((a, b) => b.score - a.score || a.order - b.order)
|
|
29
|
-
.slice(0, limit - fixed.length)
|
|
30
|
-
.map((item) => item.row),
|
|
31
|
-
];
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// A shared allowance prevents each new module from independently enlarging
|
|
35
|
-
// the prompt. Identity, current people, and exact continuity evidence survive.
|
|
36
|
-
export function boundMindContext(view, cap = MIND_CONTEXT_TOKEN_CAP) {
|
|
37
|
-
const optional = [
|
|
38
|
-
[view.inner, "senses"],
|
|
39
|
-
[view.self, "readLately"],
|
|
40
|
-
[view.self, "lastDiary"],
|
|
41
|
-
[view.inner, "reminded"],
|
|
42
|
-
[view.inner, "onMind"],
|
|
43
|
-
[view.inner, "with"],
|
|
44
|
-
[view.inner, "stood"],
|
|
45
|
-
[view.inner, "heard"],
|
|
46
|
-
[view.inner, "room"],
|
|
47
|
-
[view.inner, "expecting"],
|
|
48
|
-
[view.inner, "will"],
|
|
49
|
-
[view.self, "threads"],
|
|
50
|
-
];
|
|
51
|
-
for (const [owner, key] of optional) {
|
|
52
|
-
while (
|
|
53
|
-
estimateTokens({ self: view.self, inner: view.inner }) > cap &&
|
|
54
|
-
owner?.[key]
|
|
55
|
-
) {
|
|
56
|
-
if (Array.isArray(owner[key]) && owner[key].length > 1) owner[key].pop();
|
|
57
|
-
else delete owner[key];
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return view;
|
|
61
|
-
}
|
|
1
|
+
import { estimateTokens } from "../core/model-manager.js";
|
|
2
|
+
import { interestTerms } from "./attention.js";
|
|
3
|
+
|
|
4
|
+
export const MIND_CONTEXT_TOKEN_CAP = 6000;
|
|
5
|
+
|
|
6
|
+
// One speaker must provide the cue. Shared relevance across two unrelated
|
|
7
|
+
// speakers is not invented by concatenating the room's words.
|
|
8
|
+
export function relevantContext(
|
|
9
|
+
rows,
|
|
10
|
+
{ cues = [], limit, pinned = () => false } = {},
|
|
11
|
+
) {
|
|
12
|
+
const score = (row) => {
|
|
13
|
+
const terms = interestTerms([row.content]);
|
|
14
|
+
const overlap = Math.max(
|
|
15
|
+
0,
|
|
16
|
+
...cues.map((cue) => [...terms].filter((term) => cue.has(term)).length),
|
|
17
|
+
);
|
|
18
|
+
return (
|
|
19
|
+
overlap * 4 + Number(row.salience ?? row.importance ?? row.strength ?? 0)
|
|
20
|
+
);
|
|
21
|
+
};
|
|
22
|
+
const fixed = rows.filter(pinned).slice(0, limit);
|
|
23
|
+
return [
|
|
24
|
+
...fixed,
|
|
25
|
+
...rows
|
|
26
|
+
.filter((row) => !fixed.includes(row))
|
|
27
|
+
.map((row, order) => ({ row, order, score: score(row) }))
|
|
28
|
+
.sort((a, b) => b.score - a.score || a.order - b.order)
|
|
29
|
+
.slice(0, limit - fixed.length)
|
|
30
|
+
.map((item) => item.row),
|
|
31
|
+
];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// A shared allowance prevents each new module from independently enlarging
|
|
35
|
+
// the prompt. Identity, current people, and exact continuity evidence survive.
|
|
36
|
+
export function boundMindContext(view, cap = MIND_CONTEXT_TOKEN_CAP) {
|
|
37
|
+
const optional = [
|
|
38
|
+
[view.inner, "senses"],
|
|
39
|
+
[view.self, "readLately"],
|
|
40
|
+
[view.self, "lastDiary"],
|
|
41
|
+
[view.inner, "reminded"],
|
|
42
|
+
[view.inner, "onMind"],
|
|
43
|
+
[view.inner, "with"],
|
|
44
|
+
[view.inner, "stood"],
|
|
45
|
+
[view.inner, "heard"],
|
|
46
|
+
[view.inner, "room"],
|
|
47
|
+
[view.inner, "expecting"],
|
|
48
|
+
[view.inner, "will"],
|
|
49
|
+
[view.self, "threads"],
|
|
50
|
+
];
|
|
51
|
+
for (const [owner, key] of optional) {
|
|
52
|
+
while (
|
|
53
|
+
estimateTokens({ self: view.self, inner: view.inner }) > cap &&
|
|
54
|
+
owner?.[key]
|
|
55
|
+
) {
|
|
56
|
+
if (Array.isArray(owner[key]) && owner[key].length > 1) owner[key].pop();
|
|
57
|
+
else delete owner[key];
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return view;
|
|
61
|
+
}
|