Skip to content

Commit 9176cc0

Browse files
committed
dispatch: address inbound_claim broadcast review feedback
- Commit inbound dedupe before the broadcast-handled early return so the claim does not stay pinned in inFlight forever (Codex review concern). The other plugin-bound early returns above have the same latent issue but are out of scope for this PR. - Add positive test for the broadcast-handled short-circuit path (Greptile P1 / QC review request): asserts runInboundClaim is called exactly once, runMessageReceived is not invoked, and the agent path is not entered.
1 parent 9d51c40 commit 9176cc0

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

src/auto-reply/reply/dispatch-from-config.test.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3208,6 +3208,63 @@ describe("dispatchReplyFromConfig", () => {
32083208
expect(hookMocks.runner.runInboundClaim).toHaveBeenCalledTimes(1);
32093209
});
32103210

3211+
it("short-circuits when a global plugin handles the inbound_claim broadcast", async () => {
3212+
setNoAbort();
3213+
hookMocks.runner.hasHooks.mockImplementation(
3214+
((hookName?: string) =>
3215+
hookName === "inbound_claim" || hookName === "message_received") as () => boolean,
3216+
);
3217+
hookMocks.registry.plugins = [{ id: "openclaw-codex-app-server", status: "loaded" }];
3218+
hookMocks.runner.runInboundClaimForPluginOutcome.mockResolvedValue({
3219+
status: "no_handler",
3220+
});
3221+
hookMocks.runner.runInboundClaim.mockResolvedValue({ handled: true } as never);
3222+
sessionBindingMocks.resolveByConversation.mockReturnValue({
3223+
bindingId: "binding-broadcast-handled-1",
3224+
targetSessionKey: "plugin-binding:codex:broadcast-handled",
3225+
targetKind: "session",
3226+
conversation: {
3227+
channel: "discord",
3228+
accountId: "default",
3229+
conversationId: "channel:broadcast-handled",
3230+
},
3231+
status: "active",
3232+
boundAt: 1710000000000,
3233+
metadata: {
3234+
pluginBindingOwner: "plugin",
3235+
pluginId: "openclaw-codex-app-server",
3236+
pluginName: "Codex App Server",
3237+
pluginRoot: "/Users/huntharo/github/openclaw-app-server",
3238+
},
3239+
} satisfies SessionBindingRecord);
3240+
const dispatcher = createDispatcher();
3241+
const replyResolver = vi.fn(async () => ({ text: "openclaw fallback" }) satisfies ReplyPayload);
3242+
3243+
const result = await dispatchReplyFromConfig({
3244+
ctx: buildTestCtx({
3245+
Provider: "discord",
3246+
Surface: "discord",
3247+
OriginatingChannel: "discord",
3248+
OriginatingTo: "discord:channel:broadcast-handled",
3249+
To: "discord:channel:broadcast-handled",
3250+
AccountId: "default",
3251+
MessageSid: "msg-broadcast-handled-1",
3252+
SessionKey: "agent:main:discord:channel:broadcast-handled",
3253+
CommandBody: "hello",
3254+
RawBody: "hello",
3255+
Body: "hello",
3256+
}),
3257+
cfg: emptyConfig,
3258+
dispatcher,
3259+
replyResolver,
3260+
});
3261+
3262+
expect(result).toEqual({ queuedFinal: false, counts: { tool: 0, block: 0, final: 0 } });
3263+
expect(hookMocks.runner.runInboundClaim).toHaveBeenCalledTimes(1);
3264+
expect(hookMocks.runner.runMessageReceived).not.toHaveBeenCalled();
3265+
expect(replyResolver).not.toHaveBeenCalled();
3266+
});
3267+
32113268
it("notifies the user when a bound plugin declines the turn and keeps the binding attached", async () => {
32123269
setNoAbort();
32133270
hookMocks.runner.hasHooks.mockImplementation(

src/auto-reply/reply/dispatch-from-config.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,13 @@ export async function dispatchReplyFromConfig(
720720
inboundClaimContext,
721721
);
722722
if (broadcastResult?.handled) {
723+
// Commit dedupe before the early return so the claim does not stay
724+
// pinned in inFlight forever. The other plugin-bound early returns
725+
// above have the same latent issue; tracking that as a separate
726+
// cleanup so this PR stays focused.
727+
if (inboundDedupeClaim.status === "claimed") {
728+
commitInboundDedupe(inboundDedupeClaim.key);
729+
}
723730
markIdle("plugin_broadcast_claim");
724731
recordProcessed("completed", { reason: "plugin-broadcast-handled" });
725732
return { queuedFinal: false, counts: dispatcher.getQueuedCounts() };

0 commit comments

Comments
 (0)