87 lines
2.8 KiB
TypeScript
87 lines
2.8 KiB
TypeScript
|
|
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');
|
||
|
|
});
|
||
|
|
});
|