diff --git a/.gitignore b/.gitignore index 7efc5d0..e367c9c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ dist/ .env .env.local .DS_Store +dist/ diff --git a/citations.d.ts b/citations.d.ts new file mode 100644 index 0000000..0a7b04b --- /dev/null +++ b/citations.d.ts @@ -0,0 +1,20 @@ +import { Citation } from './types.js'; +export declare class CitationTracker { + private citations; + private citationHistory; + addCitations(citations: Citation[]): void; + getCitations(): Citation[]; + getCitationsByQuery(queryHash: string): Citation[]; + formatCitations(): string; + formatCitationsInline(): string; + clear(): void; + exportHistory(): { + timestamp: string; + citations: Citation[]; + }[]; + getTopSources(limit?: number): { + source: string; + count: number; + }[]; +} +//# sourceMappingURL=citations.d.ts.map \ No newline at end of file diff --git a/citations.d.ts.map b/citations.d.ts.map new file mode 100644 index 0000000..97120d0 --- /dev/null +++ b/citations.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"citations.d.ts","sourceRoot":"","sources":["../src/citations.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,eAAe,CAAsC;IAE7D,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI;IAQzC,YAAY,IAAI,QAAQ,EAAE;IAI1B,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,EAAE;IAIlD,eAAe,IAAI,MAAM;IAczB,qBAAqB,IAAI,MAAM;IAQ/B,KAAK,IAAI,IAAI;IAKb,aAAa,IAAI;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,QAAQ,EAAE,CAAA;KAAE,EAAE;IAQ/D,aAAa,CAAC,KAAK,GAAE,MAAU,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE;CAYtE"} \ No newline at end of file diff --git a/citations.js b/citations.js new file mode 100644 index 0000000..333235a --- /dev/null +++ b/citations.js @@ -0,0 +1,56 @@ +// Citation Tracker +// Tracks sources and citations for RAG responses +export class CitationTracker { + citations = []; + citationHistory = new Map(); + addCitations(citations) { + this.citations = citations; + // Also store by query for history + const queryKey = Date.now().toString(); + this.citationHistory.set(queryKey, [...citations]); + } + getCitations() { + return this.citations; + } + getCitationsByQuery(queryHash) { + return this.citationHistory.get(queryHash) || []; + } + formatCitations() { + if (this.citations.length === 0) { + return ''; + } + const lines = ['\n\n**Sources:**']; + this.citations.forEach((cite, i) => { + lines.push(`[${i + 1}] ${cite.source}${cite.sourceUrl ? ` - ${cite.sourceUrl}` : ''}`); + }); + return lines.join('\n'); + } + formatCitationsInline() { + if (this.citations.length === 0) { + return ''; + } + return this.citations.map(c => `[${c.source}]`).join(', '); + } + clear() { + this.citations = []; + } + // Export all citation history + exportHistory() { + return Array.from(this.citationHistory.entries()).map(([timestamp, citations]) => ({ + timestamp, + citations + })); + } + // Get most cited sources + getTopSources(limit = 5) { + const counts = new Map(); + this.citations.forEach(cite => { + counts.set(cite.source, (counts.get(cite.source) || 0) + 1); + }); + return Array.from(counts.entries()) + .map(([source, count]) => ({ source, count })) + .sort((a, b) => b.count - a.count) + .slice(0, limit); + } +} +//# sourceMappingURL=citations.js.map \ No newline at end of file diff --git a/citations.js.map b/citations.js.map new file mode 100644 index 0000000..49575b0 --- /dev/null +++ b/citations.js.map @@ -0,0 +1 @@ +{"version":3,"file":"citations.js","sourceRoot":"","sources":["../src/citations.ts"],"names":[],"mappings":"AAAA,mBAAmB;AACnB,iDAAiD;AAIjD,MAAM,OAAO,eAAe;IAClB,SAAS,GAAe,EAAE,CAAC;IAC3B,eAAe,GAA4B,IAAI,GAAG,EAAE,CAAC;IAE7D,YAAY,CAAC,SAAqB;QAChC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,kCAAkC;QAClC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;QACvC,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IACrD,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,mBAAmB,CAAC,SAAiB;QACnC,OAAO,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IACnD,CAAC;IAED,eAAe;QACb,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,KAAK,GAAG,CAAC,kBAAkB,CAAC,CAAC;QAEnC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE;YACjC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACzF,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,qBAAqB;QACnB,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAChC,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7D,CAAC;IAED,KAAK;QACH,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;IACtB,CAAC;IAED,8BAA8B;IAC9B,aAAa;QACX,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;YACjF,SAAS;YACT,SAAS;SACV,CAAC,CAAC,CAAC;IACN,CAAC;IAED,yBAAyB;IACzB,aAAa,CAAC,QAAgB,CAAC;QAC7B,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;QAEzC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;YAC5B,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;aAChC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;aAC7C,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC;aACjC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACrB,CAAC;CACF"} \ No newline at end of file diff --git a/cli/index.js b/cli/index.js new file mode 100644 index 0000000..973ad78 --- /dev/null +++ b/cli/index.js @@ -0,0 +1,146 @@ +#!/usr/bin/env node + +/** + * Phantom Knowledge CLI + * Commands: init, search, sync, stats + */ + +import { createKnowledgeEngine, GitHubConnector } from '../dist/index.js'; + +const args = process.argv.slice(2); +const command = args[0]; + +async function main() { + switch (command) { + case 'init': + await cmdInit(); + break; + case 'search': + await cmdSearch(args[1]); + break; + case 'sync': + await cmdSync(args[1]); + break; + case 'stats': + await cmdStats(); + break; + default: + console.log(` +Phantom Knowledge Layer CLI + +Usage: phantom knowledge + +Commands: + init Initialize knowledge layer + search Search knowledge base + sync Sync from connector (github) + stats Show knowledge stats + +Examples: + phantom knowledge init + phantom knowledge search "what is VAJRA?" + phantom knowledge sync github + phantom knowledge stats +`); + } +} + +async function cmdInit() { + console.log('šŸ“š Initializing Phantom Knowledge Layer...'); + + const engine = await createKnowledgeEngine({ + embeddings: { + provider: process.env.EMBEDDING_PROVIDER || 'ollama', + model: process.env.EMBEDDING_MODEL || 'nomic-embed-text' + }, + vectorStore: { + type: process.env.VECTOR_STORE_TYPE || 'file', + path: process.env.VECTOR_STORE_PATH || './knowledge.json' + }, + llm: { + model: process.env.LLM_MODEL || 'gpt-4o-mini' + } + }); + + console.log('āœ… Knowledge engine initialized!'); + console.log('\nNext steps:'); + console.log(' 1. Set GITHUB_TOKEN for GitHub connector'); + console.log(' 2. Run: phantom knowledge sync github'); + console.log(' 3. Query: phantom knowledge search "your question"'); +} + +async function cmdSearch(query) { + if (!query) { + console.log('Error: Please provide a search query'); + console.log('Usage: phantom knowledge search ""'); + process.exit(1); + } + + console.log(`šŸ” Searching for: "${query}"`); + + const engine = await createKnowledgeEngine({ + embeddings: { provider: 'ollama' }, + vectorStore: { type: 'memory' } + }); + + const result = await engine.query(query); + + console.log('\nšŸ“ Answer:'); + console.log(result.answer); + + if (result.citations.length > 0) { + console.log('\nšŸ“š Sources:'); + result.citations.forEach((cite, i) => { + console.log(` [${i + 1}] ${cite.source}${cite.sourceUrl ? ` (${cite.sourceUrl})` : ''}`); + }); + } +} + +async function cmdSync(source) { + if (!source) { + console.log('Error: Please specify a source to sync'); + console.log('Usage: phantom knowledge sync '); + console.log('Available: github'); + process.exit(1); + } + + const token = process.env.GITHUB_TOKEN; + if (!token) { + console.log('Error: GITHUB_TOKEN not set'); + console.log('Set it with: export GITHUB_TOKEN=your_token'); + process.exit(1); + } + + console.log(`šŸ“„ Syncing from ${source}...`); + + const engine = await createKnowledgeEngine({ + embeddings: { provider: 'ollama' }, + vectorStore: { type: 'file', path: './knowledge.json' } + }); + + if (source === 'github') { + const [owner, repo] = (process.env.GITHUB_REPO || 'sir-ad/phantom-knowledge').split('/'); + const github = new GitHubConnector({ token, owner, repo }); + engine.registerConnector('github', github); + await engine.syncConnector('github'); + } + + const stats = engine.getStats(); + console.log(`\nāœ… Synced! Total documents: ${stats.documentCount}`); +} + +async function cmdStats() { + const engine = await createKnowledgeEngine({ + embeddings: { provider: 'ollama' }, + vectorStore: { type: 'file', path: './knowledge.json' } + }); + + const stats = engine.getStats(); + + console.log('šŸ“Š Knowledge Stats'); + console.log('─'.repeat(20)); + console.log(`Total Documents: ${stats.documentCount}`); + console.log(`Sources: ${stats.sources.join(', ')}`); +} + +main().catch(console.error); diff --git a/connectors/github.d.ts b/connectors/github.d.ts new file mode 100644 index 0000000..1e463ee --- /dev/null +++ b/connectors/github.d.ts @@ -0,0 +1,20 @@ +import { Document, Connector } from '../types.js'; +interface GitHubConfig { + token: string; + owner: string; + repo: string; +} +export declare class GitHubConnector implements Connector { + name: string; + private config; + private baseUrl; + constructor(config: GitHubConfig); + connect(): Promise; + fetch(): Promise; + sync(): Promise; + private fetchIssues; + private fetchPRs; + private fetchDiscussions; +} +export {}; +//# sourceMappingURL=github.d.ts.map \ No newline at end of file diff --git a/connectors/github.d.ts.map b/connectors/github.d.ts.map new file mode 100644 index 0000000..5e75918 --- /dev/null +++ b/connectors/github.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/connectors/github.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElD,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAuCD,qBAAa,eAAgB,YAAW,SAAS;IAC/C,IAAI,SAAY;IAChB,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,OAAO,CAA4B;gBAE/B,MAAM,EAAE,YAAY;IAI1B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAcxB,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAU5B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAMb,WAAW;YAmDX,QAAQ;YAkDR,gBAAgB;CAoE/B"} \ No newline at end of file diff --git a/connectors/github.js b/connectors/github.js new file mode 100644 index 0000000..1320d15 --- /dev/null +++ b/connectors/github.js @@ -0,0 +1,183 @@ +// GitHub Connector +// Fetches issues, PRs, discussions from GitHub repositories +export class GitHubConnector { + name = 'github'; + config; + baseUrl = 'https://api.github.com'; + constructor(config) { + this.config = config; + } + async connect() { + // Test connection + const response = await fetch(`${this.baseUrl}/repos/${this.config.owner}/${this.config.repo}`, { + headers: { + 'Authorization': `token ${this.config.token}`, + 'Accept': 'application/vnd.github.v3+json' + } + }); + if (!response.ok) { + throw new Error(`GitHub connection failed: ${response.statusText}`); + } + } + async fetch() { + const [issues, prs, discussions] = await Promise.all([ + this.fetchIssues(), + this.fetchPRs(), + this.fetchDiscussions() + ]); + return [...issues, ...prs, ...discussions]; + } + async sync() { + // For now, sync just fetches all + // Later, can implement incremental sync with last sync timestamp + await this.fetch(); + } + async fetchIssues() { + const documents = []; + let page = 1; + let hasMore = true; + while (hasMore && page <= 10) { + const response = await fetch(`${this.baseUrl}/repos/${this.config.owner}/${this.config.repo}/issues?state=all&page=${page}&per_page=100`, { + headers: { + 'Authorization': `token ${this.config.token}`, + 'Accept': 'application/vnd.github.v3+json' + } + }); + if (!response.ok) + break; + const issues = await response.json(); + if (issues.length === 0) { + hasMore = false; + } + else { + for (const issue of issues) { + // Skip PRs (they appear in issues API) + if ('pull_request' in issue) + continue; + const labels = issue.labels.map(l => l.name).join(', '); + documents.push({ + id: `issue-${issue.number}`, + content: `Issue #${issue.number}: ${issue.title}\n\n${issue.body || 'No description'}\n\nLabels: ${labels || 'None'}`, + source: `GitHub Issue #${issue.number}`, + sourceUrl: issue.html_url, + metadata: { + state: issue.state, + author: issue.user.login, + createdAt: issue.created_at, + updatedAt: issue.updated_at, + labels + }, + embeddedAt: 0 + }); + } + page++; + } + } + return documents; + } + async fetchPRs() { + const documents = []; + let page = 1; + let hasMore = true; + while (hasMore && page <= 10) { + const response = await fetch(`${this.baseUrl}/repos/${this.config.owner}/${this.config.repo}/pulls?state=all&page=${page}&per_page=100`, { + headers: { + 'Authorization': `token ${this.config.token}`, + 'Accept': 'application/vnd.github.v3+json' + } + }); + if (!response.ok) + break; + const prs = await response.json(); + if (prs.length === 0) { + hasMore = false; + } + else { + for (const pr of prs) { + const labels = pr.labels.map(l => l.name).join(', '); + documents.push({ + id: `pr-${pr.number}`, + content: `PR #${pr.number}: ${pr.title}\n\n${pr.body || 'No description'}\n\n+${pr.additions} -${pr.deletions} lines`, + source: `GitHub PR #${pr.number}`, + sourceUrl: pr.html_url, + metadata: { + state: pr.state, + author: pr.user.login, + createdAt: pr.created_at, + updatedAt: pr.updated_at, + labels, + additions: pr.additions, + deletions: pr.deletions + }, + embeddedAt: 0 + }); + } + page++; + } + } + return documents; + } + async fetchDiscussions() { + const documents = []; + // GraphQL is needed for discussions + const query = ` + query($owner: String!, $repo: String!) { + repository(owner: $owner, name: $repo) { + discussions(first: 100) { + nodes { + id + title + body + createdAt + updatedAt + url + category { + name + } + author { + login + } + } + } + } + } + `; + const response = await fetch(`${this.baseUrl}/graphql`, { + method: 'POST', + headers: { + 'Authorization': `token ${this.config.token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + query, + variables: { + owner: this.config.owner, + repo: this.config.repo + } + }) + }); + if (!response.ok) { + // Discussions might not be enabled + return documents; + } + const data = await response.json(); + const discussions = data.data?.repository?.discussions?.nodes || []; + for (const discussion of discussions) { + documents.push({ + id: `discussion-${discussion.id}`, + content: `Discussion: ${discussion.title}\n\n${discussion.body || 'No content'}\n\nCategory: ${discussion.category.name}`, + source: `GitHub Discussion`, + sourceUrl: discussion.url, + metadata: { + category: discussion.category.name, + author: discussion.author.login, + createdAt: discussion.created_at, + updatedAt: discussion.updated_at + }, + embeddedAt: 0 + }); + } + return documents; + } +} +//# sourceMappingURL=github.js.map \ No newline at end of file diff --git a/connectors/github.js.map b/connectors/github.js.map new file mode 100644 index 0000000..1476c75 --- /dev/null +++ b/connectors/github.js.map @@ -0,0 +1 @@ +{"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/connectors/github.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/connectors/index.d.ts b/connectors/index.d.ts new file mode 100644 index 0000000..9fcdd79 --- /dev/null +++ b/connectors/index.d.ts @@ -0,0 +1,2 @@ +export { GitHubConnector } from './github.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/connectors/index.d.ts.map b/connectors/index.d.ts.map new file mode 100644 index 0000000..7c21dce --- /dev/null +++ b/connectors/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/connectors/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"} \ No newline at end of file diff --git a/connectors/index.js b/connectors/index.js new file mode 100644 index 0000000..207ab72 --- /dev/null +++ b/connectors/index.js @@ -0,0 +1,3 @@ +// Connector exports +export { GitHubConnector } from './github.js'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/connectors/index.js.map b/connectors/index.js.map new file mode 100644 index 0000000..b67c5ca --- /dev/null +++ b/connectors/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/connectors/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC"} \ No newline at end of file diff --git a/embeddings.d.ts b/embeddings.d.ts new file mode 100644 index 0000000..259c265 --- /dev/null +++ b/embeddings.d.ts @@ -0,0 +1,15 @@ +import { EmbeddingOptions } from './types.js'; +export declare class Embeddings { + private provider; + private model; + private apiKey?; + private baseUrl?; + constructor(options: EmbeddingOptions); + embed(text: string): Promise; + embedBatch(texts: string[]): Promise; + private openAIEmbed; + private openAIEmbedBatch; + private ollamaEmbed; + cosineSimilarity(a: number[], b: number[]): number; +} +//# sourceMappingURL=embeddings.d.ts.map \ No newline at end of file diff --git a/embeddings.d.ts.map b/embeddings.d.ts.map new file mode 100644 index 0000000..a352067 --- /dev/null +++ b/embeddings.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"embeddings.d.ts","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAEhE,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,OAAO,CAAC,CAAS;gBAEb,OAAO,EAAE,gBAAgB;IAO/B,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQtC,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;YAQxC,WAAW;YAqBX,gBAAgB;YAqBhB,WAAW;IAqBzB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM;CAiBnD"} \ No newline at end of file diff --git a/embeddings.js b/embeddings.js new file mode 100644 index 0000000..0ad1732 --- /dev/null +++ b/embeddings.js @@ -0,0 +1,99 @@ +// Embeddings Module +// Handles text-to-vector conversion using OpenAI or Ollama +export class Embeddings { + provider; + model; + apiKey; + baseUrl; + constructor(options) { + this.provider = options.provider; + this.model = options.model || (options.provider === 'openai' ? 'text-embedding-3-small' : 'nomic-embed-text'); + this.apiKey = process.env.OPENAI_API_KEY; + this.baseUrl = process.env.OLLAMA_BASE_URL || 'http://localhost:11434'; + } + async embed(text) { + if (this.provider === 'openai') { + return this.openAIEmbed(text); + } + else { + return this.ollamaEmbed(text); + } + } + async embedBatch(texts) { + if (this.provider === 'openai') { + return this.openAIEmbedBatch(texts); + } + else { + return Promise.all(texts.map(t => this.ollamaEmbed(t))); + } + } + async openAIEmbed(text) { + const response = await fetch('https://api.openai.com/v1/embeddings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}` + }, + body: JSON.stringify({ + model: this.model, + input: text + }) + }); + if (!response.ok) { + throw new Error(`OpenAI embedding failed: ${response.statusText}`); + } + const data = await response.json(); + return data.data[0].embedding; + } + async openAIEmbedBatch(texts) { + const response = await fetch('https://api.openai.com/v1/embeddings', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}` + }, + body: JSON.stringify({ + model: this.model, + input: texts + }) + }); + if (!response.ok) { + throw new Error(`OpenAI embedding failed: ${response.statusText}`); + } + const data = await response.json(); + return data.data.map((item) => item.embedding); + } + async ollamaEmbed(text) { + const response = await fetch(`${this.baseUrl}/api/embeddings`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + model: this.model, + prompt: text + }) + }); + if (!response.ok) { + throw new Error(`Ollama embedding failed: ${response.statusText}`); + } + const data = await response.json(); + return data.embedding; + } + // Cosine similarity between two vectors + cosineSimilarity(a, b) { + if (a.length !== b.length) { + throw new Error('Vectors must have same dimensions'); + } + let dotProduct = 0; + let normA = 0; + let normB = 0; + for (let i = 0; i < a.length; i++) { + dotProduct += a[i] * b[i]; + normA += a[i] * a[i]; + normB += b[i] * b[i]; + } + return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); + } +} +//# sourceMappingURL=embeddings.js.map \ No newline at end of file diff --git a/embeddings.js.map b/embeddings.js.map new file mode 100644 index 0000000..2355935 --- /dev/null +++ b/embeddings.js.map @@ -0,0 +1 @@ +{"version":3,"file":"embeddings.js","sourceRoot":"","sources":["../src/embeddings.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,2DAA2D;AAI3D,MAAM,OAAO,UAAU;IACb,QAAQ,CAAsB;IAC9B,KAAK,CAAS;IACd,MAAM,CAAU;IAChB,OAAO,CAAU;IAEzB,YAAY,OAAyB;QACnC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC;QAC9G,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,wBAAwB,CAAC;IACzE,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAAY;QACtB,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;aAAM,CAAC;YACN,OAAO,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,KAAe;QAC9B,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC;QACtC,CAAC;aAAM,CAAC;YACN,OAAO,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,IAAY;QACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,sCAAsC,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACzC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,IAAI;aACZ,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAyC,CAAC;QAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAChC,CAAC;IAEO,KAAK,CAAC,gBAAgB,CAAC,KAAe;QAC5C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,sCAAsC,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,EAAE;aACzC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,KAAK;aACb,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAyC,CAAC;QAC1E,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAA6B,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC1E,CAAC;IAEO,KAAK,CAAC,WAAW,CAAC,IAAY;QACpC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,iBAAiB,EAAE;YAC7D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,MAAM,EAAE,IAAI;aACb,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA6B,CAAC;QAC9D,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED,wCAAwC;IACxC,gBAAgB,CAAC,CAAW,EAAE,CAAW;QACvC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,IAAI,KAAK,GAAG,CAAC,CAAC;QAEd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1B,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACrB,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACvB,CAAC;QAED,OAAO,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5D,CAAC;CACF"} \ No newline at end of file diff --git a/engine.d.ts b/engine.d.ts new file mode 100644 index 0000000..01b9542 --- /dev/null +++ b/engine.d.ts @@ -0,0 +1,44 @@ +import { Document, QueryResult, EmbeddingOptions, VectorStoreOptions } from './types.js'; +export interface KnowledgeEngineConfig { + embeddings: EmbeddingOptions; + vectorStore: VectorStoreOptions; + llm?: { + model?: string; + apiKey?: string; + baseUrl?: string; + }; +} +export declare class KnowledgeEngine { + private embeddings; + private vectorStore; + private ragQuery; + private citations; + private connectors; + private initialized; + constructor(config: KnowledgeEngineConfig); + initialize(): Promise; + addDocument(doc: Document): Promise; + addDocuments(docs: Document[]): Promise; + query(prompt: string, options?: { + maxTokens?: number; + temperature?: number; + }): Promise; + chat(message: string, history?: { + role: string; + content: string; + }[]): Promise; + registerConnector(name: string, connector: any): void; + syncConnector(name: string): Promise; + getStats(): { + documentCount: number; + sources: string[]; + topCitations: { + source: string; + count: number; + }[]; + }; + semanticSearch(query: string, limit?: number): Promise; + private ensureInitialized; +} +export declare function createKnowledgeEngine(config: KnowledgeEngineConfig): Promise; +//# sourceMappingURL=engine.d.ts.map \ No newline at end of file diff --git a/engine.d.ts.map b/engine.d.ts.map new file mode 100644 index 0000000..07cccdb --- /dev/null +++ b/engine.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEzF,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,GAAG,CAAC,EAAE;QACJ,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,UAAU,CAA+B;IACjD,OAAO,CAAC,WAAW,CAAS;gBAEhB,MAAM,EAAE,qBAAqB;IAOnC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAO3B,WAAW,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzC,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAM7C,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAMnG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAMpG,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,GAAG,IAAI;IAK/C,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAchD,QAAQ;;;;;;;;IASF,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU;IAKrD,OAAO,CAAC,iBAAiB;CAK1B;AAGD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAInG"} \ No newline at end of file diff --git a/engine.js b/engine.js new file mode 100644 index 0000000..9ba4c31 --- /dev/null +++ b/engine.js @@ -0,0 +1,85 @@ +// Knowledge Engine +// Main orchestrator for the knowledge layer +import { Embeddings } from './embeddings.js'; +import { VectorStore } from './vector-store.js'; +import { RAGQuery } from './rag-query.js'; +import { CitationTracker } from './citations.js'; +export class KnowledgeEngine { + embeddings; + vectorStore; + ragQuery; + citations; + connectors = new Map(); + initialized = false; + constructor(config) { + this.embeddings = new Embeddings(config.embeddings); + this.vectorStore = new VectorStore(this.embeddings, config.vectorStore); + this.citations = new CitationTracker(); + this.ragQuery = new RAGQuery(this.vectorStore, this.citations, config.llm); + } + async initialize() { + await this.vectorStore.initialize(); + this.initialized = true; + console.log('āœ… Knowledge Engine initialized'); + } + // Add a document directly + async addDocument(doc) { + this.ensureInitialized(); + await this.vectorStore.addDocument(doc); + } + // Add multiple documents + async addDocuments(docs) { + this.ensureInitialized(); + await this.vectorStore.addDocuments(docs); + } + // Query the knowledge base + async query(prompt, options) { + this.ensureInitialized(); + return this.ragQuery.query(prompt, options); + } + // Chat with context + async chat(message, history = []) { + this.ensureInitialized(); + return this.ragQuery.chat(message, history); + } + // Register a connector + registerConnector(name, connector) { + this.connectors.set(name, connector); + } + // Sync from a connector + async syncConnector(name) { + const connector = this.connectors.get(name); + if (!connector) { + throw new Error(`Connector ${name} not found`); + } + await connector.connect(); + const docs = await connector.fetch(); + await this.addDocuments(docs); + console.log(`šŸ“„ Synced ${docs.length} documents from ${name}`); + } + // Get stats + getStats() { + return { + documentCount: this.vectorStore.count(), + sources: [...new Set(this.vectorStore.getAllDocuments().map(d => d.source))], + topCitations: this.citations.getTopSources() + }; + } + // Search without LLM (just vector similarity) + async semanticSearch(query, limit = 5) { + this.ensureInitialized(); + return this.vectorStore.search(query, limit); + } + ensureInitialized() { + if (!this.initialized) { + throw new Error('Knowledge Engine not initialized. Call initialize() first.'); + } + } +} +// Factory function for easy creation +export async function createKnowledgeEngine(config) { + const engine = new KnowledgeEngine(config); + await engine.initialize(); + return engine; +} +//# sourceMappingURL=engine.js.map \ No newline at end of file diff --git a/engine.js.map b/engine.js.map new file mode 100644 index 0000000..7d38cc8 --- /dev/null +++ b/engine.js.map @@ -0,0 +1 @@ +{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..2afe171 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,8 @@ +export { KnowledgeEngine, createKnowledgeEngine } from './engine.js'; +export { Embeddings } from './embeddings.js'; +export { VectorStore } from './vector-store.js'; +export { RAGQuery } from './rag-query.js'; +export { CitationTracker } from './citations.js'; +export { GitHubConnector } from './connectors/github.js'; +export type { Document, Citation, QueryResult, EmbeddingOptions, VectorStoreOptions, RAGOptions, Connector } from './types.js'; +//# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/index.d.ts.map b/index.d.ts.map new file mode 100644 index 0000000..f6a6938 --- /dev/null +++ b/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"} \ No newline at end of file diff --git a/index.js b/index.js new file mode 100644 index 0000000..601cb2f --- /dev/null +++ b/index.js @@ -0,0 +1,9 @@ +// Knowledge Layer Index +// Main entry point for Phantom Knowledge System +export { KnowledgeEngine, createKnowledgeEngine } from './engine.js'; +export { Embeddings } from './embeddings.js'; +export { VectorStore } from './vector-store.js'; +export { RAGQuery } from './rag-query.js'; +export { CitationTracker } from './citations.js'; +export { GitHubConnector } from './connectors/github.js'; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/index.js.map b/index.js.map new file mode 100644 index 0000000..9016fe2 --- /dev/null +++ b/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,wBAAwB;AACxB,gDAAgD;AAEhD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC"} \ No newline at end of file diff --git a/package.json b/package.json index 364d509..b039c9c 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,13 @@ { "name": "@phantom-pm/knowledge", - "version": "1.0.0", + "version": "1.1.0", "description": "Phantom Knowledge Layer - Vector embeddings, RAG, and connectors for Phantom PM OS", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", + "bin": { + "phantom-knowledge": "./cli/index.js" + }, "repository": { "type": "git", "url": "https://github.com/sir-ad/phantom-knowledge.git" diff --git a/rag-query.d.ts b/rag-query.d.ts new file mode 100644 index 0000000..821e587 --- /dev/null +++ b/rag-query.d.ts @@ -0,0 +1,23 @@ +import { VectorStore } from './vector-store.js'; +import { CitationTracker } from './citations.js'; +import { QueryResult, RAGOptions } from './types.js'; +export declare class RAGQuery { + private vectorStore; + private citations; + private model; + private apiKey?; + private baseUrl?; + constructor(vectorStore: VectorStore, citations: CitationTracker, options?: { + model?: string; + apiKey?: string; + baseUrl?: string; + }); + query(prompt: string, options?: RAGOptions): Promise; + private generateAnswer; + private summarizeFromContext; + chat(message: string, history?: { + role: string; + content: string; + }[]): Promise; +} +//# sourceMappingURL=rag-query.d.ts.map \ No newline at end of file diff --git a/rag-query.d.ts.map b/rag-query.d.ts.map new file mode 100644 index 0000000..1e487ee --- /dev/null +++ b/rag-query.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"rag-query.d.ts","sourceRoot":"","sources":["../src/rag-query.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAY,UAAU,EAAE,MAAM,YAAY,CAAC;AAE/D,qBAAa,QAAQ;IACnB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,SAAS,CAAkB;IACnC,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,OAAO,CAAC,CAAS;gBAGvB,WAAW,EAAE,WAAW,EACxB,SAAS,EAAE,eAAe,EAC1B,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAO;IAS/D,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,UAAe,GAAG,OAAO,CAAC,WAAW,CAAC;YA8E7D,cAAc;IA8B5B,OAAO,CAAC,oBAAoB;IAStB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,EAAO,GAAG,OAAO,CAAC,WAAW,CAAC;CASrG"} \ No newline at end of file diff --git a/rag-query.js b/rag-query.js new file mode 100644 index 0000000..037f2ed --- /dev/null +++ b/rag-query.js @@ -0,0 +1,114 @@ +// RAG Query Engine +// Retrieves relevant context and generates answers with citations +export class RAGQuery { + vectorStore; + citations; + model; + apiKey; + baseUrl; + constructor(vectorStore, citations, options = {}) { + this.vectorStore = vectorStore; + this.citations = citations; + this.model = options.model || 'gpt-4o-mini'; + this.apiKey = options.apiKey || process.env.OPENAI_API_KEY; + this.baseUrl = options.baseUrl; + } + async query(prompt, options = {}) { + const { maxTokens = 4000, temperature = 0.7, includeCitations = true } = options; + // Step 1: Retrieve relevant documents + const relevantDocs = await this.vectorStore.search(prompt, 10); + if (relevantDocs.length === 0) { + return { + answer: "I don't have any relevant information to answer that question.", + citations: [], + sources: [], + contextUsed: 0 + }; + } + // Step 2: Build context from retrieved documents + const context = relevantDocs + .map((doc, i) => `[${i + 1}] ${doc.source}: ${doc.content}`) + .join('\n\n'); + // Step 3: Track citations + const citationList = []; + const sources = []; + if (includeCitations) { + relevantDocs.forEach((doc, i) => { + citationList.push({ + documentId: doc.id, + source: doc.source, + sourceUrl: doc.sourceUrl, + excerpt: doc.content.slice(0, 200) + '...', + relevanceScore: 1 - (i * 0.1) // Decreasing relevance score + }); + if (!sources.includes(doc.source)) { + sources.push(doc.source); + } + }); + this.citations.addCitations(citationList); + } + // Step 4: Generate answer using LLM + const systemPrompt = `You are a helpful assistant. Use the provided context to answer the user's question. +If you use information from the context, cite it using the source name in brackets. +If the context doesn't contain enough information to answer the question, say so.`; + const userPrompt = `Context: +${context} + +Question: ${prompt} + +Answer:`; + let answer; + try { + answer = await this.generateAnswer(systemPrompt, userPrompt, { + maxTokens, + temperature + }); + } + catch (error) { + // Fallback: summarize from context + answer = this.summarizeFromContext(relevantDocs, prompt); + } + return { + answer, + citations: citationList, + sources, + contextUsed: relevantDocs.length + }; + } + async generateAnswer(systemPrompt, userPrompt, options) { + const response = await fetch((this.baseUrl || 'https://api.openai.com/v1') + '/chat/completions', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${this.apiKey}` + }, + body: JSON.stringify({ + model: this.model, + messages: [ + { role: 'system', content: systemPrompt }, + { role: 'user', content: userPrompt } + ], + max_tokens: options.maxTokens, + temperature: options.temperature + }) + }); + if (!response.ok) { + throw new Error(`LLM query failed: ${response.statusText}`); + } + const data = await response.json(); + return data.choices[0].message.content; + } + summarizeFromContext(docs, query) { + const sources = [...new Set(docs.map(d => d.source))].join(', '); + return `Based on the available information from ${sources}:\n\n${docs.slice(0, 3).map(d => d.content).join('\n\n')}\n\nNote: This is a simplified answer. For more accurate results, please configure an LLM API key.`; + } + // Get conversation context + async chat(message, history = []) { + const result = await this.query(message); + // Add to history + history.push({ role: 'user', content: message }); + history.push({ role: 'assistant', content: result.answer }); + return result; + } +} +//# sourceMappingURL=rag-query.js.map \ No newline at end of file diff --git a/rag-query.js.map b/rag-query.js.map new file mode 100644 index 0000000..bd37b9f --- /dev/null +++ b/rag-query.js.map @@ -0,0 +1 @@ +{"version":3,"file":"rag-query.js","sourceRoot":"","sources":["../src/rag-query.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 356f1af..0055467 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,10 +1,10 @@ // Knowledge Layer Index // Main entry point for Phantom Knowledge System -export { KnowledgeEngine } from './engine.js'; +export { KnowledgeEngine, createKnowledgeEngine } from './engine.js'; export { Embeddings } from './embeddings.js'; export { VectorStore } from './vector-store.js'; export { RAGQuery } from './rag-query.js'; export { CitationTracker } from './citations.js'; export { GitHubConnector } from './connectors/github.js'; -export type { Document, Citation, QueryResult, EmbeddingOptions } from './types.js'; +export type { Document, Citation, QueryResult, EmbeddingOptions, VectorStoreOptions, RAGOptions, Connector } from './types.js'; diff --git a/types.d.ts b/types.d.ts new file mode 100644 index 0000000..3e72403 --- /dev/null +++ b/types.d.ts @@ -0,0 +1,53 @@ +export interface Document { + id: string; + content: string; + source: string; + sourceUrl?: string; + metadata: Record; + embeddedAt: number; +} +export interface EmbeddedDocument extends Document { + embedding: number[]; +} +export interface Citation { + documentId: string; + source: string; + sourceUrl?: string; + excerpt: string; + relevanceScore: number; +} +export interface QueryResult { + answer: string; + citations: Citation[]; + sources: string[]; + contextUsed: number; +} +export interface EmbeddingOptions { + provider: 'openai' | 'ollama'; + model?: string; + dimensions?: number; +} +export interface VectorStoreOptions { + type: 'memory' | 'file' | 'pinecone'; + path?: string; + apiKey?: string; +} +export interface KnowledgeIndex { + addDocument(doc: Document): Promise; + addDocuments(docs: Document[]): Promise; + search(query: string, limit?: number): Promise; + delete(id: string): Promise; + clear(): Promise; +} +export interface RAGOptions { + maxTokens?: number; + temperature?: number; + includeCitations?: boolean; +} +export interface Connector { + name: string; + connect(): Promise; + fetch(): Promise; + sync(): Promise; +} +//# sourceMappingURL=types.d.ts.map \ No newline at end of file diff --git a/types.d.ts.map b/types.d.ts.map new file mode 100644 index 0000000..0091ac3 --- /dev/null +++ b/types.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,gBAAiB,SAAQ,QAAQ;IAChD,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,GAAG,MAAM,GAAG,UAAU,CAAC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1C,YAAY,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IACnE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,KAAK,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC7B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"} \ No newline at end of file diff --git a/types.js b/types.js new file mode 100644 index 0000000..b2d067a --- /dev/null +++ b/types.js @@ -0,0 +1,3 @@ +// Knowledge Layer Types +export {}; +//# sourceMappingURL=types.js.map \ No newline at end of file diff --git a/types.js.map b/types.js.map new file mode 100644 index 0000000..4e4d20e --- /dev/null +++ b/types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,wBAAwB"} \ No newline at end of file diff --git a/vector-store.d.ts b/vector-store.d.ts new file mode 100644 index 0000000..46be26d --- /dev/null +++ b/vector-store.d.ts @@ -0,0 +1,33 @@ +import { EmbeddedDocument, VectorStoreOptions, KnowledgeIndex } from './types.js'; +import { Embeddings } from './embeddings.js'; +export declare class VectorStore implements KnowledgeIndex { + private documents; + private embeddings; + private storagePath?; + private storageType; + constructor(embeddings: Embeddings, options: VectorStoreOptions); + initialize(): Promise; + addDocument(doc: { + id: string; + content: string; + source: string; + sourceUrl?: string; + metadata: Record; + }): Promise; + addDocuments(docs: { + id: string; + content: string; + source: string; + sourceUrl?: string; + metadata: Record; + }[]): Promise; + search(query: string, limit?: number): Promise; + delete(id: string): Promise; + clear(): Promise; + getDocument(id: string): EmbeddedDocument | undefined; + getAllDocuments(): EmbeddedDocument[]; + count(): number; + private saveToFile; + private loadFromFile; +} +//# sourceMappingURL=vector-store.d.ts.map \ No newline at end of file diff --git a/vector-store.d.ts.map b/vector-store.d.ts.map new file mode 100644 index 0000000..89e1896 --- /dev/null +++ b/vector-store.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"vector-store.d.ts","sourceRoot":"","sources":["../src/vector-store.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAClF,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAS7C,qBAAa,WAAY,YAAW,cAAc;IAChD,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAiC;gBAExC,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,kBAAkB;IAMzD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAM3B,WAAW,CAAC,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBvI,YAAY,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB3I,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,GAAE,MAAU,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAgBrE,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIrD,eAAe,IAAI,gBAAgB,EAAE;IAIrC,KAAK,IAAI,MAAM;YAID,UAAU;YAWV,YAAY;CAc3B"} \ No newline at end of file diff --git a/vector-store.js b/vector-store.js new file mode 100644 index 0000000..6422200 --- /dev/null +++ b/vector-store.js @@ -0,0 +1,102 @@ +// Vector Store Module +// Stores and retrieves embeddings with similarity search +import { readFile, writeFile, access } from 'fs/promises'; +export class VectorStore { + documents = new Map(); + embeddings; + storagePath; + storageType; + constructor(embeddings, options) { + this.embeddings = embeddings; + this.storageType = options.type; + this.storagePath = options.path; + } + async initialize() { + if (this.storageType === 'file' && this.storagePath) { + await this.loadFromFile(); + } + } + async addDocument(doc) { + const embedding = await this.embeddings.embed(doc.content); + const embeddedDoc = { + ...doc, + embedding, + embeddedAt: Date.now() + }; + this.documents.set(doc.id, embeddedDoc); + if (this.storageType === 'file') { + await this.saveToFile(); + } + } + async addDocuments(docs) { + const contents = docs.map(d => d.content); + const embeddings = await this.embeddings.embedBatch(contents); + docs.forEach((doc, i) => { + const embeddedDoc = { + ...doc, + embedding: embeddings[i], + embeddedAt: Date.now() + }; + this.documents.set(doc.id, embeddedDoc); + }); + if (this.storageType === 'file') { + await this.saveToFile(); + } + } + async search(query, limit = 5) { + const queryEmbedding = await this.embeddings.embed(query); + const results = []; + for (const doc of this.documents.values()) { + const score = this.embeddings.cosineSimilarity(queryEmbedding, doc.embedding); + results.push({ doc, score }); + } + // Sort by score descending + results.sort((a, b) => b.score - a.score); + return results.slice(0, limit).map(r => r.doc); + } + async delete(id) { + this.documents.delete(id); + if (this.storageType === 'file') { + await this.saveToFile(); + } + } + async clear() { + this.documents.clear(); + if (this.storageType === 'file') { + await this.saveToFile(); + } + } + getDocument(id) { + return this.documents.get(id); + } + getAllDocuments() { + return Array.from(this.documents.values()); + } + count() { + return this.documents.size; + } + async saveToFile() { + if (!this.storagePath) + return; + const data = { + documents: Array.from(this.documents.values()), + version: 1 + }; + await writeFile(this.storagePath, JSON.stringify(data, null, 2), 'utf-8'); + } + async loadFromFile() { + if (!this.storagePath) + return; + try { + await access(this.storagePath); + const content = await readFile(this.storagePath, 'utf-8'); + const data = JSON.parse(content); + this.documents = new Map(data.documents.map(d => [d.id, d])); + } + catch { + // File doesn't exist yet, start fresh + this.documents = new Map(); + } + } +} +//# sourceMappingURL=vector-store.js.map \ No newline at end of file diff --git a/vector-store.js.map b/vector-store.js.map new file mode 100644 index 0000000..0029bca --- /dev/null +++ b/vector-store.js.map @@ -0,0 +1 @@ +{"version":3,"file":"vector-store.js","sourceRoot":"","sources":["../src/vector-store.ts"],"names":[],"mappings":"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"} \ No newline at end of file