chat
This commit is contained in:
@@ -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 }>;
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user