@coffeexdev/openclaw-sentinel 0.5.0 → 0.5.1
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/README.md +1 -1
- package/dist/index.js +14 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -146,7 +146,7 @@ Use `sentinel_control`:
|
|
|
146
146
|
1. Sentinel evaluates conditions.
|
|
147
147
|
2. On match, it dispatches a generic callback envelope (`type: "sentinel.callback"`) to `localDispatchBase + webhookPath`.
|
|
148
148
|
3. The envelope includes stable keys (`intent`, `context`, `watcher`, `trigger`, bounded `payload`, `deliveryTargets`, `deliveryContext`, `source`) so downstream agent behavior is workflow-agnostic.
|
|
149
|
-
4. For `/hooks/sentinel`, Sentinel enqueues an instruction-prefixed system event plus structured JSON envelope
|
|
149
|
+
4. For `/hooks/sentinel`, Sentinel enqueues an instruction-prefixed system event plus structured JSON envelope with a cron-tagged callback context, then requests an immediate `cron:sentinel-callback` wake (avoids heartbeat-poll prompting).
|
|
150
150
|
5. The hook route creates a **response-delivery contract** keyed by callback dedupe key, preserving original chat/session context (`deliveryContext`) and intended relay targets.
|
|
151
151
|
6. OpenClaw processes each callback in an isolated hook session: per-watcher by default, or grouped when `hookSessionGroup` / `fire.sessionGroup` is set. Shared global hook-session mode is intentionally not supported.
|
|
152
152
|
7. When hook-session LLM output arrives, Sentinel relays assistant-authored text to the original chat context. If no assistant output arrives before `hookResponseTimeoutMs`, optional fallback relay behavior is applied (`hookResponseFallbackMode`).
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,9 @@ const DEFAULT_HOOK_RESPONSE_FALLBACK_MODE = "concise";
|
|
|
11
11
|
const MAX_SENTINEL_WEBHOOK_BODY_BYTES = 64 * 1024;
|
|
12
12
|
const MAX_SENTINEL_WEBHOOK_TEXT_CHARS = 8000;
|
|
13
13
|
const MAX_SENTINEL_PAYLOAD_JSON_CHARS = 2500;
|
|
14
|
+
const SENTINEL_CALLBACK_WAKE_REASON = "cron:sentinel-callback";
|
|
15
|
+
const SENTINEL_CALLBACK_CONTEXT_KEY = "cron:sentinel-callback";
|
|
16
|
+
const HEARTBEAT_ACK_TOKEN_PATTERN = /\bHEARTBEAT_OK\b/gi;
|
|
14
17
|
const SENTINEL_EVENT_INSTRUCTION_PREFIX = "SENTINEL_TRIGGER: This system event came from /hooks/sentinel. Evaluate action policy, decide whether to notify configured deliveryTargets, and execute safe follow-up actions.";
|
|
15
18
|
const SUPPORTED_DELIVERY_CHANNELS = new Set([
|
|
16
19
|
"telegram",
|
|
@@ -303,12 +306,16 @@ function buildRelayMessage(envelope) {
|
|
|
303
306
|
if (contextSummary)
|
|
304
307
|
lines.push(contextSummary);
|
|
305
308
|
const text = lines.join("\n").trim();
|
|
306
|
-
return text.length > 0
|
|
309
|
+
return text.length > 0
|
|
310
|
+
? text
|
|
311
|
+
: "Sentinel callback received, but no assistant detail was generated.";
|
|
307
312
|
}
|
|
308
313
|
function normalizeAssistantRelayText(assistantTexts) {
|
|
309
314
|
if (!Array.isArray(assistantTexts) || assistantTexts.length === 0)
|
|
310
315
|
return undefined;
|
|
311
|
-
const parts = assistantTexts
|
|
316
|
+
const parts = assistantTexts
|
|
317
|
+
.map((value) => value.replace(HEARTBEAT_ACK_TOKEN_PATTERN, "").trim())
|
|
318
|
+
.filter(Boolean);
|
|
312
319
|
if (parts.length === 0)
|
|
313
320
|
return undefined;
|
|
314
321
|
return trimText(parts.join("\n\n"), MAX_SENTINEL_WEBHOOK_TEXT_CHARS);
|
|
@@ -658,9 +665,12 @@ export function createSentinelPlugin(overrides) {
|
|
|
658
665
|
const envelope = buildSentinelEventEnvelope(payload);
|
|
659
666
|
const sessionKey = buildIsolatedHookSessionKey(envelope, config);
|
|
660
667
|
const text = buildSentinelSystemEvent(envelope);
|
|
661
|
-
const enqueued = api.runtime.system.enqueueSystemEvent(text, {
|
|
668
|
+
const enqueued = api.runtime.system.enqueueSystemEvent(text, {
|
|
669
|
+
sessionKey,
|
|
670
|
+
contextKey: SENTINEL_CALLBACK_CONTEXT_KEY,
|
|
671
|
+
});
|
|
662
672
|
api.runtime.system.requestHeartbeatNow({
|
|
663
|
-
reason:
|
|
673
|
+
reason: SENTINEL_CALLBACK_WAKE_REASON,
|
|
664
674
|
sessionKey,
|
|
665
675
|
});
|
|
666
676
|
const relayTargets = inferRelayTargets(payload, envelope);
|