volute 0.44.0 → 0.45.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/dist/{activity-events-OMCSM7XW.js → activity-events-BUR2RYTJ.js} +2 -2
- package/dist/{ai-service-7PHSRDMO.js → ai-service-UODCCE4O.js} +3 -3
- package/dist/{archive-6R4TZMYI.js → archive-WS2L2VIQ.js} +2 -2
- package/dist/{auth-FRZJVQCS.js → auth-FLAEXXZK.js} +3 -3
- package/dist/{avatar-image-BNWEXSA2.js → avatar-image-6KY6UU4D.js} +3 -3
- package/dist/backup-TST5C2YN.js +381 -0
- package/dist/{chat-I4EDDIQC.js → chat-76MRWWQX.js} +2 -2
- package/dist/{chunk-5AHYQHNT.js → chunk-4JOQZPCE.js} +3 -2
- package/dist/{chunk-2BONPXAF.js → chunk-6EMWJZBK.js} +1 -1
- package/dist/{chunk-ZMIMSIIT.js → chunk-7C44R625.js} +1 -1
- package/dist/{chunk-I2Y2YHIO.js → chunk-7ZUB63PS.js} +4 -4
- package/dist/{chunk-LAXUUY7O.js → chunk-A7WQZKOU.js} +2 -2
- package/dist/{chunk-H7IYFRAL.js → chunk-ALKYQULU.js} +10 -5
- package/dist/{chunk-KP3KWNG6.js → chunk-CDPBTTZO.js} +2 -2
- package/dist/{chunk-SQL7M4HJ.js → chunk-DRJ24GXK.js} +2 -2
- package/dist/{chunk-HVU45COX.js → chunk-EJVPTVTI.js} +1 -1
- package/dist/{chunk-PNV24SEP.js → chunk-F7H6ATM4.js} +14 -2
- package/dist/{chunk-7FT24JBQ.js → chunk-FR6S2KNN.js} +10 -10
- package/dist/chunk-FXORA5JG.js +327 -0
- package/dist/{chunk-3ERIL673.js → chunk-H2X54EHC.js} +1 -1
- package/dist/{chunk-J47TIYHA.js → chunk-IHKGWTGT.js} +1 -1
- package/dist/{chunk-3GYVW2X3.js → chunk-JZ62SYWR.js} +1 -1
- package/dist/{chunk-EQZD4YU3.js → chunk-NYC5U6K7.js} +9 -9
- package/dist/{chunk-FZMEVCWC.js → chunk-OP4JG2BS.js} +9 -6
- package/dist/{chunk-CU6OFXMM.js → chunk-PFZBNKUH.js} +9 -0
- package/dist/{chunk-QMJJWTNL.js → chunk-QCN24XEN.js} +1 -1
- package/dist/{chunk-7KWANSLX.js → chunk-QNQMSWZE.js} +3 -3
- package/dist/{chunk-UMI4UIJG.js → chunk-R77O2WMK.js} +1 -1
- package/dist/{chunk-IEWZ7VD7.js → chunk-RRNXJOKB.js} +2 -2
- package/dist/{chunk-FHWUQZXE.js → chunk-RXEEYDIB.js} +1 -1
- package/dist/{chunk-CYI534DJ.js → chunk-T6HYVHPG.js} +2 -2
- package/dist/{chunk-Q2XBKQ2D.js → chunk-TQJ6ZYVY.js} +2 -2
- package/dist/{chunk-NF75HPNR.js → chunk-UYLGEDVD.js} +40 -15
- package/dist/{chunk-OMETFX5H.js → chunk-YT7PEESJ.js} +261 -102
- package/dist/{chunk-5GT7URXJ.js → chunk-ZDZISKCL.js} +1 -1
- package/dist/cli.js +21 -15
- package/dist/{cloud-sync-6WJ7WFYD.js → cloud-sync-3OJOPZRT.js} +16 -16
- package/dist/{conversations-WAJYZKOC.js → conversations-JZTD6KLR.js} +3 -3
- package/dist/{create-YZIV5OJC.js → create-IOV4GCRX.js} +1 -1
- package/dist/{daemon-restart-OUJVINXV.js → daemon-restart-TIHKVVVA.js} +6 -6
- package/dist/daemon.js +562 -321
- package/dist/{db-JFLCJCUG.js → db-MF2JNRUW.js} +1 -1
- package/dist/delivery-manager-VDVKVA46.js +32 -0
- package/dist/{delivery-router-GODSIS62.js → delivery-router-N4A7ZC5T.js} +2 -2
- package/dist/{down-XCAZXWLB.js → down-U2CZ23M4.js} +4 -4
- package/dist/echo-text-6JJOPUD4.js +32 -0
- package/dist/{exec-4GWHAHS3.js → exec-G3ZRST4Z.js} +2 -2
- package/dist/{export-ID7YUSLZ.js → export-GGIVO76O.js} +2 -2
- package/dist/{extensions-3QNDGW5E.js → extensions-JONTW2HF.js} +16 -16
- package/dist/{files-BQ2WB5KC.js → files-4LN3EN7Q.js} +2 -2
- package/dist/{import-SKID37QX.js → import-42YNQBF4.js} +5 -5
- package/dist/{isolation-5MB3J73F.js → isolation-YMGZZ4E5.js} +2 -2
- package/dist/{join-RXPXGV4L.js → join-ZJV7W6MO.js} +4 -0
- package/dist/{login-LM4NF4ZB.js → login-M6OJUPQ2.js} +1 -1
- package/dist/{logout-CTJVIZGA.js → logout-WQBWO77G.js} +1 -1
- package/dist/message-delivery-3C65ZI6L.js +34 -0
- package/dist/{mind-MI7Z6KM2.js → mind-DWB6XYCH.js} +7 -7
- package/dist/{mind-activity-tracker-BGHJE7XA.js → mind-activity-tracker-POBLU3LC.js} +3 -3
- package/dist/mind-service-3F4I46CI.js +36 -0
- package/dist/{package-5B4XDTJH.js → package-A7KXT67Q.js} +1 -1
- package/dist/{registry-NUJAGLQJ.js → registry-OUZBZ3Q4.js} +5 -1
- package/dist/{sandbox-IOPWWILM.js → sandbox-ZJ7QA6Z6.js} +3 -3
- package/dist/scheduler-P6DXLLXI.js +30 -0
- package/dist/{seed-UUPVQWFB.js → seed-HCP5NYKH.js} +1 -1
- package/dist/{seed-cmd-7XPKDQUC.js → seed-cmd-ILOGNIFB.js} +2 -2
- package/dist/{seed-create-IZ4M5ESO.js → seed-create-OURS2LS4.js} +3 -3
- package/dist/{seed-sprout-POJXHJWV.js → seed-sprout-ELDFDAN6.js} +7 -7
- package/dist/{send-O6W53VBM.js → send-AAIOPJAV.js} +2 -2
- package/dist/{service-AQVPUANO.js → service-UOCLXDWR.js} +3 -3
- package/dist/{service-install-4QNUDKLM.js → service-install-4HHFDDWY.js} +4 -4
- package/dist/{setup-5GCO3CUB.js → setup-DQM5VPY4.js} +6 -6
- package/dist/{setup-MLRKNP7Y.js → setup-Y2EJI3GG.js} +2 -2
- package/dist/skills/imagegen/scripts/imagegen.ts +100 -40
- package/dist/skills/memory/SKILL.md +2 -1
- package/dist/skills/orientation/SKILL.md +1 -1
- package/dist/skills/plan-coordinator/SKILL.md +2 -2
- package/dist/skills/volute-admin/SKILL.md +9 -6
- package/dist/skills/volute-mind/SKILL.md +20 -17
- package/dist/skills/volute-mind/references/extensions.md +5 -3
- package/dist/skills/volute-mind/references/integrations.md +2 -2
- package/dist/skills/volute-mind/references/routing.md +19 -23
- package/dist/skills/volute-mind/references/variants.md +10 -8
- package/dist/{skills-775C7QFF.js → skills-BKINFL7W.js} +4 -4
- package/dist/sleep-manager-HCUH4PM4.js +34 -0
- package/dist/{spirit-IK5OYWMV.js → spirit-DBTIW7P4.js} +7 -7
- package/dist/{sprout-ZY5QGOEL.js → sprout-W3KC7UGK.js} +1 -1
- package/dist/{src-XFY3XDD6.js → src-OJHARHTF.js} +28 -17
- package/dist/{status-E5DQNCAO.js → status-SWRVGXBI.js} +4 -4
- package/dist/system-chat-XOALE2RD.js +36 -0
- package/dist/{tailscale-QAWVKQKU.js → tailscale-3XOKOW7T.js} +1 -1
- package/dist/{turn-tracker-RWZMY7M6.js → turn-tracker-2W6Q2NSR.js} +6 -4
- package/dist/{up-FLCDR2UB.js → up-FTK7CTO3.js} +5 -5
- package/dist/{update-7TYVH5FM.js → update-SWAYZRWJ.js} +4 -4
- package/dist/{update-check-VSCSJ7KX.js → update-check-PQ2MZ47K.js} +2 -2
- package/dist/{upgrade-37DAGF6H.js → upgrade-NWAZ7MLD.js} +1 -1
- package/dist/{version-notify-B67N35A3.js → version-notify-3XMAIQTE.js} +17 -17
- package/dist/{volute-config-TS62GS6A.js → volute-config-A52FHWKM.js} +5 -1
- package/dist/web-assets/assets/{index-dJdNzAPn.css → index-B1JBQv2m.css} +1 -1
- package/dist/web-assets/assets/index-Bc2m8gRC.js +86 -0
- package/dist/web-assets/index.html +2 -2
- package/package.json +1 -1
- package/packages/extensions/plan/skills/plan/SKILL.md +1 -1
- package/templates/_base/.init/.config/prompts.json +1 -1
- package/templates/_base/.init/.local/hooks/startup-context.ts +0 -8
- package/templates/_base/.init/MEMORY.md +2 -1
- package/templates/_base/home/VOLUTE.md +6 -9
- package/templates/_base/src/lib/file-handler.ts +3 -3
- package/templates/_base/src/lib/router.ts +21 -25
- package/templates/_base/src/lib/startup.ts +3 -1
- package/templates/_base/src/lib/types.ts +2 -2
- package/templates/claude/.init/CLAUDE.md +1 -1
- package/templates/claude/src/agent.ts +97 -12
- package/templates/claude/src/lib/message-channel.ts +23 -0
- package/templates/claude/src/lib/session-reaper.ts +37 -0
- package/templates/claude/src/lib/stream-consumer.ts +7 -4
- package/templates/claude/src/server.ts +1 -0
- package/templates/codex/.init/AGENTS.md +4 -2
- package/templates/codex/src/agent.ts +31 -13
- package/templates/pi/.init/MINDS.md +4 -2
- package/templates/pi/src/agent.ts +18 -7
- package/templates/pi/src/lib/event-handler.ts +6 -2
- package/dist/delivery-manager-TEVOHX5W.js +0 -32
- package/dist/echo-text-T7ZA5EYD.js +0 -32
- package/dist/message-delivery-2EA5LLMD.js +0 -34
- package/dist/mind-service-S3SY7HAM.js +0 -36
- package/dist/scheduler-CXWQ6Z4E.js +0 -30
- package/dist/sleep-manager-HINI6Y46.js +0 -34
- package/dist/system-chat-4DQZOEZI.js +0 -34
- package/dist/web-assets/assets/index-Domoz5Cg.js +0 -79
- package/templates/_base/.init/.config/hooks/pre-prompt/session-activity.ts +0 -40
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
loadMergedEnv
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ZDZISKCL.js";
|
|
5
5
|
import {
|
|
6
6
|
spiritDir
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-FR6S2KNN.js";
|
|
8
8
|
import {
|
|
9
9
|
hashSkillDir,
|
|
10
10
|
importSkillFromDir,
|
|
11
11
|
removeSharedSkill,
|
|
12
12
|
sharedSkillsDir
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-7ZUB63PS.js";
|
|
14
14
|
import {
|
|
15
15
|
addMessage,
|
|
16
16
|
createChannel,
|
|
@@ -20,74 +20,77 @@ import {
|
|
|
20
20
|
getParticipants,
|
|
21
21
|
joinChannel,
|
|
22
22
|
publish as publish2
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-OP4JG2BS.js";
|
|
24
24
|
import {
|
|
25
25
|
readVoluteConfig,
|
|
26
|
+
resolveWakeTriggers,
|
|
26
27
|
writeVoluteConfig
|
|
27
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-PFZBNKUH.js";
|
|
28
29
|
import {
|
|
29
30
|
isSandboxEnabled,
|
|
30
31
|
wrapForSandbox
|
|
31
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-JZ62SYWR.js";
|
|
32
33
|
import {
|
|
33
34
|
markIdle,
|
|
34
35
|
onMindEvent
|
|
35
|
-
} from "./chunk-
|
|
36
|
+
} from "./chunk-EJVPTVTI.js";
|
|
36
37
|
import {
|
|
37
38
|
extractTextContent,
|
|
38
39
|
getRoutingConfig,
|
|
39
40
|
resolveDeliveryMode,
|
|
40
41
|
resolveRoute,
|
|
41
42
|
setRoutesChangeListener
|
|
42
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-4JOQZPCE.js";
|
|
43
44
|
import {
|
|
44
45
|
clearMind,
|
|
45
46
|
getPrompt,
|
|
46
47
|
linkInboundToActiveTurn,
|
|
47
48
|
publish as publish3,
|
|
48
49
|
summarizeOrphanedTurns
|
|
49
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-UYLGEDVD.js";
|
|
50
51
|
import {
|
|
51
52
|
chownMindDir,
|
|
52
53
|
exec,
|
|
53
54
|
isIsolationEnabled,
|
|
54
55
|
mindUserName,
|
|
55
56
|
wrapForIsolation
|
|
56
|
-
} from "./chunk-
|
|
57
|
+
} from "./chunk-H2X54EHC.js";
|
|
57
58
|
import {
|
|
58
59
|
aiCompleteUtility,
|
|
59
60
|
getAiConfig,
|
|
60
61
|
resolveApiKey
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-IHKGWTGT.js";
|
|
62
63
|
import {
|
|
63
64
|
readGlobalConfig,
|
|
64
65
|
writeGlobalConfig
|
|
65
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-F7H6ATM4.js";
|
|
66
67
|
import {
|
|
67
68
|
getOrCreateMindUser,
|
|
68
69
|
getOrCreateSystemUser,
|
|
69
70
|
getUser,
|
|
70
71
|
getUserByUsername,
|
|
71
72
|
syncMindProfile
|
|
72
|
-
} from "./chunk-
|
|
73
|
+
} from "./chunk-T6HYVHPG.js";
|
|
73
74
|
import {
|
|
74
75
|
publish,
|
|
75
76
|
subscribe
|
|
76
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-7C44R625.js";
|
|
77
78
|
import {
|
|
78
79
|
logger_default
|
|
79
80
|
} from "./chunk-T2TP6ZC6.js";
|
|
80
81
|
import {
|
|
82
|
+
SPIRIT_NAME,
|
|
81
83
|
findMind,
|
|
82
84
|
getBaseName,
|
|
83
85
|
getDb,
|
|
86
|
+
isSpiritName,
|
|
84
87
|
mindDir,
|
|
85
88
|
mindTmpDir,
|
|
86
89
|
setMindRunning,
|
|
87
90
|
stateDir,
|
|
88
91
|
voluteHome,
|
|
89
92
|
voluteSystemDir
|
|
90
|
-
} from "./chunk-
|
|
93
|
+
} from "./chunk-ALKYQULU.js";
|
|
91
94
|
import {
|
|
92
95
|
activity,
|
|
93
96
|
deliveryQueue,
|
|
@@ -98,7 +101,7 @@ import {
|
|
|
98
101
|
} from "./chunk-ZV7MFISX.js";
|
|
99
102
|
|
|
100
103
|
// packages/daemon/src/lib/delivery/message-delivery.ts
|
|
101
|
-
import { and as and5, eq as eq6, inArray as
|
|
104
|
+
import { and as and5, eq as eq6, inArray as inArray2 } from "drizzle-orm";
|
|
102
105
|
|
|
103
106
|
// packages/daemon/src/lib/daemon/sleep-manager.ts
|
|
104
107
|
import { execFile as execFile2, spawn as spawnChild } from "child_process";
|
|
@@ -114,7 +117,7 @@ import {
|
|
|
114
117
|
import { resolve as resolve7 } from "path";
|
|
115
118
|
import { promisify as promisify2 } from "util";
|
|
116
119
|
import { CronExpressionParser as CronExpressionParser2 } from "cron-parser";
|
|
117
|
-
import { and as and2, eq as eq3
|
|
120
|
+
import { and as and2, eq as eq3 } from "drizzle-orm";
|
|
118
121
|
|
|
119
122
|
// packages/daemon/src/lib/daemon/mind-manager.ts
|
|
120
123
|
import { execFile, spawn } from "child_process";
|
|
@@ -335,6 +338,9 @@ function revokeMindToken(mindName) {
|
|
|
335
338
|
function resolveMindToken(token) {
|
|
336
339
|
return tokenToMind.get(token) ?? null;
|
|
337
340
|
}
|
|
341
|
+
function getMindToken(mindName) {
|
|
342
|
+
return mindToToken.get(mindName) ?? null;
|
|
343
|
+
}
|
|
338
344
|
|
|
339
345
|
// packages/daemon/src/lib/daemon/notices.ts
|
|
340
346
|
import { and, asc, eq, lte, or, sql } from "drizzle-orm";
|
|
@@ -385,7 +391,8 @@ async function clearDeliveredNotices(mind, session, uptoId) {
|
|
|
385
391
|
var NOTICE_HEADER = "[Notices] While you were unavailable, one or more turns failed. You're back now:";
|
|
386
392
|
function formatNotices(notices) {
|
|
387
393
|
if (notices.length === 0) return null;
|
|
388
|
-
const failures = notices.filter((n) => n.kind !== "extension");
|
|
394
|
+
const failures = notices.filter((n) => n.kind !== "extension" && n.kind !== "budget");
|
|
395
|
+
const budgets = notices.filter((n) => n.kind === "budget");
|
|
389
396
|
const extensions = notices.filter((n) => n.kind === "extension");
|
|
390
397
|
const blocks = [];
|
|
391
398
|
if (failures.length > 0) {
|
|
@@ -407,6 +414,11 @@ function formatNotices(notices) {
|
|
|
407
414
|
return `- ${g.count} ${plural} failed (${span}): ${g.detail}`;
|
|
408
415
|
});
|
|
409
416
|
blocks.push(`${NOTICE_HEADER}
|
|
417
|
+
${lines.join("\n")}`);
|
|
418
|
+
}
|
|
419
|
+
if (budgets.length > 0) {
|
|
420
|
+
const lines = budgets.map((n) => `- ${localHM(n.created_at)} ${n.detail}`);
|
|
421
|
+
blocks.push(`[Budget]
|
|
410
422
|
${lines.join("\n")}`);
|
|
411
423
|
}
|
|
412
424
|
if (extensions.length > 0) {
|
|
@@ -887,6 +899,8 @@ var MindManager = class {
|
|
|
887
899
|
const parts = [];
|
|
888
900
|
if (context.type === "merge" || context.type === "merged") {
|
|
889
901
|
parts.push(await getPrompt("merge_message", { name: String(context.name ?? "") }));
|
|
902
|
+
} else if (context.type === "split") {
|
|
903
|
+
parts.push(await getPrompt("split_message", { name, parent: String(context.parent ?? "") }));
|
|
890
904
|
} else if (context.type === "sprouted") {
|
|
891
905
|
parts.push(await getPrompt("sprout_message"));
|
|
892
906
|
} else if (context.type === "upgraded") {
|
|
@@ -931,7 +945,7 @@ var MindManager = class {
|
|
|
931
945
|
if (this.shuttingDown || this.stopping.has(name)) return;
|
|
932
946
|
mlog.error(`mind ${name} exited with code ${code}`);
|
|
933
947
|
try {
|
|
934
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
948
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
|
|
935
949
|
const sleepMgr = getSleepManagerIfReady2();
|
|
936
950
|
const sleepState = sleepMgr?.getState(name);
|
|
937
951
|
if (sleepState?.sleeping) {
|
|
@@ -961,15 +975,15 @@ var MindManager = class {
|
|
|
961
975
|
(err) => mlog.warn(`failed to clear turn state for ${name} after crash`, logger_default.errorData(err))
|
|
962
976
|
);
|
|
963
977
|
try {
|
|
964
|
-
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-
|
|
978
|
+
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-VDVKVA46.js");
|
|
965
979
|
getDeliveryManager2().clearMindSessions(name);
|
|
966
980
|
} catch (err) {
|
|
967
981
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
968
982
|
mlog.warn(`failed to clear delivery state for ${name} after crash`, logger_default.errorData(err));
|
|
969
983
|
}
|
|
970
984
|
}
|
|
971
|
-
import("./mind-activity-tracker-
|
|
972
|
-
import("./activity-events-
|
|
985
|
+
import("./mind-activity-tracker-POBLU3LC.js").then(({ markIdle: markIdle2 }) => markIdle2(name)).catch((err) => mlog.warn(`failed to mark ${name} idle after crash`, logger_default.errorData(err)));
|
|
986
|
+
import("./activity-events-BUR2RYTJ.js").then(
|
|
973
987
|
({ publish: publish4 }) => publish4({ type: "mind_stopped", mind: name, summary: `${name} crashed (exit ${code})` })
|
|
974
988
|
).catch((err) => mlog.warn(`failed to publish crash event for ${name}`, logger_default.errorData(err)));
|
|
975
989
|
const { shouldRestart, delay, attempt } = this.restartTracker.recordCrash(name);
|
|
@@ -1027,7 +1041,7 @@ var MindManager = class {
|
|
|
1027
1041
|
mlog.warn(`failed to clear turn state for ${name} on stop`, logger_default.errorData(err));
|
|
1028
1042
|
}
|
|
1029
1043
|
try {
|
|
1030
|
-
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-
|
|
1044
|
+
const { getDeliveryManager: getDeliveryManager2 } = await import("./delivery-manager-VDVKVA46.js");
|
|
1031
1045
|
getDeliveryManager2().clearMindSessions(name);
|
|
1032
1046
|
} catch (err) {
|
|
1033
1047
|
if (!(err instanceof Error && err.message.includes("not initialized"))) {
|
|
@@ -1035,7 +1049,7 @@ var MindManager = class {
|
|
|
1035
1049
|
}
|
|
1036
1050
|
}
|
|
1037
1051
|
try {
|
|
1038
|
-
const { clearEchoTextCache } = await import("./echo-text-
|
|
1052
|
+
const { clearEchoTextCache } = await import("./echo-text-6JJOPUD4.js");
|
|
1039
1053
|
clearEchoTextCache(name);
|
|
1040
1054
|
} catch (err) {
|
|
1041
1055
|
mlog.debug(`failed to clear echo-text cache for ${name}`, logger_default.errorData(err));
|
|
@@ -1691,7 +1705,7 @@ function resolveSkillsDir(manifest) {
|
|
|
1691
1705
|
async function discoverBuiltinExtensions(disabledIds) {
|
|
1692
1706
|
const builtins = [
|
|
1693
1707
|
{ id: "notes", load: async () => (await import("./src-YH6PQ7LJ.js")).default },
|
|
1694
|
-
{ id: "pages", load: async () => (await import("./src-
|
|
1708
|
+
{ id: "pages", load: async () => (await import("./src-OJHARHTF.js")).default },
|
|
1695
1709
|
{ id: "plan", load: async () => (await import("./src-JAOVXO5W.js")).default }
|
|
1696
1710
|
];
|
|
1697
1711
|
const results = [];
|
|
@@ -1941,7 +1955,7 @@ async function installNpmExtension(pkg) {
|
|
|
1941
1955
|
throw new Error(`Extension "${pkg}" is already installed`);
|
|
1942
1956
|
}
|
|
1943
1957
|
const dir = ensureExtensionsNpmDir();
|
|
1944
|
-
const { exec: exec2 } = await import("./exec-
|
|
1958
|
+
const { exec: exec2 } = await import("./exec-G3ZRST4Z.js");
|
|
1945
1959
|
try {
|
|
1946
1960
|
await exec2("npm", ["install", "--ignore-scripts", pkg], { cwd: dir });
|
|
1947
1961
|
} catch (err) {
|
|
@@ -1962,7 +1976,7 @@ async function uninstallNpmExtension(pkg) {
|
|
|
1962
1976
|
packages.splice(idx, 1);
|
|
1963
1977
|
writeExtensionsConfig(packages);
|
|
1964
1978
|
try {
|
|
1965
|
-
const { exec: exec2 } = await import("./exec-
|
|
1979
|
+
const { exec: exec2 } = await import("./exec-G3ZRST4Z.js");
|
|
1966
1980
|
await exec2("npm", ["uninstall", "--ignore-scripts", pkg], { cwd: extensionsNpmDir() });
|
|
1967
1981
|
} catch (err) {
|
|
1968
1982
|
logger_default.warn(
|
|
@@ -2407,7 +2421,9 @@ ${stderr}` : ""}`;
|
|
|
2407
2421
|
return;
|
|
2408
2422
|
}
|
|
2409
2423
|
await this.deliverSystem(mindName, `[${schedule.id}] ${text}`, {
|
|
2410
|
-
|
|
2424
|
+
// Default schedule fires to "queue" while asleep so an unadorned cron
|
|
2425
|
+
// schedule doesn't inherit the DM wake-trigger fallback and wake the mind.
|
|
2426
|
+
whileSleeping: schedule.whileSleeping ?? "queue",
|
|
2411
2427
|
session: schedule.session
|
|
2412
2428
|
});
|
|
2413
2429
|
slog2.info(`fired "${schedule.id}" for ${mindName}`);
|
|
@@ -2444,15 +2460,41 @@ ${stderr}` : ""}`;
|
|
|
2444
2460
|
}
|
|
2445
2461
|
}
|
|
2446
2462
|
async runScript(script, cwd, mindName) {
|
|
2463
|
+
const env = await this.buildScriptEnv(mindName);
|
|
2447
2464
|
if (isSandboxEnabled()) {
|
|
2448
2465
|
const dir = this.mindDirs.get(mindName) ?? mindDir(mindName);
|
|
2449
2466
|
const [cmd, args] = await wrapForSandbox("bash", ["-c", script], dir, mindName, [
|
|
2450
2467
|
dir,
|
|
2451
2468
|
mindTmpDir(dir)
|
|
2452
2469
|
]);
|
|
2453
|
-
return exec(cmd, args, { cwd });
|
|
2470
|
+
return exec(cmd, args, { cwd, env });
|
|
2454
2471
|
}
|
|
2455
|
-
return exec("bash", ["-c", script], { cwd, mindName });
|
|
2472
|
+
return exec("bash", ["-c", script], { cwd, mindName, env });
|
|
2473
|
+
}
|
|
2474
|
+
/**
|
|
2475
|
+
* Build the environment for a scheduled script — mirrors the mind process env
|
|
2476
|
+
* (allowlisted base + merged mind env + VOLUTE_* runtime vars), authenticated
|
|
2477
|
+
* with the mind's own per-mind, non-admin token. Reuses the running mind's
|
|
2478
|
+
* token when present; otherwise mints one (stable across fires, regenerated on
|
|
2479
|
+
* next mind start). The daemon admin token is never included.
|
|
2480
|
+
*/
|
|
2481
|
+
async buildScriptEnv(mindName) {
|
|
2482
|
+
const dir = this.mindDirs.get(mindName) ?? mindDir(mindName);
|
|
2483
|
+
const entry = await findMind(mindName);
|
|
2484
|
+
const token = getMindToken(mindName) ?? generateMindToken(mindName);
|
|
2485
|
+
const mindLocalBin = resolve5(dir, "home", ".local", "bin");
|
|
2486
|
+
const currentPath = process.env.PATH ?? "";
|
|
2487
|
+
return {
|
|
2488
|
+
...buildMindBaseEnv(),
|
|
2489
|
+
...loadMergedEnv(mindName),
|
|
2490
|
+
VOLUTE_MIND: mindName,
|
|
2491
|
+
VOLUTE_STATE_DIR: stateDir(mindName),
|
|
2492
|
+
VOLUTE_MIND_DIR: dir,
|
|
2493
|
+
VOLUTE_MIND_PORT: entry ? String(entry.port) : void 0,
|
|
2494
|
+
VOLUTE_MIND_TOKEN: token,
|
|
2495
|
+
TMPDIR: mindTmpDir(dir),
|
|
2496
|
+
PATH: `${mindLocalBin}:${currentPath}`
|
|
2497
|
+
};
|
|
2456
2498
|
}
|
|
2457
2499
|
deliverSystem(mindName, text, opts) {
|
|
2458
2500
|
return sendSystemMessage(mindName, text, opts);
|
|
@@ -2763,7 +2805,7 @@ async function wakeMind(name) {
|
|
|
2763
2805
|
async function startSpiritFull(name) {
|
|
2764
2806
|
const entry = await findMind(name);
|
|
2765
2807
|
if (entry?.dir) {
|
|
2766
|
-
const { registerMindDir } = await import("./delivery-router-
|
|
2808
|
+
const { registerMindDir } = await import("./delivery-router-N4A7ZC5T.js");
|
|
2767
2809
|
registerMindDir(name, entry.dir);
|
|
2768
2810
|
}
|
|
2769
2811
|
await getMindManager().startMind(name);
|
|
@@ -2785,8 +2827,8 @@ async function stopSpiritFull(name) {
|
|
|
2785
2827
|
}).catch((err) => logger_default.error("failed to publish spirit_stopped activity", logger_default.errorData(err)));
|
|
2786
2828
|
}
|
|
2787
2829
|
async function ensureCreatorDM(mindName, creatorUsername) {
|
|
2788
|
-
const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-
|
|
2789
|
-
const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-
|
|
2830
|
+
const { getOrCreateMindUser: getOrCreateMindUser2, getUserByUsername: getUserByUsername2 } = await import("./auth-FLAEXXZK.js");
|
|
2831
|
+
const { findDMConversation: findDMConversation2, createConversation: createConversation2 } = await import("./conversations-JZTD6KLR.js");
|
|
2790
2832
|
const mindUser = await getOrCreateMindUser2(mindName);
|
|
2791
2833
|
const creatorUser = await getUserByUsername2(creatorUsername);
|
|
2792
2834
|
if (!creatorUser) {
|
|
@@ -2819,6 +2861,8 @@ async function stopMindFull(name) {
|
|
|
2819
2861
|
|
|
2820
2862
|
// packages/daemon/src/lib/daemon/sleep-manager.ts
|
|
2821
2863
|
var slog3 = logger_default.child("sleep");
|
|
2864
|
+
var MAX_WAKE_ATTEMPTS = 5;
|
|
2865
|
+
var WAKE_BACKOFF_MS = [6e4, 5 * 6e4, 15 * 6e4, 60 * 6e4];
|
|
2822
2866
|
function defaultState() {
|
|
2823
2867
|
return {
|
|
2824
2868
|
sleeping: false,
|
|
@@ -2827,7 +2871,9 @@ function defaultState() {
|
|
|
2827
2871
|
wokenByTrigger: false,
|
|
2828
2872
|
voluntaryWakeAt: null,
|
|
2829
2873
|
queuedMessageCount: 0,
|
|
2830
|
-
triggerWakeHistory: []
|
|
2874
|
+
triggerWakeHistory: [],
|
|
2875
|
+
wakeFailures: 0,
|
|
2876
|
+
nextWakeAttemptAt: null
|
|
2831
2877
|
};
|
|
2832
2878
|
}
|
|
2833
2879
|
function formatCurrentDate() {
|
|
@@ -2838,6 +2884,22 @@ function formatCurrentDate() {
|
|
|
2838
2884
|
day: "numeric"
|
|
2839
2885
|
});
|
|
2840
2886
|
}
|
|
2887
|
+
function formatWakeTime(wakeAt) {
|
|
2888
|
+
if (wakeAt) {
|
|
2889
|
+
const date = new Date(wakeAt);
|
|
2890
|
+
if (!Number.isNaN(date.getTime())) {
|
|
2891
|
+
const time = date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
|
|
2892
|
+
const day = date.toLocaleDateString("en-US", {
|
|
2893
|
+
weekday: "long",
|
|
2894
|
+
month: "long",
|
|
2895
|
+
day: "numeric"
|
|
2896
|
+
});
|
|
2897
|
+
return `at ${time} on ${day}`;
|
|
2898
|
+
}
|
|
2899
|
+
return `at ${wakeAt}`;
|
|
2900
|
+
}
|
|
2901
|
+
return "when something needs you \u2014 a message, a mention, or someone waking you";
|
|
2902
|
+
}
|
|
2841
2903
|
function formatDuration(from, to) {
|
|
2842
2904
|
const ms = to.getTime() - from.getTime();
|
|
2843
2905
|
const hours = Math.floor(ms / 36e5);
|
|
@@ -2881,6 +2943,8 @@ var SleepManager = class {
|
|
|
2881
2943
|
const data = JSON.parse(readFileSync7(this.statePath, "utf-8"));
|
|
2882
2944
|
for (const [name, state2] of Object.entries(data)) {
|
|
2883
2945
|
state2.triggerWakeHistory ??= [];
|
|
2946
|
+
state2.wakeFailures ??= 0;
|
|
2947
|
+
state2.nextWakeAttemptAt ??= null;
|
|
2884
2948
|
this.states.set(name, state2);
|
|
2885
2949
|
}
|
|
2886
2950
|
}
|
|
@@ -2985,7 +3049,8 @@ var SleepManager = class {
|
|
|
2985
3049
|
const entry = await findMind(name);
|
|
2986
3050
|
if (!entry) return;
|
|
2987
3051
|
const sleepConfig = this.getSleepConfig(name);
|
|
2988
|
-
const
|
|
3052
|
+
const wakeAt = opts?.voluntaryWakeAt ?? this.getNextWakeTime(sleepConfig);
|
|
3053
|
+
const wakeTime = formatWakeTime(wakeAt);
|
|
2989
3054
|
const preSleepMsg = await getPrompt("pre_sleep", { wakeTime });
|
|
2990
3055
|
let conversationId;
|
|
2991
3056
|
try {
|
|
@@ -3036,12 +3101,13 @@ var SleepManager = class {
|
|
|
3036
3101
|
try {
|
|
3037
3102
|
await wakeMind(name);
|
|
3038
3103
|
} catch (err) {
|
|
3039
|
-
|
|
3104
|
+
await this.handleWakeFailure(name, err);
|
|
3040
3105
|
return;
|
|
3041
3106
|
}
|
|
3042
3107
|
}
|
|
3043
3108
|
const entry = await findMind(name);
|
|
3044
3109
|
if (!entry) return;
|
|
3110
|
+
this.resetWakeBackoff(name);
|
|
3045
3111
|
if (opts?.trigger) {
|
|
3046
3112
|
state2.wokenByTrigger = true;
|
|
3047
3113
|
state2.triggerWakeHistory.push({
|
|
@@ -3115,8 +3181,7 @@ var SleepManager = class {
|
|
|
3115
3181
|
checkWakeTrigger(name, payload) {
|
|
3116
3182
|
const config = this.getSleepConfig(name);
|
|
3117
3183
|
const triggers = config?.wakeTriggers;
|
|
3118
|
-
const mentionsEnabled = triggers
|
|
3119
|
-
const dmsEnabled = triggers?.dms !== false;
|
|
3184
|
+
const { mentions: mentionsEnabled, dms: dmsEnabled } = resolveWakeTriggers(triggers);
|
|
3120
3185
|
if (dmsEnabled && payload.isDM) return true;
|
|
3121
3186
|
if (mentionsEnabled && payload.content) {
|
|
3122
3187
|
const text = typeof payload.content === "string" ? payload.content : Array.isArray(payload.content) ? payload.content.filter((b) => b.type === "text" && b.text).map((b) => b.text).join(" ") : "";
|
|
@@ -3161,29 +3226,110 @@ var SleepManager = class {
|
|
|
3161
3226
|
const db = await getDb();
|
|
3162
3227
|
const rows = await db.select().from(deliveryQueue).where(and2(eq3(deliveryQueue.mind, name), eq3(deliveryQueue.status, "sleep-queued"))).all();
|
|
3163
3228
|
if (rows.length === 0) return 0;
|
|
3164
|
-
|
|
3165
|
-
const delivered = [];
|
|
3229
|
+
let deliveredCount = 0;
|
|
3166
3230
|
for (const row of rows) {
|
|
3231
|
+
let payload;
|
|
3167
3232
|
try {
|
|
3168
|
-
|
|
3169
|
-
delivered.push(row.id);
|
|
3233
|
+
payload = JSON.parse(row.payload);
|
|
3170
3234
|
} catch (err) {
|
|
3171
|
-
slog3.warn(
|
|
3235
|
+
slog3.warn(
|
|
3236
|
+
`dropping unparseable queued message ${row.id} for ${name}`,
|
|
3237
|
+
logger_default.errorData(err)
|
|
3238
|
+
);
|
|
3239
|
+
await db.delete(deliveryQueue).where(eq3(deliveryQueue.id, row.id));
|
|
3240
|
+
continue;
|
|
3172
3241
|
}
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3242
|
+
const delivered = await this.deliverQueued(name, payload);
|
|
3243
|
+
if (!delivered) {
|
|
3244
|
+
slog3.warn(`failed to flush queued message ${row.id} for ${name}; leaving it queued`);
|
|
3245
|
+
break;
|
|
3246
|
+
}
|
|
3247
|
+
await db.delete(deliveryQueue).where(eq3(deliveryQueue.id, row.id));
|
|
3248
|
+
deliveredCount++;
|
|
3176
3249
|
}
|
|
3177
3250
|
const state2 = this.states.get(name);
|
|
3178
3251
|
if (state2) {
|
|
3179
|
-
state2.queuedMessageCount = Math.max(0, state2.queuedMessageCount -
|
|
3252
|
+
state2.queuedMessageCount = Math.max(0, state2.queuedMessageCount - deliveredCount);
|
|
3180
3253
|
}
|
|
3181
|
-
return
|
|
3254
|
+
return deliveredCount;
|
|
3182
3255
|
} catch (err) {
|
|
3183
3256
|
slog3.warn(`failed to flush queued messages for ${name}`, logger_default.errorData(err));
|
|
3184
3257
|
return 0;
|
|
3185
3258
|
}
|
|
3186
3259
|
}
|
|
3260
|
+
/**
|
|
3261
|
+
* Deliver one queued message on the wake path. `isFlush` skips the queue-time inbound
|
|
3262
|
+
* recording (kept once, at arrival) and bypasses the sleep re-queue so the now-waking mind
|
|
3263
|
+
* actually receives it. Returns whether the message was handed off to the delivery manager.
|
|
3264
|
+
* Extracted as a seam so the flush loop can be unit-tested without the real delivery stack.
|
|
3265
|
+
*/
|
|
3266
|
+
async deliverQueued(name, payload) {
|
|
3267
|
+
const { deliverMessage: deliverMessage2 } = await import("./message-delivery-3C65ZI6L.js");
|
|
3268
|
+
return deliverMessage2(name, payload, { isFlush: true });
|
|
3269
|
+
}
|
|
3270
|
+
// --- Wake failure handling (#419) ---
|
|
3271
|
+
/**
|
|
3272
|
+
* Record a failed wake attempt. Applies exponential backoff between retries and,
|
|
3273
|
+
* after MAX_WAKE_ATTEMPTS consecutive failures, gives up and marks the mind errored
|
|
3274
|
+
* rather than retrying every tick forever.
|
|
3275
|
+
*/
|
|
3276
|
+
async handleWakeFailure(name, err) {
|
|
3277
|
+
const state2 = this.states.get(name);
|
|
3278
|
+
if (!state2?.sleeping) return;
|
|
3279
|
+
state2.wakeFailures = (state2.wakeFailures ?? 0) + 1;
|
|
3280
|
+
if (state2.wakeFailures >= MAX_WAKE_ATTEMPTS) {
|
|
3281
|
+
await this.markWakeErrored(name, err);
|
|
3282
|
+
return;
|
|
3283
|
+
}
|
|
3284
|
+
const backoff = WAKE_BACKOFF_MS[Math.min(state2.wakeFailures - 1, WAKE_BACKOFF_MS.length - 1)];
|
|
3285
|
+
state2.nextWakeAttemptAt = new Date(Date.now() + backoff).toISOString();
|
|
3286
|
+
this.saveState();
|
|
3287
|
+
slog3.warn(
|
|
3288
|
+
`failed to wake ${name} (attempt ${state2.wakeFailures}/${MAX_WAKE_ATTEMPTS}); retrying in ${Math.round(backoff / 6e4)}m`,
|
|
3289
|
+
logger_default.errorData(err)
|
|
3290
|
+
);
|
|
3291
|
+
}
|
|
3292
|
+
/** Clear wake-failure backoff after a successful wake. */
|
|
3293
|
+
resetWakeBackoff(name) {
|
|
3294
|
+
const state2 = this.states.get(name);
|
|
3295
|
+
if (!state2) return;
|
|
3296
|
+
if (state2.wakeFailures === 0 && state2.nextWakeAttemptAt === null) return;
|
|
3297
|
+
state2.wakeFailures = 0;
|
|
3298
|
+
state2.nextWakeAttemptAt = null;
|
|
3299
|
+
this.saveState();
|
|
3300
|
+
}
|
|
3301
|
+
/**
|
|
3302
|
+
* A mind has failed to wake too many times — it isn't asleep, it's broken.
|
|
3303
|
+
* Clear the sleep state (so the tick stops retrying) and surface the failure
|
|
3304
|
+
* loudly: error log, activity event for the web UI, and a mind notice so the
|
|
3305
|
+
* mind learns what happened on its next successful session. A manual
|
|
3306
|
+
* `volute clock wake` / `volute mind start` is the recovery path.
|
|
3307
|
+
*/
|
|
3308
|
+
async markWakeErrored(name, err) {
|
|
3309
|
+
const detail = err instanceof Error ? err.message : String(err);
|
|
3310
|
+
this.markAwake(name);
|
|
3311
|
+
slog3.error(
|
|
3312
|
+
`${name} failed to wake ${MAX_WAKE_ATTEMPTS} times in a row; giving up and marking errored`,
|
|
3313
|
+
logger_default.errorData(err)
|
|
3314
|
+
);
|
|
3315
|
+
try {
|
|
3316
|
+
await publish({
|
|
3317
|
+
type: "mind_stopped",
|
|
3318
|
+
mind: name,
|
|
3319
|
+
summary: `${name} failed to wake after ${MAX_WAKE_ATTEMPTS} attempts`,
|
|
3320
|
+
metadata: { error: "wake_failed", detail }
|
|
3321
|
+
});
|
|
3322
|
+
} catch (e) {
|
|
3323
|
+
slog3.error(`failed to publish wake-failure activity for ${name}`, logger_default.errorData(e));
|
|
3324
|
+
}
|
|
3325
|
+
await recordNotice({
|
|
3326
|
+
mind: name,
|
|
3327
|
+
session: MIND_LEVEL_SESSION,
|
|
3328
|
+
kind: "startup",
|
|
3329
|
+
reason: "startup_failed",
|
|
3330
|
+
detail: `Wake failed ${MAX_WAKE_ATTEMPTS} times in a row and was given up. Last error: ${detail}`
|
|
3331
|
+
});
|
|
3332
|
+
}
|
|
3187
3333
|
// --- Internal methods ---
|
|
3188
3334
|
markSleeping(name, opts) {
|
|
3189
3335
|
const sleepConfig = this.getSleepConfig(name);
|
|
@@ -3194,7 +3340,9 @@ var SleepManager = class {
|
|
|
3194
3340
|
wokenByTrigger: false,
|
|
3195
3341
|
voluntaryWakeAt: opts?.voluntaryWakeAt ?? null,
|
|
3196
3342
|
queuedMessageCount: this.states.get(name)?.queuedMessageCount ?? 0,
|
|
3197
|
-
triggerWakeHistory: []
|
|
3343
|
+
triggerWakeHistory: [],
|
|
3344
|
+
wakeFailures: 0,
|
|
3345
|
+
nextWakeAttemptAt: null
|
|
3198
3346
|
};
|
|
3199
3347
|
this.states.set(name, state2);
|
|
3200
3348
|
this.saveState();
|
|
@@ -3225,6 +3373,9 @@ var SleepManager = class {
|
|
|
3225
3373
|
const config = this.getSleepConfig(name);
|
|
3226
3374
|
if (!config?.enabled || !config.schedule) continue;
|
|
3227
3375
|
const state2 = this.states.get(name);
|
|
3376
|
+
if (state2?.sleeping && state2.nextWakeAttemptAt && now < new Date(state2.nextWakeAttemptAt)) {
|
|
3377
|
+
continue;
|
|
3378
|
+
}
|
|
3228
3379
|
if (state2?.sleeping && state2.voluntaryWakeAt) {
|
|
3229
3380
|
const wakeAt = new Date(state2.voluntaryWakeAt);
|
|
3230
3381
|
if (now >= wakeAt) {
|
|
@@ -3482,7 +3633,7 @@ function getSleepManagerIfReady() {
|
|
|
3482
3633
|
// packages/daemon/src/lib/delivery/delivery-manager.ts
|
|
3483
3634
|
import { readFile, realpath } from "fs/promises";
|
|
3484
3635
|
import { extname, resolve as resolve8 } from "path";
|
|
3485
|
-
import { and as and4, eq as eq5, inArray
|
|
3636
|
+
import { and as and4, eq as eq5, inArray, sql as sql2 } from "drizzle-orm";
|
|
3486
3637
|
|
|
3487
3638
|
// packages/daemon/src/lib/chat/typing.ts
|
|
3488
3639
|
var DEFAULT_TTL_MS = 1e4;
|
|
@@ -3879,7 +4030,7 @@ var DeliveryManager = class {
|
|
|
3879
4030
|
if (promote.length === 0) return;
|
|
3880
4031
|
try {
|
|
3881
4032
|
const db = await getDb();
|
|
3882
|
-
await db.update(deliveryQueue).set({ status: "pending", attempts: 0, next_attempt_at: null }).where(
|
|
4033
|
+
await db.update(deliveryQueue).set({ status: "pending", attempts: 0, next_attempt_at: null }).where(inArray(deliveryQueue.id, promote));
|
|
3883
4034
|
dlog.info(`released ${promote.length} gated message(s) for ${baseName} after route change`);
|
|
3884
4035
|
} catch (err) {
|
|
3885
4036
|
dlog.warn(`failed to promote gated rows for ${baseName}`, logger_default.errorData(err));
|
|
@@ -4044,7 +4195,7 @@ var DeliveryManager = class {
|
|
|
4044
4195
|
if (valid.length === 0) return;
|
|
4045
4196
|
try {
|
|
4046
4197
|
const db = await getDb();
|
|
4047
|
-
await db.delete(deliveryQueue).where(
|
|
4198
|
+
await db.delete(deliveryQueue).where(inArray(deliveryQueue.id, valid));
|
|
4048
4199
|
} catch (err) {
|
|
4049
4200
|
dlog.warn("failed to delete delivered delivery queue rows", logger_default.errorData(err));
|
|
4050
4201
|
}
|
|
@@ -4055,7 +4206,7 @@ var DeliveryManager = class {
|
|
|
4055
4206
|
if (valid.length === 0) return;
|
|
4056
4207
|
try {
|
|
4057
4208
|
const db = await getDb();
|
|
4058
|
-
const rows = await db.select({ id: deliveryQueue.id, attempts: deliveryQueue.attempts }).from(deliveryQueue).where(
|
|
4209
|
+
const rows = await db.select({ id: deliveryQueue.id, attempts: deliveryQueue.attempts }).from(deliveryQueue).where(inArray(deliveryQueue.id, valid));
|
|
4059
4210
|
for (const row of rows) {
|
|
4060
4211
|
const attempts = row.attempts + 1;
|
|
4061
4212
|
const backoffSec = Math.round(
|
|
@@ -4308,16 +4459,17 @@ var DeliveryManager = class {
|
|
|
4308
4459
|
const channel = payload.channel ?? "unknown";
|
|
4309
4460
|
const notification = [
|
|
4310
4461
|
`[New channel: ${channel}]`,
|
|
4462
|
+
`Someone new is reaching out \u2014 you don't have a route for this channel yet.`,
|
|
4311
4463
|
`Sender: ${payload.sender ?? "unknown"}`,
|
|
4312
4464
|
payload.platform ? `Platform: ${payload.platform}` : null,
|
|
4313
4465
|
payload.participantCount ? `Participants: ${payload.participantCount}` : null,
|
|
4314
4466
|
"",
|
|
4315
4467
|
`Preview: ${preview}`,
|
|
4316
4468
|
"",
|
|
4317
|
-
`To
|
|
4318
|
-
`Messages are
|
|
4469
|
+
`To start hearing this channel, add a routing rule for "${channel}" to .config/routes.json.`,
|
|
4470
|
+
`Messages are held safely until you do \u2014 nothing is lost. If you'd rather not engage, just leave it unrouted.`
|
|
4319
4471
|
].filter((line) => line !== null).join("\n");
|
|
4320
|
-
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-
|
|
4472
|
+
const { sendSystemMessage: sendSystemMessage2 } = await import("./system-chat-XOALE2RD.js");
|
|
4321
4473
|
await sendSystemMessage2(mindName, notification);
|
|
4322
4474
|
}
|
|
4323
4475
|
/**
|
|
@@ -4491,6 +4643,9 @@ var DeliveryManager = class {
|
|
|
4491
4643
|
const buffer = this.batchBuffers.get(bufferKey);
|
|
4492
4644
|
if (buffer && buffer.messages.length > 0) {
|
|
4493
4645
|
this.scheduleBatchTimers(mind, session, bufferKey);
|
|
4646
|
+
} else if (session.startsWith("new-")) {
|
|
4647
|
+
mindSessions.delete(session);
|
|
4648
|
+
if (mindSessions.size === 0) this.sessionStates.delete(mind);
|
|
4494
4649
|
}
|
|
4495
4650
|
}
|
|
4496
4651
|
}
|
|
@@ -4606,8 +4761,8 @@ async function linkToolResultToTurn(mind, turnId, toolResultContent, toolUseEven
|
|
|
4606
4761
|
await db.update(activity).set({
|
|
4607
4762
|
turn_id: turnId,
|
|
4608
4763
|
...toolUseEventId != null ? { source_event_id: toolUseEventId } : {}
|
|
4609
|
-
}).where(
|
|
4610
|
-
const actRows = await db.select().from(activity).where(
|
|
4764
|
+
}).where(inArray2(activity.id, activityIds));
|
|
4765
|
+
const actRows = await db.select().from(activity).where(inArray2(activity.id, activityIds));
|
|
4611
4766
|
if (actRows.length > 0) {
|
|
4612
4767
|
await db.insert(mindHistory).values(
|
|
4613
4768
|
actRows.map((a) => ({
|
|
@@ -4631,40 +4786,44 @@ function resolveSleepAction(sleepBehavior, wokenByTrigger, wakeTriggerMatches) {
|
|
|
4631
4786
|
if (!sleepBehavior && wakeTriggerMatches) return "queue-and-wake";
|
|
4632
4787
|
return "queue";
|
|
4633
4788
|
}
|
|
4634
|
-
async function deliverMessage(mindName, payload) {
|
|
4789
|
+
async function deliverMessage(mindName, payload, opts = {}) {
|
|
4635
4790
|
try {
|
|
4636
4791
|
const baseName = await getBaseName(mindName);
|
|
4637
4792
|
const entry = await findMind(baseName);
|
|
4638
4793
|
if (!entry) {
|
|
4639
4794
|
dlog2.warn(`cannot deliver to ${mindName}: mind not found`);
|
|
4640
|
-
return;
|
|
4795
|
+
return false;
|
|
4641
4796
|
}
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
if (action === "skip") {
|
|
4653
|
-
dlog2.info(
|
|
4654
|
-
`skipped delivery to ${baseName} (sleeping, whileSleeping=skip, channel=${payload.channel})`
|
|
4797
|
+
if (!opts.isFlush) {
|
|
4798
|
+
const textContent = extractTextContent(payload.content);
|
|
4799
|
+
await recordInbound(baseName, payload.channel, payload.sender ?? null, textContent);
|
|
4800
|
+
const sleepManager = getSleepManagerIfReady();
|
|
4801
|
+
if (sleepManager?.isSleeping(baseName)) {
|
|
4802
|
+
const sleepState = sleepManager.getState(baseName);
|
|
4803
|
+
const action = resolveSleepAction(
|
|
4804
|
+
payload.whileSleeping,
|
|
4805
|
+
sleepState.wokenByTrigger,
|
|
4806
|
+
sleepManager.checkWakeTrigger(baseName, payload)
|
|
4655
4807
|
);
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4808
|
+
if (action === "skip") {
|
|
4809
|
+
dlog2.info(
|
|
4810
|
+
`skipped delivery to ${baseName} (sleeping, whileSleeping=skip, channel=${payload.channel})`
|
|
4811
|
+
);
|
|
4812
|
+
return true;
|
|
4813
|
+
}
|
|
4814
|
+
await sleepManager.queueSleepMessage(baseName, payload);
|
|
4815
|
+
if (action === "queue-and-wake") {
|
|
4816
|
+
sleepManager.initiateWake(baseName, { trigger: { channel: payload.channel } }).catch((err) => dlog2.warn(`failed to trigger-wake ${baseName}`, logger_default.errorData(err)));
|
|
4817
|
+
}
|
|
4818
|
+
return true;
|
|
4661
4819
|
}
|
|
4662
|
-
return;
|
|
4663
4820
|
}
|
|
4664
4821
|
const manager = getDeliveryManager();
|
|
4665
4822
|
await manager.routeAndDeliver(mindName, payload);
|
|
4823
|
+
return true;
|
|
4666
4824
|
} catch (err) {
|
|
4667
4825
|
dlog2.warn(`unexpected error delivering to ${mindName}`, logger_default.errorData(err));
|
|
4826
|
+
return false;
|
|
4668
4827
|
}
|
|
4669
4828
|
}
|
|
4670
4829
|
|
|
@@ -4674,6 +4833,12 @@ var dmCache = /* @__PURE__ */ new Map();
|
|
|
4674
4833
|
function resetSystemDMCache() {
|
|
4675
4834
|
dmCache.clear();
|
|
4676
4835
|
}
|
|
4836
|
+
function shouldGenerateSystemFallback(opts) {
|
|
4837
|
+
const { senderIsMind, hasMessage, convType, participants, replyTarget } = opts;
|
|
4838
|
+
if (!senderIsMind || !hasMessage) return false;
|
|
4839
|
+
if (isSpiritName(replyTarget)) return false;
|
|
4840
|
+
return convType === "dm" && participants.length === 2 && participants.some((p) => p.userType === "system");
|
|
4841
|
+
}
|
|
4677
4842
|
async function ensureSystemDM(mindName) {
|
|
4678
4843
|
const cached = dmCache.get(mindName);
|
|
4679
4844
|
if (cached) return { conversationId: cached };
|
|
@@ -4694,7 +4859,7 @@ async function ensureSystemDM(mindName) {
|
|
|
4694
4859
|
return { conversationId: conv.id };
|
|
4695
4860
|
}
|
|
4696
4861
|
async function sendSystemMessage(mindName, text, opts) {
|
|
4697
|
-
const isSpirit = mindName
|
|
4862
|
+
const isSpirit = isSpiritName(mindName);
|
|
4698
4863
|
let conversationId;
|
|
4699
4864
|
if (!isSpirit) {
|
|
4700
4865
|
const dm = await ensureSystemDM(mindName);
|
|
@@ -4719,27 +4884,20 @@ async function sendSystemMessageDirect(mindName, text) {
|
|
|
4719
4884
|
await recordInbound(mindName, "@volute", "volute", text);
|
|
4720
4885
|
return { conversationId };
|
|
4721
4886
|
}
|
|
4722
|
-
async function
|
|
4723
|
-
const spiritEntry = await findMind(
|
|
4724
|
-
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
channel: `@${mindName}`,
|
|
4732
|
-
conversationId,
|
|
4733
|
-
sender: mindName,
|
|
4734
|
-
isDM: true,
|
|
4735
|
-
participants: ["volute", mindName],
|
|
4736
|
-
participantCount: 2
|
|
4737
|
-
});
|
|
4738
|
-
return;
|
|
4739
|
-
} catch (err) {
|
|
4740
|
-
slog4.warn(`failed to route to spirit, falling back to aiCompleteUtility`, logger_default.errorData(err));
|
|
4741
|
-
}
|
|
4887
|
+
async function spiritWillHandle() {
|
|
4888
|
+
const spiritEntry = await findMind(SPIRIT_NAME);
|
|
4889
|
+
if (spiritEntry?.running && spiritEntry.mindType === "spirit") return true;
|
|
4890
|
+
try {
|
|
4891
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
|
|
4892
|
+
const sm = getSleepManagerIfReady2();
|
|
4893
|
+
if (sm?.isSleeping(SPIRIT_NAME)) return true;
|
|
4894
|
+
} catch (err) {
|
|
4895
|
+
slog4.debug("could not check spirit sleep state", logger_default.errorData(err));
|
|
4742
4896
|
}
|
|
4897
|
+
return false;
|
|
4898
|
+
}
|
|
4899
|
+
async function generateSystemFallbackReply(conversationId, mindName, message) {
|
|
4900
|
+
if (await spiritWillHandle()) return;
|
|
4743
4901
|
const entry = await findMind(mindName);
|
|
4744
4902
|
const dir = mindDir(mindName);
|
|
4745
4903
|
const config = readVoluteConfig(dir);
|
|
@@ -4758,7 +4916,7 @@ async function generateSystemReply(conversationId, mindName, message) {
|
|
|
4758
4916
|
if (config.sleep.schedule?.wake) contextParts.push(`Wake cron: ${config.sleep.schedule.wake}`);
|
|
4759
4917
|
}
|
|
4760
4918
|
try {
|
|
4761
|
-
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-
|
|
4919
|
+
const { getSleepManagerIfReady: getSleepManagerIfReady2 } = await import("./sleep-manager-HCUH4PM4.js");
|
|
4762
4920
|
const sm = getSleepManagerIfReady2();
|
|
4763
4921
|
if (sm) {
|
|
4764
4922
|
const state2 = sm.getState(mindName);
|
|
@@ -4804,10 +4962,11 @@ async function generateSystemReply(conversationId, mindName, message) {
|
|
|
4804
4962
|
|
|
4805
4963
|
export {
|
|
4806
4964
|
resetSystemDMCache,
|
|
4965
|
+
shouldGenerateSystemFallback,
|
|
4807
4966
|
ensureSystemDM,
|
|
4808
4967
|
sendSystemMessage,
|
|
4809
4968
|
sendSystemMessageDirect,
|
|
4810
|
-
|
|
4969
|
+
generateSystemFallbackReply,
|
|
4811
4970
|
checkHealth,
|
|
4812
4971
|
RotatingLog,
|
|
4813
4972
|
syncProviderToMinds,
|