test: cover discussion hook close and idle behavior
This commit is contained in:
131
test/discussion-hooks.test.ts
Normal file
131
test/discussion-hooks.test.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
|
||||
import { registerBeforeMessageWriteHook } from '../plugin/hooks/before-message-write.ts';
|
||||
import { registerMessageSentHook } from '../plugin/hooks/message-sent.ts';
|
||||
import { initTurnOrder, onNewMessage, getTurnDebugInfo, resetTurn } from '../plugin/turn-manager.ts';
|
||||
|
||||
type Handler = (event: Record<string, unknown>, ctx: Record<string, unknown>) => unknown;
|
||||
|
||||
function makeApi() {
|
||||
const handlers = new Map<string, Handler>();
|
||||
return {
|
||||
handlers,
|
||||
logger: {
|
||||
info: (_msg: string) => {},
|
||||
warn: (_msg: string) => {},
|
||||
},
|
||||
on(name: string, handler: Handler) {
|
||||
handlers.set(name, handler);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
test('before_message_write leaves ordinary channels dormant without sending a discussion idle reminder', async () => {
|
||||
const channelId = 'normal-channel';
|
||||
resetTurn(channelId);
|
||||
initTurnOrder(channelId, ['agent-a', 'agent-b']);
|
||||
onNewMessage(channelId, 'human-user', true);
|
||||
|
||||
const state = getTurnDebugInfo(channelId);
|
||||
const [firstSpeaker, secondSpeaker] = state.turnOrder as string[];
|
||||
assert.ok(firstSpeaker);
|
||||
assert.ok(secondSpeaker);
|
||||
|
||||
const sessionChannelId = new Map<string, string>([
|
||||
['sess-a', channelId],
|
||||
['sess-b', channelId],
|
||||
]);
|
||||
const sessionAccountId = new Map<string, string>([
|
||||
['sess-a', firstSpeaker],
|
||||
['sess-b', secondSpeaker],
|
||||
]);
|
||||
const sessionAllowed = new Map<string, boolean>([
|
||||
['sess-a', true],
|
||||
['sess-b', true],
|
||||
]);
|
||||
const sessionTurnHandled = new Set<string>();
|
||||
|
||||
const idleReminderCalls: string[] = [];
|
||||
const moderatorMessages: string[] = [];
|
||||
const api = makeApi();
|
||||
|
||||
registerBeforeMessageWriteHook({
|
||||
api: api as any,
|
||||
baseConfig: { endSymbols: ['🔚'], moderatorBotToken: 'bot-token' } as any,
|
||||
policyState: { channelPolicies: {} },
|
||||
sessionAllowed,
|
||||
sessionChannelId,
|
||||
sessionAccountId,
|
||||
sessionTurnHandled,
|
||||
ensurePolicyStateLoaded: () => {},
|
||||
shouldDebugLog: () => false,
|
||||
ensureTurnOrder: () => {},
|
||||
resolveDiscordUserId: () => undefined,
|
||||
isMultiMessageMode: () => false,
|
||||
sendModeratorMessage: async (_token, _channelId, content) => {
|
||||
moderatorMessages.push(content);
|
||||
return { ok: true };
|
||||
},
|
||||
discussionService: {
|
||||
maybeSendIdleReminder: async (id) => {
|
||||
idleReminderCalls.push(id);
|
||||
},
|
||||
getDiscussion: () => undefined,
|
||||
},
|
||||
});
|
||||
|
||||
const beforeMessageWrite = api.handlers.get('before_message_write');
|
||||
assert.ok(beforeMessageWrite);
|
||||
|
||||
await beforeMessageWrite?.({ message: { role: 'assistant', content: 'NO_REPLY' } }, { sessionKey: 'sess-a' });
|
||||
await beforeMessageWrite?.({ message: { role: 'assistant', content: 'NO_REPLY' } }, { sessionKey: 'sess-b' });
|
||||
|
||||
assert.deepEqual(idleReminderCalls, []);
|
||||
assert.deepEqual(moderatorMessages, []);
|
||||
assert.equal(getTurnDebugInfo(channelId).dormant, true);
|
||||
});
|
||||
|
||||
test('message_sent skips handoff after discuss-callback has closed the discussion channel', async () => {
|
||||
const channelId = 'discussion-closed-channel';
|
||||
resetTurn(channelId);
|
||||
initTurnOrder(channelId, ['agent-a', 'agent-b']);
|
||||
onNewMessage(channelId, 'human-user', true);
|
||||
|
||||
const state = getTurnDebugInfo(channelId);
|
||||
const currentSpeaker = state.currentSpeaker as string;
|
||||
assert.ok(currentSpeaker);
|
||||
|
||||
const moderatorMessages: string[] = [];
|
||||
const api = makeApi();
|
||||
|
||||
registerMessageSentHook({
|
||||
api: api as any,
|
||||
baseConfig: {
|
||||
endSymbols: ['🔚'],
|
||||
moderatorBotToken: 'bot-token',
|
||||
schedulingIdentifier: '➡️',
|
||||
} as any,
|
||||
policyState: { channelPolicies: {} },
|
||||
sessionChannelId: new Map([['sess-closed', channelId]]),
|
||||
sessionAccountId: new Map([['sess-closed', currentSpeaker]]),
|
||||
sessionTurnHandled: new Set(),
|
||||
ensurePolicyStateLoaded: () => {},
|
||||
resolveDiscordUserId: () => 'discord-user-next',
|
||||
sendModeratorMessage: async (_token, _channelId, content) => {
|
||||
moderatorMessages.push(content);
|
||||
return { ok: true };
|
||||
},
|
||||
discussionService: {
|
||||
isClosedDiscussion: (id) => id === channelId,
|
||||
},
|
||||
});
|
||||
|
||||
const messageSent = api.handlers.get('message_sent');
|
||||
assert.ok(messageSent);
|
||||
|
||||
await messageSent?.({ content: 'NO_REPLY' }, { sessionKey: 'sess-closed', accountId: currentSpeaker, channelId });
|
||||
|
||||
assert.deepEqual(moderatorMessages, []);
|
||||
assert.equal(getTurnDebugInfo(channelId).currentSpeaker, currentSpeaker);
|
||||
});
|
||||
Reference in New Issue
Block a user