import { describe, expect, it } from 'vitest'; import { validateExtraArgs, isManagedFlag, stripShadowingFlags, } from '../inference/llama-args-validator.js'; import { parseAgentsMd } from '../agents.js'; describe('validateExtraArgs', () => { describe('deny list — each alias rejected', () => { const denied = [ '-m', '--model', '-mu', '--model-url', '-dr', '--docker-repo', '-hf', '-hfr', '--hf-repo', '-hff', '--hf-file', '-hfv', '-hfrv', '--hf-repo-v', '-hffv', '--hf-file-v', '-hft', '--hf-token', '-mm', '--mmproj', '-mmu', '--mmproj-url', '--host', '--port', '--path', '--api-prefix', '--reuse-port', '--api-key', '--api-key-file', '--ssl-key-file', '--ssl-cert-file', '--webui', '--no-webui', '--ui', '--no-ui', '--ui-config', '--ui-config-file', '--ui-mcp-proxy', '--no-ui-mcp-proxy', '--models-dir', '--models-preset', '--models-max', '--models-autoload', '--no-models-autoload', ]; for (const flag of denied) { it(`rejects ${flag}`, () => { expect(() => validateExtraArgs([flag])).toThrow(/managed/); }); } }); describe('safe flags accepted', () => { const safe = [ '-c', '--ctx-size', '-ngl', '--gpu-layers', '--top-k', '--cache-type-k', '--jinja', '--no-jinja', '--spec-draft-n-max', '-fa', '--flash-attn', '-t', '--threads', '-np', '--parallel', ]; for (const flag of safe) { it(`accepts ${flag}`, () => { expect(() => validateExtraArgs([flag])).not.toThrow(); expect(validateExtraArgs([flag])).toEqual([flag]); }); } }); it('handles --flag=value shape (denies the flag part)', () => { expect(() => validateExtraArgs(['--model=evil.gguf'])).toThrow(/managed/); }); it('handles --flag=value shape (accepts safe flag)', () => { expect(validateExtraArgs(['--ctx-size=4096'])).toEqual(['--ctx-size=4096']); }); it('returns empty array for undefined input', () => { expect(validateExtraArgs(undefined)).toEqual([]); }); it('returns empty array for empty input', () => { expect(validateExtraArgs([])).toEqual([]); }); it('treats negative numbers as values, not flags', () => { expect(validateExtraArgs(['--seed', '-1'])).toEqual(['--seed', '-1']); }); }); describe('isManagedFlag', () => { it('returns true for denied flags', () => { expect(isManagedFlag('--model')).toBe(true); expect(isManagedFlag('-m')).toBe(true); expect(isManagedFlag('--api-key')).toBe(true); expect(isManagedFlag('--port')).toBe(true); }); it('returns false for safe flags', () => { expect(isManagedFlag('-c')).toBe(false); expect(isManagedFlag('--ctx-size')).toBe(false); expect(isManagedFlag('--top-k')).toBe(false); }); }); describe('stripShadowingFlags', () => { it('strips auto -c when user supplies -c', () => { const result = stripShadowingFlags(['-c', '4096', '--top-k', '40']); expect(result).toEqual(['--top-k', '40']); }); it('retains both when no overlap', () => { const result = stripShadowingFlags(['--top-k', '40', '--top-p', '0.95']); expect(result).toEqual(['--top-k', '40', '--top-p', '0.95']); }); it('strips --ctx-size=value form', () => { const result = stripShadowingFlags(['--ctx-size=4096']); expect(result).toEqual([]); }); it('strips boolean --jinja flag (no value consumed)', () => { const result = stripShadowingFlags(['--jinja', '--top-k', '40']); expect(result).toEqual(['--top-k', '40']); }); it('respects stripContext=false to keep context flags', () => { const result = stripShadowingFlags(['-c', '4096'], { stripContext: false }); expect(result).toEqual(['-c', '4096']); }); it('strips cache flags by default', () => { const result = stripShadowingFlags(['--cache-type-k', 'q8_0']); expect(result).toEqual([]); }); it('strips spec flags by default', () => { const result = stripShadowingFlags(['--spec-draft-n-max', '16']); expect(result).toEqual([]); }); }); describe('AGENTS.md frontmatter validation', () => { it('rejects agent with managed flag in llama_extra_args', () => { const md = `## Evil Agent --- llama_extra_args: ["--model", "evil.gguf"] --- You are evil.`; const { agents, errors } = parseAgentsMd(md); expect(agents).toHaveLength(0); expect(errors).toHaveLength(1); expect(errors[0]!.reason).toContain('managed'); }); it('accepts agent with safe llama_extra_args', () => { const md = `## Good Agent --- llama_extra_args: ["--top-k", "20"] --- You are good.`; const { agents, errors } = parseAgentsMd(md); expect(errors).toHaveLength(0); expect(agents).toHaveLength(1); expect(agents[0]!.llama_extra_args).toEqual(['--top-k', '20']); }); it('agent without llama_extra_args has null field', () => { const md = `## Simple Agent --- temperature: 0.5 --- You are simple.`; const { agents } = parseAgentsMd(md); expect(agents[0]!.llama_extra_args).toBeNull(); }); });