diff --git a/src/leettools/chat/_impl/duckdb/history_manager_duckdb.py b/src/leettools/chat/_impl/duckdb/history_manager_duckdb.py index c43ae0e..10bbf2e 100644 --- a/src/leettools/chat/_impl/duckdb/history_manager_duckdb.py +++ b/src/leettools/chat/_impl/duckdb/history_manager_duckdb.py @@ -230,6 +230,7 @@ def _dict_to_chat_history(self, chat_dict: Dict[str, Any]) -> ChatHistory: kb_id=chat_dict[ChatHistory.FIELD_KB_ID], creator_id=chat_dict[ChatHistory.FIELD_CREATOR_ID], article_type=ArticleType(chat_dict[ChatHistory.FIELD_ARTICLE_TYPE]), + flow_type=chat_dict[ChatHistory.FIELD_FLOW_TYPE], description=chat_dict[ChatHistory.FIELD_DESCRIPTION], share_to_public=chat_dict[ChatHistory.FIELD_SHARE_TO_PUBLIC], org_id=chat_dict[ChatHistory.FIELD_ORG_ID], @@ -545,16 +546,53 @@ def get_ch_entry(self, username: str, chat_id: str) -> Optional[ChatHistory]: return None return self._dict_to_chat_history(rtn_dict) - def get_ch_entries_by_username(self, username: str) -> List[ChatHistory]: + def get_ch_entries_by_username( + self, + username: str, + org: Optional[Org] = None, + kb: Optional[KnowledgeBase] = None, + article_type: Optional[ArticleType] = None, + flow_type: Optional[str] = None, + ) -> List[ChatHistory]: """Get all chat history entries for a user.""" table_name = self._get_table_name_for_user(username) - where_clause = f"WHERE {ChatHistory.FIELD_CREATOR_ID} = ? ORDER BY {ChatHistory.FIELD_UPDATED_AT} DESC" - value_list = [username] + query = {ChatHistory.FIELD_CREATOR_ID: username} + if org is not None: + query[ChatHistory.FIELD_ORG_ID] = org.org_id + if kb is not None: + query[ChatHistory.FIELD_KB_ID] = kb.kb_id + if article_type is not None: + query[ChatHistory.FIELD_ARTICLE_TYPE] = article_type.value + if flow_type is not None: + query[ChatHistory.FIELD_FLOW_TYPE] = flow_type + + condition_clause = " AND ".join([f"{k} = ?" for k in query.keys()]) + where_clause = ( + f"WHERE {condition_clause} ORDER BY {ChatHistory.FIELD_UPDATED_AT} DESC" + ) + value_list = list(query.values()) + rtn_dicts = self.duckdb_client.fetch_all_from_table( table_name=table_name, where_clause=where_clause, value_list=value_list, ) + + handle_legacy_date = False + if flow_type is not None and rtn_dicts == []: + query.pop(ChatHistory.FIELD_FLOW_TYPE) + condition_clause = " AND ".join([f"{k} = ?" for k in query.keys()]) + where_clause = ( + f"WHERE {condition_clause} ORDER BY {ChatHistory.FIELD_UPDATED_AT} DESC" + ) + value_list = list(query.values()) + rtn_dicts = self.duckdb_client.fetch_all_from_table( + table_name=table_name, + where_clause=where_clause, + value_list=value_list, + ) + handle_legacy_date = True + rtn_ch_list: List[ChatHistory] = [] for rtn_dict in rtn_dicts: if rtn_dict is None: @@ -562,6 +600,12 @@ def get_ch_entries_by_username(self, username: str) -> List[ChatHistory]: ch = self._dict_to_chat_history(rtn_dict) if ch is None: continue + if handle_legacy_date: + if ch.flow_type is None: + if ch.metadata is not None: + ch.flow_type = ch.metadata.flow_type + if ch.flow_type != flow_type: + continue rtn_ch_list.append(ch) return rtn_ch_list diff --git a/src/leettools/chat/chat_utils.py b/src/leettools/chat/chat_utils.py index aaa7d13..2314ea8 100644 --- a/src/leettools/chat/chat_utils.py +++ b/src/leettools/chat/chat_utils.py @@ -158,6 +158,7 @@ def setup_exec_info( creator_id=user.username, description=f"Created by CLI command for query {query}", article_type=flow.get_article_type(), + flow_type=flow_type, ) ) diff --git a/src/leettools/chat/history_manager.py b/src/leettools/chat/history_manager.py index 2e56f3d..7449a8c 100644 --- a/src/leettools/chat/history_manager.py +++ b/src/leettools/chat/history_manager.py @@ -11,6 +11,7 @@ from leettools.common.logging import EventLogger from leettools.common.singleton_meta import SingletonMeta from leettools.common.utils import content_utils +from leettools.common.utils.deprecatied import deprecated from leettools.context_manager import Context from leettools.core.consts.article_type import ArticleType from leettools.core.schemas.chat_query_item import ChatQueryItem, ChatQueryItemCreate @@ -168,17 +169,34 @@ def delete_ch_entry_item(self, username: str, chat_id: str, query_id: str) -> No @abstractmethod def get_ch_entry(self, username: str, chat_id: str) -> Optional[ChatHistory]: """ - Gets a knowledge base entry by its ID. + Gets a chat history entry by its ID. """ pass @abstractmethod - def get_ch_entries_by_username(self, username: str) -> List[ChatHistory]: + def get_ch_entries_by_username( + self, + username: str, + org: Optional[Org] = None, + kb: Optional[KnowledgeBase] = None, + article_type: Optional[ArticleType] = None, + flow_type: Optional[str] = None, + ) -> List[ChatHistory]: """ - Gets all knowledge base entries given a username + Gets all knowledge base entries given a username. + + - username: The username to get the chat history entries from. + - org: The organization to get the chat history entries from, None means default org. + - kb: The knowledge base to get the chat history entries from, None if all kbs. + - article_type: The article type to filter by. If None, all article types are returned. + - flow_type: The flow type to filter by. If None, all flow types are returned. + + Returns: + A list of chat history entries. """ pass + @deprecated(reason="Use get_ch_entries_by_username instead") @abstractmethod def get_ch_entries_by_username_with_type( self, username: str, article_type: str @@ -188,6 +206,7 @@ def get_ch_entries_by_username_with_type( """ pass + @deprecated(reason="Use get_ch_entries_by_username instead") @abstractmethod def get_ch_entries_by_username_with_type_in_kb( self, diff --git a/src/leettools/chat/schemas/chat_history.py b/src/leettools/chat/schemas/chat_history.py index baa009d..3ae4e65 100644 --- a/src/leettools/chat/schemas/chat_history.py +++ b/src/leettools/chat/schemas/chat_history.py @@ -31,6 +31,7 @@ class CHBase(BaseModel): share_to_public: Optional[bool] = Field( False, description="Whether the chat is shared to the public." ) + flow_type: Optional[str] = Field(None, description="The flow type used in the chat") class CHCreate(CHBase): @@ -94,6 +95,7 @@ def from_ch_create(CHInDB, ch_create: CHCreate) -> "CHInDB": kb_id=ch_create.kb_id, description=ch_create.description, article_type=ch_create.article_type, + flow_type=ch_create.flow_type, chat_id=str(uuid.uuid4()), created_at=ct, updated_at=ct, @@ -118,7 +120,6 @@ class ChatHistory(CHInDB): and etc. """ - # kb_name: Optional[str] = Field( None, description="For adhoc chat, we need to return the kb_name created." ) @@ -150,6 +151,13 @@ def get_history_str(self, ignore_last: bool = False) -> str: def from_ch_in_db(ChatHistory, ch_in_db: CHInDB) -> "ChatHistory": # we need to assignt attributes with non-None values # also complext objects that we do not want to deep-copy + if ch_in_db.flow_type is None: + if ch_in_db.metadata is not None: + flow_type = ch_in_db.metadata.flow_type + else: + flow_type = None + else: + flow_type = ch_in_db.flow_type ch = ChatHistory( name=ch_in_db.name, org_id=ch_in_db.org_id, @@ -157,6 +165,7 @@ def from_ch_in_db(ChatHistory, ch_in_db: CHInDB) -> "ChatHistory": creator_id=ch_in_db.creator_id, article_type=ch_in_db.article_type, share_to_public=ch_in_db.share_to_public, + flow_type=flow_type, queryies=ch_in_db.queries, answers=ch_in_db.answers, metadata=ch_in_db.metadata, @@ -186,6 +195,7 @@ def get_base_columns(cls) -> Dict[str, str]: ChatHistory.FIELD_KB_ID: "VARCHAR", ChatHistory.FIELD_CREATOR_ID: "VARCHAR", ChatHistory.FIELD_ARTICLE_TYPE: "VARCHAR", + ChatHistory.FIELD_FLOW_TYPE: "VARCHAR", ChatHistory.FIELD_DESCRIPTION: "TEXT", ChatHistory.FIELD_SHARE_TO_PUBLIC: "BOOLEAN DEFAULT FALSE", ChatHistory.FIELD_ORG_ID: "VARCHAR", diff --git a/src/leettools/common/utils/deprecatied.py b/src/leettools/common/utils/deprecatied.py new file mode 100644 index 0000000..a871243 --- /dev/null +++ b/src/leettools/common/utils/deprecatied.py @@ -0,0 +1,26 @@ +import functools +import warnings + + +def deprecated(reason: str): + """ + A basic decorator to mark functions as deprecated. + """ + + def decorator(func): + @functools.wraps(func) # Preserves original function metadata + def wrapper(*args, **kwargs): + warnings.warn( + f"{func.__name__}() is deprecated: {reason}", + category=DeprecationWarning, + stacklevel=2, # Points to the caller of the decorated function + ) + return func(*args, **kwargs) + + # Add note to docstring if possible + docstring = func.__doc__ if func.__doc__ else "" + reason_note = f"\n\n.. deprecated::\n {reason}" + wrapper.__doc__ = docstring + reason_note + return wrapper + + return decorator diff --git a/src/leettools/core/user/_impl/duckdb/user_settings_store_duckdb.py b/src/leettools/core/user/_impl/duckdb/user_settings_store_duckdb.py index a1c3867..3fe93e1 100644 --- a/src/leettools/core/user/_impl/duckdb/user_settings_store_duckdb.py +++ b/src/leettools/core/user/_impl/duckdb/user_settings_store_duckdb.py @@ -168,6 +168,7 @@ def _update_settings_for_user( else: cur = self._dict_to_user_settings(result) + # first update the settings with the default values for key, item in default.items(): if key not in cur.settings: if key not in update.settings: @@ -182,6 +183,13 @@ def _update_settings_for_user( # the key already exists and the update does not contain the key pass + # Now update the settings with the new values + for key, item in update.settings.items(): + if key not in cur.settings: + cur.settings[key] = item + else: + cur.settings[key].value = item.value + return self._update_user_settings(cur) def _user_settings_to_dict(self, user_settings: UserSettings) -> Dict[str, Any]: diff --git a/src/leettools/eds/scheduler/_impl/task_scanner_kb.py b/src/leettools/eds/scheduler/_impl/task_scanner_kb.py index 61e9910..fb39b0a 100644 --- a/src/leettools/eds/scheduler/_impl/task_scanner_kb.py +++ b/src/leettools/eds/scheduler/_impl/task_scanner_kb.py @@ -157,7 +157,7 @@ def _process_docsource( f"Found new doc source tasks {len(new_doc_source_tasks)}: {dssig}" ) else: - self.logger.debug(f"No new doc source tasks: {dssig}") + self.logger.noop(f"No new doc source tasks: {dssig}", noop_lvl=3) new_docsink_tasks = [] docsinks = self.docsink_store.get_docsinks_for_docsource(org, kb, docsource) @@ -176,7 +176,7 @@ def _process_docsource( f"Found new docsink tasks {len(new_docsink_tasks)}: {dssig}" ) else: - self.logger.debug(f"No new docsink tasks: {dssig}") + self.logger.noop(f"No new docsink tasks: {dssig}", noop_lvl=3) new_split_tasks = [] documents = self.document_store.get_documents_for_docsource(org, kb, docsource) @@ -192,7 +192,7 @@ def _process_docsource( if new_split_tasks: self.logger.debug(f"Found new split tasks {len(new_split_tasks)}: {dssig}") else: - self.logger.debug(f"No new split tasks: {dssig}") + self.logger.noop(f"No new split tasks: {dssig}", noop_lvl=3) new_embed_tasks = [] for doc in documents: @@ -209,7 +209,7 @@ def _process_docsource( if new_embed_tasks: self.logger.debug(f"Found new embed tasks {len(new_embed_tasks)}: {dssig}") else: - self.logger.debug(f"No new embed tasks: {dssig}") + self.logger.noop(f"No new embed tasks: {dssig}", noop_lvl=3) all_new_tasks = ( new_doc_source_tasks + new_docsink_tasks + new_split_tasks + new_embed_tasks @@ -538,8 +538,9 @@ def _need_to_check_docsource() -> bool: # now the docsource is finished if _docsource_in_cur_tasks(org, kb, docsource): - self.logger.debug( - f"Found finished docsource with unfinished tasks: {dssig}" + self.logger.noop( + f"Found finished docsource with unfinished tasks: {dssig}", + noop_lvl=1, ) return True else: @@ -557,8 +558,9 @@ def _need_to_check_docsource() -> bool: try: all_new_tasks = self._process_docsource(org, kb, docsource) - self.logger.debug( - f"{len(all_new_tasks)} new tasks for docsource: {dssig}" + self.logger.noop( + f"{len(all_new_tasks)} new tasks for docsource: {dssig}", + noop_lvl=2, ) if len(all_new_tasks) > 0: new_tasks += all_new_tasks @@ -568,8 +570,9 @@ def _need_to_check_docsource() -> bool: if not docsource.is_finished(): self._update_docsource_status(org, kb, docsource) else: - self.logger.debug( - f"DocSource is already marked as {docsource.docsource_status}: {dssig}" + self.logger.noop( + f"DocSource is already marked as {docsource.docsource_status}: {dssig}", + noop_lvl=2, ) # last_scan_time is intended to compare the updated_at time of the docsource # but right now the updated_at time is not updated when the status is changed @@ -583,5 +586,5 @@ def _need_to_check_docsource() -> bool: ) end_time = time.perf_counter() elapsed_time = end_time - start_time - self.logger.noop(f"Task scanning took {elapsed_time:.6f} seconds.", noop_lvl=2) + self.logger.noop(f"Task scanning took {elapsed_time:.6f} seconds.", noop_lvl=1) return new_tasks diff --git a/src/leettools/svc/api/v1/routers/chat_router.py b/src/leettools/svc/api/v1/routers/chat_router.py index eaeeda0..d57db67 100644 --- a/src/leettools/svc/api/v1/routers/chat_router.py +++ b/src/leettools/svc/api/v1/routers/chat_router.py @@ -1,3 +1,4 @@ +import asyncio import os import re from typing import List, Optional, Set, Tuple @@ -13,6 +14,7 @@ from leettools.common.logging import logger from leettools.common.logging.log_location import LogLocator from leettools.core.consts import flow_option +from leettools.core.consts.article_type import ArticleType from leettools.core.knowledgebase.kb_manager import get_kb_name_from_query from leettools.core.schemas.chat_query_item import ChatQueryItemCreate from leettools.core.schemas.chat_query_options import ChatQueryOptions @@ -127,6 +129,7 @@ def _setup_query( kb_id=kb.kb_id, creator_id=user.username, article_type=flow.get_article_type(), + flow_type=flow_type, ) ) chat_query_item_create.chat_id = chat_history.chat_id @@ -156,22 +159,66 @@ def __init__(self, *args, **kwargs): } async def read_log_file(file_path: str, full_log: bool): - async with aiofiles.open(file_path, mode="r") as file: - async for line in file: - if full_log: - yield line.encode() - else: - # Make the regex more flexible - match = re.match( - r"^\[(\d{2}/\d{2}/\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\]\s+(\S+)\s+\[(.*?)\]\s+(.*)$", - line, - ) - if match: - log_level = match.group(2) - status_type = match.group(3) - message = match.group(4) - if status_type.lower() in status_filter: - yield line.encode() + """ + Read and stream log file contents until an end marker is encountered or timeout occurs. + + Args: + file_path (str): Path to the log file to read + full_log (bool): Whether to stream the entire log or filter by status + + Yields: + bytes: Encoded log lines + + Notes: + The stream will terminate if either: + - The end marker is encountered + - No updates have been detected for 30 seconds + """ + END_MARKER = "[Status] Query completed" + last_position = 0 + last_update_time = asyncio.get_event_loop().time() + TIMEOUT_SECONDS = 30.0 + + while True: + current_time = asyncio.get_event_loop().time() + if current_time - last_update_time > TIMEOUT_SECONDS: + logger().info( + f"Log streaming timed out after {TIMEOUT_SECONDS} seconds of no updates" + ) + return + + async with aiofiles.open(file_path, mode="r") as file: + await file.seek(last_position) + has_new_content = False + async for line in file: + has_new_content = True + if END_MARKER in line: + return + + if full_log: + yield line.encode() + else: + # Make the regex more flexible + match = re.match( + r"^\[(\d{2}/\d{2}/\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3})\]\s+(\S+)\s+\[(.*?)\]\s+(.*)$", + line, + ) + if match: + log_level = match.group(2) + status_type = match.group(3) + message = match.group(4) + if status_type.lower() in status_filter: + yield line.encode() + + # Remember where we left off + last_position = await file.tell() + + # Update the last update time if we found new content + if has_new_content: + last_update_time = asyncio.get_event_loop().time() + + # Wait a bit before checking for new content + await asyncio.sleep(0.1) @self.get("/stream_logs/{chat_id}/{query_id}") async def stream_log( @@ -239,6 +286,7 @@ async def list_chat_history( @self.get("/articles", response_model=List[ChatHistory]) async def list_articles( article_type: Optional[str] = None, + flow_type: Optional[str] = None, org_name: Optional[str] = None, kb_name: Optional[str] = None, list_only: Optional[bool] = False, @@ -250,6 +298,8 @@ async def list_articles( Args: - article_type: The type of article to retrieve. If not set of set to "" or "all", all types of articles are retrieved. + - flow_type: The type of flow to retrieve. If not set of set to "" or "all", + all types of flows are retrieved. - org_name: The name of the organization to retrieve articles from. - kb_name: The name of the knowledge base to retrieve articles from. - list_only: If True, only return the list of articles without the queries @@ -285,18 +335,26 @@ async def list_articles( detail=f"User {calling_user.username} does not have access to KB {kb_name}", ) - if article_type is None or article_type == "" or article_type == "all": + if ( + article_type is None + or article_type == "" + or article_type.lower() == "all" + ): target_article_type = None else: - target_article_type = article_type + target_article_type = ArticleType(article_type) - chat_history_list = ( - self.chat_manager.get_ch_entries_by_username_with_type_in_kb( - username=calling_user.username, - article_type=target_article_type, - org=org, - kb=kb, - ) + if flow_type is None or flow_type == "" or flow_type.lower() == "all": + target_flow_type = None + else: + target_flow_type = flow_type + + chat_history_list = self.chat_manager.get_ch_entries_by_username( + org=org, + kb=kb, + username=calling_user.username, + article_type=target_article_type, + flow_type=target_flow_type, ) if list_only == True: for ch in chat_history_list: diff --git a/tests/leettools/chat/test_chat_manager.py b/tests/leettools/chat/test_chat_manager.py index 6f0947c..e5830f8 100644 --- a/tests/leettools/chat/test_chat_manager.py +++ b/tests/leettools/chat/test_chat_manager.py @@ -24,6 +24,7 @@ def test_chat_manager(): from leettools.settings import preset_store_types_for_tests for store_types in preset_store_types_for_tests(): + logger().info(f"Testing with store_types: {store_types}") temp_setup = TempSetup() context = temp_setup.context @@ -68,6 +69,7 @@ def _test_function(context: Context, org: Org, kb: KnowledgeBase): kb_id=kb_id, description=test_desc, creator_id=test_user.username, + flow_type="dummy", ) ch1 = chat_manager.add_ch_entry(ch_create) @@ -245,3 +247,58 @@ def _test_function(context: Context, org: Org, kb: KnowledgeBase): break assert found_query == False assert found_answer == False + + # test get_ch_entries_by_username + ch_entries = chat_manager.get_ch_entries_by_username(test_username) + assert len(ch_entries) == 1 + assert ch_entries[0].chat_id == ch1.chat_id + assert ch_entries[0].creator_id == test_user.username + assert ch_entries[0].name == "new_name" + assert ch_entries[0].description == "new_desc" + assert ch_entries[0].org_id == org.org_id + assert ch_entries[0].kb_id == kb_id + assert ch_entries[0].created_at is not None + assert ch_entries[0].updated_at is not None + assert ch_entries[0].flow_type == "dummy" + assert ch_entries[0].article_type == ArticleType.CHAT.value + + ch_entries_by_username_with_type = chat_manager.get_ch_entries_by_username( + test_username, article_type=ArticleType.CHAT + ) + assert len(ch_entries_by_username_with_type) == 1 + assert ch_entries_by_username_with_type[0].chat_id == ch1.chat_id + assert ch_entries_by_username_with_type[0].creator_id == test_user.username + assert ch_entries_by_username_with_type[0].name == "new_name" + assert ch_entries_by_username_with_type[0].description == "new_desc" + + ch_entries_by_username_with_type_in_kb = chat_manager.get_ch_entries_by_username( + test_username, kb=kb + ) + assert len(ch_entries_by_username_with_type_in_kb) == 1 + assert ch_entries_by_username_with_type_in_kb[0].chat_id == ch1.chat_id + assert ch_entries_by_username_with_type_in_kb[0].creator_id == test_user.username + assert ch_entries_by_username_with_type_in_kb[0].name == "new_name" + assert ch_entries_by_username_with_type_in_kb[0].description == "new_desc" + assert ch_entries_by_username_with_type_in_kb[0].org_id == org.org_id + assert ch_entries_by_username_with_type_in_kb[0].kb_id == kb_id + + ch_entries_by_username_with_type_in_kb_with_org = ( + chat_manager.get_ch_entries_by_username(test_username, org=org, kb=kb) + ) + assert len(ch_entries_by_username_with_type_in_kb_with_org) == 1 + assert ch_entries_by_username_with_type_in_kb_with_org[0].chat_id == ch1.chat_id + assert ( + ch_entries_by_username_with_type_in_kb_with_org[0].creator_id + == test_user.username + ) + assert ch_entries_by_username_with_type_in_kb_with_org[0].name == "new_name" + assert ch_entries_by_username_with_type_in_kb_with_org[0].description == "new_desc" + assert ch_entries_by_username_with_type_in_kb_with_org[0].org_id == org.org_id + assert ch_entries_by_username_with_type_in_kb_with_org[0].kb_id == kb_id + + ch_entries_by_username_with_flow_type = chat_manager.get_ch_entries_by_username( + test_username, flow_type="dummy" + ) + assert len(ch_entries_by_username_with_flow_type) == 1 + assert ch_entries_by_username_with_flow_type[0].chat_id == ch1.chat_id + assert ch_entries_by_username_with_flow_type[0].creator_id == test_user.username diff --git a/tests/leettools/core/repo/test_docsinkstore.py b/tests/leettools/core/repo/test_docsinkstore.py index 5769dbd..f7086b8 100644 --- a/tests/leettools/core/repo/test_docsinkstore.py +++ b/tests/leettools/core/repo/test_docsinkstore.py @@ -133,6 +133,7 @@ def _test_function(tmp_path, context: Context, org: Org, kb: KnowledgeBase): docsink_update = DocSinkUpdate( docsink_uuid=docsink1.docsink_uuid, docsource_uuids=[docsource_uuid], + docsource_type=DocSourceType.URL, org_id=org.org_id, kb_id=kb_id, original_doc_uri="http://www.example.com/", diff --git a/tests/leettools/core/repo/test_user_settings_store.py b/tests/leettools/core/repo/test_user_settings_store.py index 319a780..a123ae9 100644 --- a/tests/leettools/core/repo/test_user_settings_store.py +++ b/tests/leettools/core/repo/test_user_settings_store.py @@ -1,3 +1,4 @@ +from leettools.common.logging import logger from leettools.common.temp_setup import TempSetup from leettools.context_manager import Context from leettools.core.schemas.api_provider_config import APIFunction, APIProviderConfig @@ -18,6 +19,8 @@ def test_user_settings_store(): for store_types in preset_store_types_for_tests(): + logger().info(f"Testing with store_types: {store_types}") + temp_setup = TempSetup() context = temp_setup.context context.settings.DOC_STORE_TYPE = store_types["doc_store"] @@ -30,6 +33,7 @@ def test_user_settings_store(): _test_api_config_provider(context, org, kb, user) finally: temp_setup.clear_tmp_org_kb_user(org, kb, user) + logger().info(f"Cleared temp org, kb, user for store_types: {store_types}") def _test_settings_store(context: Context, org: Org, kb: KnowledgeBase, user: User): diff --git a/tests/leettools/svc/test_chat_router.py b/tests/leettools/svc/test_chat_router.py index eb14674..81bbd56 100644 --- a/tests/leettools/svc/test_chat_router.py +++ b/tests/leettools/svc/test_chat_router.py @@ -61,6 +61,7 @@ def _test_router( kb_id=kb.kb_id, creator_id=username, org_id=org.org_id, + flow_type="dummy", ) response = client.post("/", json=chat_create.model_dump(), headers=headers) assert response.status_code == 200 @@ -217,6 +218,7 @@ def _test_router( kb_id=kb.kb_id, creator_id=username, article_type=ArticleType.RESEARCH, + flow_type="dummy", org_id=org.org_id, ) response = client.post("/", json=chat_create2.model_dump(), headers=headers)