mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-22 14:41:34 +00:00
* fix(acp): implicit streamToParent for mode=run without thread When spawning ACP sessions with mode=run and no thread binding, automatically route output to parent session instead of Discord. This enables agent-to-agent supervision patterns where the spawning agent wants results returned programmatically, not posted as chat. The change makes sessions_spawn with runtime=acp and thread=false behave like direct acpx invocation - output goes to the spawning session, not to Discord. Fixes the issue where mode=run without thread still posted to Discord because hasDeliveryTarget was true when called from a Discord context. * fix: use resolved spawnMode instead of params.mode Move implicit streamToParent check to after resolveSpawnMode so that both explicit mode="run" and omitted mode (which defaults to "run" when thread is false) correctly trigger parent routing. This fixes the issue where callers that rely on default mode selection would not get the intended parent streaming behavior. * fix: tighten implicit ACP parent relay gating (#42404) (thanks @davidguttman) --------- Co-authored-by: Onur Solmaz <2453968+osolmaz@users.noreply.github.com>
58 lines
1.4 KiB
TypeScript
58 lines
1.4 KiB
TypeScript
export type HeartbeatReasonKind =
|
|
| "retry"
|
|
| "interval"
|
|
| "manual"
|
|
| "exec-event"
|
|
| "wake"
|
|
| "cron"
|
|
| "hook"
|
|
| "other";
|
|
|
|
function trimReason(reason?: string): string {
|
|
return typeof reason === "string" ? reason.trim() : "";
|
|
}
|
|
|
|
export function normalizeHeartbeatWakeReason(reason?: string): string {
|
|
const trimmed = trimReason(reason);
|
|
return trimmed.length > 0 ? trimmed : "requested";
|
|
}
|
|
|
|
export function resolveHeartbeatReasonKind(reason?: string): HeartbeatReasonKind {
|
|
const trimmed = trimReason(reason);
|
|
if (trimmed === "retry") {
|
|
return "retry";
|
|
}
|
|
if (trimmed === "interval") {
|
|
return "interval";
|
|
}
|
|
if (trimmed === "manual") {
|
|
return "manual";
|
|
}
|
|
if (trimmed === "exec-event") {
|
|
return "exec-event";
|
|
}
|
|
if (trimmed === "wake") {
|
|
return "wake";
|
|
}
|
|
if (trimmed.startsWith("acp:spawn:")) {
|
|
return "wake";
|
|
}
|
|
if (trimmed.startsWith("cron:")) {
|
|
return "cron";
|
|
}
|
|
if (trimmed.startsWith("hook:")) {
|
|
return "hook";
|
|
}
|
|
return "other";
|
|
}
|
|
|
|
export function isHeartbeatEventDrivenReason(reason?: string): boolean {
|
|
const kind = resolveHeartbeatReasonKind(reason);
|
|
return kind === "exec-event" || kind === "cron" || kind === "wake" || kind === "hook";
|
|
}
|
|
|
|
export function isHeartbeatActionWakeReason(reason?: string): boolean {
|
|
const kind = resolveHeartbeatReasonKind(reason);
|
|
return kind === "manual" || kind === "exec-event" || kind === "hook";
|
|
}
|