Refactor KB RAG to strategy pattern, remove callback-based API#484
Conversation
@workglow/cli
@workglow/ai
@workglow/browser-control
@workglow/indexeddb
@workglow/javascript
@workglow/job-queue
@workglow/knowledge-base
@workglow/mcp
@workglow/storage
@workglow/task-graph
@workglow/tasks
@workglow/util
workglow
@workglow/anthropic
@workglow/bun-webview
@workglow/chrome-ai
@workglow/electron
@workglow/google-gemini
@workglow/huggingface-inference
@workglow/huggingface-transformers
@workglow/node-llama-cpp
@workglow/ollama
@workglow/openai
@workglow/playwright
@workglow/postgres
@workglow/sqlite
@workglow/supabase
@workglow/tf-mediapipe
commit: |
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Pull request overview
This PR refactors the KnowledgeBase “RAG” layer from callback hooks to a single pluggable IKbAiStrategy, making kb.upsert() / kb.delete() / kb.search() the primary public entry points while keeping low-level storage operations available as strategy-facing building blocks.
Changes:
- Introduces
IKbAiStrategy+IKbStrategyTarget, and updatesKnowledgeBase/createKnowledgeBaseto install and delegate to a strategy instead of callbacks. - Adds a “standard” strategy factory (
createStandardKbStrategy) plus new AI tasks (TextRerankerTask,KbReindexTask) and updatesKbSearchTaskoutput to include parallel arrays. - Adds a HuggingFace Transformers provider run-fn for cross-encoder reranking (
HFT_TextReranker) and registers it.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| providers/huggingface-transformers/src/ai/common/HFT_TextReranker.ts | Adds HF Transformers run-fn for TextRerankerTask using text-classification pipeline over [query, doc] pairs. |
| providers/huggingface-transformers/src/ai/common/HFT_JobRunFns.ts | Registers TextRerankerTask -> HFT_TextReranker mapping. |
| packages/test/src/test/rag/DocumentRepository.test.ts | Updates tests from callback behavior to strategy delegation expectations. |
| packages/knowledge-base/src/knowledge-base/KnowledgeBase.ts | Replaces callback-based RAG entry points with upsert/delete/search delegation + adds reindex(). |
| packages/knowledge-base/src/knowledge-base/IKbAiStrategy.ts | Adds strategy interfaces, config enums, and helper toInsertChunkEntities. |
| packages/knowledge-base/src/knowledge-base/createKnowledgeBase.ts | Updates KB construction options to include model IDs + strategy instead of callbacks. |
| packages/knowledge-base/src/common.ts | Re-exports IKbAiStrategy surface from the package. |
| packages/ai/src/task/TextRerankerTask.ts | Adds a new AI task type for model-based cross-encoder reranking. |
| packages/ai/src/task/RerankerTask.ts | Updates docs to clarify heuristic-only purpose (but needs doc fixes). |
| packages/ai/src/task/KbSearchTask.ts | Makes KB search output richer (chunks/ids/scores arrays) and aligns docs with strategy approach. |
| packages/ai/src/task/KbReindexTask.ts | Adds task wrapper for strategy-driven KB reindexing. |
| packages/ai/src/task/index.ts | Registers/exports new tasks. |
| packages/ai/src/kb/createStandardKbStrategy.ts | Adds “standard” KB strategy implementation (ingest + retrieval incl rerank). |
| packages/ai/src/common.ts | Exports createStandardKbStrategy from @workglow/ai. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!doc.doc_id) { | ||
| // Let storage auto-generate by writing the document first. | ||
| await kb.upsertDocument(doc); | ||
| } |
| * For `searchMode === "rerank"`: how many candidates to retrieve before | ||
| * reranking. Defaults to `max(topK * 5, 20)`. |
| const result = await new TextRerankerTask().run({ | ||
| query, | ||
| documents: docs, | ||
| model: kb.rerankerModel, | ||
| topK, | ||
| }); | ||
| const indices = (result.indices as number[]) ?? []; | ||
| const scores = (result.scores as number[]) ?? []; | ||
| return indices.map((idx) => { | ||
| const candidate = firstStage[idx]; | ||
| const newScore = scores[idx]; | ||
| return { | ||
| ...candidate, | ||
| score: typeof newScore === "number" ? newScore : candidate.score, | ||
| }; | ||
| }); | ||
| } | ||
|
|
||
| // No reranker model configured but mode is "rerank" — fall back to a | ||
| // local heuristic so callers still get a usable ordering. |
There was a problem hiding this comment.
Addressed in 3a3e54d — added "TextRerankerTask" to onnx:Xenova/bge-reranker-base:q8's tasks array in packages/test/src/samples/ONNXModelSamples.ts so AiTask.narrowInput resolves the model under the new strategy. (Not visible as an outdated marker here because the fix is in the model sample file, not in this strategy file.)
Generated by Claude Code
| deleteChunksForDocument(doc_id: string): Promise<void>; | ||
| /** Low-level: bulk-write chunk vectors. */ | ||
| upsertChunksBulk(chunks: InsertChunkVectorEntity[]): Promise<unknown>; | ||
| /** Low-level: pure-vector retrieval. */ |
There was a problem hiding this comment.
Addressed in 3a3e54d — return type tightened to Promise<ChunkVectorEntity[]>. The thread didn't auto-outdate because GitHub aligns by line content (or the line numbers shifted within the range it tracks); the change is on the same method.
Generated by Claude Code
| * Heuristic reranking task. Cross-encoder reranking (via model) is handled | ||
| * by `createAiKbStrategy` directly — it dispatches to provider-registered | ||
| * RerankerTask run-fns through `AiProviderRegistry`. This task remains the | ||
| * model-free fallback for workflows that don't want to require a reranker | ||
| * model. |
| * cross-encoder pipeline on `[query, doc]` pairs). `createAiKbStrategy` | ||
| * uses this task to power `kb.searchWithRerank()` when a reranker model | ||
| * is configured on the KB. |
- createStandardKbStrategy.ingest: drop the duplicate upsertDocument when doc.doc_id is initially missing. upsertDocument already returns the stored doc with the assigned id, so a second write was both wasted I/O and a hidden trap for ScopedKnowledgeBase overrides that do scope-injection work on every write. - createStandardKbStrategy: rewrite the firstStageMultiplier docstring to match the implementation (no 20-floor — just `topK * multiplier` with a `topK` floor so we never return fewer than the caller asked for). - IKbStrategyTarget.upsertChunksBulk: tighten the return type from Promise<unknown> to Promise<ChunkVectorEntity[]> so strategies don't have to cast. - ONNXModelSamples: add "TextRerankerTask" to bge-reranker-base's `tasks` array. The new standard strategy invokes TextRerankerTask (not the legacy heuristic RerankerTask), and AiTask.narrowInput resolves models by task tag — without this, rerank mode silently fails model resolution. - RerankerTask + TextRerankerTask: rewrite the JSDoc comments that referenced the now-removed `createAiKbStrategy` and `kb.searchWithRerank()`. Both now point readers at `createStandardKbStrategy` and the `searchMode: "rerank"` integration point. All 191 rag tests pass. https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
…eType Address libs PR #484 review plan in one sweep, ordered by blast radius. Data integrity — ingest now delete-then-upsert-then-insert: - createStandardKbStrategy.ingest deletes old chunks BEFORE rewriting the document when doc.doc_id is set, so a partial failure (e.g. upsertChunksBulk rejecting) leaves "doc row preserved, chunks removed" rather than "new doc row pointing at stale old chunks." When doc.doc_id is unset, upserts first to mint the id, then runs deleteChunksForDocument as a defensive no-op so the post-condition ("after ingest, doc owns exactly the new chunks") holds even on storage backends that recycle ids. Concurrency — strategy snapshot per public op: - KnowledgeBase.upsert/delete/search/reindex now make the snapshot explicit (const strategy = this.requireStrategy(...)) and document the semantics on setAiStrategy: replacing the strategy does NOT affect ops already in flight; each public op resolves its strategy at entry. reindex captures once and uses the same strategy for the whole loop. Search correctness — surface canonical text + drop JSON.stringify fallback: - New chunkText(c) helper on @workglow/knowledge-base reads metadata.text and throws (with the chunk_id) when missing. Replaces the inline `meta?.text … JSON.stringify(meta ?? {})` map in createStandardKbStrategy and KbSearchTask. Documents metadata.text as a load-bearing contract on InsertChunkVectorEntity. Score semantics — tag rerank with scoreType: "rerank": - ScoreType union extended with "rerank". Both cross-encoder and heuristic-fallback rerank paths now set scoreType: "rerank" as const, overriding the first-stage cosine/RRF tag. Docstrings on createStandardKbStrategy, IKbAiStrategy.search, and the ScoreType union itself flag that cross-encoder logits are NOT comparable to cosine/BM25/RRF scores; callers must inspect scoreType before applying a score threshold. scoreThreshold is intentionally not honored in the rerank branch (commented in-code). ChunkRetrievalTask output schema enum extended to keep parity with the canonical union; the task itself only emits cosine/rrf. Tests: - mid-op setAiStrategy(B) during search/upsert/reindex: assert the in-flight op completes via the original strategy (DocumentRepository "strategy contract" block, 3 tests). - chunkText helper: present → returns text; missing → throws with chunk_id (DocumentRepository, 2 tests). - KbSearchTask: result with metadata lacking text throws with chunk_id rather than emitting JSON.stringify (KbSearchTask.test, 1 test). - New KnowledgeBaseStandardStrategy.test.ts exercises the actual createStandardKbStrategy: ingest-order partial-failure leaves no orphan chunks; rerank heuristic-fallback tags results "rerank". Setup registers a stub TextEmbeddingTask runFn + model record so the strategy's embedTexts call resolves without real providers. All new tests + KbSearchTask + DocumentRepository tests pass (191 rag tests pass, the 7 remaining failures are pre-existing HuggingFace-503 flakes in EndToEnd / RagWorkflow integration tests). https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
2fe707c to
d170868
Compare
- createStandardKbStrategy.ingest: drop the duplicate upsertDocument when doc.doc_id is initially missing. upsertDocument already returns the stored doc with the assigned id, so a second write was both wasted I/O and a hidden trap for ScopedKnowledgeBase overrides that do scope-injection work on every write. - createStandardKbStrategy: rewrite the firstStageMultiplier docstring to match the implementation (no 20-floor — just `topK * multiplier` with a `topK` floor so we never return fewer than the caller asked for). - IKbStrategyTarget.upsertChunksBulk: tighten the return type from Promise<unknown> to Promise<ChunkVectorEntity[]> so strategies don't have to cast. - ONNXModelSamples: add "TextRerankerTask" to bge-reranker-base's `tasks` array. The new standard strategy invokes TextRerankerTask (not the legacy heuristic RerankerTask), and AiTask.narrowInput resolves models by task tag — without this, rerank mode silently fails model resolution. - RerankerTask + TextRerankerTask: rewrite the JSDoc comments that referenced the now-removed `createAiKbStrategy` and `kb.searchWithRerank()`. Both now point readers at `createStandardKbStrategy` and the `searchMode: "rerank"` integration point. All 191 rag tests pass. https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
…eType Address libs PR #484 review plan in one sweep, ordered by blast radius. Data integrity — ingest now delete-then-upsert-then-insert: - createStandardKbStrategy.ingest deletes old chunks BEFORE rewriting the document when doc.doc_id is set, so a partial failure (e.g. upsertChunksBulk rejecting) leaves "doc row preserved, chunks removed" rather than "new doc row pointing at stale old chunks." When doc.doc_id is unset, upserts first to mint the id, then runs deleteChunksForDocument as a defensive no-op so the post-condition ("after ingest, doc owns exactly the new chunks") holds even on storage backends that recycle ids. Concurrency — strategy snapshot per public op: - KnowledgeBase.upsert/delete/search/reindex now make the snapshot explicit (const strategy = this.requireStrategy(...)) and document the semantics on setAiStrategy: replacing the strategy does NOT affect ops already in flight; each public op resolves its strategy at entry. reindex captures once and uses the same strategy for the whole loop. Search correctness — surface canonical text + drop JSON.stringify fallback: - New chunkText(c) helper on @workglow/knowledge-base reads metadata.text and throws (with the chunk_id) when missing. Replaces the inline `meta?.text … JSON.stringify(meta ?? {})` map in createStandardKbStrategy and KbSearchTask. Documents metadata.text as a load-bearing contract on InsertChunkVectorEntity. Score semantics — tag rerank with scoreType: "rerank": - ScoreType union extended with "rerank". Both cross-encoder and heuristic-fallback rerank paths now set scoreType: "rerank" as const, overriding the first-stage cosine/RRF tag. Docstrings on createStandardKbStrategy, IKbAiStrategy.search, and the ScoreType union itself flag that cross-encoder logits are NOT comparable to cosine/BM25/RRF scores; callers must inspect scoreType before applying a score threshold. scoreThreshold is intentionally not honored in the rerank branch (commented in-code). ChunkRetrievalTask output schema enum extended to keep parity with the canonical union; the task itself only emits cosine/rrf. Tests: - mid-op setAiStrategy(B) during search/upsert/reindex: assert the in-flight op completes via the original strategy (DocumentRepository "strategy contract" block, 3 tests). - chunkText helper: present → returns text; missing → throws with chunk_id (DocumentRepository, 2 tests). - KbSearchTask: result with metadata lacking text throws with chunk_id rather than emitting JSON.stringify (KbSearchTask.test, 1 test). - New KnowledgeBaseStandardStrategy.test.ts exercises the actual createStandardKbStrategy: ingest-order partial-failure leaves no orphan chunks; rerank heuristic-fallback tags results "rerank". Setup registers a stub TextEmbeddingTask runFn + model record so the strategy's embedTexts call resolves without real providers. All new tests + KbSearchTask + DocumentRepository tests pass (191 rag tests pass, the 7 remaining failures are pre-existing HuggingFace-503 flakes in EndToEnd / RagWorkflow integration tests). https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
d170868 to
432d33d
Compare
- createStandardKbStrategy.ingest: drop the duplicate upsertDocument when doc.doc_id is initially missing. upsertDocument already returns the stored doc with the assigned id, so a second write was both wasted I/O and a hidden trap for ScopedKnowledgeBase overrides that do scope-injection work on every write. - createStandardKbStrategy: rewrite the firstStageMultiplier docstring to match the implementation (no 20-floor — just `topK * multiplier` with a `topK` floor so we never return fewer than the caller asked for). - IKbStrategyTarget.upsertChunksBulk: tighten the return type from Promise<unknown> to Promise<ChunkVectorEntity[]> so strategies don't have to cast. - ONNXModelSamples: add "TextRerankerTask" to bge-reranker-base's `tasks` array. The new standard strategy invokes TextRerankerTask (not the legacy heuristic RerankerTask), and AiTask.narrowInput resolves models by task tag — without this, rerank mode silently fails model resolution. - RerankerTask + TextRerankerTask: rewrite the JSDoc comments that referenced the now-removed `createAiKbStrategy` and `kb.searchWithRerank()`. Both now point readers at `createStandardKbStrategy` and the `searchMode: "rerank"` integration point. All 191 rag tests pass. https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
…eType Address libs PR #484 review plan in one sweep, ordered by blast radius. Data integrity — ingest now delete-then-upsert-then-insert: - createStandardKbStrategy.ingest deletes old chunks BEFORE rewriting the document when doc.doc_id is set, so a partial failure (e.g. upsertChunksBulk rejecting) leaves "doc row preserved, chunks removed" rather than "new doc row pointing at stale old chunks." When doc.doc_id is unset, upserts first to mint the id, then runs deleteChunksForDocument as a defensive no-op so the post-condition ("after ingest, doc owns exactly the new chunks") holds even on storage backends that recycle ids. Concurrency — strategy snapshot per public op: - KnowledgeBase.upsert/delete/search/reindex now make the snapshot explicit (const strategy = this.requireStrategy(...)) and document the semantics on setAiStrategy: replacing the strategy does NOT affect ops already in flight; each public op resolves its strategy at entry. reindex captures once and uses the same strategy for the whole loop. Search correctness — surface canonical text + drop JSON.stringify fallback: - New chunkText(c) helper on @workglow/knowledge-base reads metadata.text and throws (with the chunk_id) when missing. Replaces the inline `meta?.text … JSON.stringify(meta ?? {})` map in createStandardKbStrategy and KbSearchTask. Documents metadata.text as a load-bearing contract on InsertChunkVectorEntity. Score semantics — tag rerank with scoreType: "rerank": - ScoreType union extended with "rerank". Both cross-encoder and heuristic-fallback rerank paths now set scoreType: "rerank" as const, overriding the first-stage cosine/RRF tag. Docstrings on createStandardKbStrategy, IKbAiStrategy.search, and the ScoreType union itself flag that cross-encoder logits are NOT comparable to cosine/BM25/RRF scores; callers must inspect scoreType before applying a score threshold. scoreThreshold is intentionally not honored in the rerank branch (commented in-code). ChunkRetrievalTask output schema enum extended to keep parity with the canonical union; the task itself only emits cosine/rrf. Tests: - mid-op setAiStrategy(B) during search/upsert/reindex: assert the in-flight op completes via the original strategy (DocumentRepository "strategy contract" block, 3 tests). - chunkText helper: present → returns text; missing → throws with chunk_id (DocumentRepository, 2 tests). - KbSearchTask: result with metadata lacking text throws with chunk_id rather than emitting JSON.stringify (KbSearchTask.test, 1 test). - New KnowledgeBaseStandardStrategy.test.ts exercises the actual createStandardKbStrategy: ingest-order partial-failure leaves no orphan chunks; rerank heuristic-fallback tags results "rerank". Setup registers a stub TextEmbeddingTask runFn + model record so the strategy's embedTexts call resolves without real providers. All new tests + KbSearchTask + DocumentRepository tests pass (191 rag tests pass, the 7 remaining failures are pre-existing HuggingFace-503 flakes in EndToEnd / RagWorkflow integration tests). https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
432d33d to
429b16b
Compare
- createStandardKbStrategy.ingest: drop the duplicate upsertDocument when doc.doc_id is initially missing. upsertDocument already returns the stored doc with the assigned id, so a second write was both wasted I/O and a hidden trap for ScopedKnowledgeBase overrides that do scope-injection work on every write. - createStandardKbStrategy: rewrite the firstStageMultiplier docstring to match the implementation (no 20-floor — just `topK * multiplier` with a `topK` floor so we never return fewer than the caller asked for). - IKbStrategyTarget.upsertChunksBulk: tighten the return type from Promise<unknown> to Promise<ChunkVectorEntity[]> so strategies don't have to cast. - ONNXModelSamples: add "TextRerankerTask" to bge-reranker-base's `tasks` array. The new standard strategy invokes TextRerankerTask (not the legacy heuristic RerankerTask), and AiTask.narrowInput resolves models by task tag — without this, rerank mode silently fails model resolution. - RerankerTask + TextRerankerTask: rewrite the JSDoc comments that referenced the now-removed `createAiKbStrategy` and `kb.searchWithRerank()`. Both now point readers at `createStandardKbStrategy` and the `searchMode: "rerank"` integration point. All 191 rag tests pass. https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
…eType Address libs PR #484 review plan in one sweep, ordered by blast radius. Data integrity — ingest now delete-then-upsert-then-insert: - createStandardKbStrategy.ingest deletes old chunks BEFORE rewriting the document when doc.doc_id is set, so a partial failure (e.g. upsertChunksBulk rejecting) leaves "doc row preserved, chunks removed" rather than "new doc row pointing at stale old chunks." When doc.doc_id is unset, upserts first to mint the id, then runs deleteChunksForDocument as a defensive no-op so the post-condition ("after ingest, doc owns exactly the new chunks") holds even on storage backends that recycle ids. Concurrency — strategy snapshot per public op: - KnowledgeBase.upsert/delete/search/reindex now make the snapshot explicit (const strategy = this.requireStrategy(...)) and document the semantics on setAiStrategy: replacing the strategy does NOT affect ops already in flight; each public op resolves its strategy at entry. reindex captures once and uses the same strategy for the whole loop. Search correctness — surface canonical text + drop JSON.stringify fallback: - New chunkText(c) helper on @workglow/knowledge-base reads metadata.text and throws (with the chunk_id) when missing. Replaces the inline `meta?.text … JSON.stringify(meta ?? {})` map in createStandardKbStrategy and KbSearchTask. Documents metadata.text as a load-bearing contract on InsertChunkVectorEntity. Score semantics — tag rerank with scoreType: "rerank": - ScoreType union extended with "rerank". Both cross-encoder and heuristic-fallback rerank paths now set scoreType: "rerank" as const, overriding the first-stage cosine/RRF tag. Docstrings on createStandardKbStrategy, IKbAiStrategy.search, and the ScoreType union itself flag that cross-encoder logits are NOT comparable to cosine/BM25/RRF scores; callers must inspect scoreType before applying a score threshold. scoreThreshold is intentionally not honored in the rerank branch (commented in-code). ChunkRetrievalTask output schema enum extended to keep parity with the canonical union; the task itself only emits cosine/rrf. Tests: - mid-op setAiStrategy(B) during search/upsert/reindex: assert the in-flight op completes via the original strategy (DocumentRepository "strategy contract" block, 3 tests). - chunkText helper: present → returns text; missing → throws with chunk_id (DocumentRepository, 2 tests). - KbSearchTask: result with metadata lacking text throws with chunk_id rather than emitting JSON.stringify (KbSearchTask.test, 1 test). - New KnowledgeBaseStandardStrategy.test.ts exercises the actual createStandardKbStrategy: ingest-order partial-failure leaves no orphan chunks; rerank heuristic-fallback tags results "rerank". Setup registers a stub TextEmbeddingTask runFn + model record so the strategy's embedTexts call resolves without real providers. All new tests + KbSearchTask + DocumentRepository tests pass (191 rag tests pass, the 7 remaining failures are pre-existing HuggingFace-503 flakes in EndToEnd / RagWorkflow integration tests). https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
429b16b to
c1b92d5
Compare
| * vectorDimensions: 1024, | ||
| * docEmbeddingModel: "onnx:Xenova/bge-base-en-v1.5:q8", | ||
| * }); | ||
| * kb.setAiStrategy(createAiKbStrategy(kb)); |
…se example The JSDoc @example called `createAiKbStrategy(kb)`, which is the old factory name that was renamed to `createStandardKbStrategy()` (no `kb` argument — the strategy receives the KB on each public-op call). Addresses Copilot review on PR #484. https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex
Adds an HFT text-reranking capability backed by a Transformers.js pipeline, registered alongside existing HFT capability sets. The run function validates the pipeline output shape and throws a typed error on mismatch so consumers fail fast instead of silently returning malformed scores. Includes a unit test that exercises the shape validator via an extracted pure helper.
… and document tasks Collapses the KnowledgeBase public API to upsert/delete/search/reindex and moves embedding/reranker model configuration onto the KnowledgeBase itself. The previously hand-wired pipeline becomes a pluggable IKbAiStrategy, with createStandardKbStrategy supplying the default chunker → embedder → vector search → optional reranker flow. Strategies own ingest ordering, snapshotting, chunkText handling, scoreType, the firstStageMinimum floor for rerank candidate pools, and scoreThreshold forwarding. Threads an optional IRunConfig through IKbAiStrategy, KnowledgeBase upsert/delete/search/reindex, and createStandardKbStrategy's sub-task calls so callers can scope per-operation concerns (signals, telemetry) without mutating KB state. Adds task-graph as a knowledge-base peer dependency. Adds three new high-level AI tasks that drive a KnowledgeBase end-to-end — KbAddDocumentTask, KbDeleteTask, KbReindexTask — and a TextRerankerTask that consumes the new text-reranking capability. KbSearchTask grows scoreThreshold and forwards IExecuteContext through to kb.search. Documents the strategy trust model on IKbAiStrategy / IKbStrategyTarget / KnowledgeBase / setAiStrategy.
…*, examples/cli Broadens the preview-publish glob so every workspace in packages/, providers/, and examples/cli participates in pkg-pr-new previews, not just a hand-picked subset.
bede624 to
0784401
Compare
Summary
This PR refactors the KnowledgeBase RAG architecture from a callback-based model to a pluggable strategy pattern. The public API is simplified to three methods (
upsert,delete,search) that delegate to an installedIKbAiStrategy, while low-level storage operations remain available for strategies and subclasses to use.Key Changes
New Strategy Interface: Introduced
IKbAiStrategywith three methods (ingest,delete,search) that encapsulate all RAG behavior. Strategies receive a narrowIKbStrategyTargetinterface exposing only the building blocks they need.Removed Callbacks: Replaced
onDocumentUpsert,onDocumentDelete, andonSearchcallbacks with the strategy pattern. This eliminates the awkward "storage committed before callback runs" contract and makes RAG flow explicit.KB Configuration: Added model ID and strategy fields to
KnowledgeBaseOptions:docEmbeddingModel/queryEmbeddingModel/rerankerModel(model IDs)chunkStrategy/searchMode(RAG behavior flags)aiStrategy(the installed strategy instance)Standard Strategy Factory: Created
createStandardKbStrategy()in@workglow/aithat implements the common case: hierarchical chunking + embedding during ingest, configurable retrieval (similarity/hybrid/rerank) during search. Reads KB model IDs and config at op time.New Tasks: Added
TextRerankerTask(cross-encoder reranking) andKbReindexTask(bulk re-chunk/re-embed via strategy).HuggingFace Provider: Implemented
HFT_TextRerankerrun-fn for transformers.js cross-encoder models.Simplified Public API:
kb.upsert(),kb.delete(),kb.search()are now the only entry points for application code. Storage methods (upsertDocument,upsertChunksBulk,similaritySearch, etc.) remain public as "strategy-facing" building blocks.Implementation Details
kb.setAiStrategy()and can be swapped post-construction.ScopedKnowledgeBase) to intercept low-level ops without the strategy knowing.createStandardKbStrategy()supports tuning options (chunker token budgets, search mode overrides, reranker candidate multiplier) while defaulting to KB-stored config.TextRerankerTask) and local heuristics (viaRerankerTask) as fallback.https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex