import type { IndemnClient } from './client.js'; import type { KnowledgeBase, CreateKBInput, UpdateKBInput, DataSource, AddDataSourceInput, KBMapping, } from './types.js'; export class KBSDK { constructor(private client: IndemnClient) {} async listKBs(): Promise { return this.client.copilotGet( '/organization/:org_id/knowledge-bases', ); } async getKB(id: string): Promise { const result = await this.client.copilotGet( `/organization/:org_id/knowledge-bases/${id}`, ); // Server may return an array; extract the first element return Array.isArray(result) ? result[0] : result; } async createKB(input: CreateKBInput): Promise { return this.client.copilotPost( '/organization/:org_id/knowledge-bases', input, ); } async updateKB(id: string, input: UpdateKBInput): Promise { return this.client.copilotPut( `/organization/:org_id/knowledge-bases/${id}`, input, ); } async deleteKB(id: string): Promise { await this.client.copilotDelete( `/organization/:org_id/knowledge-bases/${id}`, ); } async listDataSources( kbId: string, query?: { page?: string; limit?: string }, ): Promise<{ dataSources: DataSource[]; total: number; page: number; pages: number }> { return this.client.copilotGet<{ dataSources: DataSource[]; total: number; page: number; pages: number }>( `/organization/:org_id/knowledge-bases/${kbId}/data-source`, query as Record | undefined, ); } async addDataSource(kbId: string, input: AddDataSourceInput): Promise { if (input.source_url) { // URL type — must use /import endpoint (data-source POST only supports text) return this.client.copilotPost( `/organization/:org_id/knowledge-bases/${kbId}/import`, { type: 'url', sources: [{ url: input.source_url, crawl_mode: 'full' }], }, ); } // Text/QnA type return this.client.copilotPost( `/organization/:org_id/knowledge-bases/${kbId}/data-source`, { type: 'text', payload: { question: input.question, answer: input.answer, isManual: true } }, ); } async scrapeUrl(kbId: string, url: string, crawlMode: string = 'full'): Promise { return this.client.copilotPost( `/organization/:org_id/knowledge-bases/${kbId}/import`, { type: 'url', sources: [{ url, crawl_mode: crawlMode }], }, ); } async uploadFile(kbId: string, filePath: string): Promise { const fs = await import('fs'); const path = await import('path'); if (!fs.existsSync(filePath)) { throw new Error(`File not found: ${filePath}`); } const fileBuffer = fs.readFileSync(filePath); const fileName = path.basename(filePath); const blob = new Blob([fileBuffer]); const formData = new FormData(); formData.append('file', blob, fileName); // Need a raw fetch since copilotPost sets Content-Type to JSON const hosts = this.client.getHosts(); const orgId = this.client.getOrgId(); const apiKey = this.client.getApiKey(); const url_str = `${hosts.copilot}/organization/${orgId}/knowledge-bases/${kbId}/upload-urls`; const res = await fetch(url_str, { method: 'POST', headers: { 'Authorization': `Bearer ${apiKey}`, }, body: formData, }); if (!res.ok) { const text = await res.text(); throw new Error(`Upload failed (${res.status}): ${text}`); } const json = await res.json() as { data?: unknown }; return json.data || json; } async updateDataSource( kbId: string, sourceId: string, input: Partial, ): Promise { return this.client.copilotPut( `/organization/:org_id/knowledge-bases/${kbId}/data-source/${sourceId}`, { payload: { question: input.question, answer: input.answer, isManual: true } }, ); } async deleteDataSource(kbId: string, sourceId: string): Promise { await this.client.copilotDelete( `/organization/:org_id/knowledge-bases/${kbId}/data-source/${sourceId}`, ); } async linkKB(agentId: string, kbIds: string[]): Promise { return this.client.copilotPost( `/organization/:org_id/ai-studio/bots/${agentId}/mappings`, { id_kb: kbIds }, ); } async unlinkKB(agentId: string, kbId: string): Promise { // Mappings response: [{ id: "kb_id", connectedBots: [{ id: "bot_id", id_mapping: "mapping_id" }] }] const mappings = await this.client.copilotGet; }>>( `/organization/:org_id/ai-studio/bots/${agentId}/mappings`, ); const kbEntry = mappings.find((m) => m.id === kbId); if (!kbEntry) { throw new Error(`No mapping found for KB ${kbId} on agent ${agentId}`); } const botMapping = kbEntry.connectedBots.find((b) => b.id === agentId); if (!botMapping) { throw new Error(`No mapping found for KB ${kbId} on agent ${agentId}`); } await this.client.copilotDelete( `/organization/:org_id/ai-studio/bots/${agentId}/mappings/${botMapping.id_mapping}`, ); } async exportKB(kbId: string, format: string): Promise { return this.client.copilotPost( `/organization/:org_id/knowledge-bases/${kbId}/export`, { type: format }, ); } async importKB(kbId: string, data: unknown): Promise { return this.client.copilotPost( `/organization/:org_id/knowledge-bases/${kbId}/import`, data, ); } }