volute 0.50.0 → 0.52.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-H7YI3BTF.js → activity-events-LQII6PZS.js} +3 -3
- package/dist/{ai-service-V4CTNGI3.js → ai-service-YW5SWCSB.js} +7 -3
- package/dist/{archive-ORM3ENHI.js → archive-FOHGXHPT.js} +3 -3
- package/dist/{auth-DT7GY7EZ.js → auth-KRDSM55Q.js} +6 -4
- package/dist/{avatar-image-QEPAP3A5.js → avatar-image-52WGXLHV.js} +3 -3
- package/dist/{backup-IE6PMXJO.js → backup-YVGV2ZNM.js} +7 -7
- package/dist/{chat-W5K6HCBE.js → chat-VAZ25KVT.js} +4 -4
- package/dist/{chunk-5IIVOWSP.js → chunk-2RNMBXD2.js} +16 -0
- package/dist/{chunk-U3EJJ7JN.js → chunk-5N32EN4O.js} +2 -2
- package/dist/{chunk-ZUG76D3P.js → chunk-5Y54AE3L.js} +1 -1
- package/dist/{chunk-5FVANDON.js → chunk-6NLW72HP.js} +2 -2
- package/dist/{chunk-ALIVXDM4.js → chunk-724DVYHU.js} +95 -51
- package/dist/{chunk-UC6BNMGT.js → chunk-7LT3YZUR.js} +15 -3
- package/dist/{chunk-PW65BXY5.js → chunk-7YJY3F2R.js} +11 -1
- package/dist/{chunk-7OZWKHA3.js → chunk-AXFLY5GU.js} +28 -5
- package/dist/{chunk-SSNZ6ZNN.js → chunk-CV6BNGFK.js} +3 -3
- package/dist/{chunk-MLZBBLMT.js → chunk-CW7BQKF6.js} +4 -4
- package/dist/{chunk-QFVGPKJI.js → chunk-DMK5ASKV.js} +1 -1
- package/dist/{chunk-WBBKYUGF.js → chunk-EDR47UE2.js} +2 -2
- package/dist/{chunk-632FJ23O.js → chunk-EGV6R6UF.js} +26 -7
- package/dist/{chunk-KAEZOVP6.js → chunk-FLIEXG2T.js} +1 -1
- package/dist/{chunk-5TPC4KCV.js → chunk-FXWBFDQR.js} +2 -2
- package/dist/{chunk-74T3CEXK.js → chunk-G7A5LEVI.js} +2 -2
- package/dist/{chunk-7UWXAJMK.js → chunk-GLM7TVWP.js} +1 -1
- package/dist/{chunk-CAIYV33P.js → chunk-H6X6CKDN.js} +2 -1
- package/dist/{chunk-C3KLHJDB.js → chunk-HTRSSOHY.js} +1 -1
- package/dist/{chunk-77IZUVBB.js → chunk-I7U5EEZC.js} +2 -2
- package/dist/{chunk-X67VT4QO.js → chunk-ICXY54ZC.js} +1 -1
- package/dist/{chunk-HW6Q7AMB.js → chunk-ITK6HV47.js} +6 -7
- package/dist/{chunk-5PKFJHCR.js → chunk-JHKBALS2.js} +2 -2
- package/dist/{chunk-SFRYRW37.js → chunk-K2F237KS.js} +9 -9
- package/dist/{chunk-7XDOTN4R.js → chunk-L7BKTZ5U.js} +1 -1
- package/dist/{chunk-AFSLNUTT.js → chunk-LAUCO2HC.js} +1 -1
- package/dist/{chunk-AJWFDIEY.js → chunk-M77B73VV.js} +1 -1
- package/dist/{chunk-4CN7OCJE.js → chunk-OXWUEU5V.js} +2 -2
- package/dist/{chunk-TGJHGVBZ.js → chunk-RPPTGPYF.js} +4 -4
- package/dist/{chunk-JI67D7O2.js → chunk-RU74YG46.js} +120 -25
- package/dist/{chunk-7FDWPQCU.js → chunk-SW2U6HRB.js} +6 -6
- package/dist/{chunk-574M6I7F.js → chunk-TPX6E6PL.js} +3 -3
- package/dist/{chunk-3BAFMGCJ.js → chunk-U54PJPTB.js} +2 -2
- package/dist/{chunk-6BM2I736.js → chunk-UDZLPR34.js} +1 -1
- package/dist/{chunk-E5S3ILVA.js → chunk-UFTDRTCP.js} +1 -1
- package/dist/{chunk-YQOYZ6G7.js → chunk-VPOMJMV6.js} +2 -2
- package/dist/{chunk-RRZ4RQQU.js → chunk-X67BDDZR.js} +5 -7
- package/dist/{chunk-636GFQNE.js → chunk-XRWUQPCA.js} +8 -7
- package/dist/{chunk-7DXLIYPY.js → chunk-YVR6EHWL.js} +6 -6
- package/dist/{chunk-EQKSRVDE.js → chunk-ZEZQNP2G.js} +113 -49
- package/dist/cli.js +19 -19
- package/dist/{clock-LH7UFNLJ.js → clock-ZT5YT6HA.js} +2 -2
- package/dist/{cloud-sync-IDJFVDEP.js → cloud-sync-H7EWZASD.js} +22 -22
- package/dist/{conversations-S2232Y5I.js → conversations-ZL6PHROD.js} +4 -4
- package/dist/{create-2M7DAHQX.js → create-G2RIKQYK.js} +1 -1
- package/dist/{daemon-restart-2AAGYFHE.js → daemon-restart-4FWUA5JF.js} +6 -6
- package/dist/daemon.js +622 -340
- package/dist/{db-QAY45Z56.js → db-BONH4SUG.js} +2 -2
- package/dist/{delete-O7PEFQDF.js → delete-CYVZUAV2.js} +4 -0
- package/dist/delivery-manager-VYXVKUMP.js +35 -0
- package/dist/{delivery-router-JE7SHYNU.js → delivery-router-RHANNTAC.js} +3 -3
- package/dist/{down-D4IRNEMJ.js → down-QSNEMTTX.js} +5 -5
- package/dist/echo-text-PEEV7FQU.js +39 -0
- package/dist/{env-ABM5IMA7.js → env-IBW2QI6K.js} +1 -1
- package/dist/{env-AZK5X4W7.js → env-SQFCWW52.js} +3 -3
- package/dist/{exec-2H65LMTA.js → exec-ABD3DYA2.js} +3 -3
- package/dist/{export-3E3EL6W3.js → export-VBNWM7I4.js} +3 -3
- package/dist/{extensions-7KP3X6G7.js → extensions-N6L5NYTK.js} +22 -22
- package/dist/{files-6BMKVG5G.js → files-BRY5RRIM.js} +3 -3
- package/dist/{import-UPNTEBBT.js → import-DB2KULRO.js} +6 -6
- package/dist/{isolation-OKDFM6WA.js → isolation-GVV2IBAU.js} +3 -3
- package/dist/{join-PYA36HEC.js → join-KLRU72JJ.js} +10 -2
- package/dist/{list-4BVGH7AN.js → list-UQGIW7OF.js} +1 -1
- package/dist/{login-MOXVLULE.js → login-SB5OENMV.js} +2 -2
- package/dist/{logout-DWD3OQVT.js → logout-YFZAJRPY.js} +2 -2
- package/dist/message-delivery-7URC52ME.js +43 -0
- package/dist/{migrate-thread-config-4A5LW36Z.js → migrate-thread-config-EQSEP2XG.js} +2 -2
- package/dist/{mind-NYRALSV2.js → mind-NEXGT3KE.js} +9 -9
- package/dist/{mind-activity-tracker-L7GCYXQR.js → mind-activity-tracker-QF6DCX2X.js} +4 -4
- package/dist/{mind-history-NXXOOTX6.js → mind-history-OGNR4L7W.js} +1 -1
- package/dist/mind-service-E26ZQXDS.js +47 -0
- package/dist/{mind-sleep-TH6BRQ5X.js → mind-sleep-LZAFBDZD.js} +2 -2
- package/dist/{package-XYSV7NUT.js → package-2W2XKSIP.js} +2 -2
- package/dist/{prompts-QKFPX6DQ.js → prompts-NBO3HRK3.js} +3 -3
- package/dist/{read-ZXGUT4QC.js → read-RJ5NAW5J.js} +3 -14
- package/dist/{registry-4UF6OCOE.js → registry-TRC2HJXR.js} +2 -2
- package/dist/{sandbox-EGEU5GGE.js → sandbox-NNWCTHRI.js} +3 -3
- package/dist/scheduler-JTTWZDYU.js +25 -0
- package/dist/{schema-C2GIPD4V.js → schema-ZZQVM4GR.js} +3 -1
- package/dist/{seed-3IMBOAGK.js → seed-64XEHRUP.js} +1 -1
- package/dist/{seed-cmd-U73XVQMI.js → seed-cmd-UEL2QB3Q.js} +2 -2
- package/dist/{seed-create-FBLNVSUP.js → seed-create-4JRQDPGA.js} +3 -3
- package/dist/{seed-readiness-QRA46ZJQ.js → seed-readiness-DYOVCYHN.js} +4 -4
- package/dist/{seed-sprout-3B4SZX7J.js → seed-sprout-NIDIOJXT.js} +7 -7
- package/dist/{send-NBRZJXKX.js → send-2YKOZJJ5.js} +81 -49
- package/dist/{service-XMXAXGJD.js → service-XQPMZAGI.js} +4 -4
- package/dist/{service-install-MOKTEG7B.js → service-install-2EWD7KXD.js} +5 -5
- package/dist/{setup-JGYAXXW7.js → setup-4IX6PCD3.js} +6 -6
- package/dist/{setup-CAJFOR2N.js → setup-WZSXHHRJ.js} +2 -2
- package/dist/{skill-NXIHDQCG.js → skill-B5OJEQUA.js} +1 -1
- package/dist/skills/volute-mind/references/variants.md +1 -1
- package/dist/{skills-5MSMT7PT.js → skills-MPUALV3S.js} +4 -4
- package/dist/sleep-manager-OFP2GFXF.js +41 -0
- package/dist/{spirit-IL5EMWYZ.js → spirit-4ECYIVGE.js} +7 -7
- package/dist/spirit-availability-Y54Y3675.js +42 -0
- package/dist/{sprout-UPXGJ5HX.js → sprout-GJMZFRGZ.js} +1 -1
- package/dist/{status-IL67CYM4.js → status-MWLE3RVC.js} +5 -5
- package/dist/{system-events-A6IGCEC3.js → system-events-V43HDA3T.js} +5 -3
- package/dist/{tailscale-SJUW2ETR.js → tailscale-KHNZFC7L.js} +2 -2
- package/dist/{template-hash-GSOUARW4.js → template-hash-YKWMVYMM.js} +2 -2
- package/dist/{template-staleness-T27VCGYA.js → template-staleness-PY2CULH6.js} +5 -5
- package/dist/{turn-tracker-6EI2EL7G.js → turn-tracker-C5PVIC3B.js} +5 -5
- package/dist/{up-CLL4665A.js → up-H6LJZDRK.js} +5 -5
- package/dist/{update-HVAUCQPN.js → update-CIWI2JYA.js} +5 -5
- package/dist/{update-check-2MGBBAFF.js → update-check-SZ7B5IFI.js} +3 -3
- package/dist/variant-cleanup-STC6B5HR.js +22 -0
- package/dist/{version-notify-7BUHWZNT.js → version-notify-LBVHH5YV.js} +8 -8
- package/dist/web-assets/assets/index-B_eYTa3R.js +97 -0
- package/dist/web-assets/assets/index-DhZrzddW.css +1 -0
- package/dist/web-assets/index.html +2 -2
- package/drizzle/0018_api_tokens.sql +20 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +2 -2
- package/templates/_base/{biome.json.tmpl → biome.json} +2 -1
- package/templates/_base/gitignore +44 -0
- package/templates/_base/home/public/.gitkeep +0 -0
- package/templates/_base/src/lib/auto-commit.ts +49 -11
- package/templates/_base/src/lib/format-prefix.ts +15 -8
- package/templates/_base/src/lib/router.ts +13 -8
- package/templates/claude/volute-template.json +1 -3
- package/templates/codex/volute-template.json +1 -3
- package/templates/pi/{package.json.tmpl → package.json} +2 -2
- package/templates/pi/volute-template.json +1 -3
- package/dist/delivery-manager-B4OKWD2P.js +0 -33
- package/dist/echo-text-WYAAODBV.js +0 -39
- package/dist/message-delivery-3456PXB7.js +0 -43
- package/dist/mind-service-5TA7UJAT.js +0 -47
- package/dist/scheduler-UV6RUJ7P.js +0 -25
- package/dist/sleep-manager-LIEPO6WG.js +0 -41
- package/dist/spirit-availability-YFEGJNJ2.js +0 -42
- package/dist/variant-cleanup-HJ7Z75R6.js +0 -22
- package/dist/web-assets/assets/index-ClsUcXiW.js +0 -95
- package/dist/web-assets/assets/index-Dz3wTbtR.css +0 -1
- /package/templates/_base/home/.config/{config.json.tmpl → config.json} +0 -0
- /package/templates/claude/{package.json.tmpl → package.json} +0 -0
- /package/templates/codex/home/.config/{config.json.tmpl → config.json} +0 -0
- /package/templates/codex/{package.json.tmpl → package.json} +0 -0
- /package/templates/pi/home/.config/{config.json.tmpl → config.json} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
tryGetMindManager
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-724DVYHU.js";
|
|
5
5
|
import {
|
|
6
6
|
extractTextContent,
|
|
7
7
|
getRoutingConfig,
|
|
@@ -9,23 +9,27 @@ import {
|
|
|
9
9
|
resolveRoute,
|
|
10
10
|
setRoutesChangeListener,
|
|
11
11
|
shouldGate
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UDZLPR34.js";
|
|
13
13
|
import {
|
|
14
14
|
linkInboundToActiveTurn
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-YVR6EHWL.js";
|
|
16
|
+
import {
|
|
17
|
+
MIND_LEVEL_THREAD,
|
|
18
|
+
newEphemeralSession
|
|
19
|
+
} from "./chunk-AXFLY5GU.js";
|
|
16
20
|
import {
|
|
17
21
|
publish
|
|
18
22
|
} from "./chunk-LNNI3MS4.js";
|
|
19
23
|
import {
|
|
20
24
|
getParticipants,
|
|
21
25
|
publish as publish2
|
|
22
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-TPX6E6PL.js";
|
|
23
27
|
import {
|
|
24
28
|
onMindEvent
|
|
25
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-UFTDRTCP.js";
|
|
26
30
|
import {
|
|
27
31
|
renderAvatarBlock
|
|
28
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-ICXY54ZC.js";
|
|
29
33
|
import {
|
|
30
34
|
readVoluteConfig
|
|
31
35
|
} from "./chunk-WCFSBH33.js";
|
|
@@ -38,13 +42,13 @@ import {
|
|
|
38
42
|
getDb,
|
|
39
43
|
mindDir,
|
|
40
44
|
voluteHome
|
|
41
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-H6X6CKDN.js";
|
|
42
46
|
import {
|
|
43
47
|
channelGates,
|
|
44
48
|
deliveryQueue,
|
|
45
49
|
messages,
|
|
46
50
|
mindHistory
|
|
47
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-2RNMBXD2.js";
|
|
48
52
|
|
|
49
53
|
// packages/daemon/src/lib/delivery/delivery-manager.ts
|
|
50
54
|
import { realpath } from "fs/promises";
|
|
@@ -214,6 +218,7 @@ var REDRIVE_INTERVAL_MS = 15e3;
|
|
|
214
218
|
var RETRY_BASE_MS = 5e3;
|
|
215
219
|
var RETRY_MAX_MS = 5 * 6e4;
|
|
216
220
|
var REDRIVE_BATCH_LIMIT = 200;
|
|
221
|
+
var MAX_DELIVERY_ATTEMPTS = 10;
|
|
217
222
|
var GATED_RELEASE_LIMIT_PER_CHANNEL = 10;
|
|
218
223
|
var GATED_NOTIFY_EVERY = 10;
|
|
219
224
|
var mentionRegexCache = /* @__PURE__ */ new Map();
|
|
@@ -238,9 +243,14 @@ var DeliveryManager = class {
|
|
|
238
243
|
isMindRunning = (name) => tryGetMindManager()?.isRunning(name) ?? false;
|
|
239
244
|
/** Delivers a channel event to a mind (invites, release summaries); overridable in tests. */
|
|
240
245
|
notify = async (mindName, text) => {
|
|
241
|
-
const { deliverEvent } = await import("./system-events-
|
|
246
|
+
const { deliverEvent } = await import("./system-events-V43HDA3T.js");
|
|
242
247
|
await deliverEvent(mindName, { type: "channel", body: text });
|
|
243
248
|
};
|
|
249
|
+
/** Surfaces a dead-lettered delivery as a next-turn failure notice; overridable in tests. */
|
|
250
|
+
notifyFailure = async (input) => {
|
|
251
|
+
const { recordNotice } = await import("./system-events-V43HDA3T.js");
|
|
252
|
+
await recordNotice(input);
|
|
253
|
+
};
|
|
244
254
|
constructor() {
|
|
245
255
|
setRoutesChangeListener((mind) => {
|
|
246
256
|
this.releaseGated(mind).catch(
|
|
@@ -256,6 +266,10 @@ var DeliveryManager = class {
|
|
|
256
266
|
setNotifier(fn) {
|
|
257
267
|
this.notify = fn;
|
|
258
268
|
}
|
|
269
|
+
/** Test seam: capture/override dead-letter failure notices. */
|
|
270
|
+
setFailureNotifier(fn) {
|
|
271
|
+
this.notifyFailure = fn;
|
|
272
|
+
}
|
|
259
273
|
// --- Public API ---
|
|
260
274
|
/**
|
|
261
275
|
* Route and deliver a message to a mind. This is the main entry point.
|
|
@@ -268,7 +282,7 @@ var DeliveryManager = class {
|
|
|
268
282
|
if (payload.session) {
|
|
269
283
|
let sessionName2 = payload.session;
|
|
270
284
|
if (sessionName2 === "$new") {
|
|
271
|
-
sessionName2 =
|
|
285
|
+
sessionName2 = newEphemeralSession();
|
|
272
286
|
}
|
|
273
287
|
const sessionConfig2 = resolveDeliveryMode(config, sessionName2);
|
|
274
288
|
if (sessionConfig2.delivery.mode === "batch") {
|
|
@@ -312,7 +326,7 @@ var DeliveryManager = class {
|
|
|
312
326
|
}
|
|
313
327
|
let sessionName = route.session;
|
|
314
328
|
if (sessionName === "$new") {
|
|
315
|
-
sessionName =
|
|
329
|
+
sessionName = newEphemeralSession();
|
|
316
330
|
}
|
|
317
331
|
const sessionConfig = resolveDeliveryMode(config, sessionName, route.rule);
|
|
318
332
|
if (sessionConfig.delivery.mode === "batch") {
|
|
@@ -462,7 +476,7 @@ var DeliveryManager = class {
|
|
|
462
476
|
}
|
|
463
477
|
let session = route.session;
|
|
464
478
|
if (session === "$new") {
|
|
465
|
-
session =
|
|
479
|
+
session = newEphemeralSession();
|
|
466
480
|
}
|
|
467
481
|
const channel = row.channel ?? payload.channel ?? "unknown";
|
|
468
482
|
const list = byChannel.get(channel) ?? [];
|
|
@@ -764,22 +778,102 @@ var DeliveryManager = class {
|
|
|
764
778
|
dlog.warn("failed to delete delivered delivery queue rows", logger_default.errorData(err));
|
|
765
779
|
}
|
|
766
780
|
}
|
|
767
|
-
/**
|
|
768
|
-
|
|
781
|
+
/**
|
|
782
|
+
* Record the outcome of a failed delivery attempt: set a backoff window so the target
|
|
783
|
+
* isn't hot-looped, and — for a LIVE rejection — advance the dead-letter counter.
|
|
784
|
+
*
|
|
785
|
+
* Only a live rejection (`liveRejection: true`: the target was reachable and answered with
|
|
786
|
+
* a non-OK HTTP status) counts toward {@link MAX_DELIVERY_ATTEMPTS}. A transport failure
|
|
787
|
+
* (`liveRejection: false`: connection refused, reset, or timeout — the mind or a detached
|
|
788
|
+
* variant is simply down/unreachable) backs off WITHOUT advancing the counter, so a merely
|
|
789
|
+
* offline target is never dead-lettered and its message is preserved until it returns. The
|
|
790
|
+
* redrive guard only checks the base mind's up-ness, so a stopped variant reaches here on
|
|
791
|
+
* every sweep — this is what stops that from silently dropping its messages. #356
|
|
792
|
+
*
|
|
793
|
+
* A row that reaches the ceiling moves to the terminal `dead` status (excluded from
|
|
794
|
+
* redrive, which only reads `pending`) and the batch is surfaced as one failure notice.
|
|
795
|
+
*
|
|
796
|
+
* Rows here are still `inFlight` (the caller clears ownership in its own `finally`, after
|
|
797
|
+
* this resolves), so the concurrent redrive sweep skips them and can't race this update.
|
|
798
|
+
*/
|
|
799
|
+
async scheduleRetry(ids, opts) {
|
|
769
800
|
const valid = [...new Set(ids.filter((id) => typeof id === "number"))];
|
|
770
801
|
if (valid.length === 0) return;
|
|
771
802
|
try {
|
|
772
803
|
const db = await getDb();
|
|
773
|
-
const rows = await db.select({
|
|
804
|
+
const rows = await db.select({
|
|
805
|
+
id: deliveryQueue.id,
|
|
806
|
+
attempts: deliveryQueue.attempts,
|
|
807
|
+
mind: deliveryQueue.mind,
|
|
808
|
+
target_mind: deliveryQueue.target_mind,
|
|
809
|
+
thread: deliveryQueue.thread,
|
|
810
|
+
channel: deliveryQueue.channel,
|
|
811
|
+
sender: deliveryQueue.sender,
|
|
812
|
+
created_at: deliveryQueue.created_at
|
|
813
|
+
}).from(deliveryQueue).where(inArray(deliveryQueue.id, valid));
|
|
814
|
+
const dead = [];
|
|
774
815
|
for (const row of rows) {
|
|
816
|
+
if (!opts.liveRejection) {
|
|
817
|
+
await db.update(deliveryQueue).set({ next_attempt_at: this.backoffExpr(row.attempts) }).where(eq2(deliveryQueue.id, row.id));
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
775
820
|
const attempts = row.attempts + 1;
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
821
|
+
if (attempts >= MAX_DELIVERY_ATTEMPTS) {
|
|
822
|
+
dlog.error(
|
|
823
|
+
`dead-lettering delivery queue row ${row.id} for ${row.mind} after ${attempts} live rejections (channel=${row.channel ?? "?"}, sender=${row.sender ?? "?"})`
|
|
824
|
+
);
|
|
825
|
+
const flipped = await db.update(deliveryQueue).set({ attempts, status: "dead", next_attempt_at: null }).where(and2(eq2(deliveryQueue.id, row.id), eq2(deliveryQueue.status, "pending"))).returning({ id: deliveryQueue.id });
|
|
826
|
+
if (flipped.length > 0) dead.push(row);
|
|
827
|
+
continue;
|
|
828
|
+
}
|
|
829
|
+
await db.update(deliveryQueue).set({ attempts, next_attempt_at: this.backoffExpr(attempts) }).where(eq2(deliveryQueue.id, row.id));
|
|
780
830
|
}
|
|
831
|
+
if (dead.length > 0) await this.notifyDeadLettered(dead);
|
|
832
|
+
} catch (err) {
|
|
833
|
+
dlog.error("failed to record delivery retry / dead-letter", logger_default.errorData(err));
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
/** Exponential backoff window (capped at {@link RETRY_MAX_MS}) as a SQL datetime expr. */
|
|
837
|
+
backoffExpr(attempts) {
|
|
838
|
+
const backoffSec = Math.round(
|
|
839
|
+
Math.min(RETRY_MAX_MS, RETRY_BASE_MS * 2 ** Math.min(attempts, 20)) / 1e3
|
|
840
|
+
);
|
|
841
|
+
return sql`datetime('now', ${`+${backoffSec} seconds`})`;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Surface a batch of dead-lettered rows as ONE next-turn failure notice, so a whole failing
|
|
845
|
+
* batch can't emit dozens of notices and evict unrelated ones via the per-thread overflow
|
|
846
|
+
* cap. The notice names the channel(s) and send times and points the mind at the surviving
|
|
847
|
+
* channel history, and never throws back into the delivery path — the rows are terminal. #356
|
|
848
|
+
*/
|
|
849
|
+
async notifyDeadLettered(rows) {
|
|
850
|
+
const mind = rows[0].mind;
|
|
851
|
+
const threads = new Set(rows.map((r) => r.thread));
|
|
852
|
+
const single = threads.size === 1 ? [...threads][0] : MIND_LEVEL_THREAD;
|
|
853
|
+
const thread = single.startsWith("new-") ? MIND_LEVEL_THREAD : single;
|
|
854
|
+
const lines = rows.map((r) => {
|
|
855
|
+
const from = r.sender ? ` from ${r.sender}` : "";
|
|
856
|
+
const on = r.channel ? ` on ${r.channel}` : "";
|
|
857
|
+
const to = r.target_mind && r.target_mind !== r.mind ? ` to your variant ${r.target_mind}` : "";
|
|
858
|
+
return `- a message${from}${on}${to} (sent ${r.created_at})`;
|
|
859
|
+
});
|
|
860
|
+
const channels = [...new Set(rows.map((r) => r.channel).filter((c) => !!c))];
|
|
861
|
+
const recovery = channels.length > 0 ? `The original message(s) remain in the channel history \u2014 read them with ${channels.map((c) => `\`volute chat read ${c}\``).join(" or ")}.` : `The original message(s) remain in the channel history.`;
|
|
862
|
+
const detail = [
|
|
863
|
+
`${rows.length} message(s) sent to you could not be delivered after ${MAX_DELIVERY_ATTEMPTS} attempts and were dropped:`,
|
|
864
|
+
...lines,
|
|
865
|
+
recovery
|
|
866
|
+
].join("\n");
|
|
867
|
+
try {
|
|
868
|
+
await this.notifyFailure({
|
|
869
|
+
mind,
|
|
870
|
+
thread,
|
|
871
|
+
kind: "delivery_failed",
|
|
872
|
+
reason: "delivery_failed",
|
|
873
|
+
detail
|
|
874
|
+
});
|
|
781
875
|
} catch (err) {
|
|
782
|
-
dlog.warn(
|
|
876
|
+
dlog.warn(`failed to send dead-letter notice for ${mind}`, logger_default.errorData(err));
|
|
783
877
|
}
|
|
784
878
|
}
|
|
785
879
|
async deliverToMind(mindName, session, payload, sessionConfig, queueId) {
|
|
@@ -821,7 +915,7 @@ var DeliveryManager = class {
|
|
|
821
915
|
if (!ok) {
|
|
822
916
|
this.decrementActive(baseName, session);
|
|
823
917
|
publishTypingForChannels(typingMap.deleteSender(baseName), typingMap);
|
|
824
|
-
await this.scheduleRetry([queueId]);
|
|
918
|
+
await this.scheduleRetry([queueId], { liveRejection: true });
|
|
825
919
|
} else {
|
|
826
920
|
await this.deleteQueueRows([queueId]);
|
|
827
921
|
}
|
|
@@ -829,7 +923,7 @@ var DeliveryManager = class {
|
|
|
829
923
|
dlog.warn(`failed to deliver to ${mindName}`, logger_default.errorData(err));
|
|
830
924
|
this.decrementActive(baseName, session);
|
|
831
925
|
publishTypingForChannels(typingMap.deleteSender(baseName), typingMap);
|
|
832
|
-
await this.scheduleRetry([queueId]);
|
|
926
|
+
await this.scheduleRetry([queueId], { liveRejection: false });
|
|
833
927
|
} finally {
|
|
834
928
|
if (queueId != null) this.inFlight.delete(queueId);
|
|
835
929
|
}
|
|
@@ -908,7 +1002,7 @@ var DeliveryManager = class {
|
|
|
908
1002
|
if (!ok) {
|
|
909
1003
|
this.decrementActive(baseName, session);
|
|
910
1004
|
publishTypingForChannels(typingMap.deleteSender(baseName), typingMap);
|
|
911
|
-
await this.scheduleRetry(queueIds);
|
|
1005
|
+
await this.scheduleRetry(queueIds, { liveRejection: true });
|
|
912
1006
|
} else {
|
|
913
1007
|
await this.deleteQueueRows(queueIds);
|
|
914
1008
|
}
|
|
@@ -916,7 +1010,7 @@ var DeliveryManager = class {
|
|
|
916
1010
|
dlog.warn(`failed to deliver batch to ${mindName}`, logger_default.errorData(err));
|
|
917
1011
|
this.decrementActive(baseName, session);
|
|
918
1012
|
publishTypingForChannels(typingMap.deleteSender(baseName), typingMap);
|
|
919
|
-
await this.scheduleRetry(queueIds);
|
|
1013
|
+
await this.scheduleRetry(queueIds, { liveRejection: false });
|
|
920
1014
|
} finally {
|
|
921
1015
|
for (const id of queueIds) this.inFlight.delete(id);
|
|
922
1016
|
}
|
|
@@ -1036,7 +1130,7 @@ var DeliveryManager = class {
|
|
|
1036
1130
|
const details = detailLines.length > 0 ? `${detailLines.join("\n")}
|
|
1037
1131
|
|
|
1038
1132
|
` : "\n";
|
|
1039
|
-
const { getPrompt } = await import("./prompts-
|
|
1133
|
+
const { getPrompt } = await import("./prompts-NBO3HRK3.js");
|
|
1040
1134
|
const notification = await getPrompt("channel_invite", {
|
|
1041
1135
|
channel,
|
|
1042
1136
|
heldLine,
|
|
@@ -1215,6 +1309,7 @@ export {
|
|
|
1215
1309
|
publishTypingForChannels,
|
|
1216
1310
|
checkStaleSend,
|
|
1217
1311
|
formatHoldNotice,
|
|
1312
|
+
MAX_DELIVERY_ATTEMPTS,
|
|
1218
1313
|
DeliveryManager,
|
|
1219
1314
|
initDeliveryManager,
|
|
1220
1315
|
getDeliveryManager,
|
|
@@ -6,24 +6,24 @@ import {
|
|
|
6
6
|
getMindToken,
|
|
7
7
|
loadJsonMap,
|
|
8
8
|
saveJsonMapAsync
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-724DVYHU.js";
|
|
10
10
|
import {
|
|
11
11
|
deliverEvent
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-AXFLY5GU.js";
|
|
13
13
|
import {
|
|
14
14
|
isSandboxEnabled,
|
|
15
15
|
wrapForSandbox
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-5Y54AE3L.js";
|
|
17
17
|
import {
|
|
18
18
|
readVoluteConfig,
|
|
19
19
|
writeVoluteConfig
|
|
20
20
|
} from "./chunk-WCFSBH33.js";
|
|
21
21
|
import {
|
|
22
22
|
exec
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-M77B73VV.js";
|
|
24
24
|
import {
|
|
25
25
|
loadMergedEnv
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-GLM7TVWP.js";
|
|
27
27
|
import {
|
|
28
28
|
logger_default
|
|
29
29
|
} from "./chunk-QUSMYGNQ.js";
|
|
@@ -34,7 +34,7 @@ import {
|
|
|
34
34
|
mindTmpEnv,
|
|
35
35
|
stateDir,
|
|
36
36
|
voluteSystemDir
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-H6X6CKDN.js";
|
|
38
38
|
|
|
39
39
|
// packages/daemon/src/lib/daemon/scheduler.ts
|
|
40
40
|
import { resolve } from "path";
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
import {
|
|
3
3
|
bufferEvent,
|
|
4
4
|
subscribe
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-U54PJPTB.js";
|
|
6
6
|
import {
|
|
7
7
|
logger_default
|
|
8
8
|
} from "./chunk-QUSMYGNQ.js";
|
|
9
9
|
import {
|
|
10
10
|
getDb
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-H6X6CKDN.js";
|
|
12
12
|
import {
|
|
13
13
|
channels,
|
|
14
14
|
conversationParticipants,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
conversations,
|
|
17
17
|
messages,
|
|
18
18
|
users
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-2RNMBXD2.js";
|
|
20
20
|
|
|
21
21
|
// packages/daemon/src/lib/events/conversations.ts
|
|
22
22
|
import { randomUUID } from "crypto";
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
} from "./chunk-QUSMYGNQ.js";
|
|
5
5
|
import {
|
|
6
6
|
getDb
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-H6X6CKDN.js";
|
|
8
8
|
import {
|
|
9
9
|
activity
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2RNMBXD2.js";
|
|
11
11
|
|
|
12
12
|
// packages/daemon/src/lib/events/event-sequencer.ts
|
|
13
13
|
var BUFFER_SIZE = 1e3;
|
|
@@ -8,12 +8,12 @@ import {
|
|
|
8
8
|
modeLabel,
|
|
9
9
|
pollHealth,
|
|
10
10
|
startService
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-6NLW72HP.js";
|
|
12
12
|
import {
|
|
13
13
|
readGlobalConfig,
|
|
14
14
|
voluteHome,
|
|
15
15
|
voluteSystemDir
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-H6X6CKDN.js";
|
|
17
17
|
|
|
18
18
|
// src/commands/up.ts
|
|
19
19
|
import { spawn } from "child_process";
|
|
@@ -80,10 +80,8 @@ function copyTemplateToDir(composedDir, destDir, mindName, manifest) {
|
|
|
80
80
|
}
|
|
81
81
|
function renderComposedPackageJson(composedDir, mindName) {
|
|
82
82
|
const dest = resolve(composedDir, "package.json");
|
|
83
|
-
if (existsSync(dest)) return
|
|
84
|
-
const
|
|
85
|
-
if (!existsSync(tmpl)) return null;
|
|
86
|
-
const content = readFileSync(tmpl, "utf-8").replaceAll("{{name}}", mindName);
|
|
83
|
+
if (!existsSync(dest)) return null;
|
|
84
|
+
const content = readFileSync(dest, "utf-8").replaceAll("{{name}}", mindName);
|
|
87
85
|
writeFileSync(dest, content);
|
|
88
86
|
return dest;
|
|
89
87
|
}
|
|
@@ -128,11 +126,11 @@ function applyTemplateHomeFiles(homeDir, template) {
|
|
|
128
126
|
} else {
|
|
129
127
|
rmSync(settingsDest, { force: true });
|
|
130
128
|
}
|
|
131
|
-
const templateConfig = resolve(root, template, "home", ".config", "config.json
|
|
132
|
-
const
|
|
129
|
+
const templateConfig = resolve(root, template, "home", ".config", "config.json");
|
|
130
|
+
const configSrc = existsSync(templateConfig) ? templateConfig : resolve(root, "_base", "home", ".config", "config.json");
|
|
133
131
|
const configDest = resolve(homeDir, ".config", "config.json");
|
|
134
132
|
mkdirSync(dirname(configDest), { recursive: true });
|
|
135
|
-
writeFileSync(configDest, readFileSync(
|
|
133
|
+
writeFileSync(configDest, readFileSync(configSrc, "utf-8"));
|
|
136
134
|
}
|
|
137
135
|
function listFiles(dir) {
|
|
138
136
|
const results = [];
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
findBridgeForChannel,
|
|
4
4
|
getBridgeConfig
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-L7BKTZ5U.js";
|
|
6
6
|
import {
|
|
7
7
|
recordOutbound
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-ZEZQNP2G.js";
|
|
9
9
|
import {
|
|
10
10
|
getOrCreateMindUser,
|
|
11
11
|
getUserByUsername
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7LT3YZUR.js";
|
|
13
13
|
import {
|
|
14
14
|
publish
|
|
15
15
|
} from "./chunk-LNNI3MS4.js";
|
|
@@ -20,18 +20,18 @@ import {
|
|
|
20
20
|
getChannelName,
|
|
21
21
|
getConversation,
|
|
22
22
|
getParticipants
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-TPX6E6PL.js";
|
|
24
24
|
import {
|
|
25
25
|
readVoluteConfig
|
|
26
26
|
} from "./chunk-WCFSBH33.js";
|
|
27
27
|
import {
|
|
28
28
|
daemonConfigPath,
|
|
29
29
|
readDaemonToken
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-6NLW72HP.js";
|
|
31
31
|
import {
|
|
32
32
|
readEnv,
|
|
33
33
|
sharedEnvPath
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-GLM7TVWP.js";
|
|
35
35
|
import {
|
|
36
36
|
logger_default
|
|
37
37
|
} from "./chunk-QUSMYGNQ.js";
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
} from "./chunk-LGNUFVMR.js";
|
|
41
41
|
import {
|
|
42
42
|
mindDir
|
|
43
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-H6X6CKDN.js";
|
|
44
44
|
import {
|
|
45
45
|
__export
|
|
46
46
|
} from "./chunk-K3NQKI34.js";
|
|
@@ -581,6 +581,7 @@ async function read4(env, channelSlug, limit) {
|
|
|
581
581
|
}
|
|
582
582
|
return data.items.slice(-limit).map((m) => {
|
|
583
583
|
const text = Array.isArray(m.content) ? m.content.filter((b) => b.type === "text").map((b) => b.text).join("") : m.content;
|
|
584
|
+
if (m.role === "event") return `\xB7 ${text}`;
|
|
584
585
|
return `${m.sender_name ?? m.role}: ${text}`;
|
|
585
586
|
}).join("\n");
|
|
586
587
|
}
|
|
@@ -4,22 +4,22 @@ import {
|
|
|
4
4
|
} from "./chunk-LNNI3MS4.js";
|
|
5
5
|
import {
|
|
6
6
|
getPrompt
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-FXWBFDQR.js";
|
|
8
8
|
import {
|
|
9
9
|
aiCompleteUtility
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-EGV6R6UF.js";
|
|
11
11
|
import {
|
|
12
12
|
logger_default
|
|
13
13
|
} from "./chunk-QUSMYGNQ.js";
|
|
14
14
|
import {
|
|
15
15
|
getDb
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-H6X6CKDN.js";
|
|
17
17
|
import {
|
|
18
18
|
messages,
|
|
19
19
|
mindHistory,
|
|
20
20
|
summaries,
|
|
21
21
|
turns
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-2RNMBXD2.js";
|
|
23
23
|
|
|
24
24
|
// packages/daemon/src/lib/daemon/turn-tracker.ts
|
|
25
25
|
import { randomUUID } from "crypto";
|
|
@@ -1060,11 +1060,11 @@ var Summarizer = class {
|
|
|
1060
1060
|
}
|
|
1061
1061
|
};
|
|
1062
1062
|
async function reconcileWedgedTurns(idleMs) {
|
|
1063
|
-
const { sweepWedgedTurns: sweepWedgedTurns2, summarizeOrphanedTurns: summarizeOrphanedTurns2 } = await import("./turn-tracker-
|
|
1063
|
+
const { sweepWedgedTurns: sweepWedgedTurns2, summarizeOrphanedTurns: summarizeOrphanedTurns2 } = await import("./turn-tracker-C5PVIC3B.js");
|
|
1064
1064
|
const wedged = await sweepWedgedTurns2(idleMs);
|
|
1065
1065
|
if (wedged.length === 0) return;
|
|
1066
1066
|
summarizeOrphanedTurns2(wedged);
|
|
1067
|
-
const { tryGetDeliveryManager } = await import("./delivery-manager-
|
|
1067
|
+
const { tryGetDeliveryManager } = await import("./delivery-manager-VYXVKUMP.js");
|
|
1068
1068
|
const dm = tryGetDeliveryManager();
|
|
1069
1069
|
if (!dm) return;
|
|
1070
1070
|
for (const t of wedged) {
|