packages/blueprints/gen-ai-chatbot/static-assets/chatbot-genai-components/backend/python/app/agents/parser.py (77 lines of code) (raw):

import re from typing import Union from langchain_core.agents import AgentAction, AgentFinish from langchain_core.exceptions import OutputParserException from langchain_core.output_parsers import BaseOutputParser FINAL_ANSWER_TAG = "final-answer" MISSING_THOUGHT_TAG_ERROR_MESSAGE = "Invalid Format: Missing '<thought></thought>' tag" MISSING_ACTION_TAG_ERROR_MESSAGE = ( "Invalid Format: Missing '<action></action>' tag after '<thought></thought>'" ) MISSING_ACTION_INPUT_TAG_ERROR_MESSAGE = "Invalid Format: Missing '<action-input></action-input>' tag after '<action></action>'" class ReActSingleInputOutputParser(BaseOutputParser): """Parses ReAct-style LLM calls that have a single tool input.""" def parse(self, text: str) -> Union[AgentAction, AgentFinish]: includes_answer = f"<{FINAL_ANSWER_TAG}>" in text thought_match = re.search(r"<thought>(.*?)</thought>", text, re.DOTALL) action_match = re.search(r"<action>(.*?)</action>", text, re.DOTALL) action_input_match = re.search( r"<action-input>(.*?)</action-input>", text, re.DOTALL ) if thought_match and action_match and action_input_match: thought = thought_match.group(1).strip() action = action_match.group(1).strip() action_input = action_input_match.group(1).strip() if includes_answer: return AgentFinish( { "output": re.search( f"<{FINAL_ANSWER_TAG}>(.*?)</{FINAL_ANSWER_TAG}>", text, re.DOTALL, ) .group(1) # type: ignore .strip() }, text, ) else: return AgentAction(action, action_input, text) elif includes_answer: return AgentFinish( { "output": re.search( f"<{FINAL_ANSWER_TAG}>(.*?)</{FINAL_ANSWER_TAG}>", text, re.DOTALL, ) .group(1) # type: ignore .strip() }, text, ) if not thought_match: raise OutputParserException( f"Could not parse LLM output: `{text}`", observation=MISSING_THOUGHT_TAG_ERROR_MESSAGE, llm_output=text, send_to_llm=True, ) elif not action_match: raise OutputParserException( f"Could not parse LLM output: `{text}`", observation=MISSING_ACTION_TAG_ERROR_MESSAGE, llm_output=text, send_to_llm=True, ) elif not action_input_match: raise OutputParserException( f"Could not parse LLM output: `{text}`", observation=MISSING_ACTION_INPUT_TAG_ERROR_MESSAGE, llm_output=text, send_to_llm=True, ) else: raise OutputParserException(f"Could not parse LLM output: `{text}`") @property def _type(self) -> str: return "react-single-input"