feat(ai): add local RAG vector store and interactive RAGChat widget#779
feat(ai): add local RAG vector store and interactive RAGChat widget#779Tejas9406 wants to merge 3 commits into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds AIAdapter.embed, a LocalVectorStore with chunking, cosine-similarity search, directory indexer and JSON persistence, a RAGChat terminal widget that streams AI responses, accompanying tests, and barrel exports plus UI package dependency updates. ChangesRAG Vector Store and Chat Feature
Sequence Diagram(s)sequenceDiagram
participant Client
participant LocalVectorStore
participant AIAdapter
Client->>LocalVectorStore: query(queryText)
LocalVectorStore->>AIAdapter: embed(queryText)
AIAdapter-->>LocalVectorStore: embedding (number[])
LocalVectorStore->>LocalVectorStore: compute cosineSimilarity
LocalVectorStore->>LocalVectorStore: sort & limit
LocalVectorStore-->>Client: DocumentChunk[]
sequenceDiagram
participant User
participant RAGChat
participant LocalVectorStore
participant AIAdapter
User->>RAGChat: submit query
RAGChat->>LocalVectorStore: query(userText, limit=3)
LocalVectorStore->>AIAdapter: embed(userText)
AIAdapter-->>LocalVectorStore: embedding
LocalVectorStore-->>RAGChat: DocumentChunk[]
RAGChat->>AIAdapter: chat(messages with context)
AIAdapter-->>RAGChat: AsyncIterable<token>
RAGChat->>RAGChat: stream tokens into display
RAGChat-->>User: rendered response
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (3)
packages/adapters/src/commander/index.ts (1)
14-14: ⚡ Quick winAdd an inline justification for the type assertion on Line 14.
as Tcurrently violates the repo rule requiring an inline explanation for type assertions.Suggested patch
- options: program.opts() as T, + options: program.opts() as T, // Commander returns an untyped options bag; caller-provided generic `T` defines the expected shape.As per coding guidelines, "No type assertions without an inline comment explaining why."
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/adapters/src/commander/index.ts` at line 14, The type assertion on the options assignment (options: program.opts() as T) needs an inline comment explaining why the assertion is safe; update the line to keep the assertion but add a brief justification comment after it (e.g., stating that commander validates/returns the expected shape or that upstream type inference cannot express the generic T but runtime checks cover it), referencing the exact expression "options: program.opts() as T" so future readers know why the assertion is allowed.packages/ui/src/RAGChat.ts (1)
98-133: ⚡ Quick winRemove
console.errorfrom library source code.Line 124 logs errors directly to the console. Library code should propagate errors to the caller (e.g., via a callback or event) so consumers control logging behavior.
As per coding guidelines:
packages/**/src/**/*.{ts,tsx}: Noconsole.login source files.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ui/src/RAGChat.ts` around lines 98 - 133, The catch block in _submitQuery currently calls console.error('RAG query failed:', error) which violates the no-console rule; remove that console call and instead propagate the error to the consumer by invoking a dedicated error-handling hook (e.g., call this._handleError(error) or emit an 'error' event via this.emit('error', error)) and keep the existing push of an assistant error message; update or add the handler (e.g., _handleError or an EventEmitter hookup) so callers can subscribe and control logging behavior and ensure _submitQuery still sets _loading = false and markDirty() in finally.packages/adapters/src/ai/vectorStore.ts (1)
98-150: ⚡ Quick winRemove
console.errorcalls from library source code.Lines 90 and 124 use
console.errorto log initialization and query failures. Library code should avoid writing directly to console; instead, propagate errors to the caller or emit events/callbacks so consumers can handle logging.As per coding guidelines:
packages/**/src/**/*.{ts,tsx}: Noconsole.login source files.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/adapters/src/ai/vectorStore.ts` around lines 98 - 150, Remove any console.error calls in LocalVectorStore (e.g., in the constructor, load(), query() or any other methods) and stop swallowing errors there; instead either rethrow the caught error or let promise rejections propagate to the caller so callers can handle logging. Concretely, in load() keep the ENOENT branch that sets this._documents = [], but for other errors remove console.error and throw the error (or do not catch it). In query() and addDocuments() remove any console.error around AI calls and allow embed() failures to surface (or emit an error via an EventEmitter you add to LocalVectorStore) so consumers control logging. Ensure no console.* remains in LocalVectorStore, and preserve existing behavior for ENOENT only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/adapters/src/ai/index.ts`:
- Around line 118-129: The embed method currently returns an empty array when
OpenAI's response lacks an embedding, which yields a zero-magnitude vector and
corrupts cosineSimilarity; modify the embed function (the async embed(text:
string) implementation for provider === 'openai') to detect missing
response.data[0]?.embedding and throw a descriptive Error (or rethrow the
provider error) instead of returning [] so callers can surface the failure
rather than treat it as a valid zero vector.
In `@packages/adapters/src/ai/vectorStore.ts`:
- Around line 74-96: The for-loop inside indexDirectory is shadowing the
chunkText function by using the loop variable name `chunkText`; rename that loop
variable (e.g., to `chunk`, `chunkStr`, or `chunkTextSlice`) and update its
usage in the docs.push call so it no longer conflicts with the `chunkText`
function name defined earlier, leaving the rest of indexDirectory and the call
to store.addDocuments(ai) unchanged.
In `@packages/ui/src/RAGChat.ts`:
- Around line 45-96: The constructor uses a type coercion for borderClr when
assigning this._borderColor (see RAGChat constructor and the borderClr ->
this._borderColor code) — replace the bare "as any" with a short inline comment
explaining why the runtime value cannot be typed more precisely (e.g., it can be
a named color string or a Style['fg'] object from upstream libs) and keep the
cast only with that justification; and in _initIndex replace the silent
console.error('Failed to initialize RAG index:', error) with error propagation
(either rethrow the caught error or rethrow after logging) so callers can handle
initialization failures instead of swallowing them (modify _initIndex's catch to
rethrow or remove console.error and throw the original error).
- Around line 187-293: In _renderSelf add short inline comments next to every
"as any" explaining why the cast is required and why it is safe: annotate the ba
assignment (ba = { ... } as any) to state the border color union mismatch and
why runtime value is valid; annotate fgColor (fgColor = ... as any) to explain
the intended CellAttr shape for user messages; annotate the two places in the
indexing/loading screen.writeString calls where fg is cast as any to say the
color literal is intentionally used despite TypeScript mismatch; keep each
comment one short sentence referencing the variable (ba, fgColor,
indexing/loading writeString fg) and the reason (third‑party type mismatch or
known runtime shape).
---
Nitpick comments:
In `@packages/adapters/src/ai/vectorStore.ts`:
- Around line 98-150: Remove any console.error calls in LocalVectorStore (e.g.,
in the constructor, load(), query() or any other methods) and stop swallowing
errors there; instead either rethrow the caught error or let promise rejections
propagate to the caller so callers can handle logging. Concretely, in load()
keep the ENOENT branch that sets this._documents = [], but for other errors
remove console.error and throw the error (or do not catch it). In query() and
addDocuments() remove any console.error around AI calls and allow embed()
failures to surface (or emit an error via an EventEmitter you add to
LocalVectorStore) so consumers control logging. Ensure no console.* remains in
LocalVectorStore, and preserve existing behavior for ENOENT only.
In `@packages/adapters/src/commander/index.ts`:
- Line 14: The type assertion on the options assignment (options: program.opts()
as T) needs an inline comment explaining why the assertion is safe; update the
line to keep the assertion but add a brief justification comment after it (e.g.,
stating that commander validates/returns the expected shape or that upstream
type inference cannot express the generic T but runtime checks cover it),
referencing the exact expression "options: program.opts() as T" so future
readers know why the assertion is allowed.
In `@packages/ui/src/RAGChat.ts`:
- Around line 98-133: The catch block in _submitQuery currently calls
console.error('RAG query failed:', error) which violates the no-console rule;
remove that console call and instead propagate the error to the consumer by
invoking a dedicated error-handling hook (e.g., call this._handleError(error) or
emit an 'error' event via this.emit('error', error)) and keep the existing push
of an assistant error message; update or add the handler (e.g., _handleError or
an EventEmitter hookup) so callers can subscribe and control logging behavior
and ensure _submitQuery still sets _loading = false and markDirty() in finally.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 1f3111de-6329-41bf-ab60-dfae7340e8a1
📒 Files selected for processing (9)
packages/adapters/src/ai/index.tspackages/adapters/src/ai/vectorStore.test.tspackages/adapters/src/ai/vectorStore.tspackages/adapters/src/commander/index.tspackages/adapters/src/index.tspackages/ui/package.jsonpackages/ui/src/RAGChat.test.tspackages/ui/src/RAGChat.tspackages/ui/src/index.ts
…checks, type assertions, and error hooks
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
packages/ui/src/RAGChat.ts (1)
87-93:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd an inline justification for the event emitter
as anycast.Line 92 uses
as anywithout an inline rationale. Add a short inline comment (or a typed wrapper) to justify why this cast is required.Suggested minimal fix
- (this.events as any).emit('error', err); + // Cast needed: Widget event typings do not include custom 'error', but runtime emitter supports it. + (this.events as any).emit('error', err);As per coding guidelines:
**/*.{ts,tsx}: Use TypeScript strict mode. Noanywithout an inline comment explaining why. No type assertions without an inline comment explaining why.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@packages/ui/src/RAGChat.ts` around lines 87 - 93, In _handleError, the cast (this.events as any) is used to access emit but lacks justification; either add a short inline comment explaining why a typed cast is necessary (e.g., events uses a dynamic/emitter API not expressible in current Events type) or introduce a small typed wrapper/override that exposes emit (e.g., a local variable typed as EventEmitter-like) and use that instead; update references in _handleError to use the justified cast or wrapper and mention the matching reason and link to the underlying type limitation (keep comment concise and adjacent to the cast/wrapper).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/ui/src/RAGChat.test.ts`:
- Line 145: Add short inline comments next to each use of `any`/`as any` in
RAGChat.test.ts to justify the cast: explain that the test is wiring a
lightweight mock that doesn't implement the full EventEmitter/interface so `} as
any` (around the mocked props) is used to bypass strict typing, that `store:
any` is a minimal partial store used only for test setup, and that `('error' as
any, ...)`/similar casts are to satisfy the event API signature on a mocked
emitter rather than the real typed EventEmitter; place each comment directly
after the cast (near the symbols in the file) so future readers know these are
deliberate test-only loosenings.
---
Duplicate comments:
In `@packages/ui/src/RAGChat.ts`:
- Around line 87-93: In _handleError, the cast (this.events as any) is used to
access emit but lacks justification; either add a short inline comment
explaining why a typed cast is necessary (e.g., events uses a dynamic/emitter
API not expressible in current Events type) or introduce a small typed
wrapper/override that exposes emit (e.g., a local variable typed as
EventEmitter-like) and use that instead; update references in _handleError to
use the justified cast or wrapper and mention the matching reason and link to
the underlying type limitation (keep comment concise and adjacent to the
cast/wrapper).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 0de60ec6-6a7c-4e25-a249-97b81f1891a2
📒 Files selected for processing (5)
packages/adapters/src/ai/index.tspackages/adapters/src/ai/vectorStore.tspackages/adapters/src/commander/index.tspackages/ui/src/RAGChat.test.tspackages/ui/src/RAGChat.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- packages/adapters/src/commander/index.ts
- packages/adapters/src/ai/vectorStore.ts
Description
This PR implements a lightweight, local, zero-dependency RAG (Retrieval-Augmented Generation) system. It introduces a pure-TypeScript vector database (
LocalVectorStore) utilizing in-memory cosine similarity search, an automated directory indexer (indexDirectory) that chunks markdown and text files, and an interactive TUI<RAGChat>assistant widget supporting scrollable histories, multiline query input, and real-time streaming answers.Related Issue
Closes #777
Which package(s)?
@termuijs/adapters, @termuijs/ui
Type of Change
type:bug)type:feature)type:docs)type:testing)type:refactor)type:design)type:accessibility)type:performance)type:devops)type:security)Checklist
needs-starcheck blocks your merge otherwise.bun vitest runbun run buildbun run typecheckCONTRIBUTING.md.type: short description.markDirty()(if your change affects rendering).anytypes without an inline comment explaining why.GSSoC 2026 Participation
https://gssoc.girlscript.org/profile/666f63ca-ed6a-4d0f-8ac8-1518b06ec839Screenshots / Recordings (UI changes)
(Terminal screenshots / recordings can be dropped here if needed)
Notes for the Reviewer
@termuijs/adaptersand@termuijs/uipass.packages/adapters/src/commander/index.tsso the workspace TypeScript declarations compile cleanly.Summary by CodeRabbit
New Features
Tests