fix: handle A-Copilot agent responses and image filename encoding

This commit is contained in:
2026-10-19 14:47:21 +09:00
parent 8c051c4bf4
commit 6c70c53b33
9 changed files with 197 additions and 14 deletions
+27 -3
View File
@@ -35,9 +35,10 @@ describe('managed A-Copilot backend', () => {
expect(request.body).not.toMatch(/server-only-secret|untrusted/);
}
expect(JSON.parse(fetchMock.mock.calls[0][1].body).messages[0].content).toBe('공식 교육 내용');
expect(JSON.parse(fetchMock.mock.calls[1][1].body).messages).toEqual([
{ role: 'user', content: 'Return an agent JSON plan' }, { role: 'user', content: '워크스페이스 문맥' },
]);
const messages = JSON.parse(fetchMock.mock.calls[1][1].body).messages;
expect(messages[0].content).toContain('Return an agent JSON plan');
expect(messages[1]).toEqual({ role: 'user', content: '워크스페이스 문맥' });
expect(messages.at(-1).content).toContain('answer 본문');
});
it('follows the AI tab server selection when OpenAI is configured, without accepting course overrides', async () => {
@@ -76,6 +77,29 @@ describe('managed A-Copilot backend', () => {
expect(fetchMock).not.toHaveBeenCalled();
});
it('normalizes a real RAG-style answer containing prose and one agent plan without a repair call', async () => {
const answer = `모듈 구성표를 먼저 조회합니다.\n\n\`\`\`json\n${JSON.stringify(plan)}\n\`\`\``;
const fetchMock = jest.fn().mockResolvedValue({ ok: true, json: async () => ({ answer }) });
global.fetch = fetchMock as typeof fetch;
const provider = new AiProviderService(config(configuration));
const result = await provider.complete({ provider: 'A_COPILOT', model: 'a-copilot', apiKey: '', system: 'JSON plan only', json: true, messages: [{ role: 'user', content: JSON.stringify({ request: '모듈 목록 확인' }) }] });
expect(JSON.parse(result.content)).toEqual(plan);
expect(fetchMock).toHaveBeenCalledTimes(1);
});
it('distinguishes an empty upstream answer and retains its request ID without inventing a response', async () => {
global.fetch = jest.fn().mockResolvedValue({ ok: true, status: 200, json: async () => ({ answer: '', request_id: 'fixture-request-123' }) }) as typeof fetch;
const provider = new AiProviderService(config(configuration));
try {
await provider.complete({ provider: 'A_COPILOT', model: 'a-copilot', apiKey: '', system: 'test', messages: [] });
throw Error('Expected an upstream error');
} catch (error) {
expect((error as { getResponse: () => unknown }).getResponse()).toEqual(expect.objectContaining({
code: 'COPILOT_EMPTY_ANSWER', upstreamRequestId: 'fixture-request-123', message: expect.stringContaining('API 연결은 성공'),
}));
}
});
it('creates and repairs an agent JSON plan using server credentials, without a course credential', async () => {
const fetchMock = jest.fn()
.mockResolvedValueOnce({ ok: true, json: async () => ({ answer: 'invalid plan JSON' }) })