mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 22:44:36 +00:00
refactor(agents): unify subagent announce delivery pipeline
Co-authored-by: Smith Labs <SmithLabsLLC@users.noreply.github.com> Co-authored-by: Do Cao Hieu <docaohieu2808@users.noreply.github.com>
This commit is contained in:
@@ -32,6 +32,10 @@ import {
|
||||
queueEmbeddedPiMessage,
|
||||
waitForEmbeddedPiRunEnd,
|
||||
} from "./pi-embedded.js";
|
||||
import {
|
||||
runSubagentAnnounceDispatch,
|
||||
type SubagentAnnounceDeliveryResult,
|
||||
} from "./subagent-announce-dispatch.js";
|
||||
import { type AnnounceQueueItem, enqueueAnnounce } from "./subagent-announce-queue.js";
|
||||
import { getSubagentDepthFromSessionStore } from "./subagent-depth.js";
|
||||
import type { SpawnSubagentMode } from "./subagent-spawn.js";
|
||||
@@ -53,14 +57,6 @@ type ToolResultMessage = {
|
||||
content?: unknown;
|
||||
};
|
||||
|
||||
type SubagentDeliveryPath = "queued" | "steered" | "direct" | "none";
|
||||
|
||||
type SubagentAnnounceDeliveryResult = {
|
||||
delivered: boolean;
|
||||
path: SubagentDeliveryPath;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
function resolveSubagentAnnounceTimeoutMs(cfg: ReturnType<typeof loadConfig>): number {
|
||||
const configured = cfg.agents?.defaults?.subagents?.announceTimeoutMs;
|
||||
if (typeof configured !== "number" || !Number.isFinite(configured)) {
|
||||
@@ -705,27 +701,6 @@ async function maybeQueueSubagentAnnounce(params: {
|
||||
return "none";
|
||||
}
|
||||
|
||||
function queueOutcomeToDeliveryResult(
|
||||
outcome: "steered" | "queued" | "none",
|
||||
): SubagentAnnounceDeliveryResult {
|
||||
if (outcome === "steered") {
|
||||
return {
|
||||
delivered: true,
|
||||
path: "steered",
|
||||
};
|
||||
}
|
||||
if (outcome === "queued") {
|
||||
return {
|
||||
delivered: true,
|
||||
path: "queued",
|
||||
};
|
||||
}
|
||||
return {
|
||||
delivered: false,
|
||||
path: "none",
|
||||
};
|
||||
}
|
||||
|
||||
async function sendSubagentAnnounceDirectly(params: {
|
||||
targetRequesterSessionKey: string;
|
||||
triggerMessage: string;
|
||||
@@ -905,64 +880,34 @@ async function deliverSubagentAnnouncement(params: {
|
||||
directIdempotencyKey: string;
|
||||
signal?: AbortSignal;
|
||||
}): Promise<SubagentAnnounceDeliveryResult> {
|
||||
if (params.signal?.aborted) {
|
||||
return {
|
||||
delivered: false,
|
||||
path: "none",
|
||||
};
|
||||
}
|
||||
// Non-completion mode mirrors historical behavior: try queued/steered delivery first,
|
||||
// then (only if not queued) attempt direct delivery.
|
||||
if (!params.expectsCompletionMessage) {
|
||||
const queueOutcome = await maybeQueueSubagentAnnounce({
|
||||
requesterSessionKey: params.requesterSessionKey,
|
||||
announceId: params.announceId,
|
||||
triggerMessage: params.triggerMessage,
|
||||
summaryLine: params.summaryLine,
|
||||
requesterOrigin: params.requesterOrigin,
|
||||
signal: params.signal,
|
||||
});
|
||||
const queued = queueOutcomeToDeliveryResult(queueOutcome);
|
||||
if (queued.delivered) {
|
||||
return queued;
|
||||
}
|
||||
}
|
||||
|
||||
// Completion-mode uses direct send first so manual spawns can return immediately
|
||||
// in the common ready-to-deliver case.
|
||||
const direct = await sendSubagentAnnounceDirectly({
|
||||
targetRequesterSessionKey: params.targetRequesterSessionKey,
|
||||
triggerMessage: params.triggerMessage,
|
||||
completionMessage: params.completionMessage,
|
||||
directIdempotencyKey: params.directIdempotencyKey,
|
||||
completionDirectOrigin: params.completionDirectOrigin,
|
||||
completionRouteMode: params.completionRouteMode,
|
||||
spawnMode: params.spawnMode,
|
||||
directOrigin: params.directOrigin,
|
||||
requesterIsSubagent: params.requesterIsSubagent,
|
||||
return await runSubagentAnnounceDispatch({
|
||||
expectsCompletionMessage: params.expectsCompletionMessage,
|
||||
signal: params.signal,
|
||||
bestEffortDeliver: params.bestEffortDeliver,
|
||||
queue: async () =>
|
||||
await maybeQueueSubagentAnnounce({
|
||||
requesterSessionKey: params.requesterSessionKey,
|
||||
announceId: params.announceId,
|
||||
triggerMessage: params.triggerMessage,
|
||||
summaryLine: params.summaryLine,
|
||||
requesterOrigin: params.requesterOrigin,
|
||||
signal: params.signal,
|
||||
}),
|
||||
direct: async () =>
|
||||
await sendSubagentAnnounceDirectly({
|
||||
targetRequesterSessionKey: params.targetRequesterSessionKey,
|
||||
triggerMessage: params.triggerMessage,
|
||||
completionMessage: params.completionMessage,
|
||||
directIdempotencyKey: params.directIdempotencyKey,
|
||||
completionDirectOrigin: params.completionDirectOrigin,
|
||||
completionRouteMode: params.completionRouteMode,
|
||||
spawnMode: params.spawnMode,
|
||||
directOrigin: params.directOrigin,
|
||||
requesterIsSubagent: params.requesterIsSubagent,
|
||||
expectsCompletionMessage: params.expectsCompletionMessage,
|
||||
signal: params.signal,
|
||||
bestEffortDeliver: params.bestEffortDeliver,
|
||||
}),
|
||||
});
|
||||
if (direct.delivered || !params.expectsCompletionMessage) {
|
||||
return direct;
|
||||
}
|
||||
|
||||
// If completion path failed direct delivery, try queueing as a fallback so the
|
||||
// report can still be delivered once the requester session is idle.
|
||||
const queueOutcome = await maybeQueueSubagentAnnounce({
|
||||
requesterSessionKey: params.requesterSessionKey,
|
||||
announceId: params.announceId,
|
||||
triggerMessage: params.triggerMessage,
|
||||
summaryLine: params.summaryLine,
|
||||
requesterOrigin: params.requesterOrigin,
|
||||
signal: params.signal,
|
||||
});
|
||||
if (queueOutcome === "steered" || queueOutcome === "queued") {
|
||||
return queueOutcomeToDeliveryResult(queueOutcome);
|
||||
}
|
||||
|
||||
return direct;
|
||||
}
|
||||
|
||||
function loadSessionEntryByKey(sessionKey: string) {
|
||||
|
||||
Reference in New Issue
Block a user