2026-04-05 21:09:33 -05:00
|
|
|
/**
|
|
|
|
|
* Graph RAG retrieval pipeline.
|
|
|
|
|
*
|
|
|
|
|
* This is the core RAG pipeline that:
|
|
|
|
|
* 1. Extracts concepts from the query
|
|
|
|
|
* 2. Embeds concepts to find matching entities
|
|
|
|
|
* 3. Traverses the knowledge graph from those entities
|
|
|
|
|
* 4. Scores and filters edges
|
|
|
|
|
* 5. Synthesizes an answer with the selected context
|
|
|
|
|
*
|
|
|
|
|
* Python reference: trustgraph-flow/trustgraph/retrieval/graph_rag/graph_rag.py
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
import type {
|
|
|
|
|
EmbeddingsRequest,
|
|
|
|
|
EmbeddingsResponse,
|
|
|
|
|
GraphEmbeddingsRequest,
|
|
|
|
|
GraphEmbeddingsResponse,
|
2026-05-12 08:06:58 -05:00
|
|
|
FlowRequestor,
|
2026-04-05 21:09:33 -05:00
|
|
|
PromptRequest,
|
|
|
|
|
PromptResponse,
|
|
|
|
|
Term,
|
2026-04-05 22:52:40 -05:00
|
|
|
TextCompletionRequest,
|
|
|
|
|
TextCompletionResponse,
|
2026-04-05 21:09:33 -05:00
|
|
|
Triple,
|
2026-04-05 22:52:40 -05:00
|
|
|
TriplesQueryRequest,
|
|
|
|
|
TriplesQueryResponse,
|
2026-04-05 21:09:33 -05:00
|
|
|
} from "@trustgraph/base";
|
|
|
|
|
|
|
|
|
|
export interface GraphRagConfig {
|
|
|
|
|
entityLimit?: number;
|
|
|
|
|
tripleLimit?: number;
|
|
|
|
|
maxSubgraphSize?: number;
|
|
|
|
|
maxPathLength?: number;
|
|
|
|
|
edgeScoreLimit?: number;
|
|
|
|
|
edgeLimit?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface GraphRagClients {
|
2026-05-12 08:06:58 -05:00
|
|
|
llm: FlowRequestor<TextCompletionRequest, TextCompletionResponse>;
|
|
|
|
|
embeddings: FlowRequestor<EmbeddingsRequest, EmbeddingsResponse>;
|
|
|
|
|
graphEmbeddings: FlowRequestor<GraphEmbeddingsRequest, GraphEmbeddingsResponse>;
|
|
|
|
|
triples: FlowRequestor<TriplesQueryRequest, TriplesQueryResponse>;
|
|
|
|
|
prompt: FlowRequestor<PromptRequest, PromptResponse>;
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type ChunkCallback = (text: string, endOfStream: boolean) => Promise<void>;
|
|
|
|
|
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
export interface GraphRagResult {
|
|
|
|
|
answer: string;
|
|
|
|
|
subgraph: Triple[];
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-05 21:09:33 -05:00
|
|
|
export class GraphRag {
|
2026-05-12 08:06:58 -05:00
|
|
|
private readonly clients: GraphRagClients;
|
2026-04-05 21:09:33 -05:00
|
|
|
private config: Required<GraphRagConfig>;
|
|
|
|
|
|
|
|
|
|
constructor(
|
2026-05-12 08:06:58 -05:00
|
|
|
clients: GraphRagClients,
|
2026-04-05 21:09:33 -05:00
|
|
|
config: GraphRagConfig = {},
|
|
|
|
|
) {
|
2026-05-12 08:06:58 -05:00
|
|
|
this.clients = clients;
|
2026-04-05 21:09:33 -05:00
|
|
|
this.config = {
|
|
|
|
|
entityLimit: config.entityLimit ?? 50,
|
|
|
|
|
tripleLimit: config.tripleLimit ?? 30,
|
|
|
|
|
maxSubgraphSize: config.maxSubgraphSize ?? 1000,
|
|
|
|
|
maxPathLength: config.maxPathLength ?? 2,
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
edgeScoreLimit: config.edgeScoreLimit ?? 50,
|
2026-04-05 21:09:33 -05:00
|
|
|
edgeLimit: config.edgeLimit ?? 25,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async query(
|
|
|
|
|
queryText: string,
|
|
|
|
|
options?: {
|
|
|
|
|
collection?: string;
|
|
|
|
|
streaming?: boolean;
|
|
|
|
|
chunkCallback?: ChunkCallback;
|
|
|
|
|
},
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
): Promise<GraphRagResult> {
|
|
|
|
|
console.log(`[GraphRag] Query: "${queryText.slice(0, 80)}..."`);
|
|
|
|
|
|
2026-04-05 21:09:33 -05:00
|
|
|
// Step 1: Extract concepts from the query via prompt + LLM
|
|
|
|
|
const concepts = await this.extractConcepts(queryText);
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Step 1: extracted ${concepts.length} concepts: ${concepts.slice(0, 5).join(", ")}`);
|
2026-04-05 21:09:33 -05:00
|
|
|
|
|
|
|
|
// Step 2: Embed concepts concurrently
|
|
|
|
|
const vectors = await this.getVectors(concepts);
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Step 2: got ${vectors.length} vectors (dim=${vectors[0]?.length ?? 0})`);
|
2026-04-05 21:09:33 -05:00
|
|
|
|
|
|
|
|
// Step 3: Find matching entities via graph embeddings
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
const entities = await this.getEntities(vectors, options?.collection);
|
|
|
|
|
console.log(`[GraphRag] Step 3: found ${entities.length} matching entities`);
|
2026-04-05 21:09:33 -05:00
|
|
|
|
|
|
|
|
// Step 4: Traverse the knowledge graph from entities
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
const subgraph = await this.followEdges(entities, options?.collection);
|
|
|
|
|
console.log(`[GraphRag] Step 4: traversed graph, ${subgraph.length} triples in subgraph`);
|
2026-04-05 21:09:33 -05:00
|
|
|
|
|
|
|
|
// Step 5: Score and filter edges via LLM
|
|
|
|
|
const scoredEdges = await this.scoreEdges(queryText, subgraph);
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Step 5: scored down to ${scoredEdges.length} edges`);
|
2026-04-05 21:09:33 -05:00
|
|
|
|
|
|
|
|
// Step 6: Synthesize answer
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Step 6: synthesizing answer from ${scoredEdges.length} edges...`);
|
|
|
|
|
const answer = await this.synthesize(
|
2026-04-05 22:52:40 -05:00
|
|
|
queryText,
|
|
|
|
|
scoredEdges,
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
options?.chunkCallback,
|
2026-04-05 22:52:40 -05:00
|
|
|
);
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Step 6: done (${answer.length} chars)`);
|
|
|
|
|
|
|
|
|
|
return { answer, subgraph: scoredEdges };
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async extractConcepts(query: string): Promise<string[]> {
|
|
|
|
|
const promptResp = await this.clients.prompt.request({
|
|
|
|
|
name: "extract-concepts",
|
|
|
|
|
variables: { query },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const llmResp = await this.clients.llm.request({
|
|
|
|
|
system: (promptResp as PromptResponse).system,
|
|
|
|
|
prompt: (promptResp as PromptResponse).prompt,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Parse concepts from LLM response (newline-separated)
|
|
|
|
|
return (llmResp as TextCompletionResponse).response
|
|
|
|
|
.split("\n")
|
|
|
|
|
.map((c) => c.trim())
|
2026-05-12 08:06:58 -05:00
|
|
|
.filter((c) => c.length > 0);
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async getVectors(concepts: string[]): Promise<number[][]> {
|
|
|
|
|
const resp = await this.clients.embeddings.request({ text: concepts });
|
|
|
|
|
return (resp as EmbeddingsResponse).vectors;
|
|
|
|
|
}
|
|
|
|
|
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
private async getEntities(vectors: number[][], collection?: string): Promise<Term[]> {
|
2026-04-05 21:09:33 -05:00
|
|
|
const resp = await this.clients.graphEmbeddings.request({
|
|
|
|
|
vectors,
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
user: "default",
|
|
|
|
|
collection: collection ?? "default",
|
2026-04-05 21:09:33 -05:00
|
|
|
limit: this.config.entityLimit,
|
|
|
|
|
});
|
|
|
|
|
return (resp as GraphEmbeddingsResponse).entities;
|
|
|
|
|
}
|
|
|
|
|
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
private async followEdges(entities: Term[], collection?: string): Promise<Triple[]> {
|
2026-04-05 22:44:45 -05:00
|
|
|
// BFS multi-hop traversal up to maxPathLength
|
|
|
|
|
const visited = new Set<string>();
|
|
|
|
|
const subgraph: Triple[] = [];
|
2026-04-05 21:09:33 -05:00
|
|
|
|
2026-04-05 22:44:45 -05:00
|
|
|
// Current frontier: the set of entities to expand at this depth level
|
|
|
|
|
let currentLevel = new Set<string>(
|
|
|
|
|
entities.map((e) => termToString(e)),
|
2026-04-05 21:09:33 -05:00
|
|
|
);
|
|
|
|
|
|
2026-04-05 22:44:45 -05:00
|
|
|
for (let depth = 0; depth < this.config.maxPathLength; depth++) {
|
|
|
|
|
if (currentLevel.size === 0 || subgraph.length >= this.config.maxSubgraphSize) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Filter out already-visited entities
|
|
|
|
|
const unvisited = [...currentLevel].filter((e) => !visited.has(e));
|
|
|
|
|
if (unvisited.length === 0) break;
|
|
|
|
|
|
|
|
|
|
// Batch triple queries for all unvisited entities at this depth
|
|
|
|
|
// Query each entity as subject to get outgoing edges
|
|
|
|
|
const queries = unvisited.map((entityStr) => {
|
|
|
|
|
const term = stringToTerm(entityStr);
|
2026-05-12 08:06:58 -05:00
|
|
|
const request: TriplesQueryRequest = {
|
2026-04-05 22:44:45 -05:00
|
|
|
s: term,
|
|
|
|
|
limit: this.config.tripleLimit,
|
2026-05-12 08:06:58 -05:00
|
|
|
...(collection !== undefined ? { collection } : {}),
|
|
|
|
|
};
|
|
|
|
|
return this.clients.triples.request(request);
|
2026-04-05 22:44:45 -05:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const results = await Promise.all(queries);
|
|
|
|
|
|
|
|
|
|
const nextLevel = new Set<string>();
|
|
|
|
|
|
|
|
|
|
for (const result of results) {
|
|
|
|
|
const triples = (result as TriplesQueryResponse).triples;
|
|
|
|
|
for (const triple of triples) {
|
|
|
|
|
subgraph.push(triple);
|
|
|
|
|
|
|
|
|
|
// Collect objects as next-level entities for further expansion
|
|
|
|
|
// (only if we have more depth levels remaining)
|
|
|
|
|
if (depth < this.config.maxPathLength - 1) {
|
|
|
|
|
const objStr = termToString(triple.o);
|
|
|
|
|
if (!visited.has(objStr)) {
|
|
|
|
|
nextLevel.add(objStr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (subgraph.length >= this.config.maxSubgraphSize) {
|
|
|
|
|
return subgraph;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mark current level as visited and move to next
|
|
|
|
|
for (const e of currentLevel) {
|
|
|
|
|
visited.add(e);
|
|
|
|
|
}
|
|
|
|
|
currentLevel = nextLevel;
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
2026-04-05 22:44:45 -05:00
|
|
|
return subgraph.slice(0, this.config.maxSubgraphSize);
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async scoreEdges(query: string, triples: Triple[]): Promise<Triple[]> {
|
2026-04-05 22:44:45 -05:00
|
|
|
if (triples.length === 0) return [];
|
|
|
|
|
|
|
|
|
|
// If the subgraph is small enough, skip LLM scoring entirely
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
// 500 triples is well within LLM context limits and avoids lossy scoring
|
|
|
|
|
if (triples.length <= 500) {
|
|
|
|
|
console.log(`[GraphRag] Skipping edge scoring — ${triples.length} triples fits in context directly`);
|
2026-04-05 22:44:45 -05:00
|
|
|
return triples;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build a numbered list of edges for the LLM to score
|
|
|
|
|
const edgeDescriptions = triples.map((t, i) => ({
|
|
|
|
|
id: String(i),
|
|
|
|
|
s: termToString(t.s),
|
|
|
|
|
p: termToString(t.p),
|
|
|
|
|
o: termToString(t.o),
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Limit how many edges we send for scoring to avoid overflowing context
|
|
|
|
|
const toScore = edgeDescriptions.slice(0, this.config.edgeScoreLimit);
|
|
|
|
|
|
|
|
|
|
const knowledgeJson = JSON.stringify(toScore, null, 2);
|
|
|
|
|
|
|
|
|
|
// Ask the LLM to score each edge for relevance to the query
|
|
|
|
|
const promptResp = await this.clients.prompt.request({
|
|
|
|
|
name: "kg-edge-scoring",
|
|
|
|
|
variables: {
|
|
|
|
|
query,
|
|
|
|
|
knowledge: knowledgeJson,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const llmResp = await this.clients.llm.request({
|
|
|
|
|
system: (promptResp as PromptResponse).system,
|
|
|
|
|
prompt: (promptResp as PromptResponse).prompt,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const responseText = (llmResp as TextCompletionResponse).response;
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Edge scoring LLM response (first 500 chars): ${responseText.slice(0, 500)}`);
|
2026-04-05 22:44:45 -05:00
|
|
|
|
|
|
|
|
// Parse scores from LLM response
|
|
|
|
|
// Expected format: JSON array of { id: string, score: number }
|
|
|
|
|
// or newline-separated JSON objects
|
|
|
|
|
const scored: Array<{ id: string; score: number }> = [];
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// Try parsing as a JSON array first
|
|
|
|
|
const parsed = JSON.parse(responseText) as Array<{ id: string; score: number }>;
|
|
|
|
|
if (Array.isArray(parsed)) {
|
|
|
|
|
for (const item of parsed) {
|
2026-05-12 08:06:58 -05:00
|
|
|
if (
|
|
|
|
|
typeof item === "object" &&
|
|
|
|
|
item !== null &&
|
|
|
|
|
typeof item.id === "string" &&
|
|
|
|
|
typeof item.score === "number"
|
|
|
|
|
) {
|
2026-04-05 22:44:45 -05:00
|
|
|
scored.push({ id: item.id, score: item.score });
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Fall back to parsing line-by-line JSON objects
|
|
|
|
|
for (const line of responseText.split("\n")) {
|
|
|
|
|
const trimmed = line.trim();
|
2026-05-12 08:06:58 -05:00
|
|
|
if (trimmed.length === 0) continue;
|
2026-04-05 22:44:45 -05:00
|
|
|
try {
|
|
|
|
|
const obj = JSON.parse(trimmed) as { id?: string; score?: number };
|
2026-05-12 08:06:58 -05:00
|
|
|
if (
|
|
|
|
|
typeof obj === "object" &&
|
|
|
|
|
obj !== null &&
|
|
|
|
|
typeof obj.id === "string" &&
|
|
|
|
|
typeof obj.score === "number"
|
|
|
|
|
) {
|
2026-04-05 22:44:45 -05:00
|
|
|
scored.push({ id: obj.id, score: obj.score });
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
// Skip unparseable lines
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sort by score descending and keep top N
|
|
|
|
|
scored.sort((a, b) => b.score - a.score);
|
|
|
|
|
const topN = scored.slice(0, this.config.edgeLimit);
|
|
|
|
|
// Map back to triples
|
|
|
|
|
const result: Triple[] = [];
|
|
|
|
|
for (const entry of topN) {
|
|
|
|
|
const idx = parseInt(entry.id, 10);
|
|
|
|
|
if (!isNaN(idx) && idx >= 0 && idx < triples.length) {
|
|
|
|
|
result.push(triples[idx]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
feat: fix RAG pipelines, Beep Graph branding, PWA, and ambient glow UI
Pipeline fixes:
- Fix agent getting empty response from graph-rag by combining answer +
explain data in single message (RequestResponse returns first msg)
- Fix Doc RAG pipeline: add content field to Qdrant doc payload, seed 10
document chunks, fix type mismatches across base/flow/client
- Forward explainability events from agent's KnowledgeQuery to client
- Add "agent" to TERM_BEARING_RESPONSE_SERVICES for triple translation
- Fix embeddings env var (OLLAMA_URL), user/collection threading, edge
scoring threshold, and various protocol mismatches
Branding:
- Rename TrustGraph → Beep Graph (title, sidebar, settings, about)
- Custom lambda + ThugLife pixel glasses SVG logo component
- Forest green color palette (brand-50 through brand-900)
- SVG favicon + PNG icons (16/32/180/192/512)
- PWA manifest with service worker for offline shell caching
- Splash screen with animated logo pulse on app load
- Ambient glow background with drifting green radial blobs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 10:19:10 -05:00
|
|
|
console.log(`[GraphRag] Edge scoring: LLM returned ${scored.length} scores, keeping top ${topN.length}, mapped ${result.length} triples`);
|
|
|
|
|
|
2026-04-05 22:44:45 -05:00
|
|
|
// If scoring failed entirely, fall back to returning the first edgeLimit triples
|
|
|
|
|
if (result.length === 0) {
|
|
|
|
|
return triples.slice(0, this.config.edgeLimit);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async synthesize(
|
|
|
|
|
query: string,
|
|
|
|
|
edges: Triple[],
|
|
|
|
|
chunkCallback?: ChunkCallback,
|
|
|
|
|
): Promise<string> {
|
|
|
|
|
// Format edges as context
|
|
|
|
|
const context = edges
|
|
|
|
|
.map((t) => `${termToString(t.s)} -> ${termToString(t.p)} -> ${termToString(t.o)}`)
|
|
|
|
|
.join("\n");
|
|
|
|
|
|
|
|
|
|
const promptResp = await this.clients.prompt.request({
|
|
|
|
|
name: "graph-rag-synthesize",
|
|
|
|
|
variables: { query, context },
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-12 08:06:58 -05:00
|
|
|
if (chunkCallback !== undefined) {
|
2026-04-05 21:09:33 -05:00
|
|
|
// Streaming response
|
|
|
|
|
let fullText = "";
|
|
|
|
|
await this.clients.llm.request(
|
|
|
|
|
{
|
|
|
|
|
system: (promptResp as PromptResponse).system,
|
|
|
|
|
prompt: (promptResp as PromptResponse).prompt,
|
|
|
|
|
streaming: true,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
recipient: async (resp) => {
|
|
|
|
|
const r = resp as TextCompletionResponse;
|
2026-05-12 08:06:58 -05:00
|
|
|
if (r.response.length > 0) {
|
2026-04-05 21:09:33 -05:00
|
|
|
fullText += r.response;
|
2026-05-12 08:06:58 -05:00
|
|
|
await chunkCallback(r.response, r.endOfStream === true);
|
2026-04-05 21:09:33 -05:00
|
|
|
}
|
2026-05-12 08:06:58 -05:00
|
|
|
return r.endOfStream === true;
|
2026-04-05 21:09:33 -05:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
return fullText;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const resp = await this.clients.llm.request({
|
|
|
|
|
system: (promptResp as PromptResponse).system,
|
|
|
|
|
prompt: (promptResp as PromptResponse).prompt,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return (resp as TextCompletionResponse).response;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function termToString(term: Term): string {
|
|
|
|
|
switch (term.type) {
|
|
|
|
|
case "IRI":
|
|
|
|
|
return term.iri;
|
|
|
|
|
case "LITERAL":
|
|
|
|
|
return term.value;
|
|
|
|
|
case "BLANK":
|
|
|
|
|
return `_:${term.id}`;
|
|
|
|
|
case "TRIPLE":
|
|
|
|
|
return `(${termToString(term.triple.s)} ${termToString(term.triple.p)} ${termToString(term.triple.o)})`;
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-04-05 22:44:45 -05:00
|
|
|
|
|
|
|
|
function stringToTerm(value: string): Term {
|
|
|
|
|
if (value.startsWith("http://") || value.startsWith("https://")) {
|
|
|
|
|
return { type: "IRI", iri: value };
|
|
|
|
|
}
|
|
|
|
|
if (value.startsWith("_:")) {
|
|
|
|
|
return { type: "BLANK", id: value.slice(2) };
|
|
|
|
|
}
|
|
|
|
|
return { type: "LITERAL", value };
|
|
|
|
|
}
|