feat: implement local deep search engine
This commit is contained in:
+48
-3
@@ -9,6 +9,8 @@ import {
|
||||
} from './mindsearch-config.mjs';
|
||||
import { buildAgentExtensionPolicy, DEFAULT_USER_CAPABILITIES } from './capabilities.mjs';
|
||||
import {
|
||||
cancelResearchTask,
|
||||
getResearchTask,
|
||||
searchGithubCode,
|
||||
searchResearchService,
|
||||
searchSearxng,
|
||||
@@ -22,7 +24,8 @@ test('MindSearch defaults to disabled and normalizes unsafe modes', () => {
|
||||
assert.equal(config.mode, 'off');
|
||||
assert.deepEqual(config.providers, { searxng: false, github: true, reader: false });
|
||||
assert.equal(config.services.find((service) => service.id === 'github').enabled, true);
|
||||
assert.deepEqual(config.routes, { web: 'searxng', news: 'searxng', code: 'github', read: 'reader', research: '' });
|
||||
assert.deepEqual(config.routes, { web: 'searxng', news: 'searxng', code: 'github', read: 'reader', research: 'deep-search' });
|
||||
assert.equal(config.services.find((service) => service.id === 'deep-search').enabled, false);
|
||||
});
|
||||
|
||||
test('MindSearch service registry accepts research orchestrators and rejects unsafe endpoints', () => {
|
||||
@@ -89,6 +92,20 @@ test('MindSearch never changes legacy web extension and is gated by capability/c
|
||||
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'));
|
||||
policy = buildAgentExtensionPolicy({ ...base, search_external: true }, {
|
||||
userId: 'user-123',
|
||||
mindSearchConfig: {
|
||||
enabled: true,
|
||||
mode: 'assist',
|
||||
providers: {},
|
||||
services: [{ id: 'deep-search', enabled: true, adapter: 'research-http' }],
|
||||
routes: { research: 'deep-search' },
|
||||
},
|
||||
});
|
||||
const extension = policy.extensionOverrides.find((ext) => ext.name === 'tkmind-search');
|
||||
assert.equal(extension.envs.TKMIND_SEARCH_USER_ID, 'user-123');
|
||||
assert.ok(extension.available_tools.includes('tkmind_research_status'));
|
||||
assert.ok(extension.available_tools.includes('tkmind_research_cancel'));
|
||||
});
|
||||
|
||||
test('SearXNG adapter normalizes provider results without requiring a live network', async () => {
|
||||
@@ -111,12 +128,40 @@ test('Research service adapter uses the stable HTTP contract', async () => {
|
||||
if (String(url).endsWith('/v1/research')) {
|
||||
return { ok: true, json: async () => ({ task_id: 'task-1', status: 'running' }) };
|
||||
}
|
||||
if (String(url).endsWith('/v1/research/task-1')) {
|
||||
return {
|
||||
ok: true,
|
||||
status: 200,
|
||||
json: async () => ({
|
||||
id: 'task-1',
|
||||
status: options?.method === 'DELETE' ? 'cancelling' : 'researching',
|
||||
progress: 55,
|
||||
}),
|
||||
};
|
||||
}
|
||||
return { ok: true, json: async () => ({ results: [{ title: 'Report', url: 'https://example.com/report', snippet: 'evidence' }] }) };
|
||||
};
|
||||
const results = await searchResearchService('AI Agent', { endpoint: 'http://research.local', limit: 5, fetchImpl });
|
||||
const task = await startResearchTask('Analyze AI Agent', { endpoint: 'http://research.local', depth: 'deep', fetchImpl });
|
||||
const task = await startResearchTask('Analyze AI Agent', {
|
||||
endpoint: 'http://research.local',
|
||||
depth: 'deep',
|
||||
userId: 'user-1',
|
||||
secret: 'secret-1',
|
||||
fetchImpl,
|
||||
});
|
||||
const status = await getResearchTask('task-1', { endpoint: 'http://research.local', fetchImpl });
|
||||
const cancelled = await cancelResearchTask('task-1', { endpoint: 'http://research.local', fetchImpl });
|
||||
assert.equal(results[0].source, 'research-service');
|
||||
assert.deepEqual(task, { taskId: 'task-1', status: 'running', service: 'research-service' });
|
||||
assert.equal(status.status, 'researching');
|
||||
assert.equal(cancelled.status, 'cancelling');
|
||||
assert.equal(JSON.parse(requests[0].options.body).query, 'AI Agent');
|
||||
assert.deepEqual(JSON.parse(requests[1].options.body), { question: 'Analyze AI Agent', depth: 'deep' });
|
||||
assert.deepEqual(JSON.parse(requests[1].options.body), {
|
||||
question: 'Analyze AI Agent',
|
||||
depth: 'deep',
|
||||
userId: 'user-1',
|
||||
});
|
||||
assert.equal(requests[1].options.headers['x-user-id'], 'user-1');
|
||||
assert.equal(requests[1].options.headers['x-secret-key'], 'secret-1');
|
||||
assert.equal(requests[3].options.method, 'DELETE');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user