import { describe, it, expect } from 'vitest'; import type { ProxyModelDetails } from '../../src/commands/console/unified-types.js'; /** * Tests that ProxyModelDetails handles both pipeline and plugin types. * The ProvenanceView component renders these — a plugin has hooks but no stages/appliesTo. * This validates the type contract so rendering won't crash. */ describe('ProxyModelDetails type contract', () => { it('pipeline-type has stages and appliesTo', () => { const details: ProxyModelDetails = { name: 'default', source: 'built-in', type: 'pipeline', controller: 'gate', stages: [ { type: 'passthrough' }, { type: 'paginate', config: { maxPageSize: 8000 } }, ], appliesTo: ['toolResult', 'prompt'], cacheable: true, }; expect(details.stages).toHaveLength(2); expect(details.appliesTo).toHaveLength(2); expect(details.cacheable).toBe(true); }); it('plugin-type has hooks but no stages/appliesTo', () => { const details: ProxyModelDetails = { name: 'gate', source: 'built-in', type: 'plugin', hooks: ['onInitialize', 'onToolsList', 'onToolCallBefore'], extends: [], description: 'Gate-only plugin', }; // These fields are undefined for plugins expect(details.stages).toBeUndefined(); expect(details.appliesTo).toBeUndefined(); expect(details.cacheable).toBeUndefined(); expect(details.hooks).toHaveLength(3); }); it('safe access patterns for optional fields (what ProvenanceView does)', () => { const pluginDetails: ProxyModelDetails = { name: 'gate', source: 'built-in', type: 'plugin', hooks: ['onInitialize', 'onToolsList'], }; // These are the patterns used in ProvenanceView — must not crash const cacheLine = pluginDetails.cacheable ? ', cached' : ''; expect(cacheLine).toBe(''); const appliesLine = pluginDetails.appliesTo && pluginDetails.appliesTo.length > 0 ? pluginDetails.appliesTo.join(', ') : ''; expect(appliesLine).toBe(''); const stages = (pluginDetails.stages ?? []).map((s) => s.type); expect(stages).toEqual([]); const hooks = pluginDetails.hooks && pluginDetails.hooks.length > 0 ? pluginDetails.hooks.join(', ') : ''; expect(hooks).toBe('onInitialize, onToolsList'); }); it('default plugin extends gate and content-pipeline', () => { const details: ProxyModelDetails = { name: 'default', source: 'built-in', type: 'plugin', hooks: ['onSessionCreate', 'onInitialize', 'onToolsList', 'onToolCallBefore', 'onToolCallAfter'], extends: ['gate', 'content-pipeline'], description: 'Default plugin with gating and content pipeline', }; expect(details.extends).toContain('gate'); expect(details.extends).toContain('content-pipeline'); }); });