mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-23 15:28:11 +00:00
fix(agents): wake active parents for subagent completions
This commit is contained in:
@@ -229,6 +229,8 @@ async function deliverDiscordDirectMessageCompletion(params: {
|
||||
callGateway: typeof runtimeCallGateway;
|
||||
sendMessage?: typeof runtimeSendMessage;
|
||||
internalEvents?: AgentInternalEvent[];
|
||||
isActive?: boolean;
|
||||
queueEmbeddedAgentMessageWithOutcome?: QueueEmbeddedAgentMessageWithOutcome;
|
||||
sourceTool?: string;
|
||||
}) {
|
||||
const origin = {
|
||||
@@ -240,10 +242,13 @@ async function deliverDiscordDirectMessageCompletion(params: {
|
||||
callGateway: params.callGateway,
|
||||
getRequesterSessionActivity: () => ({
|
||||
sessionId: "requester-session-dm",
|
||||
isActive: false,
|
||||
isActive: params.isActive === true,
|
||||
}),
|
||||
getRuntimeConfig: () => ({}) as never,
|
||||
sendMessage: params.sendMessage ?? runtimeSendMessage,
|
||||
...(params.queueEmbeddedAgentMessageWithOutcome
|
||||
? { queueEmbeddedAgentMessageWithOutcome: params.queueEmbeddedAgentMessageWithOutcome }
|
||||
: {}),
|
||||
});
|
||||
|
||||
return deliverSubagentAnnouncement({
|
||||
@@ -4786,6 +4791,58 @@ describe("deliverSubagentAnnouncement completion delivery", () => {
|
||||
expect(sendMessage).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("retries active direct subagent completion wake without forced message-tool mode", async () => {
|
||||
const callGateway = createGatewayMock({
|
||||
result: {
|
||||
payloads: [{ text: "The subagent is done: child completion output" }],
|
||||
didSendViaMessagingTool: true,
|
||||
},
|
||||
});
|
||||
const queueEmbeddedAgentMessageWithOutcome = createQueueOutcomeSequenceMock([
|
||||
"source_reply_delivery_mode_mismatch",
|
||||
true,
|
||||
]);
|
||||
|
||||
const result = await deliverDiscordDirectMessageCompletion({
|
||||
callGateway,
|
||||
isActive: true,
|
||||
queueEmbeddedAgentMessageWithOutcome,
|
||||
sourceTool: "subagent_announce",
|
||||
internalEvents: [
|
||||
{
|
||||
type: "task_completion",
|
||||
source: "subagent",
|
||||
childSessionKey: "agent:worker:subagent:child",
|
||||
childSessionId: "child-session-id",
|
||||
announceType: "subagent task",
|
||||
taskLabel: "direct completion active wake",
|
||||
status: "ok",
|
||||
statusLabel: "completed successfully",
|
||||
result: "child completion output",
|
||||
replyInstruction: "Summarize the result.",
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
expectRecordFields(result, {
|
||||
delivered: true,
|
||||
path: "steered",
|
||||
});
|
||||
expect(queueEmbeddedAgentMessageWithOutcome).toHaveBeenCalledTimes(2);
|
||||
expectRecordFields(mockCallArg(queueEmbeddedAgentMessageWithOutcome, 0, 2), {
|
||||
sourceReplyDeliveryMode: "message_tool_only",
|
||||
waitForTranscriptCommit: true,
|
||||
});
|
||||
const retryOptions = mockCallArg(queueEmbeddedAgentMessageWithOutcome, 1, 2);
|
||||
expectRecordFields(retryOptions, {
|
||||
waitForTranscriptCommit: true,
|
||||
});
|
||||
expect(
|
||||
(retryOptions as { sourceReplyDeliveryMode?: unknown }).sourceReplyDeliveryMode,
|
||||
).toBeUndefined();
|
||||
expect(callGateway).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back to the external requester route when completion origin is internal", async () => {
|
||||
const callGateway = createGatewayMock({
|
||||
result: {
|
||||
|
||||
@@ -285,6 +285,18 @@ async function resolveActiveWakeWithRetries(
|
||||
outcome = await resolveQueueEmbeddedAgentMessageOutcome(sessionId, message, currentOptions);
|
||||
continue;
|
||||
}
|
||||
if (
|
||||
outcome.reason === "source_reply_delivery_mode_mismatch" &&
|
||||
currentOptions.sourceReplyDeliveryMode !== undefined
|
||||
) {
|
||||
// Active requester runs own their final delivery mode. Direct-completion
|
||||
// policy must not make an already-running automatic parent unreachable.
|
||||
const activeRunOptions = { ...currentOptions };
|
||||
delete activeRunOptions.sourceReplyDeliveryMode;
|
||||
currentOptions = activeRunOptions;
|
||||
outcome = await resolveQueueEmbeddedAgentMessageOutcome(sessionId, message, currentOptions);
|
||||
continue;
|
||||
}
|
||||
if (outcome.reason === "compacting") {
|
||||
const remainingDeliveryTimeoutMs =
|
||||
compactionDeadlineMs === undefined ? undefined : compactionDeadlineMs - Date.now();
|
||||
|
||||
Reference in New Issue
Block a user