@adaptic/maestro 1.10.2 → 1.10.4
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/bin/maestro.mjs
CHANGED
|
@@ -625,6 +625,8 @@ rubrics: []
|
|
|
625
625
|
"slack:events:stop": "./scripts/slack-events-ctl.sh stop",
|
|
626
626
|
"slack:events:status": "./scripts/slack-events-ctl.sh status",
|
|
627
627
|
upgrade: "npx @adaptic/maestro upgrade",
|
|
628
|
+
init: "npx @adaptic/maestro init",
|
|
629
|
+
doctor: "npx @adaptic/maestro doctor",
|
|
628
630
|
},
|
|
629
631
|
dependencies: {
|
|
630
632
|
"@google/genai": "^1.42.0",
|
package/package.json
CHANGED
|
@@ -109,9 +109,13 @@ test("guarded cadence completes inline when there's no work", async () => {
|
|
|
109
109
|
test("guarded cadence escalates when guard says work is pending", async () => {
|
|
110
110
|
const root = await makeAgentRoot();
|
|
111
111
|
// Seed an inbox item so the inbox-processor guard returns "escalate".
|
|
112
|
+
// Also set INBOX_CADENCE_ESCALATE=1 because the default behaviour is
|
|
113
|
+
// now inline (reactive daemon owns inbox dispatch — see cadence-handlers.mjs).
|
|
112
114
|
mkdirSync(join(root, "state/inbox/slack"), { recursive: true });
|
|
113
115
|
writeFileSync(join(root, "state/inbox/slack/item.json"), JSON.stringify({ id: "msg1" }));
|
|
114
116
|
plantPrompt(root, "inbox-processor");
|
|
117
|
+
const prevEnv = process.env.INBOX_CADENCE_ESCALATE;
|
|
118
|
+
process.env.INBOX_CADENCE_ESCALATE = "1";
|
|
115
119
|
const spawnCalls = [];
|
|
116
120
|
const consumer = startConsumer({
|
|
117
121
|
agentRoot: root,
|
|
@@ -131,6 +135,8 @@ test("guarded cadence escalates when guard says work is pending", async () => {
|
|
|
131
135
|
} finally {
|
|
132
136
|
await consumer.stop();
|
|
133
137
|
await rmRoot(root);
|
|
138
|
+
if (prevEnv === undefined) delete process.env.INBOX_CADENCE_ESCALATE;
|
|
139
|
+
else process.env.INBOX_CADENCE_ESCALATE = prevEnv;
|
|
134
140
|
}
|
|
135
141
|
});
|
|
136
142
|
|
|
@@ -431,9 +437,13 @@ test("explicit reason is attached to event metadata before escalation", async ()
|
|
|
431
437
|
// but for audit visibility we attach guard data to event.metadata.
|
|
432
438
|
const root = await makeAgentRoot();
|
|
433
439
|
// Force a guard:escalate outcome via inbox-processor with pending items.
|
|
440
|
+
// Default behaviour is now inline (reactive daemon owns inbox), so
|
|
441
|
+
// override with INBOX_CADENCE_ESCALATE=1.
|
|
434
442
|
mkdirSync(join(root, "state/inbox/internal"), { recursive: true });
|
|
435
443
|
writeFileSync(join(root, "state/inbox/internal/x.json"), "{}");
|
|
436
444
|
plantPrompt(root, "inbox-processor");
|
|
445
|
+
const prevEnv = process.env.INBOX_CADENCE_ESCALATE;
|
|
446
|
+
process.env.INBOX_CADENCE_ESCALATE = "1";
|
|
437
447
|
const seen = [];
|
|
438
448
|
const consumer = startConsumer({
|
|
439
449
|
agentRoot: root, pollMs: 50,
|
|
@@ -462,5 +472,7 @@ test("explicit reason is attached to event metadata before escalation", async ()
|
|
|
462
472
|
} finally {
|
|
463
473
|
await consumer.stop();
|
|
464
474
|
await rmRoot(root);
|
|
475
|
+
if (prevEnv === undefined) delete process.env.INBOX_CADENCE_ESCALATE;
|
|
476
|
+
else process.env.INBOX_CADENCE_ESCALATE = prevEnv;
|
|
465
477
|
}
|
|
466
478
|
});
|
|
@@ -109,10 +109,19 @@ async function handleStaleRecovery({ event, agentRoot }) {
|
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
111
|
* inbox-processor guard:
|
|
112
|
-
* -
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
112
|
+
* The reactive daemon (agent-daemon.mjs) continuously polls inbound
|
|
113
|
+
* services + drains state/inbox/ + dispatches sessions via classifier
|
|
114
|
+
* and dispatcher. Running the cadence-bus inbox-processor cadence on
|
|
115
|
+
* top causes DOUBLE responses to the same message — observed in
|
|
116
|
+
* ravi-ai when a CEO DM got TWO substantive replies (one from each
|
|
117
|
+
* path) on 2026-05-12.
|
|
118
|
+
*
|
|
119
|
+
* So this guard now always returns inline. The reactive daemon owns
|
|
120
|
+
* inbox dispatch. Operators who want the cadence-only mode (no reactive
|
|
121
|
+
* daemon) can set INBOX_CADENCE_ESCALATE=1 in .env to flip behaviour.
|
|
122
|
+
*
|
|
123
|
+
* Pre-check is still done (count pending items) so the inline result
|
|
124
|
+
* carries useful telemetry, but escalation is suppressed.
|
|
116
125
|
*/
|
|
117
126
|
async function guardInboxProcessor({ agentRoot }) {
|
|
118
127
|
const inboxRoot = join(agentRoot, "state", "inbox");
|
|
@@ -121,10 +130,19 @@ async function guardInboxProcessor({ agentRoot }) {
|
|
|
121
130
|
for (const src of sources) {
|
|
122
131
|
pending += countFiles(join(inboxRoot, src), /\.(json|ya?ml)$/i);
|
|
123
132
|
}
|
|
124
|
-
if (
|
|
125
|
-
|
|
133
|
+
if (process.env.INBOX_CADENCE_ESCALATE === "1") {
|
|
134
|
+
if (pending === 0) {
|
|
135
|
+
return { ok: true, decision: "inline", reason: "inbox empty", pending: 0 };
|
|
136
|
+
}
|
|
137
|
+
return { ok: true, decision: "escalate", pending };
|
|
126
138
|
}
|
|
127
|
-
return {
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
decision: "inline",
|
|
142
|
+
reason: "reactive-daemon-owns-inbox",
|
|
143
|
+
pending,
|
|
144
|
+
note: "Set INBOX_CADENCE_ESCALATE=1 to override.",
|
|
145
|
+
};
|
|
128
146
|
}
|
|
129
147
|
|
|
130
148
|
/**
|