Use Effect fn for RAG helpers

This commit is contained in:
elpresidank 2026-06-04 07:11:00 -05:00
parent 935ded616c
commit d939e6523c
3 changed files with 43 additions and 32 deletions

View file

@ -2122,6 +2122,27 @@ Notes:
- `cd ts && bun run lint`
- `git diff --check`
### 2026-06-04: Retrieval RAG Effect.fn Helper Slice
- Status: migrated and package-verified.
- Completed:
- `ts/packages/flow/src/retrieval/document-rag.ts` now defines its reusable
document RAG query program with `Effect.fn` instead of a function returning
`Effect.gen`.
- `ts/packages/flow/src/retrieval/graph-rag.ts` now defines the graph RAG
query, concept extraction, vector lookup, entity lookup, edge traversal,
edge scoring, and synthesis helpers with named `Effect.fn` providers.
- Public Promise facades and requestor compatibility surfaces are unchanged.
- The focused scan for retrieval `return Effect.gen(...)` helper patterns is
clean.
- Verification:
- `cd ts/packages/flow && bunx --bun vitest run src/__tests__/retrieval-rag.test.ts`
- `cd ts && bun run check:tsgo`
- `cd ts && bun run build`
- `cd ts && bun run test`
- `cd ts && bun run lint`
- `git diff --check`
## Subagent Findings To Preserve
- MCP/workbench:
@ -2281,8 +2302,8 @@ Notes:
slices found no production normal `Error`, raw `try`/`catch`, native
`switch`, or Effect-focused type assertions under `ts/packages`.
- Remaining real helper-normalization targets from the fresh sweep are
retrieval/document-rag, retrieval/graph-rag, embeddings/ollama, base
processor flow helpers, and one workbench atom helper.
embeddings/ollama, base processor flow helpers, and one workbench atom
helper.
- Remaining real long-lived native collection targets include base processor
registries, Librarian service / collection manager state, prompt template
cache, and a workbench module cache. Local traversal sets and test fakes

View file

@ -93,12 +93,11 @@ export function makeDocumentRag(clients: DocumentRagClients): DocumentRag {
};
}
function queryDocumentRag(
const queryDocumentRag = Effect.fn("DocumentRagEngine.queryDocumentRag")(function* (
clients: DocumentRagClients,
queryText: string,
options?: DocumentRagQueryOptions,
): Effect.Effect<string, DocumentRagEngineError> {
return Effect.gen(function* () {
) {
const collection = options?.collection ?? "default";
const embResp = yield* clients.embeddings.request({ text: [queryText] }).pipe(
@ -139,4 +138,3 @@ function queryDocumentRag(
return resp.response;
});
}

View file

@ -149,13 +149,12 @@ export function makeGraphRag(
};
}
function queryGraphRag(
const queryGraphRag = Effect.fn("GraphRagEngine.queryGraphRag")(function* (
clients: GraphRagClients,
queryText: string,
options?: GraphRagQueryOptions,
rawConfig?: GraphRagConfig,
): Effect.Effect<GraphRagResult, GraphRagEngineError> {
return Effect.gen(function* () {
) {
const config = normalizeGraphRagConfig(rawConfig);
yield* Effect.log(`[GraphRag] Query: "${queryText.slice(0, 80)}..."`);
@ -185,10 +184,11 @@ function queryGraphRag(
return { answer, subgraph: scoredEdges };
});
}
function extractConcepts(clients: GraphRagClients, query: string): Effect.Effect<string[], GraphRagEngineError> {
return Effect.gen(function* () {
const extractConcepts = Effect.fn("GraphRagEngine.extractConcepts")(function* (
clients: GraphRagClients,
query: string,
) {
const promptResp = yield* requestClient(
clients.prompt,
"extract-concepts-prompt",
@ -212,22 +212,21 @@ function extractConcepts(clients: GraphRagClients, query: string): Effect.Effect
.map((concept) => concept.trim())
.filter((concept) => concept.length > 0);
});
}
function getVectors(clients: GraphRagClients, concepts: string[]): Effect.Effect<number[][], GraphRagEngineError> {
return Effect.gen(function* () {
const getVectors = Effect.fn("GraphRagEngine.getVectors")(function* (
clients: GraphRagClients,
concepts: string[],
) {
const resp = yield* requestClient(clients.embeddings, "get-vectors", { text: concepts });
return resp.vectors;
});
}
function getEntities(
const getEntities = Effect.fn("GraphRagEngine.getEntities")(function* (
clients: GraphRagClients,
config: NormalizedGraphRagConfig,
vectors: number[][],
collection?: string,
): Effect.Effect<Term[], GraphRagEngineError> {
return Effect.gen(function* () {
) {
const resp = yield* requestClient(
clients.graphEmbeddings,
"get-entities",
@ -240,15 +239,13 @@ function getEntities(
);
return resp.entities;
});
}
function followEdges(
const followEdges = Effect.fn("GraphRagEngine.followEdges")(function* (
clients: GraphRagClients,
config: NormalizedGraphRagConfig,
entities: Term[],
collection?: string,
): Effect.Effect<Triple[], GraphRagEngineError> {
return Effect.gen(function* () {
) {
const visited = new Set<string>();
const subgraph: Triple[] = [];
let currentLevel = new Set<string>(
@ -301,15 +298,13 @@ function followEdges(
return subgraph.slice(0, config.maxSubgraphSize);
});
}
function scoreEdges(
const scoreEdges = Effect.fn("GraphRagEngine.scoreEdges")(function* (
clients: GraphRagClients,
config: NormalizedGraphRagConfig,
query: string,
triples: Triple[],
): Effect.Effect<Triple[], GraphRagEngineError> {
return Effect.gen(function* () {
) {
if (triples.length === 0) return [];
if (triples.length <= 500) {
@ -372,15 +367,13 @@ function scoreEdges(
return result;
});
}
function synthesize(
const synthesize = Effect.fn("GraphRagEngine.synthesize")(function* (
clients: GraphRagClients,
query: string,
edges: Triple[],
chunkCallback?: ChunkCallback,
): Effect.Effect<string, GraphRagEngineError> {
return Effect.gen(function* () {
) {
const context = edges
.map((triple) => `${termToString(triple.s)} -> ${termToString(triple.p)} -> ${termToString(triple.o)}`)
.join("\n");
@ -431,7 +424,6 @@ function synthesize(
return resp.response;
});
}
const ScoredEdge = S.Struct({
id: S.String,