Files
memind/mindsearch.test.mjs

45 lines
3.5 KiB
JavaScript

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');
});