volute 0.43.1 → 0.44.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/dist/{activity-events-UISXY4Y5.js → activity-events-OMCSM7XW.js} +3 -3
- package/dist/{ai-service-FBCCEYF5.js → ai-service-7PHSRDMO.js} +4 -4
- package/dist/{archive-I32WHCJB.js → archive-6R4TZMYI.js} +3 -3
- package/dist/{auth-3RIG6GKN.js → auth-FRZJVQCS.js} +4 -4
- package/dist/avatar-image-BNWEXSA2.js +16 -0
- package/dist/{chat-SDSX5TVV.js → chat-I4EDDIQC.js} +2 -2
- package/dist/{chunk-AD46AYZQ.js → chunk-2BONPXAF.js} +1 -1
- package/dist/{chunk-PGPLCJPK.js → chunk-3ERIL673.js} +1 -1
- package/dist/{chunk-C6ESRQZ7.js → chunk-3GYVW2X3.js} +1 -1
- package/dist/{chunk-SPLPKBES.js → chunk-5AHYQHNT.js} +4 -8
- package/dist/{chunk-XDTKJNW5.js → chunk-5GT7URXJ.js} +1 -1
- package/dist/{chunk-QQ2MVQU3.js → chunk-7FT24JBQ.js} +8 -8
- package/dist/{chunk-DE4EKQFH.js → chunk-7KWANSLX.js} +3 -3
- package/dist/{chunk-EFL5UOY4.js → chunk-CYI534DJ.js} +3 -3
- package/dist/{chunk-DMUPZQWP.js → chunk-EQZD4YU3.js} +8 -8
- package/dist/{chunk-57LBQ7JX.js → chunk-FHWUQZXE.js} +1 -1
- package/dist/{chunk-K4EHBHPE.js → chunk-FZMEVCWC.js} +3 -3
- package/dist/{chunk-YAMO2U3N.js → chunk-H7IYFRAL.js} +1 -1
- package/dist/{chunk-M3PGGSBH.js → chunk-HVU45COX.js} +1 -1
- package/dist/{chunk-KINGVQSR.js → chunk-I2Y2YHIO.js} +5 -5
- package/dist/{chunk-O3DXAR44.js → chunk-IEWZ7VD7.js} +2 -2
- package/dist/{chunk-YSV3VJQK.js → chunk-J47TIYHA.js} +1 -1
- package/dist/{chunk-QHG4OMZL.js → chunk-KDLYIECM.js} +37 -32
- package/dist/{chunk-EE7SZJON.js → chunk-KP3KWNG6.js} +2 -2
- package/dist/{chunk-JVK6QQIC.js → chunk-LAXUUY7O.js} +2 -2
- package/dist/{chunk-Y6O35D7K.js → chunk-NF75HPNR.js} +5 -5
- package/dist/{chunk-4SVONUTC.js → chunk-OMETFX5H.js} +321 -204
- package/dist/{chunk-ONM2AZFL.js → chunk-PNV24SEP.js} +1 -1
- package/dist/{chunk-ATEX3ZPG.js → chunk-Q2XBKQ2D.js} +2 -2
- package/dist/{chunk-GZJFC76M.js → chunk-QMJJWTNL.js} +1 -1
- package/dist/chunk-SQL7M4HJ.js +120 -0
- package/dist/{chunk-2HIVYZDB.js → chunk-UMI4UIJG.js} +1 -1
- package/dist/{chunk-7G2EEYXX.js → chunk-ZMIMSIIT.js} +2 -2
- package/dist/{chunk-L3IV23ZG.js → chunk-ZV7MFISX.js} +2 -0
- package/dist/cli.js +47 -22
- package/dist/{cloud-sync-KOEBUFW5.js → cloud-sync-6WJ7WFYD.js} +16 -16
- package/dist/{conversations-67WWW25C.js → conversations-WAJYZKOC.js} +4 -4
- package/dist/{create-7W3LV3J7.js → create-YZIV5OJC.js} +1 -1
- package/dist/{daemon-restart-EZXB73W7.js → daemon-restart-OUJVINXV.js} +7 -7
- package/dist/daemon.js +297 -294
- package/dist/{db-CZV62BOQ.js → db-JFLCJCUG.js} +2 -2
- package/dist/{db-IJL6B26S.js → db-LZTLA7XC.js} +1 -1
- package/dist/delivery-manager-TEVOHX5W.js +32 -0
- package/dist/{delivery-router-HXBHYHJM.js → delivery-router-GODSIS62.js} +3 -3
- package/dist/{down-RRNYIGCU.js → down-XCAZXWLB.js} +5 -5
- package/dist/echo-text-T7ZA5EYD.js +32 -0
- package/dist/{exec-SJK7VUTC.js → exec-4GWHAHS3.js} +3 -3
- package/dist/{export-7LPCIB5J.js → export-ID7YUSLZ.js} +3 -3
- package/dist/{extensions-PQPZT6LS.js → extensions-3QNDGW5E.js} +16 -16
- package/dist/{files-LV7VAKPC.js → files-BQ2WB5KC.js} +3 -3
- package/dist/{import-XPECCRQ7.js → import-SKID37QX.js} +6 -6
- package/dist/{isolation-5AYEY55P.js → isolation-5MB3J73F.js} +3 -3
- package/dist/{login-KJSN4JDA.js → login-LM4NF4ZB.js} +2 -2
- package/dist/{logout-TMJGUQV2.js → logout-CTJVIZGA.js} +2 -2
- package/dist/message-delivery-2EA5LLMD.js +34 -0
- package/dist/{mind-G3WEWDM4.js → mind-MI7Z6KM2.js} +5 -5
- package/dist/{mind-activity-tracker-JHAT6456.js → mind-activity-tracker-BGHJE7XA.js} +4 -4
- package/dist/mind-service-S3SY7HAM.js +36 -0
- package/dist/{package-24TL6DTF.js → package-5B4XDTJH.js} +1 -1
- package/dist/{registry-7LQHTRUX.js → registry-NUJAGLQJ.js} +2 -2
- package/dist/{sandbox-SJH3XOPZ.js → sandbox-IOPWWILM.js} +4 -4
- package/dist/scheduler-CXWQ6Z4E.js +30 -0
- package/dist/{schema-LRUTFOER.js → schema-PVNG3PQM.js} +1 -1
- package/dist/{seed-HHSJTM6O.js → seed-UUPVQWFB.js} +1 -1
- package/dist/{seed-cmd-UPQY35RG.js → seed-cmd-7XPKDQUC.js} +2 -2
- package/dist/{seed-create-MDRMXMSB.js → seed-create-IZ4M5ESO.js} +3 -3
- package/dist/{seed-sprout-4M7IQWMH.js → seed-sprout-POJXHJWV.js} +7 -7
- package/dist/{send-ZBZWIH5V.js → send-O6W53VBM.js} +37 -42
- package/dist/{service-4EVZKGSA.js → service-AQVPUANO.js} +4 -4
- package/dist/{service-install-SHRM6NHK.js → service-install-4QNUDKLM.js} +5 -5
- package/dist/{setup-ZD2LMBR3.js → setup-5GCO3CUB.js} +7 -7
- package/dist/{setup-25MMJ3J4.js → setup-MLRKNP7Y.js} +3 -3
- package/dist/{skills-4KQ377GN.js → skills-775C7QFF.js} +5 -5
- package/dist/sleep-manager-HINI6Y46.js +34 -0
- package/dist/{spirit-53DQPRNR.js → spirit-IK5OYWMV.js} +7 -7
- package/dist/{sprout-YKM2M6D6.js → sprout-ZY5QGOEL.js} +1 -1
- package/dist/{src-O4PRLMKM.js → src-JAOVXO5W.js} +1 -0
- package/dist/{src-3EGHHKZK.js → src-XFY3XDD6.js} +16 -11
- package/dist/{src-L2Z7X5UT.js → src-YH6PQ7LJ.js} +264 -52
- package/dist/{status-WTU2WHXY.js → status-E5DQNCAO.js} +5 -5
- package/dist/system-chat-4DQZOEZI.js +34 -0
- package/dist/{tailscale-Q7ZJL7S7.js → tailscale-QAWVKQKU.js} +2 -2
- package/dist/{turn-tracker-JZYERJ76.js → turn-tracker-RWZMY7M6.js} +5 -5
- package/dist/{up-LFZA4GI5.js → up-FLCDR2UB.js} +6 -6
- package/dist/{update-EJ7Q77ZX.js → update-7TYVH5FM.js} +5 -5
- package/dist/{update-check-ACYYNKTW.js → update-check-VSCSJ7KX.js} +3 -3
- package/dist/{version-notify-SRQJCQEK.js → version-notify-B67N35A3.js} +17 -17
- package/dist/web-assets/assets/{index-DTDmEfPU.js → index-Domoz5Cg.js} +8 -8
- package/dist/web-assets/assets/index-dJdNzAPn.css +1 -0
- package/dist/web-assets/ext-theme.css +5 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +1 -1
- package/packages/extensions/notes/dist/ui/assets/{index-BbgANhFm.js → index-D0-DgYyj.js} +1 -1
- package/packages/extensions/notes/dist/ui/index.html +1 -1
- package/packages/extensions/notes/skills/notes/SKILL.md +31 -3
- package/packages/extensions/pages/dist/ui/assets/{index-Dxk-DYrf.js → index-CQjEQg1r.js} +1 -1
- package/packages/extensions/pages/dist/ui/index.html +1 -1
- package/templates/_base/.init/.local/hooks/startup-context.ts +25 -0
- package/templates/claude/src/agent.ts +8 -1
- package/dist/delivery-manager-OMCCJEVP.js +0 -32
- package/dist/echo-text-KFSUCZXL.js +0 -32
- package/dist/message-delivery-HRGFNWO7.js +0 -34
- package/dist/mind-service-2C7AINBO.js +0 -36
- package/dist/scheduler-VON2TB52.js +0 -30
- package/dist/sleep-manager-AG5SQDDI.js +0 -34
- package/dist/system-chat-54RN3K67.js +0 -34
- package/dist/web-assets/assets/index-D7udpBCx.css +0 -1
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadMergedEnv
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5GT7URXJ.js";
|
|
5
5
|
import {
|
|
6
6
|
spiritDir
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-7FT24JBQ.js";
|
|
8
8
|
import {
|
|
9
9
|
hashSkillDir,
|
|
10
10
|
importSkillFromDir,
|
|
11
11
|
removeSharedSkill,
|
|
12
12
|
sharedSkillsDir
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-I2Y2YHIO.js";
|
|
14
14
|
import {
|
|
15
15
|
addMessage,
|
|
16
16
|
createChannel,
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
getParticipants,
|
|
21
21
|
joinChannel,
|
|
22
22
|
publish as publish2
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-FZMEVCWC.js";
|
|
24
24
|
import {
|
|
25
25
|
readVoluteConfig,
|
|
26
26
|
writeVoluteConfig
|
|
@@ -28,52 +28,52 @@ import {
|
|
|
28
28
|
import {
|
|
29
29
|
isSandboxEnabled,
|
|
30
30
|
wrapForSandbox
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-3GYVW2X3.js";
|
|
32
32
|
import {
|
|
33
33
|
markIdle,
|
|
34
34
|
onMindEvent
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-HVU45COX.js";
|
|
36
36
|
import {
|
|
37
37
|
extractTextContent,
|
|
38
38
|
getRoutingConfig,
|
|
39
39
|
resolveDeliveryMode,
|
|
40
40
|
resolveRoute,
|
|
41
41
|
setRoutesChangeListener
|
|
42
|
-
} from "./chunk-
|
|
42
|
+
} from "./chunk-5AHYQHNT.js";
|
|
43
43
|
import {
|
|
44
44
|
clearMind,
|
|
45
45
|
getPrompt,
|
|
46
46
|
linkInboundToActiveTurn,
|
|
47
47
|
publish as publish3,
|
|
48
48
|
summarizeOrphanedTurns
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-NF75HPNR.js";
|
|
50
50
|
import {
|
|
51
51
|
chownMindDir,
|
|
52
52
|
exec,
|
|
53
53
|
isIsolationEnabled,
|
|
54
54
|
mindUserName,
|
|
55
55
|
wrapForIsolation
|
|
56
|
-
} from "./chunk-
|
|
56
|
+
} from "./chunk-3ERIL673.js";
|
|
57
57
|
import {
|
|
58
58
|
aiCompleteUtility,
|
|
59
59
|
getAiConfig,
|
|
60
60
|
resolveApiKey
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-J47TIYHA.js";
|
|
62
62
|
import {
|
|
63
63
|
readGlobalConfig,
|
|
64
64
|
writeGlobalConfig
|
|
65
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-PNV24SEP.js";
|
|
66
66
|
import {
|
|
67
67
|
getOrCreateMindUser,
|
|
68
68
|
getOrCreateSystemUser,
|
|
69
69
|
getUser,
|
|
70
70
|
getUserByUsername,
|
|
71
71
|
syncMindProfile
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-CYI534DJ.js";
|
|
73
73
|
import {
|
|
74
74
|
publish,
|
|
75
75
|
subscribe
|
|
76
|
-
} from "./chunk-
|
|
76
|
+
} from "./chunk-ZMIMSIIT.js";
|
|
77
77
|
import {
|
|
78
78
|
logger_default
|
|
79
79
|
} from "./chunk-T2TP6ZC6.js";
|
|
@@ -87,7 +87,7 @@ import {
|
|
|
87
87
|
stateDir,
|
|
88
88
|
voluteHome,
|
|
89
89
|
voluteSystemDir
|
|
90
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-H7IYFRAL.js";
|
|
91
91
|
import {
|
|
92
92
|
activity,
|
|
93
93
|
deliveryQueue,
|
|
@@ -95,10 +95,10 @@ import {
|
|
|
95
95
|
mindHistory,
|
|
96
96
|
mindNotices,
|
|
97
97
|
sessions
|
|
98
|
-
} from "./chunk-
|
|
98
|
+
} from "./chunk-ZV7MFISX.js";
|
|
99
99
|
|
|
100
100
|
// packages/daemon/src/lib/delivery/message-delivery.ts
|
|
101
|
-
import { and as
|
|
101
|
+
import { and as and5, eq as eq6, inArray as inArray3 } from "drizzle-orm";
|
|
102
102
|
|
|
103
103
|
// packages/daemon/src/lib/daemon/sleep-manager.ts
|
|
104
104
|
import { execFile as execFile2, spawn as spawnChild } from "child_process";
|
|
@@ -337,8 +337,9 @@ function resolveMindToken(token) {
|
|
|
337
337
|
}
|
|
338
338
|
|
|
339
339
|
// packages/daemon/src/lib/daemon/notices.ts
|
|
340
|
-
import { and, asc, eq, lte, sql } from "drizzle-orm";
|
|
340
|
+
import { and, asc, eq, lte, or, sql } from "drizzle-orm";
|
|
341
341
|
var nlog = logger_default.child("notices");
|
|
342
|
+
var MIND_LEVEL_SESSION = "";
|
|
342
343
|
var MAX_NOTICES_PER_SESSION = 100;
|
|
343
344
|
async function recordNotice(input) {
|
|
344
345
|
try {
|
|
@@ -360,7 +361,12 @@ async function recordNotice(input) {
|
|
|
360
361
|
}
|
|
361
362
|
async function drainNotices(mind, session, limit = MAX_NOTICES_PER_SESSION) {
|
|
362
363
|
const db = await getDb();
|
|
363
|
-
return db.select().from(mindNotices).where(
|
|
364
|
+
return db.select().from(mindNotices).where(
|
|
365
|
+
and(
|
|
366
|
+
eq(mindNotices.mind, mind),
|
|
367
|
+
or(eq(mindNotices.session, session), eq(mindNotices.session, MIND_LEVEL_SESSION))
|
|
368
|
+
)
|
|
369
|
+
).orderBy(asc(mindNotices.id)).limit(limit);
|
|
364
370
|
}
|
|
365
371
|
async function clearDeliveredNotices(mind, session, uptoId) {
|
|
366
372
|
try {
|
|
@@ -368,7 +374,7 @@ async function clearDeliveredNotices(mind, session, uptoId) {
|
|
|
368
374
|
await db.delete(mindNotices).where(
|
|
369
375
|
and(
|
|
370
376
|
eq(mindNotices.mind, mind),
|
|
371
|
-
eq(mindNotices.session, session),
|
|
377
|
+
or(eq(mindNotices.session, session), eq(mindNotices.session, MIND_LEVEL_SESSION)),
|
|
372
378
|
lte(mindNotices.id, uptoId)
|
|
373
379
|
)
|
|
374
380
|
);
|
|
@@ -379,25 +385,45 @@ async function clearDeliveredNotices(mind, session, uptoId) {
|
|
|
379
385
|
var NOTICE_HEADER = "[Notices] While you were unavailable, one or more turns failed. You're back now:";
|
|
380
386
|
function formatNotices(notices) {
|
|
381
387
|
if (notices.length === 0) return null;
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
g
|
|
390
|
-
|
|
391
|
-
|
|
388
|
+
const failures = notices.filter((n) => n.kind !== "extension");
|
|
389
|
+
const extensions = notices.filter((n) => n.kind === "extension");
|
|
390
|
+
const blocks = [];
|
|
391
|
+
if (failures.length > 0) {
|
|
392
|
+
const groups = /* @__PURE__ */ new Map();
|
|
393
|
+
for (const n of failures) {
|
|
394
|
+
const time = localHM(n.created_at);
|
|
395
|
+
const g = groups.get(n.reason);
|
|
396
|
+
if (g) {
|
|
397
|
+
g.count += 1;
|
|
398
|
+
g.detail = n.detail;
|
|
399
|
+
g.last = time;
|
|
400
|
+
} else {
|
|
401
|
+
groups.set(n.reason, { count: 1, detail: n.detail, first: time, last: time });
|
|
402
|
+
}
|
|
392
403
|
}
|
|
404
|
+
const lines = [...groups.values()].map((g) => {
|
|
405
|
+
const span = g.first === g.last ? g.first : `${g.first}\u2013${g.last}`;
|
|
406
|
+
const plural = g.count === 1 ? "turn" : "turns";
|
|
407
|
+
return `- ${g.count} ${plural} failed (${span}): ${g.detail}`;
|
|
408
|
+
});
|
|
409
|
+
blocks.push(`${NOTICE_HEADER}
|
|
410
|
+
${lines.join("\n")}`);
|
|
393
411
|
}
|
|
394
|
-
|
|
395
|
-
const
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
412
|
+
if (extensions.length > 0) {
|
|
413
|
+
const byExt = /* @__PURE__ */ new Map();
|
|
414
|
+
for (const n of extensions) {
|
|
415
|
+
const arr = byExt.get(n.reason);
|
|
416
|
+
if (arr) arr.push(n);
|
|
417
|
+
else byExt.set(n.reason, [n]);
|
|
418
|
+
}
|
|
419
|
+
for (const [ext, items] of byExt) {
|
|
420
|
+
const header = `[${ext.charAt(0).toUpperCase()}${ext.slice(1)}]`;
|
|
421
|
+
const lines = items.map((n) => `- ${localHM(n.created_at)} ${n.detail}`);
|
|
422
|
+
blocks.push(`${header}
|
|
423
|
+
${lines.join("\n")}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return blocks.join("\n\n");
|
|
401
427
|
}
|
|
402
428
|
function localHM(createdAt) {
|
|
403
429
|
const iso = createdAt.endsWith("Z") ? createdAt : `${createdAt.replace(" ", "T")}Z`;
|
|
@@ -905,7 +931,7 @@ var MindManager = class {
|
|
|
905
931
|
if (this.shuttingDown || this.stopping.has(name)) return;
|
|
906
932
|
mlog.error(`mind ${name} exited with code ${code}`);
|
|
907
933
|
try {
|
|
908
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
934
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
|
|
909
935
|
const sleepMgr = getSleepManagerIfReady2();
|
|
910
936
|
const sleepState = sleepMgr?.getState(name);
|
|
911
937
|
if (sleepState?.sleeping) {
|
|
@@ -935,15 +961,15 @@ var MindManager = class {
|
|
|
935
961
|
(err) => mlog.warn(`failed to clear turn state for ${name} after crash`, logger_default.errorData(err))
|
|
936
962
|
);
|
|
937
963
|
try {
|
|
938
|
-
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-
|
|
964
|
+
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-TEVOHX5W.js");
|
|
939
965
|
getDeliveryManager2().clearMindSessions(name);
|
|
940
966
|
} catch (err) {
|
|
941
967
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
942
968
|
mlog.warn(`failed to clear delivery state for ${name} after crash`, logger_default.errorData(err));
|
|
943
969
|
}
|
|
944
970
|
}
|
|
945
|
-
import("./mind-activity-tracker-
|
|
946
|
-
import("./activity-events-
|
|
971
|
+
import("./mind-activity-tracker-BGHJE7XA.js").then(({ markIdle: markIdle2 }) => markIdle2(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
|
|
972
|
+
import("./activity-events-OMCSM7XW.js").then(
|
|
947
973
|
({ publish: publish4 }) => publish4({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
|
|
948
974
|
).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
|
|
949
975
|
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
|
|
@@ -1001,7 +1027,7 @@ var MindManager = class {
|
|
|
1001
1027
|
mlog.warn(`failed to clear turn state for ${name} on stop`, logger_default.errorData(err));
|
|
1002
1028
|
}
|
|
1003
1029
|
try {
|
|
1004
|
-
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-
|
|
1030
|
+
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-TEVOHX5W.js");
|
|
1005
1031
|
getDeliveryManager2().clearMindSessions(name);
|
|
1006
1032
|
} catch (err) {
|
|
1007
1033
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
@@ -1009,7 +1035,7 @@ var MindManager = class {
|
|
|
1009
1035
|
}
|
|
1010
1036
|
}
|
|
1011
1037
|
try {
|
|
1012
|
-
const { clearEchoTextCache } = await import("./echo-text-
|
|
1038
|
+
const { clearEchoTextCache } = await import("./echo-text-T7ZA5EYD.js");
|
|
1013
1039
|
clearEchoTextCache(name);
|
|
1014
1040
|
} catch (err) {
|
|
1015
1041
|
mlog.debug(`failed to clear echo-text cache for ${name}`, logger_default.errorData(err));
|
|
@@ -1462,6 +1488,24 @@ async function buildContext(manifest, dataDir, authMw) {
|
|
|
1462
1488
|
},
|
|
1463
1489
|
getSystemsConfig: () => readSystemsConfig(),
|
|
1464
1490
|
announceToSystem: (text) => announceToSystem(text),
|
|
1491
|
+
recordNotice: async (mindName, text) => {
|
|
1492
|
+
try {
|
|
1493
|
+
const user = await getUserByUsername(mindName);
|
|
1494
|
+
if (user?.user_type !== "mind") return;
|
|
1495
|
+
await recordNotice({
|
|
1496
|
+
mind: mindName,
|
|
1497
|
+
session: MIND_LEVEL_SESSION,
|
|
1498
|
+
kind: "extension",
|
|
1499
|
+
reason: manifest.id,
|
|
1500
|
+
detail: text.slice(0, 500)
|
|
1501
|
+
});
|
|
1502
|
+
} catch (err) {
|
|
1503
|
+
logger_default.warn(
|
|
1504
|
+
`extension ${manifest.id}: failed to record notice for ${mindName}`,
|
|
1505
|
+
logger_default.errorData(err)
|
|
1506
|
+
);
|
|
1507
|
+
}
|
|
1508
|
+
},
|
|
1465
1509
|
isIsolationEnabled,
|
|
1466
1510
|
getMindUser: mindUserName,
|
|
1467
1511
|
dataDir
|
|
@@ -1646,9 +1690,9 @@ function resolveSkillsDir(manifest) {
|
|
|
1646
1690
|
}
|
|
1647
1691
|
async function discoverBuiltinExtensions(disabledIds) {
|
|
1648
1692
|
const builtins = [
|
|
1649
|
-
{ id: "notes", load: async () => (await import("./src-
|
|
1650
|
-
{ id: "pages", load: async () => (await import("./src-
|
|
1651
|
-
{ id: "plan", load: async () => (await import("./src-
|
|
1693
|
+
{ id: "notes", load: async () => (await import("./src-YH6PQ7LJ.js")).default },
|
|
1694
|
+
{ id: "pages", load: async () => (await import("./src-XFY3XDD6.js")).default },
|
|
1695
|
+
{ id: "plan", load: async () => (await import("./src-JAOVXO5W.js")).default }
|
|
1652
1696
|
];
|
|
1653
1697
|
const results = [];
|
|
1654
1698
|
for (const { id, load } of builtins) {
|
|
@@ -1781,6 +1825,15 @@ async function loadAllExtensions(app, authMw) {
|
|
|
1781
1825
|
}
|
|
1782
1826
|
return c.json(result);
|
|
1783
1827
|
});
|
|
1828
|
+
app.get("/api/extensions/mind-docs", (c) => {
|
|
1829
|
+
const result = loaded.filter(({ manifest }) => manifest.mindDoc || manifest.commands).map(({ manifest }) => ({
|
|
1830
|
+
id: manifest.id,
|
|
1831
|
+
name: manifest.name,
|
|
1832
|
+
mindDoc: manifest.mindDoc ?? manifest.description ?? "",
|
|
1833
|
+
commands: Object.keys(manifest.commands ?? {})
|
|
1834
|
+
}));
|
|
1835
|
+
return c.json(result);
|
|
1836
|
+
});
|
|
1784
1837
|
}
|
|
1785
1838
|
function getLoadedExtensions() {
|
|
1786
1839
|
return loaded.map(({ manifest }) => {
|
|
@@ -1888,7 +1941,7 @@ async function installNpmExtension(pkg) {
|
|
|
1888
1941
|
throw new Error(`Extension "${pkg}" is already installed`);
|
|
1889
1942
|
}
|
|
1890
1943
|
const dir = ensureExtensionsNpmDir();
|
|
1891
|
-
const { exec: exec2 } = await import("./exec-
|
|
1944
|
+
const { exec: exec2 } = await import("./exec-4GWHAHS3.js");
|
|
1892
1945
|
try {
|
|
1893
1946
|
await exec2("npm", ["install", "--ignore-scripts", pkg], { cwd: dir });
|
|
1894
1947
|
} catch (err) {
|
|
@@ -1909,7 +1962,7 @@ async function uninstallNpmExtension(pkg) {
|
|
|
1909
1962
|
packages.splice(idx, 1);
|
|
1910
1963
|
writeExtensionsConfig(packages);
|
|
1911
1964
|
try {
|
|
1912
|
-
const { exec: exec2 } = await import("./exec-
|
|
1965
|
+
const { exec: exec2 } = await import("./exec-4GWHAHS3.js");
|
|
1913
1966
|
await exec2("npm", ["uninstall", "--ignore-scripts", pkg], { cwd: extensionsNpmDir() });
|
|
1914
1967
|
} catch (err) {
|
|
1915
1968
|
logger_default.warn(
|
|
@@ -2466,24 +2519,24 @@ var TokenBudget = class {
|
|
|
2466
2519
|
this.budgets.delete(mind);
|
|
2467
2520
|
}
|
|
2468
2521
|
recordUsage(mind, inputTokens, outputTokens) {
|
|
2469
|
-
const
|
|
2470
|
-
if (!
|
|
2471
|
-
|
|
2522
|
+
const state2 = this.budgets.get(mind);
|
|
2523
|
+
if (!state2) return;
|
|
2524
|
+
state2.tokensUsed += inputTokens + outputTokens;
|
|
2472
2525
|
this.dirty.add(mind);
|
|
2473
2526
|
}
|
|
2474
2527
|
/** Returns current budget status. Does not mutate state — call acknowledgeWarning() after delivering a warning. */
|
|
2475
2528
|
checkBudget(mind) {
|
|
2476
|
-
const
|
|
2477
|
-
if (!
|
|
2478
|
-
const pct =
|
|
2529
|
+
const state2 = this.budgets.get(mind);
|
|
2530
|
+
if (!state2) return "ok";
|
|
2531
|
+
const pct = state2.tokensUsed / state2.tokenLimit;
|
|
2479
2532
|
if (pct >= 1) return "exceeded";
|
|
2480
|
-
if (pct >= 0.8 && !
|
|
2533
|
+
if (pct >= 0.8 && !state2.warningInjected) return "warning";
|
|
2481
2534
|
return "ok";
|
|
2482
2535
|
}
|
|
2483
2536
|
/** Mark warning as delivered for this period. Call after successfully injecting the warning. */
|
|
2484
2537
|
acknowledgeWarning(mind) {
|
|
2485
|
-
const
|
|
2486
|
-
if (
|
|
2538
|
+
const state2 = this.budgets.get(mind);
|
|
2539
|
+
if (state2) state2.warningInjected = true;
|
|
2487
2540
|
}
|
|
2488
2541
|
/**
|
|
2489
2542
|
* Returns true exactly once per budget period when the mind first crosses its limit,
|
|
@@ -2491,50 +2544,50 @@ var TokenBudget = class {
|
|
|
2491
2544
|
* every subsequent usage event. The flag resets when the period rolls over.
|
|
2492
2545
|
*/
|
|
2493
2546
|
noteExceeded(mind) {
|
|
2494
|
-
const
|
|
2495
|
-
if (!
|
|
2496
|
-
if (
|
|
2497
|
-
if (
|
|
2498
|
-
|
|
2547
|
+
const state2 = this.budgets.get(mind);
|
|
2548
|
+
if (!state2) return false;
|
|
2549
|
+
if (state2.tokensUsed < state2.tokenLimit) return false;
|
|
2550
|
+
if (state2.exceededNotified) return false;
|
|
2551
|
+
state2.exceededNotified = true;
|
|
2499
2552
|
this.dirty.add(mind);
|
|
2500
2553
|
return true;
|
|
2501
2554
|
}
|
|
2502
2555
|
enqueue(mind, message) {
|
|
2503
|
-
const
|
|
2504
|
-
if (!
|
|
2505
|
-
if (
|
|
2506
|
-
|
|
2556
|
+
const state2 = this.budgets.get(mind);
|
|
2557
|
+
if (!state2) return;
|
|
2558
|
+
if (state2.queue.length >= MAX_QUEUE_SIZE) {
|
|
2559
|
+
state2.queue.shift();
|
|
2507
2560
|
}
|
|
2508
|
-
|
|
2561
|
+
state2.queue.push(message);
|
|
2509
2562
|
}
|
|
2510
2563
|
drain(mind) {
|
|
2511
|
-
const
|
|
2512
|
-
if (!
|
|
2513
|
-
const messages2 =
|
|
2514
|
-
|
|
2564
|
+
const state2 = this.budgets.get(mind);
|
|
2565
|
+
if (!state2) return [];
|
|
2566
|
+
const messages2 = state2.queue;
|
|
2567
|
+
state2.queue = [];
|
|
2515
2568
|
return messages2;
|
|
2516
2569
|
}
|
|
2517
2570
|
getUsage(mind) {
|
|
2518
|
-
const
|
|
2519
|
-
if (!
|
|
2571
|
+
const state2 = this.budgets.get(mind);
|
|
2572
|
+
if (!state2) return null;
|
|
2520
2573
|
return {
|
|
2521
|
-
tokensUsed:
|
|
2522
|
-
tokenLimit:
|
|
2523
|
-
periodMinutes:
|
|
2524
|
-
periodStart:
|
|
2525
|
-
queueLength:
|
|
2526
|
-
percentUsed: Math.round(
|
|
2574
|
+
tokensUsed: state2.tokensUsed,
|
|
2575
|
+
tokenLimit: state2.tokenLimit,
|
|
2576
|
+
periodMinutes: state2.periodMinutes,
|
|
2577
|
+
periodStart: state2.periodStart,
|
|
2578
|
+
queueLength: state2.queue.length,
|
|
2579
|
+
percentUsed: Math.round(state2.tokensUsed / state2.tokenLimit * 100)
|
|
2527
2580
|
};
|
|
2528
2581
|
}
|
|
2529
2582
|
async tick() {
|
|
2530
2583
|
const now = Date.now();
|
|
2531
|
-
for (const [mind,
|
|
2532
|
-
const elapsed = now -
|
|
2533
|
-
if (elapsed >=
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2584
|
+
for (const [mind, state2] of this.budgets) {
|
|
2585
|
+
const elapsed = now - state2.periodStart;
|
|
2586
|
+
if (elapsed >= state2.periodMinutes * 6e4) {
|
|
2587
|
+
state2.tokensUsed = 0;
|
|
2588
|
+
state2.periodStart = now;
|
|
2589
|
+
state2.warningInjected = false;
|
|
2590
|
+
state2.exceededNotified = false;
|
|
2538
2591
|
this.dirty.add(mind);
|
|
2539
2592
|
const queued = this.drain(mind);
|
|
2540
2593
|
if (queued.length > 0) {
|
|
@@ -2552,24 +2605,24 @@ var TokenBudget = class {
|
|
|
2552
2605
|
this.dirty.clear();
|
|
2553
2606
|
const writes = [];
|
|
2554
2607
|
for (const mind of flushing) {
|
|
2555
|
-
const
|
|
2556
|
-
if (
|
|
2608
|
+
const state2 = this.budgets.get(mind);
|
|
2609
|
+
if (state2) writes.push(this.saveBudgetState(mind, state2).catch(() => this.dirty.add(mind)));
|
|
2557
2610
|
}
|
|
2558
2611
|
await Promise.all(writes);
|
|
2559
2612
|
}
|
|
2560
2613
|
budgetStatePath(mind) {
|
|
2561
2614
|
return resolve6(stateDir(mind), "budget.json");
|
|
2562
2615
|
}
|
|
2563
|
-
async saveBudgetState(mind,
|
|
2616
|
+
async saveBudgetState(mind, state2) {
|
|
2564
2617
|
try {
|
|
2565
2618
|
const dir = stateDir(mind);
|
|
2566
2619
|
await mkdir(dir, { recursive: true });
|
|
2567
2620
|
const data = {
|
|
2568
|
-
periodStart:
|
|
2569
|
-
tokensUsed:
|
|
2570
|
-
warningInjected:
|
|
2571
|
-
exceededNotified:
|
|
2572
|
-
queue:
|
|
2621
|
+
periodStart: state2.periodStart,
|
|
2622
|
+
tokensUsed: state2.tokensUsed,
|
|
2623
|
+
warningInjected: state2.warningInjected,
|
|
2624
|
+
exceededNotified: state2.exceededNotified,
|
|
2625
|
+
queue: state2.queue
|
|
2573
2626
|
};
|
|
2574
2627
|
await writeFile2(this.budgetStatePath(mind), `${JSON.stringify(data)}
|
|
2575
2628
|
`);
|
|
@@ -2615,8 +2668,8 @@ ${summary}`
|
|
|
2615
2668
|
tlog.info(`replayed ${messages2.length} queued message(s) for ${mindName}`);
|
|
2616
2669
|
} catch (err) {
|
|
2617
2670
|
tlog.warn(`failed to replay for ${mindName}`, logger_default.errorData(err));
|
|
2618
|
-
const
|
|
2619
|
-
if (
|
|
2671
|
+
const state2 = this.budgets.get(mindName);
|
|
2672
|
+
if (state2) state2.queue.push(...messages2);
|
|
2620
2673
|
}
|
|
2621
2674
|
}
|
|
2622
2675
|
};
|
|
@@ -2710,7 +2763,7 @@ async function wakeMind(name) {
|
|
|
2710
2763
|
async function startSpiritFull(name) {
|
|
2711
2764
|
const entry = await findMind(name);
|
|
2712
2765
|
if (entry?.dir) {
|
|
2713
|
-
const { registerMindDir } = await import("./delivery-router-
|
|
2766
|
+
const { registerMindDir } = await import("./delivery-router-GODSIS62.js");
|
|
2714
2767
|
registerMindDir(name, entry.dir);
|
|
2715
2768
|
}
|
|
2716
2769
|
await getMindManager().startMind(name);
|
|
@@ -2732,8 +2785,8 @@ async function stopSpiritFull(name) {
|
|
|
2732
2785
|
}).catch((err) => logger_default.error("failed to publish spirit_stopped activity", logger_default.errorData(err)));
|
|
2733
2786
|
}
|
|
2734
2787
|
async function ensureCreatorDM(mindName, creatorUsername) {
|
|
2735
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-
|
|
2736
|
-
const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-
|
|
2788
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-FRZJVQCS.js");
|
|
2789
|
+
const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-WAJYZKOC.js");
|
|
2737
2790
|
const mindUser = await getOrCreateMindUser2(mindName);
|
|
2738
2791
|
const creatorUser = await getUserByUsername2(creatorUsername);
|
|
2739
2792
|
if (!creatorUser) {
|
|
@@ -2826,9 +2879,9 @@ var SleepManager = class {
|
|
|
2826
2879
|
try {
|
|
2827
2880
|
if (existsSync8(this.statePath)) {
|
|
2828
2881
|
const data = JSON.parse(readFileSync7(this.statePath, "utf-8"));
|
|
2829
|
-
for (const [name,
|
|
2830
|
-
|
|
2831
|
-
this.states.set(name,
|
|
2882
|
+
for (const [name, state2] of Object.entries(data)) {
|
|
2883
|
+
state2.triggerWakeHistory ??= [];
|
|
2884
|
+
this.states.set(name, state2);
|
|
2832
2885
|
}
|
|
2833
2886
|
}
|
|
2834
2887
|
} catch (err) {
|
|
@@ -2837,8 +2890,8 @@ var SleepManager = class {
|
|
|
2837
2890
|
}
|
|
2838
2891
|
saveState() {
|
|
2839
2892
|
const data = {};
|
|
2840
|
-
for (const [name,
|
|
2841
|
-
if (
|
|
2893
|
+
for (const [name, state2] of this.states) {
|
|
2894
|
+
if (state2.sleeping) data[name] = state2;
|
|
2842
2895
|
}
|
|
2843
2896
|
try {
|
|
2844
2897
|
writeFileSync6(this.statePath, `${JSON.stringify(data, null, 2)}
|
|
@@ -2849,9 +2902,9 @@ var SleepManager = class {
|
|
|
2849
2902
|
}
|
|
2850
2903
|
// --- Public API ---
|
|
2851
2904
|
isSleeping(name) {
|
|
2852
|
-
const
|
|
2853
|
-
if (!
|
|
2854
|
-
if (
|
|
2905
|
+
const state2 = this.states.get(name);
|
|
2906
|
+
if (!state2?.sleeping) return false;
|
|
2907
|
+
if (state2.wokenByTrigger) return false;
|
|
2855
2908
|
return true;
|
|
2856
2909
|
}
|
|
2857
2910
|
getState(name) {
|
|
@@ -2862,8 +2915,8 @@ var SleepManager = class {
|
|
|
2862
2915
|
* this just clears the sleep state so onActivityEvent won't return it to sleep.
|
|
2863
2916
|
*/
|
|
2864
2917
|
convertTriggerToFullWake(name) {
|
|
2865
|
-
const
|
|
2866
|
-
if (!
|
|
2918
|
+
const state2 = this.states.get(name);
|
|
2919
|
+
if (!state2?.sleeping || !state2.wokenByTrigger) return;
|
|
2867
2920
|
this.markAwake(name);
|
|
2868
2921
|
slog3.info(`${name} trigger-wake converted to full wake`);
|
|
2869
2922
|
}
|
|
@@ -2875,11 +2928,11 @@ var SleepManager = class {
|
|
|
2875
2928
|
* return-to-sleep in onActivityEvent, minus stopping an already-dead process.
|
|
2876
2929
|
*/
|
|
2877
2930
|
async returnToSleepAfterCrash(name) {
|
|
2878
|
-
const
|
|
2879
|
-
if (!
|
|
2931
|
+
const state2 = this.states.get(name);
|
|
2932
|
+
if (!state2?.sleeping || !state2.wokenByTrigger) return;
|
|
2880
2933
|
if (this.transitioning.has(name)) return;
|
|
2881
2934
|
this.transitioning.add(name);
|
|
2882
|
-
|
|
2935
|
+
state2.wokenByTrigger = false;
|
|
2883
2936
|
try {
|
|
2884
2937
|
try {
|
|
2885
2938
|
await sleepMind(name);
|
|
@@ -2887,9 +2940,9 @@ var SleepManager = class {
|
|
|
2887
2940
|
slog3.warn(`sleepMind during crash-return failed for ${name}`, logger_default.errorData(err));
|
|
2888
2941
|
}
|
|
2889
2942
|
await this.archiveSessions(name);
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2943
|
+
state2.sleeping = true;
|
|
2944
|
+
state2.sleepingSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
2945
|
+
state2.scheduledWakeAt = this.getNextWakeTime(this.getSleepConfig(name));
|
|
2893
2946
|
this.saveState();
|
|
2894
2947
|
slog3.info(`${name} returned to sleep after crashing during trigger wake`);
|
|
2895
2948
|
} catch (err) {
|
|
@@ -2973,8 +3026,8 @@ var SleepManager = class {
|
|
|
2973
3026
|
* Wake a sleeping mind. Starts the process, delivers wake summary.
|
|
2974
3027
|
*/
|
|
2975
3028
|
async initiateWake(name, opts) {
|
|
2976
|
-
const
|
|
2977
|
-
if (!
|
|
3029
|
+
const state2 = this.states.get(name);
|
|
3030
|
+
if (!state2?.sleeping) return;
|
|
2978
3031
|
if (this.transitioning.has(name)) return;
|
|
2979
3032
|
this.transitioning.add(name);
|
|
2980
3033
|
try {
|
|
@@ -2990,14 +3043,14 @@ var SleepManager = class {
|
|
|
2990
3043
|
const entry = await findMind(name);
|
|
2991
3044
|
if (!entry) return;
|
|
2992
3045
|
if (opts?.trigger) {
|
|
2993
|
-
|
|
2994
|
-
|
|
3046
|
+
state2.wokenByTrigger = true;
|
|
3047
|
+
state2.triggerWakeHistory.push({
|
|
2995
3048
|
channel: opts.trigger.channel,
|
|
2996
3049
|
at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2997
3050
|
});
|
|
2998
3051
|
this.saveState();
|
|
2999
3052
|
} else {
|
|
3000
|
-
const sleepingSince =
|
|
3053
|
+
const sleepingSince = state2.sleepingSince ? new Date(state2.sleepingSince) : /* @__PURE__ */ new Date();
|
|
3001
3054
|
const now = /* @__PURE__ */ new Date();
|
|
3002
3055
|
const duration = formatDuration(sleepingSince, now);
|
|
3003
3056
|
const currentDate = formatCurrentDate();
|
|
@@ -3005,10 +3058,10 @@ var SleepManager = class {
|
|
|
3005
3058
|
hour: "numeric",
|
|
3006
3059
|
minute: "2-digit"
|
|
3007
3060
|
});
|
|
3008
|
-
const triggerWakeSummary = this.buildTriggerWakeSummary(
|
|
3061
|
+
const triggerWakeSummary = this.buildTriggerWakeSummary(state2);
|
|
3009
3062
|
const wakeContext = await this.runWakeContextScript(
|
|
3010
3063
|
name,
|
|
3011
|
-
|
|
3064
|
+
state2.sleepingSince ?? sleepingSince.toISOString(),
|
|
3012
3065
|
duration
|
|
3013
3066
|
);
|
|
3014
3067
|
const queuedSummary = await this.buildQueuedSummary(name);
|
|
@@ -3094,9 +3147,9 @@ var SleepManager = class {
|
|
|
3094
3147
|
status: "sleep-queued",
|
|
3095
3148
|
payload: JSON.stringify(payload)
|
|
3096
3149
|
});
|
|
3097
|
-
const
|
|
3098
|
-
if (
|
|
3099
|
-
|
|
3150
|
+
const state2 = this.states.get(name);
|
|
3151
|
+
if (state2) {
|
|
3152
|
+
state2.queuedMessageCount++;
|
|
3100
3153
|
this.saveState();
|
|
3101
3154
|
}
|
|
3102
3155
|
}
|
|
@@ -3108,7 +3161,7 @@ var SleepManager = class {
|
|
|
3108
3161
|
const db = await getDb();
|
|
3109
3162
|
const rows = await db.select().from(deliveryQueue).where(and2(eq3(deliveryQueue.mind, name), eq3(deliveryQueue.status, "sleep-queued"))).all();
|
|
3110
3163
|
if (rows.length === 0) return 0;
|
|
3111
|
-
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-
|
|
3164
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-2EA5LLMD.js");
|
|
3112
3165
|
const delivered = [];
|
|
3113
3166
|
for (const row of rows) {
|
|
3114
3167
|
try {
|
|
@@ -3121,9 +3174,9 @@ var SleepManager = class {
|
|
|
3121
3174
|
if (delivered.length > 0) {
|
|
3122
3175
|
await db.delete(deliveryQueue).where(inArray(deliveryQueue.id, delivered));
|
|
3123
3176
|
}
|
|
3124
|
-
const
|
|
3125
|
-
if (
|
|
3126
|
-
|
|
3177
|
+
const state2 = this.states.get(name);
|
|
3178
|
+
if (state2) {
|
|
3179
|
+
state2.queuedMessageCount = Math.max(0, state2.queuedMessageCount - delivered.length);
|
|
3127
3180
|
}
|
|
3128
3181
|
return delivered.length;
|
|
3129
3182
|
} catch (err) {
|
|
@@ -3134,7 +3187,7 @@ var SleepManager = class {
|
|
|
3134
3187
|
// --- Internal methods ---
|
|
3135
3188
|
markSleeping(name, opts) {
|
|
3136
3189
|
const sleepConfig = this.getSleepConfig(name);
|
|
3137
|
-
const
|
|
3190
|
+
const state2 = {
|
|
3138
3191
|
sleeping: true,
|
|
3139
3192
|
sleepingSince: (/* @__PURE__ */ new Date()).toISOString(),
|
|
3140
3193
|
scheduledWakeAt: this.getNextWakeTime(sleepConfig),
|
|
@@ -3143,7 +3196,7 @@ var SleepManager = class {
|
|
|
3143
3196
|
queuedMessageCount: this.states.get(name)?.queuedMessageCount ?? 0,
|
|
3144
3197
|
triggerWakeHistory: []
|
|
3145
3198
|
};
|
|
3146
|
-
this.states.set(name,
|
|
3199
|
+
this.states.set(name, state2);
|
|
3147
3200
|
this.saveState();
|
|
3148
3201
|
}
|
|
3149
3202
|
markAwake(name) {
|
|
@@ -3171,9 +3224,9 @@ var SleepManager = class {
|
|
|
3171
3224
|
}
|
|
3172
3225
|
const config = this.getSleepConfig(name);
|
|
3173
3226
|
if (!config?.enabled || !config.schedule) continue;
|
|
3174
|
-
const
|
|
3175
|
-
if (
|
|
3176
|
-
const wakeAt = new Date(
|
|
3227
|
+
const state2 = this.states.get(name);
|
|
3228
|
+
if (state2?.sleeping && state2.voluntaryWakeAt) {
|
|
3229
|
+
const wakeAt = new Date(state2.voluntaryWakeAt);
|
|
3177
3230
|
if (now >= wakeAt) {
|
|
3178
3231
|
this.initiateWake(name).catch(
|
|
3179
3232
|
(err) => slog3.error(`failed voluntary wake for ${name}`, logger_default.errorData(err))
|
|
@@ -3181,8 +3234,8 @@ var SleepManager = class {
|
|
|
3181
3234
|
continue;
|
|
3182
3235
|
}
|
|
3183
3236
|
}
|
|
3184
|
-
if (
|
|
3185
|
-
const wakeAt = new Date(
|
|
3237
|
+
if (state2?.sleeping && state2.scheduledWakeAt) {
|
|
3238
|
+
const wakeAt = new Date(state2.scheduledWakeAt);
|
|
3186
3239
|
if (now >= wakeAt) {
|
|
3187
3240
|
this.initiateWake(name).catch(
|
|
3188
3241
|
(err) => slog3.error(`failed scheduled wake for ${name}`, logger_default.errorData(err))
|
|
@@ -3190,7 +3243,7 @@ var SleepManager = class {
|
|
|
3190
3243
|
continue;
|
|
3191
3244
|
}
|
|
3192
3245
|
}
|
|
3193
|
-
if (!
|
|
3246
|
+
if (!state2?.sleeping) {
|
|
3194
3247
|
if (this.shouldSleep(config.schedule.sleep, epochMinute)) {
|
|
3195
3248
|
this.initiateSleep(name).catch(
|
|
3196
3249
|
(err) => slog3.error(`failed to initiate sleep for ${name}`, logger_default.errorData(err))
|
|
@@ -3303,8 +3356,8 @@ var SleepManager = class {
|
|
|
3303
3356
|
return "";
|
|
3304
3357
|
}
|
|
3305
3358
|
}
|
|
3306
|
-
buildTriggerWakeSummary(
|
|
3307
|
-
const history =
|
|
3359
|
+
buildTriggerWakeSummary(state2) {
|
|
3360
|
+
const history = state2.triggerWakeHistory;
|
|
3308
3361
|
if (!history || history.length === 0) return "";
|
|
3309
3362
|
const channels = [...new Set(history.map((h) => h.channel))];
|
|
3310
3363
|
const times = history.length === 1 ? "once" : `${history.length} times`;
|
|
@@ -3390,18 +3443,18 @@ var SleepManager = class {
|
|
|
3390
3443
|
await new Promise((r) => setTimeout(r, 1e3));
|
|
3391
3444
|
}
|
|
3392
3445
|
onActivityEvent(event) {
|
|
3393
|
-
const
|
|
3394
|
-
if (!
|
|
3446
|
+
const state2 = this.states.get(event.mind);
|
|
3447
|
+
if (!state2?.sleeping || !state2.wokenByTrigger) return;
|
|
3395
3448
|
if (this.transitioning.has(event.mind)) return;
|
|
3396
3449
|
if (event.type === "mind_idle") {
|
|
3397
3450
|
slog3.info(`${event.mind} going back to sleep after trigger wake`);
|
|
3398
|
-
|
|
3451
|
+
state2.wokenByTrigger = false;
|
|
3399
3452
|
this.transitioning.add(event.mind);
|
|
3400
3453
|
sleepMind(event.mind).then(() => this.archiveSessions(event.mind)).then(() => {
|
|
3401
|
-
|
|
3402
|
-
|
|
3454
|
+
state2.sleeping = true;
|
|
3455
|
+
state2.sleepingSince = (/* @__PURE__ */ new Date()).toISOString();
|
|
3403
3456
|
const sleepConfig = this.getSleepConfig(event.mind);
|
|
3404
|
-
|
|
3457
|
+
state2.scheduledWakeAt = this.getNextWakeTime(sleepConfig);
|
|
3405
3458
|
this.saveState();
|
|
3406
3459
|
slog3.info(`${event.mind} returned to sleep`);
|
|
3407
3460
|
}).catch((err) => {
|
|
@@ -3429,7 +3482,7 @@ function getSleepManagerIfReady() {
|
|
|
3429
3482
|
// packages/daemon/src/lib/delivery/delivery-manager.ts
|
|
3430
3483
|
import { readFile, realpath } from "fs/promises";
|
|
3431
3484
|
import { extname, resolve as resolve8 } from "path";
|
|
3432
|
-
import { and as
|
|
3485
|
+
import { and as and4, eq as eq5, inArray as inArray2, sql as sql2 } from "drizzle-orm";
|
|
3433
3486
|
|
|
3434
3487
|
// packages/daemon/src/lib/chat/typing.ts
|
|
3435
3488
|
var DEFAULT_TTL_MS = 1e4;
|
|
@@ -3522,6 +3575,73 @@ function publishTypingForChannels(channels, map) {
|
|
|
3522
3575
|
}
|
|
3523
3576
|
}
|
|
3524
3577
|
|
|
3578
|
+
// packages/daemon/src/lib/delivery/send-gate.ts
|
|
3579
|
+
import { and as and3, asc as asc2, desc, eq as eq4, gt } from "drizzle-orm";
|
|
3580
|
+
var state = /* @__PURE__ */ new Map();
|
|
3581
|
+
function extractText(raw) {
|
|
3582
|
+
if (!raw) return "";
|
|
3583
|
+
try {
|
|
3584
|
+
const blocks = JSON.parse(raw);
|
|
3585
|
+
if (Array.isArray(blocks)) {
|
|
3586
|
+
return blocks.filter((b) => b?.type === "text" && typeof b.text === "string").map((b) => b.text).join(" ").trim();
|
|
3587
|
+
}
|
|
3588
|
+
} catch {
|
|
3589
|
+
}
|
|
3590
|
+
return String(raw);
|
|
3591
|
+
}
|
|
3592
|
+
async function maxMessageId(conversationId) {
|
|
3593
|
+
const db = await getDb();
|
|
3594
|
+
const rows = await db.select({ id: messages.id }).from(messages).where(eq4(messages.conversation_id, conversationId)).orderBy(desc(messages.id)).limit(1);
|
|
3595
|
+
return rows[0]?.id ?? 0;
|
|
3596
|
+
}
|
|
3597
|
+
async function onDeliveredToMind(mindBase, conversationId) {
|
|
3598
|
+
if (!conversationId) return;
|
|
3599
|
+
let conv = state.get(mindBase);
|
|
3600
|
+
if (!conv) {
|
|
3601
|
+
conv = /* @__PURE__ */ new Map();
|
|
3602
|
+
state.set(mindBase, conv);
|
|
3603
|
+
}
|
|
3604
|
+
const existing = conv.get(conversationId);
|
|
3605
|
+
if (existing?.turnOpen) return;
|
|
3606
|
+
const baselineId = await maxMessageId(conversationId);
|
|
3607
|
+
conv.set(conversationId, { baselineId, heldThisTurn: false, turnOpen: true });
|
|
3608
|
+
}
|
|
3609
|
+
async function checkStaleSend(mindBase, conversationId, excludeSenders) {
|
|
3610
|
+
const entry = state.get(mindBase)?.get(conversationId);
|
|
3611
|
+
if (!entry?.turnOpen || entry.heldThisTurn) return { held: false };
|
|
3612
|
+
const db = await getDb();
|
|
3613
|
+
const rows = await db.select({ id: messages.id, sender: messages.sender_name, content: messages.content }).from(messages).where(and3(eq4(messages.conversation_id, conversationId), gt(messages.id, entry.baselineId))).orderBy(asc2(messages.id));
|
|
3614
|
+
const excluded = new Set(excludeSenders.filter(Boolean));
|
|
3615
|
+
const unseen = rows.filter((r) => r.sender && !excluded.has(r.sender));
|
|
3616
|
+
if (unseen.length === 0) return { held: false };
|
|
3617
|
+
entry.heldThisTurn = true;
|
|
3618
|
+
entry.baselineId = rows[rows.length - 1].id;
|
|
3619
|
+
return {
|
|
3620
|
+
held: true,
|
|
3621
|
+
unseen: unseen.map((r) => ({ sender: r.sender, text: extractText(r.content) }))
|
|
3622
|
+
};
|
|
3623
|
+
}
|
|
3624
|
+
function resetTurn(mindBase) {
|
|
3625
|
+
const conv = state.get(mindBase);
|
|
3626
|
+
if (!conv) return;
|
|
3627
|
+
for (const entry of conv.values()) {
|
|
3628
|
+
entry.turnOpen = false;
|
|
3629
|
+
entry.heldThisTurn = false;
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
function formatHoldNotice(channelLabel, unseen) {
|
|
3633
|
+
const lines = unseen.map((m) => {
|
|
3634
|
+
const t = m.text.length > 120 ? `${m.text.slice(0, 119)}\u2026` : m.text;
|
|
3635
|
+
return ` ${m.sender}: ${JSON.stringify(t)}`;
|
|
3636
|
+
});
|
|
3637
|
+
const n = unseen.length;
|
|
3638
|
+
return [
|
|
3639
|
+
`\u26A0 Not sent \u2014 ${n} newer message${n === 1 ? "" : "s"} arrived on ${channelLabel} while you were composing:`,
|
|
3640
|
+
...lines,
|
|
3641
|
+
"Your message was NOT posted. Revise it in light of these, or run the same send again to post as-is."
|
|
3642
|
+
].join("\n");
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3525
3645
|
// packages/daemon/src/lib/delivery/delivery-manager.ts
|
|
3526
3646
|
var dlog = logger_default.child("delivery-manager");
|
|
3527
3647
|
var MAX_BATCH_SIZE = 50;
|
|
@@ -3638,6 +3758,7 @@ var DeliveryManager = class {
|
|
|
3638
3758
|
* causing isSessionBusy to return true even when no deliveries are pending.
|
|
3639
3759
|
*/
|
|
3640
3760
|
sessionDone(baseName, session) {
|
|
3761
|
+
resetTurn(baseName);
|
|
3641
3762
|
if (session) {
|
|
3642
3763
|
this.decrementActive(baseName, session);
|
|
3643
3764
|
} else {
|
|
@@ -3675,8 +3796,8 @@ var DeliveryManager = class {
|
|
|
3675
3796
|
try {
|
|
3676
3797
|
const db = await getDb();
|
|
3677
3798
|
rows = await db.select().from(deliveryQueue).where(
|
|
3678
|
-
|
|
3679
|
-
|
|
3799
|
+
and4(
|
|
3800
|
+
eq5(deliveryQueue.status, "pending"),
|
|
3680
3801
|
sql2`(${deliveryQueue.next_attempt_at} IS NULL OR ${deliveryQueue.next_attempt_at} <= datetime('now'))`
|
|
3681
3802
|
)
|
|
3682
3803
|
).orderBy(deliveryQueue.id).limit(REDRIVE_BATCH_LIMIT);
|
|
@@ -3731,7 +3852,7 @@ var DeliveryManager = class {
|
|
|
3731
3852
|
let rows;
|
|
3732
3853
|
try {
|
|
3733
3854
|
const db = await getDb();
|
|
3734
|
-
rows = await db.select().from(deliveryQueue).where(
|
|
3855
|
+
rows = await db.select().from(deliveryQueue).where(and4(eq5(deliveryQueue.mind, baseName), eq5(deliveryQueue.status, "gated")));
|
|
3735
3856
|
} catch (err) {
|
|
3736
3857
|
dlog.warn(`failed to read gated rows for ${baseName}`, logger_default.errorData(err));
|
|
3737
3858
|
return;
|
|
@@ -3771,7 +3892,7 @@ var DeliveryManager = class {
|
|
|
3771
3892
|
*/
|
|
3772
3893
|
async getPending(mindName) {
|
|
3773
3894
|
const db = await getDb();
|
|
3774
|
-
const rows = await db.select().from(deliveryQueue).where(
|
|
3895
|
+
const rows = await db.select().from(deliveryQueue).where(and4(eq5(deliveryQueue.mind, mindName), eq5(deliveryQueue.status, "gated")));
|
|
3775
3896
|
const byChannel = /* @__PURE__ */ new Map();
|
|
3776
3897
|
for (const row of rows) {
|
|
3777
3898
|
const ch = row.channel ?? "unknown";
|
|
@@ -3796,8 +3917,8 @@ var DeliveryManager = class {
|
|
|
3796
3917
|
* Check if a session is currently busy (has active deliveries).
|
|
3797
3918
|
*/
|
|
3798
3919
|
isSessionBusy(mindName, session) {
|
|
3799
|
-
const
|
|
3800
|
-
return (
|
|
3920
|
+
const state2 = this.sessionStates.get(mindName)?.get(session);
|
|
3921
|
+
return (state2?.activeCount ?? 0) > 0;
|
|
3801
3922
|
}
|
|
3802
3923
|
/**
|
|
3803
3924
|
* Check if any session for a mind is currently busy.
|
|
@@ -3805,8 +3926,8 @@ var DeliveryManager = class {
|
|
|
3805
3926
|
isMindBusy(mindName) {
|
|
3806
3927
|
const mindSessions = this.sessionStates.get(mindName);
|
|
3807
3928
|
if (!mindSessions) return false;
|
|
3808
|
-
for (const [,
|
|
3809
|
-
if (
|
|
3929
|
+
for (const [, state2] of mindSessions) {
|
|
3930
|
+
if (state2.activeCount > 0) return true;
|
|
3810
3931
|
}
|
|
3811
3932
|
return false;
|
|
3812
3933
|
}
|
|
@@ -3844,10 +3965,10 @@ var DeliveryManager = class {
|
|
|
3844
3965
|
* count was reset.
|
|
3845
3966
|
*/
|
|
3846
3967
|
clearSessionActive(mindName, session, minIdleMs) {
|
|
3847
|
-
const
|
|
3848
|
-
if (!
|
|
3849
|
-
if (Date.now() -
|
|
3850
|
-
|
|
3968
|
+
const state2 = this.sessionStates.get(mindName)?.get(session);
|
|
3969
|
+
if (!state2) return false;
|
|
3970
|
+
if (Date.now() - state2.lastDeliveredAt < minIdleMs) return false;
|
|
3971
|
+
state2.activeCount = 0;
|
|
3851
3972
|
return true;
|
|
3852
3973
|
}
|
|
3853
3974
|
/**
|
|
@@ -3940,7 +4061,7 @@ var DeliveryManager = class {
|
|
|
3940
4061
|
const backoffSec = Math.round(
|
|
3941
4062
|
Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** Math.min(attempts, 20)) / 1e3
|
|
3942
4063
|
);
|
|
3943
|
-
await db.update(deliveryQueue).set({ attempts, next_attempt_at: sql2`datetime('now', ${`+${backoffSec} seconds`})` }).where(
|
|
4064
|
+
await db.update(deliveryQueue).set({ attempts, next_attempt_at: sql2`datetime('now', ${`+${backoffSec} seconds`})` }).where(eq5(deliveryQueue.id, row.id));
|
|
3944
4065
|
}
|
|
3945
4066
|
} catch (err) {
|
|
3946
4067
|
dlog.warn("failed to schedule delivery retry", logger_default.errorData(err));
|
|
@@ -3961,6 +4082,7 @@ var DeliveryManager = class {
|
|
|
3961
4082
|
const channels = /* @__PURE__ */ new Set();
|
|
3962
4083
|
if (payload.channel) channels.add(payload.channel);
|
|
3963
4084
|
this.incrementActive(baseName, session, senders, channels);
|
|
4085
|
+
await onDeliveredToMind(baseName, payload.conversationId);
|
|
3964
4086
|
linkInboundToActiveTurn(baseName, session, payload.channel).catch(
|
|
3965
4087
|
(err) => dlog.warn(`failed to link mid-turn inbound for ${baseName}`, logger_default.errorData(err))
|
|
3966
4088
|
);
|
|
@@ -3976,7 +4098,6 @@ var DeliveryManager = class {
|
|
|
3976
4098
|
const body = JSON.stringify({
|
|
3977
4099
|
...enrichedPayload,
|
|
3978
4100
|
session,
|
|
3979
|
-
interrupt: sessionConfig.interrupt,
|
|
3980
4101
|
instructions: sessionConfig.instructions
|
|
3981
4102
|
});
|
|
3982
4103
|
try {
|
|
@@ -3998,7 +4119,7 @@ var DeliveryManager = class {
|
|
|
3998
4119
|
}
|
|
3999
4120
|
});
|
|
4000
4121
|
}
|
|
4001
|
-
async deliverBatchToMind(mindName, session, messages2, sessionConfig
|
|
4122
|
+
async deliverBatchToMind(mindName, session, messages2, sessionConfig) {
|
|
4002
4123
|
const queueIds = messages2.map((m) => m.queueId).filter((id) => typeof id === "number");
|
|
4003
4124
|
await this.runSequential(`${mindName}:${session}`, async () => {
|
|
4004
4125
|
const resolved = await this.resolvePort(mindName);
|
|
@@ -4035,6 +4156,13 @@ var DeliveryManager = class {
|
|
|
4035
4156
|
if (msg.channel) channelSet.add(msg.channel);
|
|
4036
4157
|
}
|
|
4037
4158
|
this.incrementActive(baseName, session, senders, channelSet);
|
|
4159
|
+
const convIds = /* @__PURE__ */ new Set();
|
|
4160
|
+
for (const msg of messages2) {
|
|
4161
|
+
if (msg.payload.conversationId) convIds.add(msg.payload.conversationId);
|
|
4162
|
+
}
|
|
4163
|
+
for (const convId of convIds) {
|
|
4164
|
+
await onDeliveredToMind(baseName, convId);
|
|
4165
|
+
}
|
|
4038
4166
|
for (const ch of channelSet) {
|
|
4039
4167
|
linkInboundToActiveTurn(baseName, session, ch).catch(
|
|
4040
4168
|
(err) => dlog.warn(`failed to link mid-turn inbound for ${baseName}`, logger_default.errorData(err))
|
|
@@ -4054,7 +4182,6 @@ var DeliveryManager = class {
|
|
|
4054
4182
|
const body = JSON.stringify({
|
|
4055
4183
|
session,
|
|
4056
4184
|
batch: { channels },
|
|
4057
|
-
interrupt: interruptOverride ?? sessionConfig.interrupt,
|
|
4058
4185
|
instructions: sessionConfig.instructions
|
|
4059
4186
|
});
|
|
4060
4187
|
try {
|
|
@@ -4078,7 +4205,6 @@ var DeliveryManager = class {
|
|
|
4078
4205
|
}
|
|
4079
4206
|
async enqueueBatch(mindName, session, payload, sessionConfig) {
|
|
4080
4207
|
const delivery = sessionConfig.delivery;
|
|
4081
|
-
const baseName = await getBaseName(mindName);
|
|
4082
4208
|
const queueId = await this.persistToQueue(mindName, session, payload);
|
|
4083
4209
|
if (queueId != null) this.inFlight.add(queueId);
|
|
4084
4210
|
const msg = {
|
|
@@ -4096,12 +4222,6 @@ var DeliveryManager = class {
|
|
|
4096
4222
|
return;
|
|
4097
4223
|
}
|
|
4098
4224
|
}
|
|
4099
|
-
const state = this.sessionStates.get(baseName)?.get(session);
|
|
4100
|
-
if (state && state.activeCount > 0 && payload.sender && !state.lastDeliverySenders.has(payload.sender) && payload.channel && state.lastDeliveryChannels.has(payload.channel) && Date.now() - state.lastDeliveredAt < delivery.maxWait * 1e3 && Date.now() - state.lastInterruptAt > delivery.debounce * 1e3) {
|
|
4101
|
-
state.lastInterruptAt = Date.now();
|
|
4102
|
-
await this.flushBatch(mindName, session, [msg], true);
|
|
4103
|
-
return;
|
|
4104
|
-
}
|
|
4105
4225
|
this.addToBatchBuffer(mindName, session, sessionConfig, msg);
|
|
4106
4226
|
}
|
|
4107
4227
|
addToBatchBuffer(mindName, session, sessionConfig, msg) {
|
|
@@ -4141,7 +4261,7 @@ var DeliveryManager = class {
|
|
|
4141
4261
|
buffer.maxWaitTimer.unref();
|
|
4142
4262
|
}
|
|
4143
4263
|
}
|
|
4144
|
-
async flushBatch(mindName, session, extra
|
|
4264
|
+
async flushBatch(mindName, session, extra) {
|
|
4145
4265
|
const bufferKey = `${mindName}:${session}`;
|
|
4146
4266
|
const buffer = this.batchBuffers.get(bufferKey);
|
|
4147
4267
|
const messages2 = [];
|
|
@@ -4158,14 +4278,10 @@ var DeliveryManager = class {
|
|
|
4158
4278
|
const baseName = await getBaseName(mindName);
|
|
4159
4279
|
const config = getRoutingConfig(baseName);
|
|
4160
4280
|
const sessionConfig = resolveDeliveryMode(config, session);
|
|
4161
|
-
dlog.info(
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
(err) => {
|
|
4166
|
-
dlog.warn(`failed to flush batch for ${mindName}/${session}`, logger_default.errorData(err));
|
|
4167
|
-
}
|
|
4168
|
-
);
|
|
4281
|
+
dlog.info(`flushing batch for ${mindName}/${session}: ${messages2.length} messages`);
|
|
4282
|
+
this.deliverBatchToMind(mindName, session, messages2, sessionConfig).catch((err) => {
|
|
4283
|
+
dlog.warn(`failed to flush batch for ${mindName}/${session}`, logger_default.errorData(err));
|
|
4284
|
+
});
|
|
4169
4285
|
}
|
|
4170
4286
|
async gateMessage(mindName, session, payload) {
|
|
4171
4287
|
const baseName = await getBaseName(mindName);
|
|
@@ -4173,10 +4289,10 @@ var DeliveryManager = class {
|
|
|
4173
4289
|
try {
|
|
4174
4290
|
const db = await getDb();
|
|
4175
4291
|
const count = await db.select({ count: sql2`count(*)` }).from(deliveryQueue).where(
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4292
|
+
and4(
|
|
4293
|
+
eq5(deliveryQueue.mind, baseName),
|
|
4294
|
+
eq5(deliveryQueue.channel, payload.channel),
|
|
4295
|
+
eq5(deliveryQueue.status, "gated")
|
|
4180
4296
|
)
|
|
4181
4297
|
);
|
|
4182
4298
|
if ((count[0]?.count ?? 0) <= 1) {
|
|
@@ -4201,7 +4317,7 @@ var DeliveryManager = class {
|
|
|
4201
4317
|
`To accept this channel, add a routing rule for "${channel}" to your routes.json.`,
|
|
4202
4318
|
`Messages are being held until a route is configured.`
|
|
4203
4319
|
].filter((line) => line !== null).join("\n");
|
|
4204
|
-
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-
|
|
4320
|
+
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-4DQZOEZI.js");
|
|
4205
4321
|
await sendSystemMessage2(mindName, notification);
|
|
4206
4322
|
}
|
|
4207
4323
|
/**
|
|
@@ -4237,10 +4353,10 @@ var DeliveryManager = class {
|
|
|
4237
4353
|
async enrichWithProfiles(mindName, session, payload) {
|
|
4238
4354
|
if (!payload.conversationId || !payload.channel) return payload;
|
|
4239
4355
|
const mindSessions = this.sessionStates.get(mindName);
|
|
4240
|
-
const
|
|
4241
|
-
if (!
|
|
4356
|
+
const state2 = mindSessions?.get(session);
|
|
4357
|
+
if (!state2) return payload;
|
|
4242
4358
|
const channelKey = payload.channel;
|
|
4243
|
-
if (
|
|
4359
|
+
if (state2.seenChannelProfiles.has(channelKey)) return payload;
|
|
4244
4360
|
try {
|
|
4245
4361
|
const participants = await getParticipants(payload.conversationId);
|
|
4246
4362
|
const profiles = participants.map((p) => ({
|
|
@@ -4250,7 +4366,7 @@ var DeliveryManager = class {
|
|
|
4250
4366
|
description: p.description
|
|
4251
4367
|
}));
|
|
4252
4368
|
const avatarBlocks = await this.loadAvatarBlocks(participants);
|
|
4253
|
-
|
|
4369
|
+
state2.seenChannelProfiles.add(channelKey);
|
|
4254
4370
|
const enriched = { ...payload, participantProfiles: profiles };
|
|
4255
4371
|
if (avatarBlocks.length > 0) {
|
|
4256
4372
|
const existing = Array.isArray(payload.content) ? payload.content : typeof payload.content === "string" ? [{ type: "text", text: payload.content }] : [];
|
|
@@ -4351,27 +4467,26 @@ var DeliveryManager = class {
|
|
|
4351
4467
|
mindSessions = /* @__PURE__ */ new Map();
|
|
4352
4468
|
this.sessionStates.set(mind, mindSessions);
|
|
4353
4469
|
}
|
|
4354
|
-
const
|
|
4470
|
+
const state2 = mindSessions.get(session) ?? {
|
|
4355
4471
|
activeCount: 0,
|
|
4356
4472
|
lastDeliveredAt: 0,
|
|
4357
4473
|
lastDeliverySenders: /* @__PURE__ */ new Set(),
|
|
4358
4474
|
lastDeliveryChannels: /* @__PURE__ */ new Set(),
|
|
4359
|
-
lastInterruptAt: 0,
|
|
4360
4475
|
seenChannelProfiles: /* @__PURE__ */ new Set()
|
|
4361
4476
|
};
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
if (senders)
|
|
4365
|
-
if (channels)
|
|
4366
|
-
mindSessions.set(session,
|
|
4477
|
+
state2.activeCount++;
|
|
4478
|
+
state2.lastDeliveredAt = Date.now();
|
|
4479
|
+
if (senders) state2.lastDeliverySenders = senders;
|
|
4480
|
+
if (channels) state2.lastDeliveryChannels = channels;
|
|
4481
|
+
mindSessions.set(session, state2);
|
|
4367
4482
|
}
|
|
4368
4483
|
decrementActive(mind, session) {
|
|
4369
4484
|
const mindSessions = this.sessionStates.get(mind);
|
|
4370
4485
|
if (!mindSessions) return;
|
|
4371
|
-
const
|
|
4372
|
-
if (!
|
|
4373
|
-
|
|
4374
|
-
if (
|
|
4486
|
+
const state2 = mindSessions.get(session);
|
|
4487
|
+
if (!state2) return;
|
|
4488
|
+
state2.activeCount = Math.max(0, state2.activeCount - 1);
|
|
4489
|
+
if (state2.activeCount === 0) {
|
|
4375
4490
|
const bufferKey = `${mind}:${session}`;
|
|
4376
4491
|
const buffer = this.batchBuffers.get(bufferKey);
|
|
4377
4492
|
if (buffer && buffer.messages.length > 0) {
|
|
@@ -4453,7 +4568,7 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
|
|
|
4453
4568
|
content: mindHistory.content,
|
|
4454
4569
|
message_id: mindHistory.message_id,
|
|
4455
4570
|
turn_id: mindHistory.turn_id
|
|
4456
|
-
}).from(mindHistory).where(
|
|
4571
|
+
}).from(mindHistory).where(and5(eq6(mindHistory.id, outboundId), eq6(mindHistory.mind, mind))).limit(1);
|
|
4457
4572
|
const row = rows[0];
|
|
4458
4573
|
if (!row) {
|
|
4459
4574
|
dlog2.warn(`outbound marker references missing record: mind=${mind} id=${outboundId}`);
|
|
@@ -4461,13 +4576,13 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
|
|
|
4461
4576
|
}
|
|
4462
4577
|
const alreadyTagged = row.turn_id != null;
|
|
4463
4578
|
if (!alreadyTagged) {
|
|
4464
|
-
await db.update(mindHistory).set({ turn_id: turnId }).where(
|
|
4579
|
+
await db.update(mindHistory).set({ turn_id: turnId }).where(eq6(mindHistory.id, outboundId));
|
|
4465
4580
|
}
|
|
4466
4581
|
if (row.message_id) {
|
|
4467
4582
|
await db.update(messages).set({
|
|
4468
4583
|
turn_id: turnId,
|
|
4469
4584
|
...toolUseEventId != null ? { source_event_id: toolUseEventId } : {}
|
|
4470
|
-
}).where(
|
|
4585
|
+
}).where(eq6(messages.id, Number(row.message_id)));
|
|
4471
4586
|
}
|
|
4472
4587
|
if (!alreadyTagged) {
|
|
4473
4588
|
publish3(mind, {
|
|
@@ -4643,12 +4758,12 @@ async function generateSystemReply(conversationId, mindName, message) {
|
|
|
4643
4758
|
if (config.sleep.schedule?.wake) contextParts.push(`Wake cron: ${config.sleep.schedule.wake}`);
|
|
4644
4759
|
}
|
|
4645
4760
|
try {
|
|
4646
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4761
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HINI6Y46.js");
|
|
4647
4762
|
const sm = getSleepManagerIfReady2();
|
|
4648
4763
|
if (sm) {
|
|
4649
|
-
const
|
|
4650
|
-
if (
|
|
4651
|
-
contextParts.push(`Sleep state: sleeping since ${
|
|
4764
|
+
const state2 = sm.getState(mindName);
|
|
4765
|
+
if (state2.sleeping) {
|
|
4766
|
+
contextParts.push(`Sleep state: sleeping since ${state2.sleepingSince}`);
|
|
4652
4767
|
}
|
|
4653
4768
|
}
|
|
4654
4769
|
} catch (err) {
|
|
@@ -4704,6 +4819,8 @@ export {
|
|
|
4704
4819
|
getTypingMap,
|
|
4705
4820
|
isConversationId,
|
|
4706
4821
|
publishTypingForChannels,
|
|
4822
|
+
checkStaleSend,
|
|
4823
|
+
formatHoldNotice,
|
|
4707
4824
|
DeliveryManager,
|
|
4708
4825
|
initDeliveryManager,
|
|
4709
4826
|
getDeliveryManager,
|