Fix false autonomous safety handoffs

This commit is contained in:
jjbrunton committed 2026-08-09 21:27:53 +01:00
1 parent 84a133451f
commit c0cc661a2f
6 files changed
+144 -29

No files matched your search

+36 -4
View File
@@ -107,7 +107,7 @@ describe('conversation automation', () => {
expect((await service.processConversation(incoming(1)))?.remainingTurns).toBe(2);
const second = await service.processConversation(incoming(2));
expect(second).toMatchObject({ kind: 'human-required', remainingTurns: 0 });
expect(second).toMatchObject({ kind: 'human-required', remainingTurns: 2 });
expect(chat.sendChatMessage).toHaveBeenCalledOnce();
expect(getSaved()?.automation).toMatchObject({ turnsUsed: 1, status: 'human-required' });
expect(getSaved()?.automation.aiMessageFingerprints).toHaveLength(1);
@@ -135,7 +135,7 @@ describe('conversation automation', () => {
const result = await fixture.service.processConversation(conversation);
expect(result).toMatchObject({ kind: 'human-required', remainingTurns: 0 });
expect(result).toMatchObject({ kind: 'human-required', remainingTurns: 3 });
expect(fixture.ai.generateMediaAsk).not.toHaveBeenCalled();
expect(fixture.chat.sendChatMessage).not.toHaveBeenCalled();
expect(fixture.getSaved()?.automation.handoffReason).toContain('media request has already been made');
@@ -194,7 +194,7 @@ describe('conversation automation', () => {
const { service, chat, ai, getSaved } = harness(['onlyfans'], ['fansly.com']);
const result = await service.processConversation(incoming(1, 'My Fansly is https://www.fansly.com/example'));
expect(result).toMatchObject({ kind: 'human-required', remainingTurns: 0 });
expect(result).toMatchObject({ kind: 'human-required', remainingTurns: 3 });
expect(ai.generateMediaAsk).not.toHaveBeenCalled();
expect(chat.sendChatMessage).not.toHaveBeenCalled();
expect(getSaved()?.automation).toMatchObject({
@@ -550,7 +550,39 @@ describe('conversation automation', () => {
expect(result?.kind).toBe('human-required');
expect(fixture.chat.sendChatMessage).not.toHaveBeenCalled();
expect(fixture.getSaved()?.automation.handoffReason).toContain('failed autonomous safety checks');
expect(fixture.getSaved()?.automation.handoffReason)
.toBe('The generated reply was rejected: reply solicits media outside the configured media-ask phase.');
});
it('regenerates once when a legacy media ask contains no recognizable request', async () => {
const fixture = harness();
fixture.ai.generateMediaAsk
.mockResolvedValueOnce('That sounds fun. I would love to see that smile.')
.mockResolvedValueOnce('If you are up for it, snap a cute pic of yourself?');
const result = await fixture.service.processConversation(incoming(1));
expect(result).toMatchObject({ kind: 'sent', remainingTurns: 2 });
expect(fixture.ai.generateMediaAsk).toHaveBeenCalledTimes(2);
expect(fixture.chat.sendChatMessage).toHaveBeenCalledWith(
expect.any(String),
'If you are up for it, snap a cute pic of yourself?',
);
});
it('preserves unused turns and records the exact reason when regeneration is still invalid', async () => {
const fixture = harness();
fixture.ai.generateMediaAsk.mockResolvedValue('That sounds fun. I would love to see that smile.');
const result = await fixture.service.processConversation(incoming(1));
expect(result).toMatchObject({ kind: 'human-required', remainingTurns: 3 });
expect(fixture.ai.generateMediaAsk).toHaveBeenCalledTimes(2);
expect(fixture.getSaved()?.automation).toMatchObject({
turnsUsed: 0,
handoffReason: 'The generated media ask was rejected: media ask does not contain a recognizable image or video request.',
});
expect(fixture.chat.sendChatMessage).not.toHaveBeenCalled();
});
it('builds rapport before making exactly one optional media ask in hybrid mode', async () => {