Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added specific exception from message parsing #215

Merged
merged 2 commits into from
Jul 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 22 additions & 11 deletions agents/sirji_agents/llm/generic/infer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from sirji_tools.logger import create_logger
from sirji_messages import message_parse, MessageParsingError, MessageValidationError, ActionEnum, AgentEnum, allowed_response_templates, permissions_dict, ActionEnum
from sirji_messages import message_parse, ActionEnum, AgentEnum, allowed_response_templates, permissions_dict, ActionEnum, MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError
from ..model_providers.factory import LLMProviderFactory
from .system_prompts.factory import SystemPromptsFactory
from ...decorators import retry_on_exception
Expand Down Expand Up @@ -58,16 +58,27 @@ def __get_response(self, conversation):
parsed_response_message = message_parse(response_message)
conversation.append({"role": "assistant", "content": response_message, "parsed_content": parsed_response_message})
break
except (MessageParsingError, MessageValidationError) as e:
# Handling both MessageParsingError and MessageValidationError similarly
self.logger.info("Error while parsing the message.\n")
retry_llm_count += 1
if retry_llm_count > 2:
raise e
self.logger.info(f"Requesting LLM to resend the message in correct format.\n")
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
# Todo: @vaibhav - Change the error message language later.
conversation.append({"role": "user", "content": "Error! Your last response has two action in it and both has been discarded because of the below error:\nError in processing your last response. Your response must conform strictly to one of the allowed Response Templates, as it will be processed programmatically and only these templates are recognized. Your response must be enclosed within '***' at the beginning and end, without any additional text above or below these markers. Not conforming above rules will lead to response processing errors."})
except (MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError ) as e:
if isinstance(e, MessageIncorrectFormatError):
self.logger.info("Error while parsing the message.\n")
retry_llm_count += 1
if retry_llm_count > 2:
raise e
self.logger.info(f"Requesting LLM to resend the message in correct format.\n")
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response must conform strictly to one of the allowed Response Templates, as it will be processed programmatically and only these templates are recognized. Your response must be enclosed within '***' at the beginning and end, without any additional text above or below these markers. Not conforming above rules will lead to response processing errors."})
if isinstance(e, MessageMissingPropertyError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. your response is missing some required properties. Please refer to the allowed response templates and provide the missing properties."})
if isinstance(e, MessageUnRecognizedActionError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response contains an unrecognized action. Please refer to the allowed response templates and provide a valid action."})
if isinstance(e, MessageLengthConstraintError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response does not have all the required properties."})
if isinstance(e, MessageMultipleActionError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response contains more than one ACTION keyword."})
except Exception as e:
self.logger.info(f"Generic error while parsing message. Error: {e}\n")
raise e
Expand Down
32 changes: 22 additions & 10 deletions agents/sirji_agents/llm/orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# TODO - log file should be dynamically created based on agent ID
from sirji_tools.logger import o_logger as logger

from sirji_messages import message_parse, MessageParsingError, MessageValidationError, ActionEnum, AgentEnum, allowed_response_templates, permissions_dict
from sirji_messages import message_parse, ActionEnum, AgentEnum, allowed_response_templates, permissions_dict, MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError
from .model_providers.factory import LLMProviderFactory
from ..decorators import retry_on_exception

Expand Down Expand Up @@ -57,15 +57,27 @@ def __get_response(self, conversation):
parsed_response_message = message_parse(response_message)
conversation.append({"role": "assistant", "content": response_message, "parsed_content": parsed_response_message})
break
except (MessageParsingError, MessageValidationError) as e:
# Handling both MessageParsingError and MessageValidationError similarly
logger.info("Error while parsing the message.\n")
retry_llm_count += 1
if retry_llm_count > 2:
raise e
logger.info(f"Requesting LLM to resend the message in correct format.\n")
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response must conform strictly to one of the allowed Response Templates, as it will be processed programmatically and only these templates are recognized. Your response must be enclosed within '***' at the beginning and end, without any additional text above or below these markers. Not conforming above rules will lead to response processing errors."})
except (MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError ) as e:
if isinstance(e, MessageIncorrectFormatError):
logger.info("Error while parsing the message.\n")
retry_llm_count += 1
if retry_llm_count > 2:
raise e
logger.info(f"Requesting LLM to resend the message in correct format.\n")
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response must conform strictly to one of the allowed Response Templates, as it will be processed programmatically and only these templates are recognized. Your response must be enclosed within '***' at the beginning and end, without any additional text above or below these markers. Not conforming above rules will lead to response processing errors."})
if isinstance(e, MessageMissingPropertyError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. your response is missing some required properties. Please refer to the allowed response templates and provide the missing properties."})
if isinstance(e, MessageUnRecognizedActionError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response contains an unrecognized action. Please refer to the allowed response templates and provide a valid action."})
if isinstance(e, MessageLengthConstraintError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response does not have all the required properties."})
if isinstance(e, MessageMultipleActionError):
conversation.append({"role": "assistant", "content": response_message, "parsed_content": {}})
conversation.append({"role": "user", "content": "Error obtained in processing your last response. Your response contains more than one ACTION keyword."})
except Exception as e:
logger.info(f"Generic error while parsing message. Error: {e}\n")
raise e
Expand Down
12 changes: 6 additions & 6 deletions messages/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,15 +71,15 @@ message_str = message_class().generate({
"to_agent_id": "CODER",
"summary": "Empty",
"body": "Done."})

print(f"Generated RESPONSE message:\n{message_str}")
```

### Message Parsing

Parse structured message strings into Python dictionaries for easy access to the message components.

````python
```python
from sirji_messages import message_parse

# Example message string to parse
Expand All @@ -94,7 +94,7 @@ BODY: Welcome to sirji-messages. Here's how you can start.
# Parsing the message
message = message_parse(message_str)
print(message)
````
```

### Allowed Response Templates

Expand All @@ -113,15 +113,15 @@ print(response_templates_str)
Efficiently manage parsing and validation errors with custom exceptions for improved error handling and debugging.

```python
from sirji_messages import MessageParsingError, MessageValidationError, message_parse
from sirji_messages import MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError, message_parse

try:
# Attempt parsing an incorrectly formatted message
message_parse("INCORRECT_FORMAT")
except MessageParsingError as e:
print(f"Parsing Error: {e}")
except MessageValidationError as e:
print(f"Validation Error: {e}")
except MessageIncorrectFormatError as e:
print(f"Incorrect Format Error: {e}")
```

### Enums for Agents and Actions
Expand Down
12 changes: 8 additions & 4 deletions messages/sirji_messages/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from .action_enum import ActionEnum
from .agent_enum import AgentEnum
from .messages.factory import MessageFactory
from .custom_exceptions import MessageParsingError, MessageValidationError
from .custom_exceptions import MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError
from .permissions import validate_permission, permissions_dict
from .parser import parse as message_parse
from .helper import allowed_response_templates
Expand All @@ -12,9 +12,13 @@
'MessageFactory',
'ActionEnum',
'AgentEnum',
'MessageParsingError',
'MessageValidationError',
'validate_permission',
'permissions_dict',
'allowed_response_templates'
'allowed_response_templates',
'MessageIncorrectFormatError',
'MessageMultipleActionError',
'MessageUnRecognizedActionError',
'MessageMissingPropertyError',
'MessageLengthConstraintError',
]

30 changes: 25 additions & 5 deletions messages/sirji_messages/custom_exceptions.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,34 @@
class MessageValidationError(Exception):
class MessageMissingPropertyError(Exception):
"""Exception raised for errors in the input message format."""

def __init__(self, message="Invalid message format"):
def __init__(self, message="Message does not contain required property"):
self.message = message
super().__init__(self.message)

class MessageUnRecognizedActionError(Exception):
"""Exception raised for errors in the input message format."""

def __init__(self, message="Action is not recognized"):
self.message = message
super().__init__(self.message)

class MessageIncorrectFormatError(Exception):
"""Exception raised for errors in the input message format."""

def __init__(self, message="Message must start and end with ***"):
self.message = message
super().__init__(self.message)

class MessageParsingError(Exception):
"""Exception raised for errors in parsing the message contents."""
class MessageLengthConstraintError(Exception):
"""Exception raised for errors in the input message format."""

def __init__(self, message="Error parsing message"):
def __init__(self, message="Message does not meet the minimum length requirement"):
self.message = message
super().__init__(self.message)

class MessageMultipleActionError(Exception):
"""Exception raised for errors in the input message format."""

def __init__(self, message="Message contains more than one ACTION keyword"):
self.message = message
super().__init__(self.message)
12 changes: 7 additions & 5 deletions messages/sirji_messages/parser.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from .custom_exceptions import MessageParsingError, MessageValidationError
from .custom_exceptions import MessageIncorrectFormatError, MessageMultipleActionError, MessageUnRecognizedActionError, MessageMissingPropertyError, MessageLengthConstraintError
from .action_enum import ActionEnum

message_properties = ['FROM', 'TO', 'ACTION','STEP', 'SUMMARY', 'BODY']
Expand All @@ -11,10 +11,10 @@ def parse(input_message):
# Check if the message has all the required properties.
for prop in message_properties:
if prop not in parsed_message:
raise MessageParsingError(f"Message does not contain {prop} property")
raise MessageMissingPropertyError(f"Message does not contain {prop} property")

if parsed_message['ACTION'] not in ActionEnum.__members__:
raise MessageValidationError(f"Action {parsed_message['ACTION']} is not recognized")
raise MessageUnRecognizedActionError(f"Action {parsed_message['ACTION']} is not recognized")

return parsed_message

Expand All @@ -38,11 +38,13 @@ def _discard_format_deviations(input_message):
def _validate_message(message):
message = message.strip()
if not (message.startswith("***") and message.endswith("***")):
raise MessageValidationError("Message must start and end with ***")
raise MessageIncorrectFormatError("Message must start and end with ***")
if message.count("ACTION") > 1:
raise MessageMultipleActionError("Message contains more than one ACTION keyword")
message = message[3:-3].strip()
lines = message.split("\n")
if len(lines) < max(len(message_properties), 2):
raise MessageValidationError(
raise MessageLengthConstraintError(
"Message does not meet the minimum length requirement")
return lines

Expand Down
Loading
Loading