Skip to content

Refactor KB RAG to strategy pattern, remove callback-based API#484

Merged
sroussey merged 4 commits into
mainfrom
claude/search-with-rerank-Rl4IX
May 15, 2026
Merged

Refactor KB RAG to strategy pattern, remove callback-based API#484
sroussey merged 4 commits into
mainfrom
claude/search-with-rerank-Rl4IX

Conversation

@sroussey
Copy link
Copy Markdown
Collaborator

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 installed IKbAiStrategy, while low-level storage operations remain available for strategies and subclasses to use.

Key Changes

  • New Strategy Interface: Introduced IKbAiStrategy with three methods (ingest, delete, search) that encapsulate all RAG behavior. Strategies receive a narrow IKbStrategyTarget interface exposing only the building blocks they need.

  • Removed Callbacks: Replaced onDocumentUpsert, onDocumentDelete, and onSearch callbacks 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/ai that 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) and KbReindexTask (bulk re-chunk/re-embed via strategy).

  • HuggingFace Provider: Implemented HFT_TextReranker run-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

  • Strategies are installed via kb.setAiStrategy() and can be swapped post-construction.
  • Virtual dispatch on storage methods allows subclasses (e.g., 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.
  • Reranking supports both external cross-encoder models (via TextRerankerTask) and local heuristics (via RerankerTask) as fallback.
  • Tests updated to verify strategy delegation and error handling when no strategy is installed.

https://claude.ai/code/session_01Ya54WFZhpDFzAqRh1qG8Ex

@sroussey sroussey self-assigned this May 12, 2026
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 12, 2026

Open in StackBlitz

@workglow/cli

npm i https://pkg.pr.new/@workglow/cli@484

@workglow/ai

npm i https://pkg.pr.new/@workglow/ai@484

@workglow/browser-control

npm i https://pkg.pr.new/@workglow/browser-control@484

@workglow/indexeddb

npm i https://pkg.pr.new/@workglow/indexeddb@484

@workglow/javascript

npm i https://pkg.pr.new/@workglow/javascript@484

@workglow/job-queue

npm i https://pkg.pr.new/@workglow/job-queue@484

@workglow/knowledge-base

npm i https://pkg.pr.new/@workglow/knowledge-base@484

@workglow/mcp

npm i https://pkg.pr.new/@workglow/mcp@484

@workglow/storage

npm i https://pkg.pr.new/@workglow/storage@484

@workglow/task-graph

npm i https://pkg.pr.new/@workglow/task-graph@484

@workglow/tasks

npm i https://pkg.pr.new/@workglow/tasks@484

@workglow/util

npm i https://pkg.pr.new/@workglow/util@484

workglow

npm i https://pkg.pr.new/workglow@484

@workglow/anthropic

npm i https://pkg.pr.new/@workglow/anthropic@484

@workglow/bun-webview

npm i https://pkg.pr.new/@workglow/bun-webview@484

@workglow/chrome-ai

npm i https://pkg.pr.new/@workglow/chrome-ai@484

@workglow/electron

npm i https://pkg.pr.new/@workglow/electron@484

@workglow/google-gemini

npm i https://pkg.pr.new/@workglow/google-gemini@484

@workglow/huggingface-inference

npm i https://pkg.pr.new/@workglow/huggingface-inference@484

@workglow/huggingface-transformers

npm i https://pkg.pr.new/@workglow/huggingface-transformers@484

@workglow/node-llama-cpp

npm i https://pkg.pr.new/@workglow/node-llama-cpp@484

@workglow/ollama

npm i https://pkg.pr.new/@workglow/ollama@484

@workglow/openai

npm i https://pkg.pr.new/@workglow/openai@484

@workglow/playwright

npm i https://pkg.pr.new/@workglow/playwright@484

@workglow/postgres

npm i https://pkg.pr.new/@workglow/postgres@484

@workglow/sqlite

npm i https://pkg.pr.new/@workglow/sqlite@484

@workglow/supabase

npm i https://pkg.pr.new/@workglow/supabase@484

@workglow/tf-mediapipe

npm i https://pkg.pr.new/@workglow/tf-mediapipe@484

commit: 9900a99

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 12, 2026

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 62.25% 22078 / 35462
🔵 Statements 62.11% 22852 / 36791
🔵 Functions 64.04% 4178 / 6524
🔵 Branches 50.82% 10560 / 20777
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
providers/huggingface-transformers/src/ai/runtime.ts 100% 100% 100% 100%
providers/huggingface-transformers/src/ai/common/HFT_CapabilitySets.ts 100% 100% 100% 100%
providers/huggingface-transformers/src/ai/common/HFT_JobRunFns.ts 42.85% 0% 0% 42.85% 80-84
providers/huggingface-transformers/src/ai/common/HFT_TextReranker.ts 2.77% 0% 0% 3.03% 21-80, 104-139
Generated in workflow #2275 for commit 9900a99 by the Vitest Coverage Report Action

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 updates KnowledgeBase/createKnowledgeBase to install and delegate to a strategy instead of callbacks.
  • Adds a “standard” strategy factory (createStandardKbStrategy) plus new AI tasks (TextRerankerTask, KbReindexTask) and updates KbSearchTask output 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.

Comment on lines +108 to +111
if (!doc.doc_id) {
// Let storage auto-generate by writing the document first.
await kb.upsertDocument(doc);
}
Comment on lines +42 to +43
* For `searchMode === "rerank"`: how many candidates to retrieve before
* reranking. Defaults to `max(topK * 5, 20)`.
Comment on lines +199 to +218
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.
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment on lines +77 to +80
deleteChunksForDocument(doc_id: string): Promise<void>;
/** Low-level: bulk-write chunk vectors. */
upsertChunksBulk(chunks: InsertChunkVectorEntity[]): Promise<unknown>;
/** Low-level: pure-vector retrieval. */
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Comment thread packages/ai/src/task/RerankerTask.ts Outdated
Comment on lines +113 to +117
* 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.
Comment on lines +70 to +72
* cross-encoder pipeline on `[query, doc]` pairs). `createAiKbStrategy`
* uses this task to power `kb.searchWithRerank()` when a reranker model
* is configured on the KB.
sroussey pushed a commit that referenced this pull request May 12, 2026
- 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
sroussey pushed a commit that referenced this pull request May 12, 2026
…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
@sroussey sroussey force-pushed the claude/search-with-rerank-Rl4IX branch from 2fe707c to d170868 Compare May 12, 2026 22:30
sroussey pushed a commit that referenced this pull request May 14, 2026
- 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
sroussey pushed a commit that referenced this pull request May 14, 2026
…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
@sroussey sroussey force-pushed the claude/search-with-rerank-Rl4IX branch from d170868 to 432d33d Compare May 14, 2026 05:05
sroussey pushed a commit that referenced this pull request May 14, 2026
- 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
sroussey pushed a commit that referenced this pull request May 14, 2026
…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
@sroussey sroussey force-pushed the claude/search-with-rerank-Rl4IX branch from 432d33d to 429b16b Compare May 14, 2026 15:43
sroussey pushed a commit that referenced this pull request May 15, 2026
- 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
sroussey pushed a commit that referenced this pull request May 15, 2026
…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
@sroussey sroussey force-pushed the claude/search-with-rerank-Rl4IX branch from 429b16b to c1b92d5 Compare May 15, 2026 00:28
@sroussey sroussey requested a review from Copilot May 15, 2026 19:38
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 33 out of 34 changed files in this pull request and generated 1 comment.

* vectorDimensions: 1024,
* docEmbeddingModel: "onnx:Xenova/bge-base-en-v1.5:q8",
* });
* kb.setAiStrategy(createAiKbStrategy(kb));
sroussey pushed a commit that referenced this pull request May 15, 2026
…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
sroussey added 3 commits May 15, 2026 20:03
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.
@sroussey sroussey force-pushed the claude/search-with-rerank-Rl4IX branch from bede624 to 0784401 Compare May 15, 2026 20:10
@sroussey sroussey merged commit e8edf57 into main May 15, 2026
16 checks passed
@sroussey sroussey deleted the claude/search-with-rerank-Rl4IX branch May 15, 2026 20:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants