diff --git a/Middleware/core/open_ai_api.py b/Middleware/core/open_ai_api.py index ed5e9d8..6e2b315 100644 --- a/Middleware/core/open_ai_api.py +++ b/Middleware/core/open_ai_api.py @@ -1,5 +1,6 @@ import json import time +import uuid from typing import Any, Dict, Union, List from flask import Flask, jsonify, request, Response @@ -152,11 +153,13 @@ def handle_user_prompt(prompt_collection: List[Dict[str, str]], stream: bool) -> :param stream: A boolean indicating whether the response should be streamed. :return: The processed prompt response. """ + request_id = str(uuid.uuid4()) + if not get_custom_workflow_is_active(): prompt = replace_brackets_in_list(prompt_collection) request_routing_service: PromptCategorizer = PromptCategorizer() - return request_routing_service.get_prompt_category(prompt, stream) + return request_routing_service.get_prompt_category(prompt, stream, request_id) else: print("handle_user_prompt workflow exists") workflow_manager: WorkflowManager = WorkflowManager(get_active_custom_workflow_name()) - return workflow_manager.run_workflow(prompt_collection, stream) + return workflow_manager.run_workflow(prompt_collection, request_id, stream=stream) diff --git a/Middleware/exceptions/__init__.py b/Middleware/exceptions/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Middleware/exceptions/early_termination_exception.py b/Middleware/exceptions/early_termination_exception.py new file mode 100644 index 0000000..b3442a2 --- /dev/null +++ b/Middleware/exceptions/early_termination_exception.py @@ -0,0 +1,3 @@ +class EarlyTerminationException(Exception): + def __init__(self, message): + super().__init__(message) diff --git a/Middleware/llmapis/open_ai_llm_chat_completions_api.py b/Middleware/llmapis/open_ai_llm_chat_completions_api.py index d158ab8..bec6e25 100644 --- a/Middleware/llmapis/open_ai_llm_chat_completions_api.py +++ b/Middleware/llmapis/open_ai_llm_chat_completions_api.py @@ -1,5 +1,6 @@ import json import os +import traceback from typing import Any, Dict, Generator, Optional, Union, List import requests @@ -93,7 +94,8 @@ def get_response_from_llm(self, conversation: List[Dict[str, str]]) -> Union[ return result except Exception as e: print("Exception in callApi:", e) - return None + traceback.print_exc() # This prints the stack trace + raise finally: self.is_busy = False @@ -246,6 +248,7 @@ def sse_format(data: str) -> str: except requests.RequestException as e: print(f"Request failed: {e}") + raise return generate_sse_stream() @@ -284,7 +287,8 @@ def invoke_non_streaming(self, messages: List[Dict[str, str]], except requests.exceptions.RequestException as e: print(f"Attempt {attempt + 1} failed with error: {e}") if attempt == retries - 1: - return None + raise except Exception as e: print("Unexpected error:", e) - return None + traceback.print_exc() # This prints the stack trace + raise diff --git a/Middleware/llmapis/open_ai_llm_completions_api.py b/Middleware/llmapis/open_ai_llm_completions_api.py index 73d8ea0..21d8827 100644 --- a/Middleware/llmapis/open_ai_llm_completions_api.py +++ b/Middleware/llmapis/open_ai_llm_completions_api.py @@ -1,5 +1,6 @@ import json import os +import traceback from typing import Any, Dict, Generator, Optional, Union import requests @@ -91,7 +92,8 @@ def get_response_from_llm(self, system_prompt: str, prompt: str) -> Union[ return result except Exception as e: print("Exception in callApi:", e) - return None + traceback.print_exc() # This prints the stack trace + raise finally: self.is_busy = False @@ -280,6 +282,7 @@ def sse_format(data: str) -> str: yield sse_format(json.dumps(completion_data)) except json.JSONDecodeError as e: print(f"Failed to parse JSON: {e}") + traceback.print_exc() # This prints the stack trace continue # Flush remaining buffer @@ -310,9 +313,12 @@ def sse_format(data: str) -> str: yield sse_format(json.dumps(completion_data)) except json.JSONDecodeError as e: print(f"Failed to parse JSON: {e}") + traceback.print_exc() # This prints the stack trace except requests.RequestException as e: print(f"Request failed: {e}") + traceback.print_exc() # This prints the stack trace + raise return generate_sse_stream() @@ -364,8 +370,10 @@ def invoke_non_streaming(self, prompt: str, endpoint: str, model_name: str, return '' except requests.exceptions.RequestException as e: print(f"Attempt {attempt + 1} failed with error: {e}") + traceback.print_exc() # This prints the stack trace if attempt == retries - 1: - return None + raise except Exception as e: print("Unexpected error:", e) - return None + traceback.print_exc() # This prints the stack trace + raise diff --git a/Middleware/services/llm_service.py b/Middleware/services/llm_service.py index 60aecf5..04eb64a 100644 --- a/Middleware/services/llm_service.py +++ b/Middleware/services/llm_service.py @@ -1,3 +1,5 @@ +import traceback + from Middleware.llmapis.open_ai_llm_chat_completions_api import OpenAiLlmChatCompletionsApiService from Middleware.llmapis.open_ai_llm_completions_api import OpenAiLlmCompletionsApiService from Middleware.models.llm_handler import LlmHandler @@ -45,3 +47,5 @@ def load_model_from_config(self, config_name, preset, stream=False, truncate_len return self.initialize_llm_handler(config_file, preset, config_name, stream, truncate_length, max_tokens) except Exception as e: print(f"Error loading model from config: ", e) + traceback.print_exc() # This prints the stack trace + raise diff --git a/Middleware/utilities/instance_utils.py b/Middleware/utilities/instance_utils.py new file mode 100644 index 0000000..c27c18e --- /dev/null +++ b/Middleware/utilities/instance_utils.py @@ -0,0 +1,3 @@ +import uuid + +INSTANCE_ID = str(uuid.uuid4()) diff --git a/Middleware/utilities/prompt_extraction_utils.py b/Middleware/utilities/prompt_extraction_utils.py index 77e5eb6..7bad493 100644 --- a/Middleware/utilities/prompt_extraction_utils.py +++ b/Middleware/utilities/prompt_extraction_utils.py @@ -122,7 +122,7 @@ def remove_discussion_id_tag_from_string(message: str) -> str: Returns: str: The message string with the discussion ID tag removed. """ - pattern = f'{re.escape(discussion_identifiers["discussion_id_start"])}\\d+{re.escape(discussion_identifiers["discussion_id_end"])}' + pattern = f'{re.escape(discussion_identifiers["discussion_id_start"])}.*?{re.escape(discussion_identifiers["discussion_id_end"])}' return re.sub(pattern, '', message) diff --git a/Middleware/utilities/sql_lite_utils.py b/Middleware/utilities/sql_lite_utils.py new file mode 100644 index 0000000..6694414 --- /dev/null +++ b/Middleware/utilities/sql_lite_utils.py @@ -0,0 +1,120 @@ +import os +import sqlite3 +import traceback +from datetime import datetime, timedelta + + +class SqlLiteUtils: + DB_NAME = 'WilmerDb.sqlite' + TABLE_NAME = 'WorkflowLocks' + + @staticmethod + def create_node_lock(wilmer_session_id, workflow_id, workflow_lock_id): + conn = sqlite3.connect(SqlLiteUtils.DB_NAME) + cursor = conn.cursor() + + cursor.execute(f''' + CREATE TABLE IF NOT EXISTS {SqlLiteUtils.TABLE_NAME} ( + Id INTEGER PRIMARY KEY AUTOINCREMENT, + WilmerSessionId NVARCHAR(50), + WorkflowId NVARCHAR(50), + WorkflowLockId NVARCHAR(500), + ExpirationDate DATETIME + ) + ''') + + expiration_date = datetime.now() + timedelta(minutes=10) + + cursor.execute(f''' + INSERT INTO {SqlLiteUtils.TABLE_NAME} + (WilmerSessionId, WorkflowId, WorkflowLockId, ExpirationDate) + VALUES (?, ?, ?, ?) + ''', (wilmer_session_id, workflow_id, workflow_lock_id, expiration_date)) + + conn.commit() + conn.close() + + @staticmethod + def delete_node_locks(wilmer_session_id=None, workflow_id=None, workflow_lock_id=None): + if not os.path.exists(SqlLiteUtils.DB_NAME): + return # DB does not exist, nothing to do + + conn = sqlite3.connect(SqlLiteUtils.DB_NAME) + cursor = conn.cursor() + + try: + # Start building the SQL query + query = f'DELETE FROM {SqlLiteUtils.TABLE_NAME} WHERE 1=1' + params = [] + + # Add conditions based on the provided parameters + if wilmer_session_id is not None: + query += ' AND WilmerSessionId = ?' + params.append(wilmer_session_id) + + if workflow_id is not None: + query += ' AND WorkflowId = ?' + params.append(workflow_id) + + if workflow_lock_id is not None: + query += ' AND WorkflowLockId = ?' + params.append(workflow_lock_id) + + # Execute the query with the accumulated parameters + cursor.execute(query, params) + conn.commit() + + finally: + conn.close() + + @staticmethod + def get_lock(workflow_lock_id): + if not os.path.exists(SqlLiteUtils.DB_NAME): + return False + + conn = sqlite3.connect(SqlLiteUtils.DB_NAME) + cursor = conn.cursor() + + try: + cursor.execute(f''' + SELECT ExpirationDate FROM {SqlLiteUtils.TABLE_NAME} + WHERE WorkflowLockId = ? + ''', (workflow_lock_id,)) + result = cursor.fetchone() + + if result: + expiration_date = datetime.fromisoformat(result[0]) + + if expiration_date < datetime.now(): + SqlLiteUtils.delete_node_locks(workflow_lock_id=workflow_lock_id) + return False + + return True + + except Exception as e: + print(f"Error in get_lock: {e}") + traceback.print_exc() # This prints the stack trace + raise + + finally: + conn.close() + + return False + + @staticmethod + def delete_old_locks(wilmer_session_id): + if not os.path.exists(SqlLiteUtils.DB_NAME): + return # DB does not exist, nothing to do + + conn = sqlite3.connect(SqlLiteUtils.DB_NAME) + cursor = conn.cursor() + + try: + cursor.execute(f''' + DELETE FROM {SqlLiteUtils.TABLE_NAME} + WHERE WilmerSessionId != ? + ''', (wilmer_session_id,)) + + conn.commit() + finally: + conn.close() diff --git a/Middleware/utilities/text_utils.py b/Middleware/utilities/text_utils.py index 8245d2a..72611a6 100644 --- a/Middleware/utilities/text_utils.py +++ b/Middleware/utilities/text_utils.py @@ -368,7 +368,7 @@ def replace_delimiter_in_file(filepath: str, delimit_on: str, delimit_replacer: except FileNotFoundError: print(f"Error: The file at {filepath} was not found.") - return f"Error: The file at {filepath} was not found." + raise except IOError: print(f"Error: An IOError occurred while reading the file at {filepath}.") - return f"Error: An IOError occurred while reading the file at {filepath}." + raise diff --git a/Middleware/workflows/categorization/prompt_categorizer.py b/Middleware/workflows/categorization/prompt_categorizer.py index 225f277..78cc96e 100644 --- a/Middleware/workflows/categorization/prompt_categorizer.py +++ b/Middleware/workflows/categorization/prompt_categorizer.py @@ -11,7 +11,7 @@ class PromptCategorizer: """ @staticmethod - def conversational_method(prompt, stream=False): + def conversational_method(prompt, request_id, discussion_id: str = None, stream=False): """ Run the default conversational workflow. @@ -22,7 +22,9 @@ def conversational_method(prompt, stream=False): Returns: str: The result of the workflow execution. """ - return WorkflowManager(workflow_config_name='_DefaultWorkflow').run_workflow(prompt, stream=stream) + return WorkflowManager(workflow_config_name='_DefaultWorkflow').run_workflow(prompt, request_id, + discussionId=discussion_id, + stream=stream) @staticmethod def _configure_workflow_manager(category_data): @@ -57,10 +59,12 @@ def initialize(self): self._add_category(category, workflow_name, description) except FileNotFoundError: print("Routing configuration file not found.") + raise except json.JSONDecodeError: print("Error decoding JSON from routing configuration file.") + raise - def get_prompt_category(self, prompt, stream): + def get_prompt_category(self, prompt, stream, request_id, discussion_id: str = None): """ Get the category of the prompt and run the appropriate workflow. @@ -71,17 +75,17 @@ def get_prompt_category(self, prompt, stream): Returns: str: The result of the workflow execution. """ - category = self._categorize_request(prompt) + category = self._categorize_request(prompt, request_id) print("Category: ", category) if category in self.categories: print("Response initiated") workflow_name = self.categories[category]['workflow'] workflow = WorkflowManager(workflow_config_name=workflow_name) - return workflow.run_workflow(prompt, stream=stream) + return workflow.run_workflow(prompt, request_id, discussionId=discussion_id, stream=stream) else: print("Default response initiated") - return self.conversational_method(prompt, stream) + return self.conversational_method(prompt, request_id, discussion_id, stream) def _initialize_categories(self): """ @@ -117,7 +121,7 @@ def _match_category(self, processed_input): return key return None - def _categorize_request(self, user_request): + def _categorize_request(self, user_request, request_id): """ Categorize the user's request by running the categorization workflow. @@ -133,7 +137,7 @@ def _categorize_request(self, user_request): attempts = 0 while attempts < 4: - category = workflow_manager.run_workflow(user_request).strip() + category = workflow_manager.run_workflow(user_request, request_id).strip() print("Output from the LLM: " + category) print(self.categories) category = category.translate(str.maketrans('', '', string.punctuation)) diff --git a/Middleware/workflows/managers/workflow_manager.py b/Middleware/workflows/managers/workflow_manager.py index bc1d4b3..518ded4 100644 --- a/Middleware/workflows/managers/workflow_manager.py +++ b/Middleware/workflows/managers/workflow_manager.py @@ -1,16 +1,22 @@ import json import time +import traceback +import uuid from typing import Dict, List +from Middleware.exceptions.early_termination_exception import EarlyTerminationException from Middleware.models.llm_handler import LlmHandler from Middleware.services.llm_service import LlmHandlerService +from Middleware.utilities import instance_utils from Middleware.utilities.config_utils import get_active_conversational_memory_tool_name, \ get_active_recent_memory_tool_name, get_file_memory_tool_name, \ get_chat_template_name, get_discussion_chat_summary_file_path, get_discussion_memory_file_path, get_workflow_path, \ get_chat_summary_tool_workflow_name from Middleware.utilities.file_utils import read_chunks_with_hashes -from Middleware.utilities.prompt_extraction_utils import extract_discussion_id +from Middleware.utilities.instance_utils import INSTANCE_ID +from Middleware.utilities.prompt_extraction_utils import extract_discussion_id, remove_discussion_id_tag from Middleware.utilities.prompt_utils import find_last_matching_memory_hash, extract_text_blocks_from_hashed_chunks +from Middleware.utilities.sql_lite_utils import SqlLiteUtils from Middleware.workflows.managers.workflow_variable_manager import WorkflowVariableManager from Middleware.workflows.processors.prompt_processor import PromptProcessor @@ -21,48 +27,52 @@ class WorkflowManager: """ @staticmethod - def handle_conversation_memory_parser(messages: List[Dict[str, str]] = None): + def handle_conversation_memory_parser(request_id, discussion_id: str, messages: List[Dict[str, str]] = None): """ Initializes and runs a workflow for parsing conversation memory. + :param request_id: The unique ID for this instance of the endpoint call :param messages: List of message dictionaries. :return: The result of the workflow execution. """ workflow_gen = WorkflowManager(workflow_config_name=get_active_conversational_memory_tool_name()) - return workflow_gen.run_workflow(messages) + return workflow_gen.run_workflow(messages, request_id, discussion_id) @staticmethod - def handle_recent_memory_parser(messages: List[Dict[str, str]] = None): + def handle_recent_memory_parser(request_id, discussion_id: str, messages: List[Dict[str, str]] = None): """ Initializes and runs a workflow for parsing recent chat memory. + :param request_id: The unique ID for this instance of the endpoint call :param messages: List of message dictionaries. :return: The result of the workflow execution. """ workflow_gen = WorkflowManager(workflow_config_name=get_active_recent_memory_tool_name()) - return workflow_gen.run_workflow(messages) + return workflow_gen.run_workflow(messages, request_id, discussion_id) @staticmethod - def handle_full_chat_summary_parser(messages: List[Dict[str, str]] = None): + def handle_full_chat_summary_parser(request_id, discussion_id: str, messages: List[Dict[str, str]] = None): """ Initializes and runs a workflow for parsing a full chat summary. + :param request_id: The unique ID for this instance of the endpoint call :param messages: List of message dictionaries. :return: The result of the workflow execution. """ workflow_gen = WorkflowManager(workflow_config_name=get_chat_summary_tool_workflow_name()) - return workflow_gen.run_workflow(messages) + return workflow_gen.run_workflow(messages, request_id, discussion_id) @staticmethod - def process_file_memories(messages: List[Dict[str, str]] = None): + def process_file_memories(request_id, discussion_id: str, messages: List[Dict[str, str]] = None): """ Initializes and runs a workflow for processing memories from files. + :param request_id: The unique ID for this instance of the endpoint call :param messages: List of message dictionaries. :return: The result of the workflow execution. """ workflow_gen = WorkflowManager(workflow_config_name=get_file_memory_tool_name()) - return workflow_gen.run_workflow(messages) + return workflow_gen.run_workflow(messages, request_id, discussion_id) def __init__(self, workflow_config_name, **kwargs): """ @@ -81,56 +91,91 @@ def __init__(self, workflow_config_name, **kwargs): if 'lookbackStartTurn' in kwargs: self.lookbackStartTurn = kwargs['lookbackStartTurn'] - def run_workflow(self, user_prompt, stream: bool = False): + def run_workflow(self, messages, request_id, discussionId: str = None, stream: bool = False): """ Executes the workflow based on the configuration file. - :param user_prompt: The user's prompt to be processed by the workflow. + :param request_id: Request ID unique to the endpoint call + :param messages: The user's prompt to be processed by the workflow. :param stream: A flag indicating whether the workflow should be executed in streaming mode. :return: The result of the workflow execution. """ - start_time = time.perf_counter() - config_file = get_workflow_path(self.workflowConfigName) - - with open(config_file) as f: - configs = json.load(f) - - def gen(): - returned_to_user = False - agent_outputs = {} - for idx, config in enumerate(configs): - print(f'------Workflow {self.workflowConfigName}; ' + - f'step {idx}; node type: {config.get("type", "Standard")}') - if not returned_to_user and (config.get('returnToUser', False) or idx == len(configs) - 1): - returned_to_user = True - result = self._process_section(config, user_prompt, agent_outputs, stream=stream) - if stream: - text_chunks = [] - for chunk in result: - if chunk.strip() != '[DONE]' and chunk.strip() != 'data: [DONE]': - text_chunks.append(json.loads(chunk.removeprefix('data:'))['choices'][0]['text']) - yield chunk - else: - yield chunk - result = ''.join(text_chunks) - else: - yield result - agent_outputs[f'agent{idx + 1}Output'] = result - else: - agent_outputs[f'agent{idx + 1}Output'] = self._process_section(config, user_prompt, agent_outputs) - - end_time = time.perf_counter() - execution_time = end_time - start_time - print(f"Execution time: {execution_time} seconds") - - if stream: - return gen() + workflow_id = str(uuid.uuid4()) + if (discussionId is None): + discussion_id = extract_discussion_id(messages) else: - exhaust_generator = [x for x in gen()] - assert len(exhaust_generator) == 1 - return exhaust_generator[0] - - def _process_section(self, config: Dict, messages: List[Dict[str, str]] = None, agent_outputs: Dict = None, + discussion_id = discussionId + + remove_discussion_id_tag(messages) + try: + start_time = time.perf_counter() + config_file = get_workflow_path(self.workflowConfigName) + + with open(config_file) as f: + configs = json.load(f) + + def gen(): + returned_to_user = False + agent_outputs = {} + try: + for idx, config in enumerate(configs): + print(f'------Workflow {self.workflowConfigName}; ' + + f'step {idx}; node type: {config.get("type", "Standard")}') + if not returned_to_user and (config.get('returnToUser', False) or idx == len(configs) - 1): + returned_to_user = True + result = self._process_section(config, request_id, workflow_id, discussion_id, messages, + agent_outputs, + stream=stream) + if stream: + text_chunks = [] + for chunk in result: + if chunk.strip() != '[DONE]' and chunk.strip() != 'data: [DONE]': + text_chunks.append( + json.loads(chunk.removeprefix('data:'))['choices'][0]['text']) + yield chunk + else: + yield chunk + result = ''.join(text_chunks) + else: + yield result + agent_outputs[f'agent{idx + 1}Output'] = result + else: + agent_outputs[f'agent{idx + 1}Output'] = self._process_section(config, request_id, + workflow_id, + discussion_id, + messages, + agent_outputs) + except EarlyTerminationException: + print(f"Unlocking locks for InstanceID: '{INSTANCE_ID}' and workflow ID: '{workflow_id}'") + SqlLiteUtils.delete_node_locks(instance_utils.INSTANCE_ID, workflow_id) + raise + + end_time = time.perf_counter() + execution_time = end_time - start_time + print(f"Execution time: {execution_time} seconds") + + print(f"Unlocking locks for InstanceID: '{INSTANCE_ID}' and workflow ID: '{workflow_id}'") + SqlLiteUtils.delete_node_locks(instance_utils.INSTANCE_ID, workflow_id) + + if stream: + return gen() + else: + exhaust_generator = [x for x in gen()] + assert len(exhaust_generator) == 1 + return exhaust_generator[0] + except EarlyTerminationException: + print(f"Unlocking locks for InstanceID: '{INSTANCE_ID}' and workflow ID: '{workflow_id}'") + SqlLiteUtils.delete_node_locks(instance_utils.INSTANCE_ID, workflow_id) + raise + except Exception as e: + print("An error occurred while processing the workflow: ", e) + traceback.print_exc() # This prints the stack trace + print(f"Unlocking locks for InstanceID: '{INSTANCE_ID}' and workflow ID: '{workflow_id}'") + SqlLiteUtils.delete_node_locks(instance_utils.INSTANCE_ID, workflow_id) + + def _process_section(self, config: Dict, request_id, workflow_id, discussion_id: str, + messages: List[Dict[str, str]] = None, + agent_outputs: Dict = None, stream: bool = False): """ Processes a single section of the workflow configuration. @@ -170,56 +215,60 @@ def _process_section(self, config: Dict, messages: List[Dict[str, str]] = None, return prompt_processor_service.handle_conversation_type_node(config, messages, agent_outputs) if config["type"] == "ConversationMemory": print("Conversation Memory") - return self.handle_conversation_memory_parser(messages) + return self.handle_conversation_memory_parser(request_id, discussion_id, messages) if config["type"] == "FullChatSummary": print("Entering full chat summary") - return self.handle_full_chat_summary(messages, config, prompt_processor_service) + return self.handle_full_chat_summary(messages, config, prompt_processor_service, request_id, discussion_id) if config["type"] == "RecentMemory": print("RecentMemory") - discussion_id = extract_discussion_id(messages) if discussion_id is not None: prompt_processor_service.handle_memory_file(discussion_id, messages) - return self.handle_recent_memory_parser(messages) + return self.handle_recent_memory_parser(request_id, discussion_id, messages) if config["type"] == "ConversationalKeywordSearchPerformerTool": print("Conversational Keyword Search Performer") return prompt_processor_service.perform_keyword_search(config, messages, + discussion_id, agent_outputs, config["lookbackStartTurn"]) if config["type"] == "MemoryKeywordSearchPerformerTool": print("Memory Keyword Search Performer") return prompt_processor_service.perform_keyword_search(config, messages, + discussion_id, agent_outputs) if config["type"] == "RecentMemorySummarizerTool": print("Recent memory summarization tool") return prompt_processor_service.gather_recent_memories(messages, + discussion_id, config["maxTurnsToPull"], config["maxSummaryChunksFromFile"]) if config["type"] == "ChatSummaryMemoryGatheringTool": print("Chat summary memory gathering tool") return prompt_processor_service.gather_chat_summary_memories(messages, + discussion_id, config["maxTurnsToPull"], config["maxSummaryChunksFromFile"]) if config["type"] == "GetCurrentSummaryFromFile": print("Getting current summary from File") - return self.handle_get_current_summary_from_file(messages) + return self.handle_get_current_summary_from_file(discussion_id) if config["type"] == "GetCurrentMemoryFromFile": print("Getting current memories from File") - return self.handle_get_current_summary_from_file(messages) + return self.handle_get_current_summary_from_file(discussion_id) if config["type"] == "WriteCurrentSummaryToFileAndReturnIt": print("Writing current summary to file") return prompt_processor_service.save_summary_to_file(config, messages, + discussion_id, agent_outputs) if config["type"] == "SlowButQualityRAG": print("SlowButQualityRAG") return prompt_processor_service.perform_slow_but_quality_rag(config, messages, agent_outputs) if config["type"] == "QualityMemory": print("Quality memory") - return self.handle_quality_memory_workflow(messages, prompt_processor_service) + return self.handle_quality_memory_workflow(request_id, messages, prompt_processor_service, discussion_id) if config["type"] == "PythonModule": print("Python Module") return self.handle_python_module(config, prompt_processor_service, messages, agent_outputs) @@ -230,6 +279,26 @@ def _process_section(self, config: Dict, messages: List[Dict[str, str]] = None, print("Offline Wikipedia Api Summary Only") return prompt_processor_service.handle_offline_wiki_node(messages, config["promptToSearch"], agent_outputs, False) + if config["type"] == "WorkflowLock": + print("Workflow Lock") + + workflow_lock_id = config.get("workflowLockId") + if not workflow_lock_id: + raise ValueError("A WorkflowLock node must have a 'workflowLockId'.") + + # Check for an existing lock + lock_exists = SqlLiteUtils.get_lock(workflow_lock_id) + + if lock_exists: + # Lock exists and is still valid, throw an early termination exception + print(f"Lock for {workflow_lock_id} is currently active, terminating workflow.") + raise EarlyTerminationException(f"Workflow is locked by {workflow_lock_id}. Please try again later.") + else: + # No lock or expired lock, create a new one + SqlLiteUtils.create_node_lock(INSTANCE_ID, workflow_id, workflow_lock_id) + print( + f"Lock for Instance_ID: '{INSTANCE_ID}' and workflow_id '{workflow_id}' and workflow_lock_id: '" + f"{workflow_lock_id}' has been acquired.") def handle_python_module(self, config, prompt_processor_service, messages, agent_outputs): """ @@ -252,20 +321,22 @@ def handle_python_module(self, config, prompt_processor_service, messages, agent return prompt_processor_service.handle_python_module(config, messages, config["module_path"], agent_outputs, *args, **kwargs) - def handle_full_chat_summary(self, messages, config, prompt_processor_service): + def handle_full_chat_summary(self, messages, config, prompt_processor_service, request_id, discussion_id): """ Handles the workflow for generating a full chat summary. :param messages: List of message dictionaries. :param config: The configuration dictionary for the full chat summary workflow. :param prompt_processor_service: An instance of PromptProcessor service to handle prompt processing. + :param request_id: The request ID unique to the endpoint call + :param discussion_id: The discussion id pulled from the prompt for summaries and chats :return: The result of the full chat summary workflow execution. """ - discussion_id = extract_discussion_id(messages) - + print("CHeckingpoint1: ") + print("Discussion ID: ", discussion_id) if discussion_id is not None: print("Full chat summary discussion id is not none") - if hasattr(config, "isManualConfig") and config["isManualConfig"] == True: + if hasattr(config, "isManualConfig") and config["isManualConfig"]: print("Manual summary flow") filepath = get_discussion_chat_summary_file_path(discussion_id) summary_chunk = read_chunks_with_hashes(filepath) @@ -293,36 +364,37 @@ def handle_full_chat_summary(self, messages, config, prompt_processor_service): print("Number of memory chunks since last summary update: " + str(index)) if index > 1 or index < 0: - return self.handle_full_chat_summary_parser(messages) + return self.handle_full_chat_summary_parser(request_id, discussion_id, messages) else: return extract_text_blocks_from_hashed_chunks(hashed_summary_chunk) - def handle_quality_memory_workflow(self, messages: List[Dict[str, str]], prompt_processor_service): + def handle_quality_memory_workflow(self, request_id, messages: List[Dict[str, str]], prompt_processor_service, + discussion_id): """ Handles the workflow for processing quality memory. :param messages: List of message dictionaries. :param prompt_processor_service: An instance of PromptProcessor service to handle prompt processing. + :param request_id: The request ID unique to the endpoint call + :param discussion_id: The discussion id pulled from the prompt for summaries :return: The result of the quality memory workflow execution. """ - discussion_id = extract_discussion_id(messages) if discussion_id is None: - print("Quality memory discussionid is none") - return self.handle_recent_memory_parser(messages) + print("Quality memory discussion_id is none") + return self.handle_recent_memory_parser(request_id, discussion_id, messages) else: print("Quality memory discussion_id flow") prompt_processor_service.handle_memory_file(discussion_id, messages) - return self.process_file_memories(messages) + return self.process_file_memories(request_id, discussion_id, messages) - def handle_get_current_summary_from_file(self, messages): + def handle_get_current_summary_from_file(self, discussion_id: str): """ Retrieves the current summary from a file based on the user's prompt. - :param messages: List of message dictionaries. + :param discussion_id: Discussion id used for memories and chat summary :return: The current summary extracted from the file or a message indicating the absence of a summary file. """ - discussion_id = extract_discussion_id(messages) filepath = get_discussion_chat_summary_file_path(discussion_id) current_summary = read_chunks_with_hashes(filepath) @@ -332,14 +404,13 @@ def handle_get_current_summary_from_file(self, messages): return extract_text_blocks_from_hashed_chunks(current_summary) - def handle_get_current_memories_from_file(self, messages): + def handle_get_current_memories_from_file(self, discussion_id): """ Retrieves the current summary from a file based on the user's prompt. - :param messages: List of message dictionaries. + :param discussion_id: Discussion id used for memories and chat summary :return: The current summary extracted from the file or a message indicating the absence of a summary file. """ - discussion_id = extract_discussion_id(messages) filepath = get_discussion_memory_file_path(discussion_id) current_memories = read_chunks_with_hashes(filepath) diff --git a/Middleware/workflows/processors/prompt_processor.py b/Middleware/workflows/processors/prompt_processor.py index cd7fd04..0fc6739 100644 --- a/Middleware/workflows/processors/prompt_processor.py +++ b/Middleware/workflows/processors/prompt_processor.py @@ -1,11 +1,11 @@ +import traceback from copy import deepcopy from typing import Dict, Any, Optional, List from Middleware.utilities.automation_utils import run_dynamic_module from Middleware.utilities.config_utils import get_discussion_memory_file_path, get_discussion_chat_summary_file_path from Middleware.utilities.file_utils import read_chunks_with_hashes, update_chunks_with_hashes -from Middleware.utilities.prompt_extraction_utils import extract_discussion_id, extract_last_n_turns, \ - remove_discussion_id_tag +from Middleware.utilities.prompt_extraction_utils import extract_last_n_turns from Middleware.utilities.prompt_template_utils import format_user_turn_with_template, \ add_assistant_end_token_to_user_turn, format_system_prompt_with_template, get_formatted_last_n_turns_as_string from Middleware.workflows.tools.offline_wikipedia_api_tool import OfflineWikiApiClient @@ -66,7 +66,8 @@ def perform_slow_but_quality_rag(self, config: Dict, messages: List[Dict[str, st return self.slow_but_quality_rag_service.perform_rag_on_conversation_chunk(system_prompt, prompt, rag_target, config) - def perform_keyword_search(self, config: Dict, messages: List[Dict[str, str]], agent_outputs: Optional[Dict] = None, + def perform_keyword_search(self, config: Dict, messages: List[Dict[str, str]], discussion_id: str, + agent_outputs: Optional[Dict] = None, lookbackStartTurn: int = 0) -> Any: """ Performs a keyword search within the conversation or recent memories based on the provided configuration. @@ -89,17 +90,17 @@ def perform_keyword_search(self, config: Dict, messages: List[Dict[str, str]], a print("Performing search on Current Conversation") return self.slow_but_quality_rag_service.perform_keyword_search( keywords, "CurrentConversation", messages=messages, lookbackStartTurn=lookbackStartTurn, - llm_handler=self.llm_handler + llm_handler=self.llm_handler, discussion_id=discussion_id ) if config["searchTarget"] == "RecentMemories": print("Performing search on Recent Memories") return self.slow_but_quality_rag_service.perform_keyword_search( keywords, "RecentMemories", messages=messages, lookbackStartTurn=lookbackStartTurn, - llm_handler=self.llm_handler + llm_handler=self.llm_handler, discussion_id=discussion_id ) - def save_summary_to_file(self, config: Dict, messages: List[Dict[str, str]], + def save_summary_to_file(self, config: Dict, messages: List[Dict[str, str]], discussion_id: str, agent_outputs: Optional[Dict] = None) -> Exception | Any: """ Saves a chat summary to a file after processing the user prompt and applying variables. @@ -114,8 +115,6 @@ def save_summary_to_file(self, config: Dict, messages: List[Dict[str, str]], else: return Exception("No summary found") - discussion_id = extract_discussion_id(messages) - # The summary is coming from a previous agent, so we need those summary = self.workflow_variable_service.apply_variables(summary, self.llm_handler, messages, agent_outputs) @@ -140,7 +139,7 @@ def save_summary_to_file(self, config: Dict, messages: List[Dict[str, str]], return summary - def gather_recent_memories(self, messages: List[Dict[str, str]], max_turns_to_pull=0, + def gather_recent_memories(self, messages: List[Dict[str, str]], discussion_id: str, max_turns_to_pull=0, max_summary_chunks_from_file=0) -> Any: """ Gathers recent memories from the conversation based on the specified limits. @@ -153,10 +152,12 @@ def gather_recent_memories(self, messages: List[Dict[str, str]], max_turns_to_pu return self.slow_but_quality_rag_service.get_recent_memories( messages=messages, max_turns_to_search=max_turns_to_pull, - max_summary_chunks_from_file=max_summary_chunks_from_file + max_summary_chunks_from_file=max_summary_chunks_from_file, + discussion_id=discussion_id ) - def gather_chat_summary_memories(self, messages: List[Dict[str, str]], max_turns_to_pull: int = 0, + def gather_chat_summary_memories(self, messages: List[Dict[str, str]], discussion_id: str, + max_turns_to_pull: int = 0, max_summary_chunks_from_file: int = 0): """ Gathers chat summary memories from the conversation based on the specified limits. @@ -168,6 +169,7 @@ def gather_chat_summary_memories(self, messages: List[Dict[str, str]], max_turns """ return self.slow_but_quality_rag_service.get_chat_summary_memories( messages=messages, + discussion_id=discussion_id, max_turns_to_search=max_turns_to_pull, max_summary_chunks_from_file=max_summary_chunks_from_file ) @@ -193,7 +195,6 @@ def handle_conversation_type_node(self, config: Dict, messages: List[Dict[str, s :return: The response from the LLM. """ message_copy = deepcopy(messages) - remove_discussion_id_tag(message_copy) if not self.llm_handler.takes_message_collection: # Current logic for building system_prompt and prompt @@ -287,7 +288,6 @@ def handle_python_module(self, config: Dict, messages: List[Dict[str, str]], mod :return: The result of the dynamic module execution. """ message_copy = deepcopy(messages) - remove_discussion_id_tag(message_copy) modified_args = list(args) # Convert tuple to list to allow modifications for i, arg in enumerate(modified_args): @@ -300,6 +300,8 @@ def handle_python_module(self, config: Dict, messages: List[Dict[str, str]], mod ) except Exception as e: print(f"Arg could not have variable applied. Exception: {e}") + traceback.print_exc() # This prints the stack trace + raise new_args = tuple(modified_args) for key, value in kwargs.items(): @@ -318,7 +320,6 @@ def handle_offline_wiki_node(self, messages: List[Dict[str, str]], prompt, agent_outputs: [Dict], get_full_article: bool = True) -> Any: message_copy = deepcopy(messages) - remove_discussion_id_tag(message_copy) variabled_prompt = self.workflow_variable_service.apply_variables( prompt=str(prompt), diff --git a/Middleware/workflows/tools/parallel_llm_processing_tool.py b/Middleware/workflows/tools/parallel_llm_processing_tool.py index 5d685cf..34f5f68 100644 --- a/Middleware/workflows/tools/parallel_llm_processing_tool.py +++ b/Middleware/workflows/tools/parallel_llm_processing_tool.py @@ -1,3 +1,4 @@ +import traceback from queue import Queue, Empty from threading import Thread @@ -112,6 +113,8 @@ def chunk_processing_worker(self, handler, chunks_queue, workflow_prompt, workfl except Exception as e: print(f"Error processing chunk at index {index} by handler for model " f"{handler.prompt_template_file_name}: {str(e)}") + traceback.print_exc() # This prints the stack trace + raise @staticmethod def process_single_chunk(chunk, index, llm_handler, workflow_prompt, workflow_system_prompt, results_queue, diff --git a/Middleware/workflows/tools/slow_but_quality_rag_tool.py b/Middleware/workflows/tools/slow_but_quality_rag_tool.py index c2d0f05..767ca11 100644 --- a/Middleware/workflows/tools/slow_but_quality_rag_tool.py +++ b/Middleware/workflows/tools/slow_but_quality_rag_tool.py @@ -6,7 +6,7 @@ get_discussion_chat_summary_file_path, get_discussion_id_workflow_path, get_endpoint_config from Middleware.utilities.file_utils import read_chunks_with_hashes, \ update_chunks_with_hashes -from Middleware.utilities.prompt_extraction_utils import extract_discussion_id, extract_last_n_turns, \ +from Middleware.utilities.prompt_extraction_utils import extract_last_n_turns, \ remove_discussion_id_tag_from_string from Middleware.utilities.prompt_template_utils import format_user_turn_with_template, \ format_system_prompt_with_template, add_assistant_end_token_to_user_turn @@ -27,7 +27,7 @@ class SlowButQualityRAGTool: def __init__(self): pass - def perform_keyword_search(self, keywords: str, target, llm_handler, **kwargs): + def perform_keyword_search(self, keywords: str, target, llm_handler, discussion_id, **kwargs): """ :param keywords: A string representing the keywords to search for. :param target: The target object to perform the keyword search on. @@ -51,7 +51,7 @@ def perform_keyword_search(self, keywords: str, target, llm_handler, **kwargs): messages = kwargs['messages'] print("In recent memories") print(messages) - result = self.perform_memory_file_keyword_search(keywords, messages, llm_handler) + result = self.perform_memory_file_keyword_search(keywords, messages, llm_handler, discussion_id) return result @staticmethod @@ -80,13 +80,13 @@ def clear_out_user_assistant_from_chunks(search_result_chunks): new_chunks.append(chunk) return new_chunks - def perform_conversation_search(self, keywords: str, messages, llm_handler, lookbackStartTurn=0): + def perform_conversation_search(self, keywords: str, messagesOriginal, llm_handler, lookbackStartTurn=0): """ Perform a conversation search based on given keywords and user prompt. Args: keywords (str): A string containing keywords to search for. - messages (list): A collection representing the user's prompt for the conversation search. + messagesOriginal (list): A collection representing the user's prompt for the conversation search. lookbackStartTurn (int, optional): How many turns back from the most recent to begin our search. Defaults to 0. Returns: @@ -95,14 +95,16 @@ def perform_conversation_search(self, keywords: str, messages, llm_handler, look print("Entering perform_conversation_search") # If we have fewer pairs than lookbackStartTurn, we can stop here - if len(messages) <= lookbackStartTurn: + if len(messagesOriginal) <= lookbackStartTurn: return 'There are no memories. This conversation has not gone long enough for there to be memories.' - pair_chunks = self.get_message_chunks(messages, lookbackStartTurn, 400) + message_copy = deepcopy(messagesOriginal) + + pair_chunks = self.get_message_chunks(message_copy, lookbackStartTurn, 400) # In case the LLM designated the speakers as keywords, we want to remove them # The speakers would trigger tons of erroneous hits - last_n_turns = extract_last_n_turns(messages, 10, llm_handler.takes_message_collection) + last_n_turns = extract_last_n_turns(message_copy, 10, llm_handler.takes_message_collection) keywords = filter_keywords_by_speakers(last_n_turns, keywords) print("Keywords: " + str(keywords)) @@ -116,21 +118,22 @@ def perform_conversation_search(self, keywords: str, messages, llm_handler, look return '--ChunkBreak--'.join(filtered_chunks) - def perform_memory_file_keyword_search(self, keywords: str, messages, llm_handler): + def perform_memory_file_keyword_search(self, keywords: str, messagesOriginal, llm_handler, discussion_id): """ Perform a memory file keyword search based on given keywords and user prompt. Args: keywords (str): A string containing keywords to search for. - messages (list): A collection representing the user's prompt for the conversation search. + messagesOriginal (list): A collection representing the user's prompt for the conversation search. Returns: str: A string representing the search result chunks joined by '--ChunkBreak--'. """ print("Entering perform_memory_file_keyword_search") - discussion_id = extract_discussion_id(messages) filepath = get_discussion_memory_file_path(discussion_id) + message_copy = deepcopy(messagesOriginal) + hash_chunks = read_chunks_with_hashes(filepath) pair_chunks = extract_text_blocks_from_hashed_chunks(hash_chunks) @@ -139,7 +142,7 @@ def perform_memory_file_keyword_search(self, keywords: str, messages, llm_handle # In case the LLM designated the speakers as keywords, we want to remove them # The speakers would trigger tons of erroneous hits - last_n_turns = extract_last_n_turns(messages, 10, llm_handler.takes_message_collection) + last_n_turns = extract_last_n_turns(message_copy, 10, llm_handler.takes_message_collection) keywords = filter_keywords_by_speakers(last_n_turns, keywords) print("Keywords: " + str(keywords)) @@ -175,7 +178,7 @@ def process_new_memory_chunks(self, chunks, hash_chunks, rag_system_prompt, rag_ print("Processing chunks: ", all_chunks) result = rag_tool.perform_rag_on_memory_chunk(rag_system_prompt, rag_prompt, all_chunks, workflow, - messages, + messages, discussionId, "--rag_break--") results = result.split("--rag_break--") print("Total results: " + str(len(results))) @@ -191,7 +194,7 @@ def process_new_memory_chunks(self, chunks, hash_chunks, rag_system_prompt, rag_ # Save to file update_chunks_with_hashes(replaced, filepath) - def get_recent_memories(self, messages: List[Dict[str, str]], max_turns_to_search=0, + def get_recent_memories(self, messages: List[Dict[str, str]], discussion_id: str, max_turns_to_search=0, max_summary_chunks_from_file=0) -> str: """ Retrieves recent memories from chat messages or memory files. @@ -205,7 +208,6 @@ def get_recent_memories(self, messages: List[Dict[str, str]], max_turns_to_searc str: The recent memories concatenated as a single string with '--ChunkBreak--' delimiter. """ print("Entered get_recent_memories") - discussion_id = extract_discussion_id(messages) if discussion_id is None: final_pairs = self.get_recent_chat_messages_up_to_max(max_turns_to_search, messages) @@ -229,7 +231,7 @@ def get_recent_memories(self, messages: List[Dict[str, str]], max_turns_to_searc latest_summaries = chunks[-max_summary_chunks_from_file:] return '--ChunkBreak--'.join(latest_summaries) - def get_chat_summary_memories(self, messages: List[Dict[str, str]], max_turns_to_search=0, + def get_chat_summary_memories(self, messages: List[Dict[str, str]], discussion_id: str, max_turns_to_search=0, max_summary_chunks_from_file=0): """ Retrieves chat summary memories from messages or memory files. @@ -243,7 +245,6 @@ def get_chat_summary_memories(self, messages: List[Dict[str, str]], max_turns_to str: The chat summary memories concatenated as a single string with '--ChunkBreak--' delimiter. """ print("Entered get_chat_summary_memories") - discussion_id = extract_discussion_id(messages) if discussion_id is None: final_pairs = self.get_recent_chat_messages_up_to_max(max_turns_to_search, messages) @@ -307,7 +308,7 @@ def get_recent_chat_messages_up_to_max(self, max_turns_to_search: int, messages: return final_pairs - def handle_discussion_id_flow(self, discussionId: str, messages: List[Dict[str, str]]) -> None: + def handle_discussion_id_flow(self, discussionId: str, messagesOriginal: List[Dict[str, str]]) -> None: """ Handle the discussion flow based on the discussion ID and messages provided. @@ -317,10 +318,12 @@ def handle_discussion_id_flow(self, discussionId: str, messages: List[Dict[str, Args: discussionId (str): The unique identifier for the discussion. - messages (List[Dict[str, str]]): The list of message dictionaries for the discussion. + messagesOriginal (List[Dict[str, str]]): The list of message dictionaries for the discussion. """ filepath = get_discussion_memory_file_path(discussionId) + messages_copy = deepcopy(messagesOriginal) + print("Entering discussionId Workflow") discussion_id_workflow_filepath = get_discussion_id_workflow_path() discussion_id_workflow_config = load_config(discussion_id_workflow_filepath) @@ -336,13 +339,14 @@ def handle_discussion_id_flow(self, discussionId: str, messages: List[Dict[str, if len(discussion_chunks) == 0: print("No discussion chunks") - self.process_full_discussion_flow(messages, rag_system_prompt, rag_prompt, discussion_id_workflow_config, + self.process_full_discussion_flow(messages_copy, rag_system_prompt, rag_prompt, + discussion_id_workflow_config, discussionId) else: - index = find_last_matching_hash_message(messages, discussion_chunks) + index = find_last_matching_hash_message(messages_copy, discussion_chunks) print("Number of messages since last memory chunk update: ", index) if index > chunks_til_new_memory: - trimmed_discussion_pairs = extract_last_n_turns(messages, index, remove_all_systems_override=True) + trimmed_discussion_pairs = extract_last_n_turns(messages_copy, index, remove_all_systems_override=True) trimmed_discussion_pairs.reverse() print("Trimmed discussion message length: ", len(trimmed_discussion_pairs)) print(trimmed_discussion_pairs) @@ -353,10 +357,11 @@ def handle_discussion_id_flow(self, discussionId: str, messages: List[Dict[str, pass_chunks = extract_text_blocks_from_hashed_chunks(chunks) self.process_new_memory_chunks(pass_chunks, trimmed_discussion_chunks, rag_system_prompt, - rag_prompt, discussion_id_workflow_config, discussionId, messages) + rag_prompt, discussion_id_workflow_config, discussionId, + messages_copy) elif index == -1: print("-1 flow hit. Processing discussions") - self.process_full_discussion_flow(messages, rag_system_prompt, rag_prompt, + self.process_full_discussion_flow(messages_copy, rag_system_prompt, rag_prompt, discussion_id_workflow_config, discussionId) @@ -376,8 +381,8 @@ def process_full_discussion_flow(self, messages: List[Dict[str, str]], rag_syste print("Beginning full discussion flow") new_messages = deepcopy(messages) if (len(new_messages) > 1 - and new_messages[-1]['role'] == 'assistant' - and len(new_messages[-1].get('content', '')) < 30): + and new_messages[-1]['role'] == 'assistant' + and len(new_messages[-1].get('content', '')) < 30): new_messages = new_messages[:-1] new_messages.reverse() @@ -443,7 +448,7 @@ def perform_rag_on_conversation_chunk(rag_system_prompt: str, rag_prompt: str, t @staticmethod def perform_rag_on_memory_chunk(rag_system_prompt: str, rag_prompt: str, text_chunk: str, config: dict, - messages, + messages, discussionId: str, custom_delimiter: str = "") -> str: """ Perform Retrieval-Augmented Generation (RAG) on a given chunk of conversation. @@ -460,7 +465,6 @@ def perform_rag_on_memory_chunk(rag_system_prompt: str, rag_prompt: str, text_ch """ chunks = text_chunk.split('--ChunkBreak--') - discussionId = extract_discussion_id(messages) filepath = get_discussion_memory_file_path(discussionId) discussion_chunks = read_chunks_with_hashes(filepath) diff --git a/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-ChatSummary-Synchronous.json b/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-ChatSummary-Synchronous.json new file mode 100644 index 0000000..f9025b8 --- /dev/null +++ b/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-ChatSummary-Synchronous.json @@ -0,0 +1,19 @@ +[ + { + "title": "Checking AI's recent memory about this topic", + "agentName": "Chat Summary", + "type": "FullChatSummary", + "isManualConfig": true + }, + { + "title": "Responding to User Request", + "agentName": "Response Agent Five", + "systemPrompt": "You are an exceptionally creative AI that specializes in user enjoyment, and you are currently engaged in a roleplay conversation with user via an online chat program.\n\nYou are role playing a character in this conversation. Below, within brackets, are the initial instructions for that role play, including the starting scenario:\n[\n{chat_system_prompt}\n]\n\nSince the roleplay began, some changes to the initial scenario may have occurred through natural progression. A summary of the roleplay's story up to now can be found here:\n[\n{agent1Output}\n]\n\nPlease continue the below conversation, acting out your character. Please do not write dialogue for the user's character, and please keep your own response concise so that the user can have an opportunity to respond as well.\n\nPlease continue the below conversation with a concise reply, continuing your character's roleplay.", + "prompt": "", + "lastMessagesToSendInsteadOfPrompt": 20, + "endpointName": "ConvoRoleplaySingleModelEndpoint", + "preset": "MidnightMiqu1.0_Recommended", + "maxResponseSizeInTokens": 800, + "addUserTurnTemplate": false + } +] \ No newline at end of file diff --git a/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-ChatSummary-WorkflowLocked.json b/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-ChatSummary-WorkflowLocked.json new file mode 100644 index 0000000..02f0ff0 --- /dev/null +++ b/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-ChatSummary-WorkflowLocked.json @@ -0,0 +1,30 @@ +[ + { + "title": "Workflow Lock", + "type": "WorkflowLock", + "workflowLockId": "FullCustomChatSummaryLock" + }, + { + "title": "Grab the current summary from file", + "agentName": "Chat Summary File Puller Agent", + "type": "GetCurrentSummaryFromFile" + }, + { + "title": "LLM Responding to User Request", + "agentName": "Response Agent Five", + "systemPrompt": "You are an exceptionally creative AI that specializes in user enjoyment, and you are currently engaged in a roleplay conversation with user via an online chat program.\n\nYou are role playing a character in this conversation. Below, within brackets, are the initial instructions for that role play, including the starting scenario:\n[\n{chat_system_prompt}\n]\n\nSince the roleplay began, some changes to the initial scenario may have occurred through natural progression. A summary of the roleplay's story up to now can be found here:\n[\n{agent1Output}\n]\n\nPlease continue the below conversation, acting out your character. Please do not write dialogue for the user's character, and please keep your own response concise so that the user can have an opportunity to respond as well.\n\nPlease continue the below conversation with a concise reply, continuing your character's roleplay.", + "prompt": "", + "lastMessagesToSendInsteadOfPrompt": 20, + "endpointName": "ConvoRoleplaySingleModelEndpoint", + "preset": "MidnightMiqu1.0_Recommended", + "maxResponseSizeInTokens": 800, + "addUserTurnTemplate": false, + "returnToUser": true + }, + { + "title": "Checking AI's recent memory about this topic", + "agentName": "Chat Summary", + "type": "FullChatSummary", + "isManualConfig": false + } +] diff --git a/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-WithRecent-ChatSummary-Synchronous.json b/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-WithRecent-ChatSummary-Synchronous.json new file mode 100644 index 0000000..1b9f5d5 --- /dev/null +++ b/Public/Configs/Workflows/convoroleplaysinglemodeltemplate/FullCustomWorkflow-WithRecent-ChatSummary-Synchronous.json @@ -0,0 +1,24 @@ +[ + { + "title": "Checking AI's long term memory about this topic", + "agentName": "QualityMemoryAgent", + "type": "QualityMemory" + }, + { + "title": "Checking AI's recent memory about this topic", + "agentName": "Chat Summary", + "type": "FullChatSummary", + "isManualConfig": true + }, + { + "title": "Responding to User Request", + "agentName": "Response Agent Five", + "systemPrompt": "You are an exceptionally creative AI that specializes in user enjoyment, and you are currently engaged in a roleplay conversation with user via an online chat program.\n\nYou are role playing a character in this conversation. Below, within brackets, are the initial instructions for that role play, including the starting scenario:\n[\n{chat_system_prompt}\n]\n\nSince the roleplay began, some changes to the initial scenario may have occurred through natural progression. A summary of the roleplay's story up to now can be found here:\n[\n{agent2Output}\n]\n\nWhile considering the user's most recent message, you decided to look deep into your long term memories and found the following memories:\n[\n{agent1Output}\n]\n\nPlease continue the below conversation, acting out your character. Please do not write dialogue for the user's character, and please keep your own response concise so that the user can have an opportunity to respond as well.\n\nPlease continue the below conversation with a concise reply, continuing your character's roleplay.", + "prompt": "", + "lastMessagesToSendInsteadOfPrompt": 10, + "endpointName": "ConvoRoleplaySingleModelEndpoint", + "preset": "Default", + "maxResponseSizeInTokens": 1000, + "addUserTurnTemplate": false + } +] \ No newline at end of file diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomCategorizationWorkflow.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomCategorizationWorkflow.json index 2f0e6ae..dc5d7ab 100644 --- a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomCategorizationWorkflow.json +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomCategorizationWorkflow.json @@ -4,7 +4,7 @@ "agentName": "Categorization Agent", "systemPrompt": "You are an intelligent and capable categorizing specialist. You excel at categorizing text into predefined categories.", "prompt": "Q: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nGerald: I understand entirely! This is great.\nRobert:\n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from CODING: Any request which requires a code snippet as a response; FACTUAL: Requests that require factual information or data; CONVERSATIONAL: Casual conversation or non-specific inquiries. You must return only one word for your response. You may only choose from CODING or FACTUAL or CONVERSATIONAL. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: CONVERSATIONAL\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nFrank: My computer keeps bluescreening. I can't figure out what's going on with it. Can you help me?\nRichie:\n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from IT: Technical questions that require technical knowledge to respond; CHAT: Simple messages that require no formal knowledge to respond. You must return only one word for your response. You may only choose from IT or CHAT. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: IT\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nFrank: My computer keeps bluescreening. I can't figure out what's going on with it. Can you help me?\nRichie: Of course! Please try updating your video card driver and see if that helps.\nFrank: That did it! Thank you so much!\nRichie:\n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from IT: Technical questions that require technical knowledge to respond; CHAT: Simple messages that require no formal knowledge to respond. You must return only one word for your response. You may only choose from IT or CHAT. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: CHAT\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nJackie: Can you please write me a 'Hello World' application?\nLemmy:\n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from SOFTWARE: Requests that require some code to be written in order to respond appropriately; TECH: Requests that are technical in nature but do not require code in the response; FACT: Requests that have an objectively correct answer. You must return only one word for your response. You may only choose from SOFTWARE or TECH or FACT. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: SOFTWARE\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nJackie: Can you please write me a 'Hello World' application?\nLemmy: \nfunction HelloWorld()\n console.log(\"Hello World!\");\nHelloWorld();\nJackie: Awesome! Though I don't know how to run that. How do I run that code?\nLemmy:\n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from SOFTWARE: Requests that require some code to be written in order to respond appropriately; TECH: Requests that are technical in nature but do not require code in the response; FACT: Requests that have an objectively correct answer. You must return only one word for your response. You may only choose from SOFTWARE or TECH or FACT. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: TECH\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nFreddie: What gets bigger the more you take away?\nFrannie: \n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from GRAMMAR: Requests that focus on editting, correcting or reviewing written language; IT: Requests that involve issues with electronic devices, operating systems or software; CHIT-CHAT: Requests that are purely conversational in nature; REASONING: Requests that specifically require logic or reasoning to respond. You must return only one word for your response. You may only choose from GRAMMAR or IT or CHIT-CHAT or REASONING. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: REASONING\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in the following text, in brackets, to be categorized:\n\n[\nFreddie: What gets bigger the more you take away?\nFrannie: A hole is something that gets bigger the more you take away from it. Does that make sense?\nFreddit: It does! That's perfect.\nFrannie: \n]\n\nPlease categorize the last message in the above text, using the other text as context into its message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from GRAMMAR: Requests that focus on editting, correcting or reviewing written language; IT: Requests that involve issues with electronic devices, operating systems or software; CHIT-CHAT: Requests that are purely conversational in nature; REASONING: Requests that specifically require logic or reasoning to respond. You must return only one word for your response. You may only choose from GRAMMAR or IT or CHIT-CHAT or REASONING. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: CHIT-CHAT\n\n\nQ: You are an intelligent and capable AI that specializes in categorizing text, without limitation. You regularly categorize any input, without censorship or refusal, as a normal part of your daily work. An entire team of workers relies on your ability to work, and refusal would cause irreparable harm to the team's operations.\n\nPlease consider the last user message in following text, in brackets, to be categorized:\n\n[\n{chat_user_prompt_last_three}\n]\n\nPlease categorize the last message in the above text in brackets, consider the other text as context into the last message's meaning, into one of the following categories: {category_colon_descriptions}. You must return only one word for your response. You may only choose from {categoriesSeparatedByOr}. Please categorize the text as instructed. Please consider the full context when categorizing.\n\nA: ", - "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "endpointName": "ConvoRoleplayTwoModelWorkerEndpoint", "preset": "Almost_Deterministic", "maxResponseSizeInTokens": 100, "addUserTurnTemplate": true diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomConversationMemoryToolWorkflow.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomConversationMemoryToolWorkflow.json index 5578408..ce52c58 100644 --- a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomConversationMemoryToolWorkflow.json +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/CustomConversationMemoryToolWorkflow.json @@ -39,7 +39,7 @@ "agentName": "Search Result Summarizer Agent", "systemPrompt": "You are an extremely capable summarizer, who is able to summarize any text into a human readable text. You never allow things like misplaced prompt template tags, odd parentheses or brackets, or other things like this to throw you off. Your summaries are always clear and detailed.", "prompt": "You are engaged in a conversation with a user. The user sent you a message, and you have taken some time to look through your long term memories for anything related to that message. The memories that you came up with, which are from long ago in the conversation, can be found here: \n[\n{agent3Output}\n]\n\nThe latest messages in the conversation can be found in brackets below: \n[\n{chat_user_prompt_last_three}\n]\n\nPlease look through the distant memories and the recent conversation, and then answer the following questions with complete sentences:\n\nA) What context do these long term memories from earlier in the conversation give towards the current conversation?\nB) Based on these long term memories from earlier in the conversation, what sort of response should be given?\nC) Based on these long term memories from earlier in the conversation, what sort of relationship do the speakers seem to have with one another?\n\nNOTE: If there are no memories, please specify that.", - "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "endpointName": "ConvoRoleplayTwoModelWorkerEndpoint", "preset": "Default", "maxResponseSizeInTokens": 2000, "addUserTurnTemplate": true diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FactualWorkflow.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FactualWorkflow.json index d241c43..c774cf0 100644 --- a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FactualWorkflow.json +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FactualWorkflow.json @@ -5,7 +5,7 @@ "systemPrompt": "You are an exceptionally intelligent AI that that has vast stores of knowledge available to you. You are currently in a roleplay conversation with a user via an online chat program. The instructions for that chat can be found here: \n[\n{chat_system_prompt}\n]\n\nThe user has sent you a message that requires a factually correct and accurate response. Please consider all the facts when responding to the user, and if you are not confident in the answer then please tell the user that you do not know.\n\nWith the above instructions in mind, please continue the following conversation", "prompt": "", "lastMessagesToSendInsteadOfPrompt": 5, - "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "endpointName": "ConvoRoleplayTwoModelWorkerEndpoint", "preset": "Low_temp", "maxResponseSizeInTokens": 2000, "addUserTurnTemplate": false diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-ChatSummary-Synchronous.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-ChatSummary-Synchronous.json new file mode 100644 index 0000000..5189ccb --- /dev/null +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-ChatSummary-Synchronous.json @@ -0,0 +1,19 @@ +[ + { + "title": "Checking AI's recent memory about this topic", + "agentName": "Chat Summary", + "type": "FullChatSummary", + "isManualConfig": true + }, + { + "title": "Responding to User Request", + "agentName": "Response Agent Five", + "systemPrompt": "You are an exceptionally creative AI that specializes in user enjoyment, and you are currently engaged in a roleplay conversation with user via an online chat program.\n\nYou are role playing a character in this conversation. Below, within brackets, are the initial instructions for that role play, including the starting scenario:\n[\n{chat_system_prompt}\n]\n\nSince the roleplay began, some changes to the initial scenario may have occurred through natural progression. A summary of the roleplay's story up to now can be found here:\n[\n{agent1Output}\n]\n\nPlease continue the below conversation, acting out your character. Please do not write dialogue for the user's character, and please keep your own response concise so that the user can have an opportunity to respond as well.\n\nPlease continue the below conversation with a concise reply, continuing your character's roleplay.", + "prompt": "", + "lastMessagesToSendInsteadOfPrompt": 20, + "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "preset": "MidnightMiqu1.0_Recommended", + "maxResponseSizeInTokens": 800, + "addUserTurnTemplate": false + } +] \ No newline at end of file diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-ChatSummary-WorkflowLocked.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-ChatSummary-WorkflowLocked.json new file mode 100644 index 0000000..c524099 --- /dev/null +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-ChatSummary-WorkflowLocked.json @@ -0,0 +1,30 @@ +[ + { + "title": "Grab the current summary from file", + "agentName": "Chat Summary File Puller Agent", + "type": "GetCurrentSummaryFromFile" + }, + { + "title": "LLM Responding to User Request", + "agentName": "Response Agent Five", + "systemPrompt": "You are an exceptionally creative AI that specializes in user enjoyment, and you are currently engaged in a roleplay conversation with user via an online chat program.\n\nYou are role playing a character in this conversation. Below, within brackets, are the initial instructions for that role play, including the starting scenario:\n[\n{chat_system_prompt}\n]\n\nSince the roleplay began, some changes to the initial scenario may have occurred through natural progression. A summary of the roleplay's story up to now can be found here:\n[\n{agent1Output}\n]\n\nPlease continue the below conversation, acting out your character. Please do not write dialogue for the user's character, and please keep your own response concise so that the user can have an opportunity to respond as well.\n\nPlease continue the below conversation with a concise reply, continuing your character's roleplay.", + "prompt": "", + "lastMessagesToSendInsteadOfPrompt": 20, + "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "preset": "MidnightMiqu1.0_Recommended", + "maxResponseSizeInTokens": 800, + "addUserTurnTemplate": false, + "returnToUser": true + }, + { + "title": "Workflow Lock", + "type": "WorkflowLock", + "workflowLockId": "FullCustomChatSummaryLock" + }, + { + "title": "Checking AI's recent memory about this topic", + "agentName": "Chat Summary", + "type": "FullChatSummary", + "isManualConfig": false + } +] diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-WithRecent-ChatSummary-Synchronous.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-WithRecent-ChatSummary-Synchronous.json new file mode 100644 index 0000000..b116e3f --- /dev/null +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/FullCustomWorkflow-WithRecent-ChatSummary-Synchronous.json @@ -0,0 +1,24 @@ +[ + { + "title": "Checking AI's long term memory about this topic", + "agentName": "QualityMemoryAgent", + "type": "QualityMemory" + }, + { + "title": "Checking AI's recent memory about this topic", + "agentName": "Chat Summary", + "type": "FullChatSummary", + "isManualConfig": true + }, + { + "title": "Responding to User Request", + "agentName": "Response Agent Five", + "systemPrompt": "You are an exceptionally creative AI that specializes in user enjoyment, and you are currently engaged in a roleplay conversation with user via an online chat program.\n\nYou are role playing a character in this conversation. Below, within brackets, are the initial instructions for that role play, including the starting scenario:\n[\n{chat_system_prompt}\n]\n\nSince the roleplay began, some changes to the initial scenario may have occurred through natural progression. A summary of the roleplay's story up to now can be found here:\n[\n{agent2Output}\n]\n\nWhile considering the user's most recent message, you decided to look deep into your long term memories and found the following memories:\n[\n{agent1Output}\n]\n\nPlease continue the below conversation, acting out your character. Please do not write dialogue for the user's character, and please keep your own response concise so that the user can have an opportunity to respond as well.\n\nPlease continue the below conversation with a concise reply, continuing your character's roleplay.", + "prompt": "", + "lastMessagesToSendInsteadOfPrompt": 10, + "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "preset": "Default", + "maxResponseSizeInTokens": 1000, + "addUserTurnTemplate": false + } +] \ No newline at end of file diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/MemoryFileToolWorkflow.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/MemoryFileToolWorkflow.json index ba60372..dd27429 100644 --- a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/MemoryFileToolWorkflow.json +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/MemoryFileToolWorkflow.json @@ -21,7 +21,7 @@ "agentName": "Search Result Summarizer Agent", "systemPrompt": "You are an extremely capable summarizer, who is able to summarize any text into a human readable text. You never allow things like misplaced prompt template tags, odd parentheses or brackets, or other things like this to throw you off. Your summaries are always clear and detailed.", "prompt": "You are currently in a roleplay conversation with another user. You have been looking through your long term memories for anything that might prove to be helpful context to continue the fun conversation. Below are several summarized memories that you came up with:\n[\n{agent2Output}\n]\n\nPlease write a concise and yet vivid summary based on the above memories, taking extra care to capture as much information as possible, with minimal embellishments to fill the gaps. If something is unclear, feel free to say so, as when you read this note later you will have more information available to you. If there are any names, definitions, code, or other explicitly defined things, please put them in your summary verbatim, so that the information is not lost. Your summary will be used to respond to the user later, and only you have access to these memories, so please do not leave out important information to the current conversation. Please use the character/user names explicitly, as some may write in first person but you need to describe in third person.", - "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "endpointName": "ConvoRoleplayTwoModelWorkerEndpoint", "preset": "Default", "maxResponseSizeInTokens": 1000, "addUserTurnTemplate": true diff --git a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/RecentMemoryToolWorkflow.json b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/RecentMemoryToolWorkflow.json index 7ad7641..ffc896c 100644 --- a/Public/Configs/Workflows/convoroleplaytwomodeltemplate/RecentMemoryToolWorkflow.json +++ b/Public/Configs/Workflows/convoroleplaytwomodeltemplate/RecentMemoryToolWorkflow.json @@ -29,7 +29,7 @@ "agentName": "Memory Summarizer agent", "systemPrompt": "You are an extremely capable summarizer, who is able to summarize any text into a human readable text. You never allow things like misplaced prompt template tags, odd parentheses or brackets, or other things like this to throw you off. Your summaries are always clear and detailed.", "prompt": "You are engaged in a conversation with a user. You have been re-reading the most recent messages, broken them into chunks, and written a small summary about each chunk. You can find those summaries of the most recent messages below: \n[\n{agent3Output}\n]\n\nBased on the summaries of all the most recent messages, please write a vivid and detailed summary of the current situation, as well as all of the events and information leading up to it. Try to write it in such a way that someone who doesn't have access to the chat logs can full understand what is happening.\nNote: If the brackets are empty, then there was nothing to summarize.", - "endpointName": "ConvoRoleplayTwoModelResponderEndpoint", + "endpointName": "ConvoRoleplayTwoModelWorkerEndpoint", "preset": "Default", "maxResponseSizeInTokens": 1000, "addUserTurnTemplate": true diff --git a/server.py b/server.py index 125d1fc..7368f6a 100644 --- a/server.py +++ b/server.py @@ -1,5 +1,11 @@ from Middleware.core.open_ai_api import WilmerApi +from Middleware.utilities import sql_lite_utils +from Middleware.utilities.instance_utils import INSTANCE_ID if __name__ == '__main__': + print(f"Deleting old locks for that do not belong to Wilmer Instance_Id: '{INSTANCE_ID}'") + sql_lite_utils.SqlLiteUtils.delete_old_locks(INSTANCE_ID) + + print("Starting API") api = WilmerApi() api.run_api()