import test from 'node:test'; import assert from 'node:assert/strict'; import { buildCitations, isSafeHttpUrl, validateSearchRequest } from './search-capability.mjs'; import { MINDSEARCH_DEFAULT_CONFIG, normalizeMindSearchConfig } from './mindsearch-config.mjs'; import { buildAgentExtensionPolicy, DEFAULT_USER_CAPABILITIES } from './capabilities.mjs'; import { searchGithubCode, searchSearxng } from './mindsearch-providers.mjs'; test('MindSearch defaults to disabled and normalizes unsafe modes', () => { assert.equal(MINDSEARCH_DEFAULT_CONFIG.enabled, false); assert.deepEqual(normalizeMindSearchConfig({ enabled: true, mode: 'invalid', providers: { github: true } }), { enabled: false, mode: 'off', providers: { searxng: false, github: true, reader: false }, settings: { searxngEndpoint: '', maxResults: 10, timeoutMs: 8000, readerMaxChars: 12000 } }); }); test('search request validation and citations are deterministic', () => { assert.equal(validateSearchRequest({ query: '' }).code, 'INVALID_REQUEST'); const checked = validateSearchRequest({ query: ' Goose ', limit: 999 }); assert.deepEqual(checked.value, { query: 'Goose', type: 'web', limit: 20 }); assert.deepEqual(buildCitations([{ title: 'A', url: 'https://example.com', source: 'test' }]), [{ id: '[1]', title: 'A', url: 'https://example.com', source: 'test' }]); assert.equal(isSafeHttpUrl('http://127.0.0.1:8081/private'), false); assert.equal(isSafeHttpUrl('https://example.com/a'), true); }); test('MindSearch never changes legacy web extension and is gated by capability/config', () => { const base = { ...DEFAULT_USER_CAPABILITIES, web: true, search_external: false }; let policy = buildAgentExtensionPolicy(base, { mindSearchConfig: { enabled: true, mode: 'assist', providers: {} } }); assert.ok(policy.extensionOverrides.some((ext) => ext.name === 'web')); assert.equal(policy.extensionOverrides.some((ext) => ext.name === 'tkmind-search'), false); policy = buildAgentExtensionPolicy({ ...base, search_external: true }, { mindSearchConfig: { enabled: true, mode: 'assist', providers: {} }, policies: { network_egress: 'deny' } }); assert.equal(policy.extensionOverrides.some((ext) => ext.name === 'tkmind-search'), false); policy = buildAgentExtensionPolicy({ ...base, search_external: true }, { mindSearchConfig: { enabled: true, mode: 'assist', providers: {} } }); assert.ok(policy.extensionOverrides.some((ext) => ext.name === 'tkmind-search')); }); test('SearXNG adapter normalizes provider results without requiring a live network', async () => { const result = await searchSearxng('goose', { endpoint: 'http://search.local', fetchImpl: async () => ({ ok: true, json: async () => ({ results: [{ title: 'Goose', url: 'https://example.com', content: 'snippet' }] }) }) }); assert.deepEqual(result[0], { title: 'Goose', url: 'https://example.com', snippet: 'snippet', source: 'searxng', rank: 1 }); }); test('GitHub code adapter sends bounded queries and normalizes results', async () => { let requested; const result = await searchGithubCode('repo:openai goose', { limit: 50, fetchImpl: async (url, options) => { requested = { url: String(url), options }; return { ok: true, json: async () => ({ items: [{ repository: { full_name: 'openai/goose', description: 'agent' }, path: 'src/goose.rs', html_url: 'https://github.com/openai/goose/blob/main/src/goose.rs' }] }) }; } }); assert.match(requested.url, /per_page=20/); assert.equal(requested.options.headers.accept, 'application/vnd.github+json'); assert.equal(result[0].source, 'github'); });