This commit is contained in:
Bastian Wagner
2026-06-13 15:41:57 +02:00
parent 6642575ea9
commit 22c93f9ca1
10 changed files with 874 additions and 19 deletions

View File

@@ -114,6 +114,92 @@ describe('AssistantService', () => {
);
});
it('adds a normalized list context system message when context is present', async () => {
const providerResponse = {
choices: [
{
message: {
content: 'Ich nutze diese Liste.',
},
},
],
};
mockMistralResponse(providerResponse);
await service.chat('user-1', {
messages: [{ role: 'user', content: 'Fuege hier Brot hinzu' }],
context: {
page: 'list_detail',
route: '/lists/list-1',
list: {
id: 'list-1',
ownerId: 'user-1',
ownerName: 'Ada',
ownerEmail: 'ada@example.com',
accessRole: 'owner',
name: 'Einkauf',
description: 'Wochenende',
kind: 'shopping',
items: [
{
id: 'item-1',
title: 'Milch',
notes: '1,5 Prozent',
quantity: 2,
required: true,
checked: false,
checkedByUserId: 'user-2',
checkedByName: 'Grace',
position: 0,
createdAt: '2026-06-12T00:00:00.000Z',
updatedAt: '2026-06-12T00:00:00.000Z',
},
],
collaborators: [
{
id: 'user-2',
email: 'grace@example.com',
role: 'collaborator',
},
],
createdAt: '2026-06-12T00:00:00.000Z',
updatedAt: '2026-06-12T00:00:00.000Z',
},
},
});
const payload = getMistralRequestPayload();
const contextMessage = payload.messages.at(-2);
const contextContent = contextMessage?.content ?? '';
expect(contextMessage).toEqual(
expect.objectContaining({
role: 'system',
content: expect.stringContaining('Aktueller Listify-Kontext:'),
}),
);
expect(contextContent).toContain(
'Der User befindet sich auf einer Listendetailseite.',
);
expect(contextContent).toContain('Route: /lists/list-1');
expect(contextContent).toContain(
'Offene Liste: Einkauf (ID: list-1, Typ: shopping)',
);
expect(contextContent).toContain(
'- Milch (ID: item-1, Menge: 2, Pflicht: ja, Erledigt: nein, Notizen: 1,5 Prozent)',
);
expect(contextContent).toContain(
'bezieht sich das auf die Liste mit ID list-1.',
);
expect(contextContent).not.toContain('ada@example.com');
expect(contextContent).not.toContain('grace@example.com');
expect(contextContent).not.toContain('checkedByUserId');
expect(payload.messages.at(-1)).toEqual({
role: 'system',
content: 'benutze immer den listify connector',
});
});
it('logs full failed provider responses before throwing', async () => {
const providerResponse = {
message: 'connector failed',
@@ -263,3 +349,18 @@ function mockMistralResponse(
text: async () => JSON.stringify(response),
} as Response);
}
function getMistralRequestPayload(): {
messages: Array<{ role: string; content: string }>;
} {
const [, init] = jest.mocked(global.fetch).mock.calls.at(-1) ?? [];
const body = init?.body;
if (typeof body !== 'string') {
throw new Error('Expected Mistral request body to be JSON.');
}
return JSON.parse(body) as {
messages: Array<{ role: string; content: string }>;
};
}