| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- import { WorkflowExecutor } from './src/vl/workflow-executor.js';
- let passed = 0;
- let failed = 0;
- function test(name, fn) {
- return Promise.resolve()
- .then(fn)
- .then(() => {
- console.log(` ✓ ${name}`);
- passed++;
- })
- .catch((err) => {
- console.log(` ✗ ${name}: ${err.message}`);
- failed++;
- });
- }
- function assert(cond, msg) {
- if (!cond) throw new Error(msg || 'Assertion failed');
- }
- console.log('\n── Workflow JSON Guard Regression ──');
- function createExecutorWithResponse(text) {
- const executor = new WorkflowExecutor({ workDir: '/tmp/vlcode-json-guard', model: 'claude-opus-4-6' });
- executor.client = {
- messages: {
- async create() {
- return {
- content: [{ type: 'text', text }],
- stop_reason: 'end_turn',
- usage: {},
- model: 'stub-model',
- };
- },
- },
- };
- return executor;
- }
- await test('critical PRD generation rejects empty JSON output', async () => {
- const executor = createExecutorWithResponse('{}');
- let threw = false;
- try {
- await executor._buildLLMAdapter().call({
- docs: ['31'],
- output_config: { format: { type: 'json_object' } },
- messages: [{ role: 'user', content: 'Requirement: test' }],
- });
- } catch (err) {
- threw = true;
- assert(err.message.includes('Critical workflow JSON step'), `unexpected error: ${err.message}`);
- }
- assert(threw, 'expected critical JSON step to throw');
- });
- await test('non-critical JSON steps still fall back to empty object for compatibility', async () => {
- const executor = createExecutorWithResponse('No JSON here.');
- const result = await executor._buildLLMAdapter().call({
- docs: ['999'],
- output_config: { format: { type: 'json_object' } },
- messages: [{ role: 'user', content: 'test' }],
- });
- assert(result.content === '{}', `expected compatibility fallback, got ${result.content}`);
- });
- await test('JSON repair removes superfluous closing braces from near-valid payloads', async () => {
- const malformed = '{"apps":[{"id":"Main"}],"sections":[{"id":"Home","internal":{"blocks":[]}}}],"components":[]}';
- const executor = createExecutorWithResponse(malformed);
- const result = await executor._buildLLMAdapter().call({
- docs: ['999'],
- output_config: { format: { type: 'json_object' } },
- messages: [{ role: 'user', content: 'test' }],
- });
- const parsed = JSON.parse(result.content);
- assert(Array.isArray(parsed.apps), 'apps should be preserved after repair');
- assert(Array.isArray(parsed.sections), 'sections should be preserved after repair');
- });
- console.log(`\n── Results ──\n\n ${passed} passed, ${failed} failed\n`);
- process.exit(failed > 0 ? 1 : 0);
|