Files
wehub-resource-sync 070959e133
landing-page-staging / Deploy landing page to staging (push) Has been skipped
landing-page-ci / Validate landing page (push) Failing after 4s
visual-baseline / Capture visual baselines (push) Has been cancelled
bake-plugin-previews / Bake plugin previews (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:00:47 +08:00

97 lines
3.3 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { appendErrorStatusEvent } from '../../src/runtime/chat-events';
import type { ChatMessage } from '../../src/types';
const base: ChatMessage = { id: 'm1', role: 'assistant', content: '' };
describe('appendErrorStatusEvent', () => {
it('returns the message unchanged when detail is empty or whitespace', () => {
expect(appendErrorStatusEvent(base, '')).toBe(base);
expect(appendErrorStatusEvent(base, ' ')).toBe(base);
});
it('appends a status event with the given detail when there are no prior events', () => {
const next = appendErrorStatusEvent(base, 'boom');
expect(next).not.toBe(base);
expect(next.events).toEqual([{ kind: 'status', label: 'error', detail: 'boom' }]);
});
it('does not duplicate when the last event is an identical error status', () => {
const seeded: ChatMessage = {
...base,
events: [{ kind: 'status', label: 'error', detail: 'boom' }],
};
expect(appendErrorStatusEvent(seeded, 'boom')).toBe(seeded);
});
it('merges classification into the existing trailing error event with the same detail', () => {
// Reload/reattach race: the daemon-persisted error frame is read first
// (detail only), then the run finishes and onError arrives with the
// finalize-time classification. The helper must enrich in place, not no-op.
const seeded: ChatMessage = {
...base,
events: [{ kind: 'status', label: 'error', detail: 'quota gone' }],
};
const next = appendErrorStatusEvent(seeded, 'quota gone', 'RATE_LIMITED', {
failureCategory: 'rate_limit',
failureDetail: 'hard_quota',
});
expect(next).not.toBe(seeded);
expect(next.events).toHaveLength(1);
expect(next.events?.[0]).toEqual({
kind: 'status',
label: 'error',
detail: 'quota gone',
code: 'RATE_LIMITED',
failureCategory: 'rate_limit',
failureDetail: 'hard_quota',
});
});
it('no-ops when the new pass adds nothing beyond the existing error event', () => {
const seeded: ChatMessage = {
...base,
events: [
{
kind: 'status',
label: 'error',
detail: 'quota gone',
code: 'RATE_LIMITED',
failureCategory: 'rate_limit',
failureDetail: 'hard_quota',
},
],
};
expect(
appendErrorStatusEvent(seeded, 'quota gone', 'RATE_LIMITED', {
failureCategory: 'rate_limit',
failureDetail: 'hard_quota',
}),
).toBe(seeded);
});
it('appends when the previous error status detail differs', () => {
const seeded: ChatMessage = {
...base,
events: [{ kind: 'status', label: 'error', detail: 'first' }],
};
const next = appendErrorStatusEvent(seeded, 'second');
expect(next.events).toHaveLength(2);
expect(next.events?.[1]).toEqual({ kind: 'status', label: 'error', detail: 'second' });
});
it('preserves non-error events that precede the new one', () => {
const seeded: ChatMessage = {
...base,
events: [{ kind: 'text', text: 'hi' }, { kind: 'status', label: 'ok' }],
};
const next = appendErrorStatusEvent(seeded, 'fail');
expect(next.events).toEqual([
{ kind: 'text', text: 'hi' },
{ kind: 'status', label: 'ok' },
{ kind: 'status', label: 'error', detail: 'fail' },
]);
});
});