UNPKG

seraph-agent

Version:

An extremely lightweight, SRE autonomous AI agent for seamless integration with common observability tasks.

233 lines (232 loc) 9.18 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.buildKnowledgeBase = buildKnowledgeBase; const faiss_1 = require("@langchain/community/vectorstores/faiss"); const text_splitter_1 = require("langchain/text_splitter"); const document_1 = require("langchain/document"); const fs = __importStar(require("fs/promises")); const path = __importStar(require("path")); const embedding_provider_1 = require("./llm/embedding-provider"); const html_to_text_1 = require("html-to-text"); async function fetchGitHubReleases(repository, token) { if (!repository) { return []; } try { const url = `https://api.github.com/repos/${repository}/releases`; const headers = {}; if (token) { headers['Authorization'] = `Bearer ${token}`; } const response = await fetch(url, { headers }); const releases = await response.json(); return releases.map((release) => new document_1.Document({ pageContent: release.body, metadata: { source: 'github-releases', tag: release.tag_name, published_at: release.published_at, }, })); } catch (error) { console.error(`Error fetching GitHub releases for ${repository}:`, error); return []; } } async function fetchGitHubCode(repository, token) { if (!repository) { return []; } try { const url = `https://api.github.com/repos/${repository}/contents`; const headers = {}; if (token) { headers['Authorization'] = `Bearer ${token}`; } const response = await fetch(url, { headers }); const files = await response.json(); const documentPromises = files .filter(file => file.type === 'file') .map(async (file) => { const contentResponse = await fetch(file.download_url); const content = await contentResponse.text(); return new document_1.Document({ pageContent: content, metadata: { source: 'github-code', path: file.path, }, }); }); return Promise.all(documentPromises); } catch (error) { console.error(`Error fetching GitHub code for ${repository}:`, error); return []; } } async function fetchJiraTickets(config) { const { instanceUrl, projectKey, jql, usernameVar, apiTokenVar } = config; const username = process.env[usernameVar]; const apiToken = process.env[apiTokenVar]; if (!username || !apiToken) { console.error('JIRA username or API token not found in environment variables.'); return []; } const auth = Buffer.from(`${username}:${apiToken}`).toString('base64'); const searchQuery = jql || `project = ${projectKey}`; const url = `${instanceUrl}/rest/api/3/search?jql=${searchQuery}`; try { const response = await fetch(url, { headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json', }, }); const data = await response.json(); return data.issues.map((issue) => new document_1.Document({ pageContent: `${issue.fields.summary}\n\n${issue.fields.description}\n\n${issue.fields.comment.comments.map((c) => c.body).join('\n\n')}`, metadata: { source: 'jira', key: issue.key, url: `${instanceUrl}/browse/${issue.key}`, }, })); } catch (error) { console.error('Error fetching JIRA tickets:', error); return []; } } async function fetchConfluenceDocs(config) { const { instanceUrl, spaceKey, usernameVar, apiTokenVar } = config; const username = process.env[usernameVar]; const apiToken = process.env[apiTokenVar]; if (!username || !apiToken) { console.error('Confluence username or API token not found in environment variables.'); return []; } const auth = Buffer.from(`${username}:${apiToken}`).toString('base64'); const url = `${instanceUrl}/rest/api/content?spaceKey=${spaceKey}&expand=body.storage`; try { const response = await fetch(url, { headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json', }, }); const data = await response.json(); return data.results.map((page) => new document_1.Document({ pageContent: (0, html_to_text_1.htmlToText)(page.body.storage.value), metadata: { source: 'confluence', title: page.title, url: `${instanceUrl}${page._links.webui}`, }, })); } catch (error) { console.error('Error fetching Confluence docs:', error); return []; } } async function buildKnowledgeBase(config, sourceName) { if (!config.knowledge?.enabled) { console.log('Knowledge base is disabled in the configuration.'); return; } console.log(`Building knowledge base${sourceName ? ` for source: ${sourceName}` : ''}...`); const sourcesToBuild = sourceName ? config.knowledge.sources.filter((s) => s.name === sourceName) : config.knowledge.sources; const documents = []; for (const source of sourcesToBuild) { if (!source.enabled) { continue; } let fetchedDocs = []; switch (source.config.type) { case 'github': const token = source.config.authVar ? process.env[source.config.authVar] : undefined; if (source.config.sourceType === 'releases') { fetchedDocs = await fetchGitHubReleases(source.config.repository, token); } else if (source.config.sourceType === 'code') { fetchedDocs = await fetchGitHubCode(source.config.repository, token); } break; case 'jira': fetchedDocs = await fetchJiraTickets(source.config); break; case 'confluence': fetchedDocs = await fetchConfluenceDocs(source.config); break; default: console.warn(`Unknown knowledge source type: ${source.config.type}`); } documents.push(...fetchedDocs); } if (documents.length === 0) { console.log('No documents found to build the knowledge base.'); return; } const textSplitter = new text_splitter_1.RecursiveCharacterTextSplitter({ chunkSize: 1000, chunkOverlap: 200, }); const splitDocs = await textSplitter.splitDocuments(documents); const embeddings = (0, embedding_provider_1.createEmbeddingProvider)(config); const vectorStorePath = config.knowledge.vectorStore; const vectorStoreDir = path.dirname(vectorStorePath); await fs.mkdir(vectorStoreDir, { recursive: true }); try { const vectorStore = await faiss_1.FaissStore.load(vectorStoreDir, embeddings); if (sourceName) { const idsToDelete = Array.from(vectorStore.docstore['_docs'].values()) .filter((doc) => doc.metadata.source === sourceName) .map((doc) => doc.metadata.id); await vectorStore.delete({ ids: idsToDelete }); } await vectorStore.addDocuments(splitDocs); await vectorStore.save(vectorStorePath); } catch (error) { const vectorStore = await faiss_1.FaissStore.fromDocuments(splitDocs, embeddings); await vectorStore.save(vectorStorePath); } console.log('Knowledge base built successfully.'); }