Files
open-design/packages/contracts/tests/undesigned-cards.test.ts
98f2fd1a46 fix(chat): hide undesigned cards and auxiliary message panels (#7956)
* fix(chat): render cards inside execution records

Render supported od-card payloads inside execution records with the existing
card components, instance scopes, and browser-assistance callback. Preserve
Markdown code examples and isolate card payloads from later Markdown parsing.

* test(web): await writable scope before deleting a conversation

* fix(web): buffer streamed card opener prefixes

* fix(web): remove undesigned ChatPanel cards (OPEND-2971)

Remove task-brief and rule-proposal presentation and their exclusive UI,
styles, and translations following the explicit product decision.
Preserve quoted card examples, neighboring prose, and the three retained
card kinds, including browser-assist callbacks.

* fix(chat): stop generating undesigned brief and rule cards

* test(web): use supported role query options for removed cards

* fix(chat): hide retired brand browser assistance cards

* fix(web): hide undesigned assistant message panels

* test(web): specify the brand project kind in hidden UI fixture

* style(web): remove trailing blank line after panel styles

* fix(web): hide verification scorecards in ChatPanel

* test(chat): align retired UI expectations with approved hiding

* fix(chat): keep card payloads opaque to question form parsing

* fix(web): preserve card parsing across replay metadata

Keep marker masking aligned with physical run boundaries, and replace repeated
Markdown tail scans with a forward indexed walk. Preserve actual forms and raw
code examples with replay and paragraph-boundary regression coverage.

* fix(web): keep form field syntax inside its payload

Recognize complete forms through the existing parser before scanning their
fields for card or code markers. Preserve sibling form actions and keep outer
card/code ownership with callback-based parsing that avoids an import cycle.

* fix(chat): share question form protocol context with host detection

---------

Co-authored-by: lefarcen <935902669@qq.com>
2026-09-10 10:24:07 +00:00

60 lines
2.8 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { splitOnOdCards } from '../src/artifacts/od-card.js';
import { composeSystemPrompt } from '../src/prompts/system.js';
const memoryBody = '### Profile\n\nOperator audience.\n\n### Verified rules\n\nKeep spacing consistent.';
describe('OPEND-2971 contracts memory card instructions', () => {
for (const memoryHooks of [undefined, { rewrite: true, verify: true }]) {
describe(memoryHooks ? 'explicitly enabled hooks' : 'default hooks', () => {
it.each(['task-brief', 'rule-proposal'])('does not request a %s card', (kind) => {
const prompt = composeSystemPrompt({ memoryBody, memoryHooks });
expect(prompt).not.toContain(`<od-card type="${kind}">`);
});
});
}
it('retains personal memory, applied-memory chips, and rule verification', () => {
const prompt = composeSystemPrompt({ memoryBody });
expect(prompt).toContain(memoryBody);
expect(prompt).toContain('## Personal memory');
expect(prompt).toContain('<od-card type="memory-applied">');
expect(prompt).toContain('<od-card type="verify-scorecard">');
});
it('still honors the verification switch without dropping memory', () => {
const prompt = composeSystemPrompt({ memoryBody, memoryHooks: { verify: false } });
expect(prompt).toContain(memoryBody);
expect(prompt).toContain('<od-card type="memory-applied">');
expect(prompt).not.toContain('<od-card type="verify-scorecard">');
});
it('does not introduce memory cards when there is no memory', () => {
const prompt = composeSystemPrompt({ memoryBody: ' ' });
expect(prompt).not.toContain('<od-card type="task-brief">');
expect(prompt).not.toContain('<od-card type="rule-proposal">');
});
});
describe('historical od-card compatibility', () => {
it.each([
{ kind: 'task-brief', payload: { summary: 'Historic brief', fields: [{ label: 'Format', value: '16:9' }] } },
{ kind: 'rule-proposal', payload: { name: 'Historic rule', assertion: 'Keep spacing consistent', check: 'Inspect spacing' } },
{ kind: 'memory-applied', payload: { summary: 'Applied saved preferences', used: [] } },
{ kind: 'verify-scorecard', payload: { status: 'pass', rows: [{ rule: 'Spacing', status: 'pass' }] } },
{ kind: 'brand-browser-assist', payload: { brandId: 'brand-1', url: 'https://example.test' } },
])('still recognizes $kind without leaking its raw block into prose', ({ kind, payload }) => {
const raw = `<od-card type="${kind}">${JSON.stringify(payload)}</od-card>`;
const segments = splitOnOdCards(`Before.\n${raw}\nAfter.`);
expect(segments).toHaveLength(3);
expect(segments[0]).toEqual({ kind: 'text', text: 'Before.\n' });
expect(segments[1]).toMatchObject({ kind: 'card', card: { kind, ...payload }, raw });
expect(segments[2]).toEqual({ kind: 'text', text: '\nAfter.' });
});
});