1 Commits

Author SHA1 Message Date
65a3fb8d2d fix(wakeup): drop WAKEUP_OK ack-token theatre from wakeup message
The wakeup dispatcher's `deliver` callback only does
`logger.info(reply.slice(0,100))` — no token detection, no scheduler
state change. The "first line of your reply MUST be exactly WAKEUP_OK
so the plugin records the ack" instruction was prompt theatre that
nothing in this plugin (or in openclaw) acted on. Confirmed by
reading openclaw/dist/plugin-sdk/src/auto-reply/tokens.d.ts which
declares HEARTBEAT_OK and SILENT_REPLY tokens but nothing for wakeup.

Symptom in the wild: agents would replay WAKEUP_OK every turn for no
gain — costing model budget on a no-op token — and the workflow doc
(`ClawSkills/workflows/hf-wakeup/flow.md`) carried a wandering
appendix explaining the ack "doesn't actually do anything anyway".

Rewrite the wakeup message to tell the agent the truth: drive the
hf-wakeup workflow to completion; the scheduler keeps re-waking
every 30s until the slot transitions out of `not_started` via
harborforge_calendar_complete or _abort. No ack token expected.

ClawSkills companion change (lyn/ClawSkills d0109f3) removes
WAKEUP_OK from skills/hf-hangman-lab/SKILL.md and
workflows/hf-wakeup/flow.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 09:10:47 +01:00

View File

@@ -128,9 +128,7 @@ function register(api: PluginAPI): void {
/** Resolve agent ID from env, config, or fallback. */
function resolveAgentId(): string {
if (process.env.AGENT_ID) return process.env.AGENT_ID;
// Read from cached `api.config` first — see pushMetaToMonitor for why
// the deprecated `api.runtime?.config?.loadConfig?.()` path is heavy.
const cfg = (api as any).config ?? api.runtime?.config?.loadConfig?.();
const cfg = api.runtime?.config?.loadConfig?.();
return cfg?.agents?.list?.[0]?.id ?? cfg?.agents?.defaults?.id ?? 'unknown';
}
@@ -186,25 +184,6 @@ function register(api: PluginAPI): void {
* Push OpenClaw metadata to the Monitor bridge.
* This enriches Monitor heartbeats with OpenClaw version/plugin/agent info.
* Failures are non-fatal — Monitor continues to work without this data.
*
* IMPORTANT — read config from the cached `api.config` surface, NOT from
* the deprecated `api.runtime?.config?.loadConfig?.()` path. The
* deprecated path triggers a full plugin-metadata-snapshot rebuild on
* every call: realpathSync walks every plugin's package.json + manifest
* + source paths (lstats up the directory tree), `hashWatchedFiles`
* fingerprints all watched plugin files, and `discoverInDirectory`
* re-scans every `dist/extensions/<plugin>` dir. On t2 with ~100 plugins
* each rebuild costs ~6-7s of CPU; with this push firing every 30s
* (default reportIntervalSec) the chronic baseline was ~22-25% gateway
* CPU even with zero agent activity (V8 profile 2026-05-27 08:14:00 60s:
* lstat 44.2%, statSync 6.9%, hashWatchedFiles via memo key 1.7%, all
* routed through readPersistedInstalledPluginIndexInstallRecordsSync ->
* discoverInDirectory). Switching to `api.config` reads from the
* already-loaded snapshot cache; the elsewhere-in-this-file pattern was
* already `api.config ?? api.runtime?.config?.loadConfig?.()`.
*
* Same fix is applied to `resolveAgentId` below — that's read once at
* gateway start so the impact is smaller, but it's the same anti-pattern.
*/
async function pushMetaToMonitor() {
const bridgeClient = getBridgeClient();
@@ -212,7 +191,7 @@ function register(api: PluginAPI): void {
let agentNames: string[] = [];
try {
const cfg = (api as any).config ?? api.runtime?.config?.loadConfig?.();
const cfg = api.runtime?.config?.loadConfig?.();
const agentsList = cfg?.agents?.list;
if (Array.isArray(agentsList)) {
agentNames = agentsList
@@ -328,21 +307,22 @@ function register(api: PluginAPI): void {
)}\n\`\`\``;
}
// First-line ack `WAKEUP_OK` is the plugin's ack-receipt token; the
// agent MUST then continue in the same session and drive the
// `hf-wakeup` workflow to completion (calendar_status → task fetch →
// sub-workflow → calendar_complete/abort). Without that continuation
// the scheduler keeps re-waking every 30s because the slot stays
// `not_started` forever.
// The wakeup dispatcher's `deliver` callback below only logs the
// reply text — it does NOT inspect any ack token. The earlier
// `WAKEUP_OK` first-line-ack convention was prompt-only theatre;
// nothing in this plugin or in openclaw acted on it. The only
// thing that ends a wake cycle is the slot transitioning out of
// `not_started`, which happens when the agent calls
// `harborforge_calendar_complete` or `harborforge_calendar_abort`.
// Tell the agent that plainly instead of asking for a fake ack.
const wakeupMessage =
`You have due slots. **First line of your reply MUST be exactly ` +
`\`WAKEUP_OK\`** so the plugin records the ack. Then, **in this ` +
`same session**, drive the \`hf-wakeup\` workflow of skill ` +
`\`hf-hangman-lab\` to completion — read slot context, call the ` +
`harborforge_calendar_* tools, route to the right sub-workflow, ` +
`and finish with harborforge_calendar_complete or abort. Do NOT ` +
`stop after the ack — the scheduler will re-wake you every 30s ` +
`until the slot transitions out of \`not_started\`.${slotBlock}`;
`You have due slots. Drive the \`hf-wakeup\` workflow of skill ` +
`\`hf-hangman-lab\` to completion in this session — read slot ` +
`context, call the harborforge_calendar_* tools, route to the ` +
`right sub-workflow, and finish with harborforge_calendar_complete ` +
`or harborforge_calendar_abort. The scheduler keeps re-waking you ` +
`every 30s until the slot transitions out of \`not_started\`, so ` +
`partial work or silence just produces another wake.${slotBlock}`;
const result = await dispatchInboundMessageWithDispatcher({
ctx: {