mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 03:53:54 +00:00
Summary: - The PR changes shared, Feishu, Mattermost, Microsoft Teams, and WhatsApp inbound debounce predicates so bare abort text bypasses debounce, then adds focused tests and a changelog entry. - Reproducibility: yes. source-level. Current main sends bare `stop`, `abort`, and `wait` through a `hasContro ... ()` debounce gate, while the existing abort-aware detector and trigger set already recognize those phrases. Automerge notes: - PR branch already contained follow-up commit before automerge: fix(channels): bypass debounce for bare abort triggers [AI-assisted] - PR branch already contained follow-up commit before automerge: fix(clawsweeper): address review for automerge-openclaw-openclaw-8334… Validation: - ClawSweeper review passed for headc96bf84270. - Required merge gates passed before the squash merge. Prepared head SHA:c96bf84270Review: https://github.com/openclaw/openclaw/pull/83348#issuecomment-4473176095 Co-authored-by: IWhatsskill <284122573+IWhatsskill@users.noreply.github.com> Co-authored-by: clawsweeper <274271284+clawsweeper[bot]@users.noreply.github.com> Co-authored-by: clawsweeper[bot] <274271284+clawsweeper[bot]@users.noreply.github.com> Approved-by: takhoffman Co-authored-by: takhoffman <781889+takhoffman@users.noreply.github.com>
113 lines
4.2 KiB
TypeScript
113 lines
4.2 KiB
TypeScript
import { vi } from "vitest";
|
|
import type { OpenClawConfig, PluginRuntime, RuntimeEnv } from "../../runtime-api.js";
|
|
import type { MSTeamsMessageHandlerDeps } from "../monitor-handler.js";
|
|
import { installMSTeamsTestRuntime } from "../monitor-handler.test-helpers.js";
|
|
|
|
export const channelConversationId = "19:general@thread.tacv2";
|
|
|
|
type MessageHandlerDepsOptions = {
|
|
enqueueSystemEvent?: ReturnType<typeof vi.fn>;
|
|
readAllowFromStore?: ReturnType<typeof vi.fn>;
|
|
upsertPairingRequest?: ReturnType<typeof vi.fn>;
|
|
recordInboundSession?: ReturnType<typeof vi.fn>;
|
|
resolveAgentRoute?: (params: { peer: { kind: string; id: string } }) => unknown;
|
|
hasControlCommand?: PluginRuntime["channel"]["text"]["hasControlCommand"];
|
|
isControlCommandMessage?: PluginRuntime["channel"]["commands"]["isControlCommandMessage"];
|
|
shouldComputeCommandAuthorized?: PluginRuntime["channel"]["commands"]["shouldComputeCommandAuthorized"];
|
|
shouldHandleTextCommands?: PluginRuntime["channel"]["commands"]["shouldHandleTextCommands"];
|
|
createInboundDebouncer?: PluginRuntime["channel"]["debounce"]["createInboundDebouncer"];
|
|
resolveInboundDebounceMs?: PluginRuntime["channel"]["debounce"]["resolveInboundDebounceMs"];
|
|
};
|
|
|
|
export function createMessageHandlerDeps(
|
|
cfg: OpenClawConfig,
|
|
options: MessageHandlerDepsOptions = {},
|
|
) {
|
|
const enqueueSystemEvent = options.enqueueSystemEvent ?? vi.fn();
|
|
const readAllowFromStore = options.readAllowFromStore ?? vi.fn(async () => []);
|
|
const upsertPairingRequest = options.upsertPairingRequest ?? vi.fn(async () => null);
|
|
const recordInboundSession =
|
|
options.recordInboundSession ?? vi.fn(async (_params: { sessionKey: string }) => undefined);
|
|
const resolveAgentRoute =
|
|
options.resolveAgentRoute ??
|
|
vi.fn(({ peer }: { peer: { kind: string; id: string } }) => ({
|
|
sessionKey: `agent:main:msteams:${peer.kind}:${peer.id}`,
|
|
agentId: "main",
|
|
accountId: "default",
|
|
mainSessionKey: "agent:main:main",
|
|
lastRoutePolicy: "session" as const,
|
|
matchedBy: "default" as const,
|
|
}));
|
|
|
|
installMSTeamsTestRuntime({
|
|
enqueueSystemEvent,
|
|
readAllowFromStore,
|
|
upsertPairingRequest,
|
|
recordInboundSession,
|
|
resolveAgentRoute,
|
|
hasControlCommand: options.hasControlCommand,
|
|
isControlCommandMessage: options.isControlCommandMessage,
|
|
shouldComputeCommandAuthorized: options.shouldComputeCommandAuthorized,
|
|
shouldHandleTextCommands: options.shouldHandleTextCommands,
|
|
createInboundDebouncer: options.createInboundDebouncer,
|
|
resolveInboundDebounceMs: options.resolveInboundDebounceMs,
|
|
resolveTextChunkLimit: () => 4000,
|
|
resolveStorePath: () => "/tmp/test-store",
|
|
});
|
|
|
|
const conversationStore = {
|
|
get: vi.fn(async () => null),
|
|
upsert: vi.fn(async () => undefined),
|
|
list: vi.fn(async () => []),
|
|
remove: vi.fn(async () => false),
|
|
findPreferredDmByUserId: vi.fn(async () => null),
|
|
findByUserId: vi.fn(async () => null),
|
|
} satisfies MSTeamsMessageHandlerDeps["conversationStore"];
|
|
|
|
const deps: MSTeamsMessageHandlerDeps = {
|
|
cfg,
|
|
runtime: { error: vi.fn() } as unknown as RuntimeEnv,
|
|
appId: "test-app",
|
|
adapter: {} as MSTeamsMessageHandlerDeps["adapter"],
|
|
tokenProvider: {
|
|
getAccessToken: vi.fn(async () => "token"),
|
|
},
|
|
textLimit: 4000,
|
|
mediaMaxBytes: 1024 * 1024,
|
|
conversationStore,
|
|
pollStore: {
|
|
recordVote: vi.fn(async () => null),
|
|
} as unknown as MSTeamsMessageHandlerDeps["pollStore"],
|
|
log: {
|
|
info: vi.fn(),
|
|
debug: vi.fn(),
|
|
error: vi.fn(),
|
|
} as unknown as MSTeamsMessageHandlerDeps["log"],
|
|
};
|
|
|
|
return {
|
|
conversationStore,
|
|
deps,
|
|
enqueueSystemEvent,
|
|
readAllowFromStore,
|
|
upsertPairingRequest,
|
|
recordInboundSession,
|
|
resolveAgentRoute,
|
|
};
|
|
}
|
|
|
|
export function buildChannelActivity(overrides: Record<string, unknown> = {}) {
|
|
return {
|
|
id: "msg-1",
|
|
type: "message",
|
|
text: "hello",
|
|
from: { id: "user-id", aadObjectId: "user-aad", name: "Test User" },
|
|
recipient: { id: "bot-id", name: "Bot" },
|
|
conversation: { id: channelConversationId, conversationType: "channel" },
|
|
channelData: { team: { id: "team-1" } },
|
|
attachments: [],
|
|
entities: [{ type: "mention", mentioned: { id: "bot-id" } }],
|
|
...overrides,
|
|
};
|
|
}
|