Files
openclaw/src/auto-reply/reply/directive-handling.queue-validation.ts
Jason 70df2b8fe2 feat: steer mid-turn prompts by default (#77023)
Summary:
- Default active-run queueing to steer while preserving explicit followup/collect modes.
- Keep `/steer` fallback behavior and migrate retired queue steering config.
- Await Codex app-server steering acceptance so rejected/aborted steering can fall back safely.
- Route active subagent announcements through intentional acceptance-aware steering, with legacy queue helpers deprecated for delivery decisions.

Verification:
- git diff --check
- rg -n "^(<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|)" CHANGELOG.md docs src extensions || true
- pnpm test src/agents/subagent-announce-dispatch.test.ts src/agents/subagent-announce-delivery.test.ts src/agents/pi-embedded-runner/runs.test.ts src/agents/subagent-announce.format.e2e.test.ts src/agents/subagent-announce.test.ts
- pnpm test src/auto-reply/reply/commands-steer.test.ts src/auto-reply/reply/queue/settings.test.ts src/auto-reply/reply/queue-policy.test.ts src/auto-reply/reply/agent-runner.runreplyagent.e2e.test.ts src/auto-reply/reply/get-reply-run.media-only.test.ts extensions/codex/src/app-server/run-attempt.test.ts -- -t "queued steering|explicit all-mode steering|flushes pending default queued steering|rejects queued steering|resolveActiveRunQueueAction|resolveQueueSettings|handleSteerCommand"

Co-authored-by: fuller-stack-dev <263060202+fuller-stack-dev@users.noreply.github.com>
2026-05-13 14:00:11 +01:00

79 lines
2.9 KiB
TypeScript

import type { SessionEntry } from "../../config/sessions.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import type { ReplyPayload } from "../types.js";
import type { InlineDirectives } from "./directive-handling.parse.js";
import { withOptions } from "./directive-handling.shared.js";
import { resolveQueueSettings } from "./queue/settings.js";
export function maybeHandleQueueDirective(params: {
directives: InlineDirectives;
cfg: OpenClawConfig;
channel: string;
sessionEntry?: SessionEntry;
}): ReplyPayload | undefined {
const { directives } = params;
if (!directives.hasQueueDirective) {
return undefined;
}
const wantsStatus =
!directives.queueMode &&
!directives.queueReset &&
!directives.hasQueueOptions &&
directives.rawQueueMode === undefined &&
directives.rawDebounce === undefined &&
directives.rawCap === undefined &&
directives.rawDrop === undefined;
if (wantsStatus) {
const settings = resolveQueueSettings({
cfg: params.cfg,
channel: params.channel,
sessionEntry: params.sessionEntry,
});
const debounceLabel =
typeof settings.debounceMs === "number" ? `${settings.debounceMs}ms` : "default";
const capLabel = typeof settings.cap === "number" ? String(settings.cap) : "default";
const dropLabel = settings.dropPolicy ?? "default";
return {
text: withOptions(
`Current queue settings: mode=${settings.mode}, debounce=${debounceLabel}, cap=${capLabel}, drop=${dropLabel}.`,
"modes steer, followup, collect, interrupt; debounce:<ms|s|m>, cap:<n>, drop:old|new|summarize",
),
};
}
const queueModeInvalid =
!directives.queueMode && !directives.queueReset && Boolean(directives.rawQueueMode);
const queueDebounceInvalid =
directives.rawDebounce !== undefined && typeof directives.debounceMs !== "number";
const queueCapInvalid = directives.rawCap !== undefined && typeof directives.cap !== "number";
const queueDropInvalid = directives.rawDrop !== undefined && !directives.dropPolicy;
if (queueModeInvalid || queueDebounceInvalid || queueCapInvalid || queueDropInvalid) {
const errors: string[] = [];
if (queueModeInvalid) {
errors.push(
`Unrecognized queue mode "${directives.rawQueueMode ?? ""}". Valid modes: steer, followup, collect, interrupt.`,
);
}
if (queueDebounceInvalid) {
errors.push(
`Invalid debounce "${directives.rawDebounce ?? ""}". Use ms/s/m (e.g. debounce:1500ms, debounce:2s).`,
);
}
if (queueCapInvalid) {
errors.push(
`Invalid cap "${directives.rawCap ?? ""}". Use a positive integer (e.g. cap:10).`,
);
}
if (queueDropInvalid) {
errors.push(
`Invalid drop policy "${directives.rawDrop ?? ""}". Use drop:old, drop:new, or drop:summarize.`,
);
}
return { text: errors.join(" ") };
}
return undefined;
}