mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-09-08 22:22:52 +00:00
Some checks are pending
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Gitleaks / gitleaks (push) Waiting to run
Publish / Classify release event (push) Waiting to run
Publish / RC guard (marker + release-PR skip) (push) Blocked by required conditions
Publish / ci (push) Blocked by required conditions
Publish / Publish to npm (push) Blocked by required conditions
Publish / Build & Push RC Docker images (push) Blocked by required conditions
Scorecard / Scorecard analysis (push) Waiting to run
Skill copy sync / shipped skills drift guard (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-web) (push) Waiting to run
Trivy Image Scan / Trivy (gitnexus-cli) (push) Waiting to run
128 lines
3.7 KiB
TypeScript
128 lines
3.7 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { streamAgentResponse, type AgentMessage } from '../../src/core/llm/agent';
|
|
|
|
describe('streamAgentResponse abort', () => {
|
|
const userMessage: AgentMessage[] = [{ role: 'user', content: 'hello' }];
|
|
|
|
it('yields cancelled when the LangGraph stream throws AbortError', async () => {
|
|
const agent = {
|
|
stream: async () => {
|
|
throw new DOMException('The operation was aborted', 'AbortError');
|
|
},
|
|
};
|
|
|
|
const chunks = [];
|
|
for await (const chunk of streamAgentResponse(agent as any, userMessage, {
|
|
signal: new AbortController().signal,
|
|
})) {
|
|
chunks.push(chunk);
|
|
}
|
|
|
|
expect(chunks).toEqual([{ type: 'cancelled' }]);
|
|
});
|
|
|
|
it('yields cancelled when the abort signal is set mid-stream', async () => {
|
|
const controller = new AbortController();
|
|
const agent = {
|
|
stream: async function* () {
|
|
yield ['values', { messages: [] }];
|
|
controller.abort();
|
|
for (let i = 0; i < 100; i++) {
|
|
yield ['messages', [{ _getType: () => 'ai', content: 'still going' }]];
|
|
}
|
|
},
|
|
};
|
|
|
|
const chunks = [];
|
|
for await (const chunk of streamAgentResponse(agent as any, userMessage, {
|
|
signal: controller.signal,
|
|
})) {
|
|
chunks.push(chunk);
|
|
if (chunk.type === 'cancelled') break;
|
|
}
|
|
|
|
expect(chunks[chunks.length - 1]).toEqual({ type: 'cancelled' });
|
|
expect(chunks.filter((c) => c.type === 'error')).toEqual([]);
|
|
});
|
|
|
|
it('passes AbortSignal to agent.stream config', async () => {
|
|
const controller = new AbortController();
|
|
let capturedConfig: Record<string, unknown> | undefined;
|
|
|
|
const agent = {
|
|
stream: async (_input: unknown, config: Record<string, unknown>) => {
|
|
capturedConfig = config;
|
|
throw new DOMException('aborted', 'AbortError');
|
|
},
|
|
};
|
|
|
|
for await (const _chunk of streamAgentResponse(agent as any, userMessage, {
|
|
signal: controller.signal,
|
|
})) {
|
|
// drain
|
|
}
|
|
|
|
expect(capturedConfig?.signal).toBe(controller.signal);
|
|
});
|
|
|
|
it('yields cancelled for a plain Error with name AbortError', async () => {
|
|
const agent = {
|
|
stream: async () => {
|
|
throw Object.assign(new Error('aborted'), { name: 'AbortError' });
|
|
},
|
|
};
|
|
|
|
const chunks = [];
|
|
for await (const chunk of streamAgentResponse(agent as any, userMessage)) {
|
|
chunks.push(chunk);
|
|
}
|
|
|
|
expect(chunks).toEqual([{ type: 'cancelled' }]);
|
|
});
|
|
|
|
it('does not treat unrelated errors mentioning abort as cancellation', async () => {
|
|
const agent = {
|
|
stream: async () => {
|
|
throw new Error('Cannot abort the current transaction');
|
|
},
|
|
};
|
|
|
|
const chunks = [];
|
|
for await (const chunk of streamAgentResponse(agent as any, userMessage)) {
|
|
chunks.push(chunk);
|
|
}
|
|
|
|
expect(chunks).toEqual([{ type: 'error', error: 'Cannot abort the current transaction' }]);
|
|
});
|
|
});
|
|
|
|
describe('streamAgentResponse content blocks', () => {
|
|
const userMessage: AgentMessage[] = [{ role: 'user', content: 'hello' }];
|
|
|
|
it('emits thinking blocks as reasoning', async () => {
|
|
const agent = {
|
|
stream: async function* () {
|
|
yield [
|
|
'messages',
|
|
[
|
|
{
|
|
_getType: () => 'ai',
|
|
content: [{ type: 'thinking', thinking: 'Reviewing the repository context.' }],
|
|
tool_calls: [],
|
|
},
|
|
],
|
|
];
|
|
},
|
|
};
|
|
|
|
const chunks = [];
|
|
for await (const chunk of streamAgentResponse(agent as any, userMessage)) {
|
|
chunks.push(chunk);
|
|
}
|
|
|
|
expect(chunks).toEqual([
|
|
{ type: 'reasoning', reasoning: 'Reviewing the repository context.' },
|
|
{ type: 'done', historyMessages: undefined },
|
|
]);
|
|
});
|
|
});
|