route.ts
1 import { NextResponse } from 'next/server' 2 import { 3 createKnowledgeSource, 4 listKnowledgeSourceSummaries, 5 searchKnowledgeHits, 6 } from '@/lib/server/knowledge-sources' 7 import type { KnowledgeSourceKind } from '@/types' 8 9 function parseTags(raw: string | null): string[] | undefined { 10 if (!raw) return undefined 11 const tags = raw.split(',').map((tag) => tag.trim()).filter(Boolean) 12 return tags.length > 0 ? tags : undefined 13 } 14 15 function parseLimit(raw: string | null): number | undefined { 16 if (!raw) return undefined 17 return Math.max(1, Math.min(500, Number.parseInt(raw, 10) || 50)) 18 } 19 20 function parseBool(raw: string | null): boolean { 21 if (!raw) return false 22 const value = raw.trim().toLowerCase() 23 return value === '1' || value === 'true' || value === 'yes' 24 } 25 26 function inferKind(body: Record<string, unknown>): KnowledgeSourceKind { 27 if (body.kind === 'file' || body.kind === 'url' || body.kind === 'manual') return body.kind 28 if (typeof body.sourcePath === 'string' && body.sourcePath.trim()) return 'file' 29 if (typeof body.sourceUrl === 'string' && body.sourceUrl.trim() && typeof body.content !== 'string') return 'url' 30 return 'manual' 31 } 32 33 export async function GET(req: Request) { 34 const { searchParams } = new URL(req.url) 35 const query = searchParams.get('q') 36 const tags = parseTags(searchParams.get('tags')) 37 const limit = parseLimit(searchParams.get('limit')) 38 const includeArchived = parseBool(searchParams.get('includeArchived')) 39 40 if (query && query.trim()) { 41 const hits = await searchKnowledgeHits({ query, tags, limit, includeArchived }) 42 return NextResponse.json(hits) 43 } 44 45 const sources = await listKnowledgeSourceSummaries({ tags, limit, includeArchived }) 46 return NextResponse.json(sources) 47 } 48 49 export async function POST(req: Request) { 50 const body = await req.json().catch(() => null) 51 if (!body || typeof body !== 'object' || Array.isArray(body)) { 52 return NextResponse.json({ error: 'Invalid JSON body.' }, { status: 400 }) 53 } 54 55 const payload = body as Record<string, unknown> 56 57 try { 58 const detail = await createKnowledgeSource({ 59 kind: inferKind(payload), 60 title: typeof payload.title === 'string' ? payload.title : undefined, 61 content: typeof payload.content === 'string' ? payload.content : undefined, 62 tags: Array.isArray(payload.tags) ? payload.tags.filter((tag): tag is string => typeof tag === 'string') : undefined, 63 scope: payload.scope === 'agent' ? 'agent' : 'global', 64 agentIds: Array.isArray(payload.agentIds) ? payload.agentIds.filter((id): id is string => typeof id === 'string') : undefined, 65 sourceLabel: typeof payload.sourceLabel === 'string' 66 ? payload.sourceLabel 67 : typeof payload.source === 'string' 68 ? payload.source 69 : undefined, 70 sourceUrl: typeof payload.sourceUrl === 'string' ? payload.sourceUrl : undefined, 71 sourcePath: typeof payload.sourcePath === 'string' 72 ? payload.sourcePath 73 : typeof payload.filePath === 'string' 74 ? payload.filePath 75 : undefined, 76 metadata: payload.metadata && typeof payload.metadata === 'object' && !Array.isArray(payload.metadata) 77 ? payload.metadata as Record<string, unknown> 78 : undefined, 79 }) 80 81 return NextResponse.json(detail) 82 } catch (error) { 83 return NextResponse.json( 84 { error: error instanceof Error ? error.message : 'Failed to create knowledge source.' }, 85 { status: 400 }, 86 ) 87 } 88 }