index.ts•4.08 kB
import { http_json } from '../../../common/http.js';
import {
EnhancementProvider,
EnhancementResult,
ErrorType,
ProviderError,
} from '../../../common/types.js';
import {
retry_with_backoff,
sanitize_query,
validate_api_key,
} from '../../../common/utils.js';
import { config } from '../../../config/env.js';
export interface EnrichmentResponse {
data: Array<{
title: string;
url: string;
snippet: string;
rank?: number;
}>;
meta?: {
total_hits: number;
api_balance?: number;
};
}
export class KagiEnrichmentProvider implements EnhancementProvider {
name = 'kagi_enrichment';
description =
'Provides supplementary content from specialized indexes (Teclis for web, TinyGem for news). Ideal for discovering non-mainstream results and enriching content with specialized knowledge.';
async enhance_content(content: string): Promise<EnhancementResult> {
const api_key = validate_api_key(
config.enhancement.kagi_enrichment.api_key,
this.name,
);
const enrich_request = async () => {
try {
// Try both web and news endpoints
const [webData, newsData] = await Promise.all([
http_json<EnrichmentResponse & { message?: string }>(
this.name,
`https://kagi.com/api/v0/enrich/web?${new URLSearchParams(
{
q: sanitize_query(
'artificial intelligence software development',
),
limit: '5',
},
)}`,
{
method: 'GET',
headers: {
Authorization: `Bot ${api_key}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(
config.enhancement.kagi_enrichment.timeout,
),
},
),
http_json<EnrichmentResponse & { message?: string }>(
this.name,
`https://kagi.com/api/v0/enrich/news?${new URLSearchParams(
{
q: sanitize_query(
'artificial intelligence code generation testing',
),
limit: '5',
},
)}`,
{
method: 'GET',
headers: {
Authorization: `Bot ${api_key}`,
Accept: 'application/json',
},
signal: AbortSignal.timeout(
config.enhancement.kagi_enrichment.timeout,
),
},
),
]);
if (!webData?.data || !newsData?.data) {
throw new ProviderError(
ErrorType.API_ERROR,
'Unexpected response: missing data from enrichment endpoints',
this.name,
);
}
// Combine and filter results
const allData = [...webData.data, ...newsData.data].filter(
(result) =>
// Filter for results about software/development/AI
result.snippet?.toLowerCase().includes('software') ||
result.snippet?.toLowerCase().includes('develop') ||
result.snippet?.toLowerCase().includes('programming') ||
result.snippet?.toLowerCase().includes('code') ||
result.snippet
?.toLowerCase()
.includes('artificial intelligence') ||
result.snippet?.toLowerCase().includes('ai'),
);
// Clean and combine snippets
const enhanced_content = allData
.map((result) => result.snippet)
.filter(Boolean)
.map((snippet) =>
// Fix HTML entities
snippet
.replace(/'/g, "'")
.replace(/"/g, '"')
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>'),
)
.join('\n\n');
return {
original_content: content,
enhanced_content,
enhancements: [
{
type: 'content_enrichment',
description:
'Added supplementary information from Teclis (web) and TinyGem (news) specialized indexes',
},
],
sources: allData.map((result) => ({
title: result.title,
url: result.url,
})),
source_provider: this.name,
};
} catch (error) {
if (error instanceof ProviderError) {
throw error;
}
throw new ProviderError(
ErrorType.API_ERROR,
`Failed to fetch: ${
error instanceof Error ? error.message : 'Unknown error'
}`,
this.name,
);
}
};
return retry_with_backoff(enrich_request);
}
}