openclaw-scheduler 0.2.4 → 0.2.6
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/CHANGELOG.md +14 -0
- package/README.md +16 -6
- package/cli.js +13 -4
- package/dispatch/README.md +18 -3
- package/dispatch/completion.mjs +1312 -34
- package/dispatch/hooks.mjs +17 -5
- package/dispatch/index.mjs +600 -226
- package/dispatch/message-input.mjs +67 -0
- package/dispatch/watcher.mjs +381 -43
- package/dispatcher-strategies.js +203 -30
- package/dispatcher.js +6 -1
- package/gateway.js +71 -8
- package/index.d.ts +1 -0
- package/package.json +3 -1
- package/scripts/dispatch-cli-utils.mjs +53 -0
- package/scripts/inbox-watcher-guardrail.mjs +506 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,20 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [0.2.5] -- 2026-04-27
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- fix(dispatch): make completion prompts task-aware so `dispatch done` no longer implies `tests_passed:true` / `pushed:true` for tasks that explicitly should not push or do not require tests
|
|
9
|
+
- fix(dispatch): recover completion text conservatively from terminal assistant turns instead of treating arbitrary mid-task chatter as the final delivery payload
|
|
10
|
+
- fix(watcher): surface real missed-`done` final reports as interrupted diagnostics instead of silently timing out without useful delivery context
|
|
11
|
+
- fix(dispatch): prefer structured, human-readable completion summaries and suppress generic/internal completion noise in announce flows
|
|
12
|
+
- fix(dispatch): preserve embedded completion summaries, prefer explicit delivery targets for origin detection, and normalize dispatched completion delivery behavior
|
|
13
|
+
- fix(dispatch): harden literal-safe prompt input handling and watcher SIGTERM handoff during delivery/recovery paths
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- feat(dispatch): prefer structured human completion summaries in dispatch delivery flows
|
|
17
|
+
- feat(dispatch): add inbox watcher delivery guardrail to catch broken packaged-layout consumer wiring earlier
|
|
18
|
+
|
|
5
19
|
## [0.2.4] -- 2026-04-18
|
|
6
20
|
|
|
7
21
|
### Fixed
|
package/README.md
CHANGED
|
@@ -1728,7 +1728,7 @@ npm test
|
|
|
1728
1728
|
|
|
1729
1729
|
## Sub-agent Dispatch
|
|
1730
1730
|
|
|
1731
|
-
The dispatch module (`dispatch/index.mjs`) spawns and steers isolated agent sessions via the OpenClaw Gateway API and tracks them by a human-readable label. Unlike the scheduler's job/run model, dispatch calls the gateway directly -- no scheduler tick delay, no DB write required to start a session. Each session is assigned a unique session key, recorded in a local `labels.json` ledger, and
|
|
1731
|
+
The dispatch module (`dispatch/index.mjs`) spawns and steers isolated agent sessions via the OpenClaw Gateway API and tracks them by a human-readable label. Unlike the scheduler's job/run model, dispatch calls the gateway directly -- no scheduler tick delay, no DB write required to start a session. Each session is assigned a unique session key, recorded in a local `labels.json` ledger, and delivered back through a scheduler watcher when the agent calls `done` as its final action. That watcher is the only final-delivery path for dispatched jobs, and it normalizes completions into short human-readable summaries before posting them to chat. The module also supports symlink-based branding: a wrapper directory (such as `my-brand`) contains a `config.json` with a custom name and a symlink to `dispatch/index.mjs`, giving the same CLI a different identity in notifications and logs.
|
|
1732
1732
|
|
|
1733
1733
|
### Quick Example
|
|
1734
1734
|
|
|
@@ -1746,25 +1746,35 @@ openclaw-scheduler enqueue \
|
|
|
1746
1746
|
# Fallback (if openclaw-scheduler is not in PATH):
|
|
1747
1747
|
node ~/.openclaw/scheduler/dispatch/index.mjs enqueue \
|
|
1748
1748
|
--label "fix-deploy-script" --message "..." --deliver-to YOUR_CHAT_ID
|
|
1749
|
+
|
|
1750
|
+
# Literal-safe prompt input when the text contains shell metacharacters:
|
|
1751
|
+
cat prompt.md | openclaw-scheduler enqueue \
|
|
1752
|
+
--label "fix-deploy-script" \
|
|
1753
|
+
--message-stdin \
|
|
1754
|
+
--deliver-to YOUR_CHAT_ID
|
|
1749
1755
|
```
|
|
1750
1756
|
|
|
1757
|
+
For normal chat-triggered dispatches, always pass `--deliver-to` from the inbound metadata `chat_id`. If you omit `--origin`, dispatch now derives it from that explicit delivery target instead of guessing from whichever session was active most recently. The old active-session lookup is kept only as a manual/local fallback when both values are absent.
|
|
1758
|
+
|
|
1751
1759
|
### Flag Reference
|
|
1752
1760
|
|
|
1753
1761
|
| Flag | Default | Description |
|
|
1754
1762
|
|------|---------|-------------|
|
|
1755
1763
|
| `--label` | required | Human-readable name for the session. Used for status lookups, reuse, and watchdog tracking. |
|
|
1756
1764
|
| `--message` | required* | Prompt sent to the agent. |
|
|
1757
|
-
| `--message-file` | -- | Path to a file whose contents are used as the prompt.
|
|
1765
|
+
| `--message-file` | -- | Path to a file whose contents are used as the prompt. Use `-` to read from stdin. Safer than inline shell quoting for prompts with backticks, quotes, or markdown. |
|
|
1766
|
+
| `--message-env` | -- | Environment variable name whose value is used as the prompt. Useful when the prompt contains shell-significant characters. |
|
|
1767
|
+
| `--message-stdin` | -- | Read the prompt from stdin explicitly. If stdin is piped and no explicit prompt source is set, dispatch auto-reads stdin. |
|
|
1758
1768
|
| `--mode` | `fresh` | `fresh` creates a new session. `reuse` continues the last session recorded for this label. |
|
|
1759
1769
|
| `--thinking` | -- | Reasoning budget: `low`, `high`, or `xhigh`. |
|
|
1760
1770
|
| `--model` | -- | Model override, e.g. `anthropic/claude-sonnet-4-6`. |
|
|
1761
|
-
| `--deliver-to` | -- | Delivery target (e.g. Telegram chat ID). Registers
|
|
1771
|
+
| `--deliver-to` | -- | Delivery target (e.g. Telegram chat ID). Registers the scheduler watcher job for durable final delivery. The gateway spawn itself stays fire-and-forget so raw tool output and internal done payloads cannot leak directly to chat. Chat-triggered callers should pass inbound metadata `chat_id` here, especially for group chats. |
|
|
1762
1772
|
| `--delivery-mode` | `announce` | `announce` delivers only when output is non-empty. `announce-always` delivers unconditionally. `none` suppresses delivery. |
|
|
1763
1773
|
| `--timeout` | `300` | Session timeout in seconds. |
|
|
1764
1774
|
| `--monitor` | on | Auto-register a watchdog job that alerts if the session goes silent past the configured threshold. |
|
|
1765
1775
|
| `--no-monitor` | -- | Disable watchdog registration for this dispatch. |
|
|
1766
1776
|
|
|
1767
|
-
*
|
|
1777
|
+
*One prompt source is required: `--message`, `--message-file`, `--message-env`, `--message-stdin`, or piped stdin.
|
|
1768
1778
|
|
|
1769
1779
|
### Subcommand Reference
|
|
1770
1780
|
|
|
@@ -1775,7 +1785,7 @@ node ~/.openclaw/scheduler/dispatch/index.mjs enqueue \
|
|
|
1775
1785
|
| `stuck` | Check all running sessions against the stuck threshold. Exits 1 if genuinely stuck sessions remain after auto-resolving completed ones. |
|
|
1776
1786
|
| `result` | Retrieve the last assistant reply from a session transcript via `chat.history`. |
|
|
1777
1787
|
| `sync` | Reconcile `labels.json` with sessions store state. Auto-marks sessions as done or error based on idle time. Supports `--dry-run`. |
|
|
1778
|
-
| `done` | Agent-side completion signal. The agent calls this as its final action to mark itself done immediately (push-based; no idle timeout wait). |
|
|
1788
|
+
| `done` | Agent-side completion signal. The agent calls this as its final action to mark itself done immediately (push-based; no idle timeout wait). The stored completion payload is normalized for channel-safe delivery, with checklist/sha metadata used as a fallback when the raw summary is generic or noisy. |
|
|
1779
1789
|
| `send` | Inject a message into a running session for mid-run steering. The agent sees it as a new user turn. |
|
|
1780
1790
|
| `steer` | Alias for `send`. The name makes steering intent explicit. |
|
|
1781
1791
|
| `heartbeat` | Check whether a session has been active within the last 10 minutes. Accepts `--label` or `--session-key`. |
|
|
@@ -1808,7 +1818,7 @@ openclaw-scheduler enqueue \
|
|
|
1808
1818
|
--message "Update the API docs to reflect the new /v2 endpoints" \
|
|
1809
1819
|
--thinking high --timeout 600 --deliver-to YOUR_CHAT_ID
|
|
1810
1820
|
|
|
1811
|
-
# Each worker
|
|
1821
|
+
# Each worker gets a watcher-delivered, channel-safe completion summary when done.
|
|
1812
1822
|
# No polling needed. Watchdog jobs are auto-registered for each.
|
|
1813
1823
|
```
|
|
1814
1824
|
|
package/cli.js
CHANGED
|
@@ -100,8 +100,8 @@ Queue:
|
|
|
100
100
|
queue prune Prune old messages now
|
|
101
101
|
|
|
102
102
|
Messages:
|
|
103
|
-
messages send --from <label> [--to <agent>] [--kind <kind>] --body "<text>"
|
|
104
|
-
Send a checkpoint/status message (kind defaults to 'status', to defaults to 'main')
|
|
103
|
+
messages send --from <label> [--to <agent>] [--kind <kind>] [--channel <channel>] [--delivery-to <target>] --body "<text>"
|
|
104
|
+
Send a checkpoint/status message (kind defaults to 'status', to defaults to 'main'; channel/delivery-to override inbox-consumer defaults)
|
|
105
105
|
msg send <from> <to> <body> Send a message (positional form)
|
|
106
106
|
msg inbox <agent-id> [limit] Get inbox (unread)
|
|
107
107
|
msg team-inbox <team-id> [limit] [member-id] [task-id] Get team mailbox
|
|
@@ -610,10 +610,19 @@ switch (command) {
|
|
|
610
610
|
const mTo = mFlags.to || 'main';
|
|
611
611
|
const mKind = mFlags.kind || 'status';
|
|
612
612
|
const mBody = mFlags.body;
|
|
613
|
+
const mChannel = mFlags.channel || null;
|
|
614
|
+
const mDeliveryTo = mFlags['delivery-to'] || null;
|
|
613
615
|
if (!mFrom || !mBody) {
|
|
614
|
-
fail('Usage: messages send --from <label> [--to <agent>] [--kind <kind>] --body "<text>"');
|
|
616
|
+
fail('Usage: messages send --from <label> [--to <agent>] [--kind <kind>] [--channel <channel>] [--delivery-to <target>] --body "<text>"');
|
|
615
617
|
}
|
|
616
|
-
const msg = sendMessage({
|
|
618
|
+
const msg = sendMessage({
|
|
619
|
+
from_agent: mFrom,
|
|
620
|
+
to_agent: mTo,
|
|
621
|
+
kind: mKind,
|
|
622
|
+
body: mBody,
|
|
623
|
+
channel: mChannel,
|
|
624
|
+
delivery_to: mDeliveryTo,
|
|
625
|
+
});
|
|
617
626
|
emit({ ok: true, message: msg }, `Sent: ${fmt(msg)}`);
|
|
618
627
|
break;
|
|
619
628
|
}
|
package/dispatch/README.md
CHANGED
|
@@ -68,27 +68,38 @@ node dispatch/index.mjs enqueue \
|
|
|
68
68
|
--deliver-to YOUR_CHAT_ID \
|
|
69
69
|
--deliver-channel telegram \
|
|
70
70
|
--delivery-mode announce
|
|
71
|
+
|
|
72
|
+
# Literal-safe prompt input for shell-sensitive text:
|
|
73
|
+
cat prompt.md | node dispatch/index.mjs enqueue \
|
|
74
|
+
--label "ticket-43" \
|
|
75
|
+
--message-stdin \
|
|
76
|
+
--delivery-mode none
|
|
71
77
|
```
|
|
72
78
|
|
|
73
79
|
| Flag | Default | Description |
|
|
74
80
|
|---|---|---|
|
|
75
81
|
| `--label` | required | Human name — used for lookup/reuse |
|
|
76
|
-
| `--message` | required | Prompt sent to the agent |
|
|
82
|
+
| `--message` | required* | Prompt sent to the agent |
|
|
83
|
+
| `--message-file` | — | Read prompt text from a file. Use `-` to read from stdin. Safer than inline shell quoting for prompts with backticks, quotes, or markdown. |
|
|
84
|
+
| `--message-env` | — | Read prompt text from an environment variable. |
|
|
85
|
+
| `--message-stdin` | — | Read prompt text from stdin explicitly. If stdin is piped and no explicit source is set, dispatch auto-reads stdin. |
|
|
77
86
|
| `--mode` | `fresh` | `fresh` = new session; `reuse` = continue last session for this label |
|
|
78
87
|
| `--session-key` | — | Explicit session key (bypasses ledger lookup) |
|
|
79
88
|
| `--agent` | `main` | Agent ID |
|
|
80
89
|
| `--model` | — | Model override (e.g. `anthropic/claude-sonnet-4-6`) |
|
|
81
90
|
| `--thinking` | — | Reasoning level: `low`, `high`, `xhigh` |
|
|
82
91
|
| `--timeout` | `300` | Seconds before run times out |
|
|
83
|
-
| `--deliver-to` | — | Delivery target (chat ID, channel ID, handle, etc.). Enables `deliver:true` on the gateway call |
|
|
92
|
+
| `--deliver-to` | — | Delivery target (chat ID, channel ID, handle, etc.). Enables `deliver:true` on the gateway call. Chat-triggered callers should pass inbound metadata `chat_id` here, especially for group chats. |
|
|
84
93
|
| `--deliver-channel` | `telegram` | Delivery channel for `--deliver-to` (telegram, slack, etc.) |
|
|
85
94
|
| `--delivery-mode` | `announce` | `announce`, `announce-always`, `none` |
|
|
86
|
-
| `--origin` | -- | Dispatch origin (e.g. `telegram:12345`) |
|
|
95
|
+
| `--origin` | -- | Dispatch origin (e.g. `telegram:12345`). If omitted but `--deliver-to` is explicit, dispatch derives origin from that target. Active-session auto-detect is fallback for manual/local use only. |
|
|
87
96
|
| `--no-monitor` | false | Skip watcher monitoring |
|
|
88
97
|
| `--monitor-interval` | -- | Watcher cron expression |
|
|
89
98
|
| `--monitor-timeout` | -- | Watcher timeout in minutes |
|
|
90
99
|
| `--verify-cmd` | -- | Post-completion verification command |
|
|
91
100
|
|
|
101
|
+
*One prompt source is required: `--message`, `--message-file`, `--message-env`, `--message-stdin`, or piped stdin.
|
|
102
|
+
|
|
92
103
|
### `status` — session status for a label
|
|
93
104
|
|
|
94
105
|
```bash
|
|
@@ -151,6 +162,10 @@ Notes:
|
|
|
151
162
|
node dispatch/index.mjs send \
|
|
152
163
|
--label "ticket-42" \
|
|
153
164
|
--message "Tests still failing on line 42, focus on the edge case"
|
|
165
|
+
|
|
166
|
+
cat <<'EOF' | node dispatch/index.mjs send --label "ticket-42" --message-stdin
|
|
167
|
+
Use literal `code`, quotes, and $(examples) safely
|
|
168
|
+
EOF
|
|
154
169
|
```
|
|
155
170
|
|
|
156
171
|
Sends a message directly into the running session. The agent sees it as a new
|