From 2edeb597871308b7c0669137049e916e48ac304e Mon Sep 17 00:00:00 2001 From: Alejo Castillo Date: Mon, 13 Jul 2026 10:35:25 -0300 Subject: [PATCH] docs: clarify namespace and sessionId usage Document that chat() takes namespace top-level (not under options), and that omitting sessionId shares the default history across clients. Addresses #84 and #103 Co-authored-by: Cursor --- docs/api.mdx | 58 +++++++++++++++------------ docs/gettingstarted.mdx | 8 +++- docs/how-to.mdx | 89 +++++++++++++++++++++++++++++++---------- 3 files changed, 107 insertions(+), 48 deletions(-) diff --git a/docs/api.mdx b/docs/api.mdx index f74f160..3dc3f5f 100644 --- a/docs/api.mdx +++ b/docs/api.mdx @@ -99,13 +99,18 @@ The chat method enables conversations with a language model (LLM) using your vec {" "} - Chat session ID of the user interacting with the application + Chat session ID of the user interacting with the application. If omitted, all clients share the + default session and therefore the same chat history. Pass a unique value per conversation (or per + user) to isolate histories. {" "} - Limit included context elements to a specific namespace (i.e. results for a specific user) + Limit included context elements to a specific namespace (i.e. results for a specific user). This + is a **top-level** chat option — do not nest it under `options`. When adding context, `namespace` + goes under `options` on `context.add`; when chatting, pass `namespace` directly on `chat` (and + keep it aligned with the namespace you ingested into). {" "} @@ -161,19 +166,19 @@ const chatResponse = await ragChat.chat({ topK: 3, streaming: true, onContextFetched: (context) => { - console.log("Retrieved context:", context) - return context + console.log("Retrieved context:", context); + return context; }, metadata: { source: "product_inquiry" }, }, -}) +}); if (chatResponse.isStream) { for await (const chunk of chatResponse.output) { - console.log(chunk) + console.log(chunk); } } else { - console.log(chatResponse.output) + console.log(chatResponse.output); } ``` @@ -282,12 +287,12 @@ const result = await context.add({ fileSource: "./document.pdf", pdfConfig: { splitPages: true }, options: { metadata: { source: "company_report" } }, -}) +}); if (result.success) { - console.log(`Added ${result.ids.length} context items`) + console.log(`Added ${result.ids.length} context items`); } else { - console.error(`Failed to add context: ${result.error}`) + console.error(`Failed to add context: ${result.error}`); } ``` @@ -336,13 +341,13 @@ The method doesn't return a value, but it's asynchronous, so you should wait for await context.delete({ id: "item_123", namespace: "product_catalog", -}) +}); // Deleting multiple items await context.delete({ id: ["item_456", "item_789", "item_101"], namespace: "customer_data", -}) +}); ``` ### `deleteEntireContext` @@ -378,13 +383,13 @@ The method doesn't return a value, but it's asynchronous, so you should wait for ```javascript // Resetting the entire vector database -await context.deleteEntireContext() -console.log("Entire context deleted successfully") +await context.deleteEntireContext(); +console.log("Entire context deleted successfully"); // Resetting a specific namespace await context.deleteEntireContext({ namespace: "temporary_data", -}) +}); ``` @@ -487,7 +492,7 @@ await history.addMessage({ }, sessionId: "user_456_weather_chat", sessionTTL: 1800, // Session will expire after 30 minutes -}) +}); ``` ### `deleteMessages` @@ -516,11 +521,11 @@ The method doesn't return a value, but it's asynchronous, so you should wait for #### Example: ```javascript -const sessionIdToDelete = "user_789_support_chat" +const sessionIdToDelete = "user_789_support_chat"; -await history.deleteMessages({ sessionId: sessionIdToDelete }) +await history.deleteMessages({ sessionId: sessionIdToDelete }); -console.log(`All messages in session ${sessionIdToDelete} have been deleted`) +console.log(`All messages in session ${sessionIdToDelete} have been deleted`); ``` @@ -537,14 +542,15 @@ The `getMessages` method retrieves several messages from a chat session's histor - Chat session ID from which to retrieve messages. If not provided, a default - session ID will be used. + Chat session ID from which to retrieve messages. If not provided, a default session ID will be + used. The amount of messages to retrieve. - The starting index from which to retrieve messages (i.e. for pagination). Defaults to 0 (most recent message). + The starting index from which to retrieve messages (i.e. for pagination). Defaults to 0 (most + recent message). @@ -598,10 +604,10 @@ const messages = await history.getMessages({ sessionId: "user_123_support_chat", amount: 10, startIndex: 0, -}) +}); -console.log(`Retrieved ${messages.length} messages:`) +console.log(`Retrieved ${messages.length} messages:`); messages.forEach((msg) => { - console.log(`${msg.role}: ${msg.content} (ID: ${msg.id})`) -}) + console.log(`${msg.role}: ${msg.content} (ID: ${msg.id})`); +}); ``` diff --git a/docs/gettingstarted.mdx b/docs/gettingstarted.mdx index 7639221..372e5f6 100644 --- a/docs/gettingstarted.mdx +++ b/docs/gettingstarted.mdx @@ -5,7 +5,6 @@ title: Getting Started Upstash RAG Chat is **TypeScript toolkit for building powerful RAG applications**. With Upstash RAG Chat, you can focus on building a high-quality chatbot without having to deal with complicated AI orchestration tools. You can find the Github Repository [here](https://github.com/upstash/rag-chat). - ### Installation @@ -132,6 +131,13 @@ await ragChat.context.add({ // optional 👇: only add this knowledge to a specific namespace options: { namespace: "user-123-documents" }, }); + +// When querying that knowledge, pass the same namespace at the top level of chat options +// (not nested under `options` — that shape is only for `context.add`). +await ragChat.chat("Summarize the PDF", { + namespace: "user-123-documents", + sessionId: "user-123-session", // optional 👇: isolate this user's chat history +}); ``` #### Adding Web Content diff --git a/docs/how-to.mdx b/docs/how-to.mdx index 8be165e..e7fdb4d 100644 --- a/docs/how-to.mdx +++ b/docs/how-to.mdx @@ -19,26 +19,71 @@ const result = await ragChat.chat("THIS_IS_USERS_QUESTION", { ``` #### Adjust the context quality + If your chatbot is negatively affected by the provided context, you can adjust the context quality using the `similarityThreshold` option. The similarityThreshold is a number between 0 and 1, with a default value of 0.5. Increasing this value will improve quality, but the chatbot may reject more queries due to lack of relevant data. ```ts ragChat.chat("Tell me about machine learning", { - similarityThreshold: 0.5 + similarityThreshold: 0.5, }); ``` +#### Use namespaces correctly + +Namespaces isolate knowledge in the vector index (for example per user or tenant). + +- When **adding** context, pass `namespace` under `options`. +- When **chatting**, pass `namespace` at the **top level** of the chat options — not nested under `options`. + +```ts +const namespace = "user-123-documents"; + +await ragChat.context.add({ + type: "text", + data: "The speed of light is approximately 299,792,458 meters per second.", + options: { namespace }, +}); + +// Correct: namespace is a top-level chat option +const reply = await ragChat.chat("What is the speed of light?", { + namespace, +}); + +// Incorrect: nesting under `options` is ignored for chat retrieval +// await ragChat.chat("What is the speed of light?", { +// options: { namespace }, +// }); +``` + +If add and chat use different namespaces (or chat omits `namespace`), retrieval will look in the wrong index and the model may answer as if no context was provided. + +#### Isolate chat history with sessionId + +If you do not set `sessionId`, every client shares the default session (`upstash-rag-chat-session`) and therefore the same history. + +Pass a unique `sessionId` per conversation (or per user) on `chat`, and use the same id when reading or deleting history: + +```ts +const sessionId = "user-123-support-chat"; + +await ragChat.chat("Hello", { sessionId }); + +const history = await ragChat.history.getMessages({ sessionId, amount: 10 }); +await ragChat.history.deleteMessages({ sessionId }); +``` + #### Disable RAG to bypass context When RAG disabled, RAG chat skips the vector store and directly sends the question to the LLM model. ```ts const result = await ragChat.chat("THIS_IS_USERS_QUESTION", { - disableRAG: true + disableRAG: true, }); ``` - #### Enable debug logs + ```ts new RAGChat({ debug: true }); ``` @@ -50,21 +95,21 @@ You can access and update the context by using the `onContextFetched` callback. ```ts let response = await ragChat.chat(question, { onContextFetched: (context) => { - console.log("Retrieved context:", context) - return context + console.log("Retrieved context:", context); + return context; }, }); ``` - #### Access the chat history + You can access chat history by using the `onChatHistoryFetched` callback. This callback is called after the chat history is fetched from the Redis (or memory) before the prompt is sent to the LLM. ```ts let response = await ragChat.chat(question, { onChatHistoryFetched: (messages) => { - console.log("Retrieved chat history:", messages) - return messages + console.log("Retrieved chat history:", messages); + return messages; }, }); ``` @@ -78,7 +123,7 @@ export const rag = new RAGChat(); await rag.context.add({ type: "text", data: "Mississippi is a state in the United States of America", - options: { metadata: { source: "wikipedia" }} + options: { metadata: { source: "wikipedia" } }, }); const response = await rag.chat("Where is Mississippi?"); @@ -87,6 +132,7 @@ console.log(response.metadata); ``` #### Access the ratelimit details + You can see how much allowance a user has by using the ratelimitDetails hook. ```ts @@ -99,6 +145,7 @@ await ragChat.chat("You shall not pass", { ``` #### Access the output during streaming + You can access, read, or modify your streamed data. ```ts @@ -118,32 +165,32 @@ await ragChat.chat("", { #### Store metadata in the chat history and access context ```ts -let messages: UpstashMessage[] = [] -let context: PrepareChatResult = [] +let messages: UpstashMessage[] = []; +let context: PrepareChatResult = []; const response = await ragChat.chat(question, { onChatHistoryFetched(_messages) { - messages = _messages + messages = _messages; this.metadata = { ...this.metadata, usedHistory: JSON.stringify( messages.map((message) => { - delete message.metadata?.usedHistory - delete message.metadata?.usedContext - return message + delete message.metadata?.usedHistory; + delete message.metadata?.usedContext; + return message; }) ), - } - return _messages + }; + return _messages; }, onContextFetched(_context) { - context = _context - this.metadata = { ...this.metadata, usedContext: context.map((x) => x.data.replace("-", "")) } - return _context + context = _context; + this.metadata = { ...this.metadata, usedContext: context.map((x) => x.data.replace("-", "")) }; + return _context; }, streaming: true, metadata: { modelNameWithProvider: `${LLM_MODELS[llmModel].provider}_${llmModel}`, }, -}) +}); ```