Add consent-gated media exchange library

This commit is contained in:
jjbrunton committed 2026-08-09 19:24:38 +01:00
1 parent b8e4a1bb88
commit bf474dfe10
42 files changed
+2533 -9

No files matched your search

+18
View File
@@ -13,6 +13,7 @@ function harness(
rapportTurnsBeforeMediaAsk?: number;
},
beforeSendLoader?: (conversationId: string, observed: ActiveChat) => Promise<ActiveChat | undefined>,
mediaExchange?: { detect(conversationId: string, text: string): string | null; handle(conversationId: string, incomingKey: string, text: string): Promise<object> },
) {
const saved = new Map<string, ConversationState>();
let lastSaved: ConversationState | undefined;
@@ -63,6 +64,7 @@ function harness(
() => 1_000,
0,
beforeSendLoader ?? (async (_conversationId, observed) => observed),
mediaExchange as never,
);
return { service, chat, ai, states, openers, claims, rateLimiter, getSaved: () => lastSaved };
}
@@ -79,6 +81,22 @@ function incoming(turn: number, text = `reply ${turn}`, media?: Array<{ original
}
describe('conversation automation', () => {
it('handles a requested library image through the reply limiter before generating text', async () => {
const mediaExchange = {
detect: vi.fn().mockReturnValue('generic'),
handle: vi.fn().mockResolvedValue({ kind: 'sent', assetId: 'asset-one', requestKind: 'generic' }),
};
const fixture = harness([], [], 0, { mode: 'r4r', maxAutomatedTurns: 5 }, undefined, mediaExchange);
const result = await fixture.service.processConversation(incoming(1, 'got any pics?'));
expect(result?.kind).toBe('sent');
expect(fixture.rateLimiter.throttle).toHaveBeenCalledOnce();
expect(mediaExchange.handle).toHaveBeenCalledWith('room-alice', 'in-1', 'got any pics?');
expect(fixture.ai.generateReply).not.toHaveBeenCalled();
expect(fixture.getSaved()).toMatchObject({ askedForMedia: true, automation: { turnsUsed: 0, status: 'active' } });
});
it('allows only one autonomous media request and then hands off', async () => {
const { service, chat, getSaved } = harness();