Spaces:
Sleeping
Sleeping
| '''Functions to handle re-prompting and final reply generation | |
| downstream of LLM tool calls.''' | |
| import json | |
| import logging | |
| import queue | |
| from anthropic.types import text_block | |
| from client import prompts | |
| from client.anthropic_bridge import AnthropicBridge | |
| INTERMEDIATE_REPLY_HINTS = { | |
| 'rss_mcp_server_context_search': 'Let me find some additional context before I generate a final answer.', | |
| 'rss_mcp_server_find_article': 'I will find the title of that article.', | |
| 'rss_mcp_server_get_summary': 'I will summarize that article', | |
| 'rss_mcp_server_get_link': 'I will get the link to that article' | |
| } | |
| async def tool_loop( | |
| user_query: str, | |
| prior_reply: str, | |
| result: list, | |
| bridge: AnthropicBridge, | |
| output_queue: queue.Queue, | |
| dialog: logging.Logger | |
| ) -> None: | |
| '''Re-prompts the LLM in a loop until it generates a final reply based on tool output. | |
| Args: | |
| user_query: the original user input that provoked the tool call | |
| result: the complete model reply containing the tool call | |
| bridge: AnthropicBridge class instance | |
| output_queue: queue to send results back to Gradio UI | |
| dialog: logger instance to record intermediate responses and internal dialog | |
| ''' | |
| tool_call = result['tool_call'] | |
| tool_name = tool_call['name'] | |
| if tool_name == 'rss_mcp_server_get_feed': | |
| reply = await get_feed_call( | |
| user_query, | |
| result, | |
| bridge, | |
| output_queue, | |
| dialog | |
| ) | |
| output_queue.put(reply) | |
| else: | |
| tool_call = result['tool_call'] | |
| tool_name = tool_call['name'] | |
| tool_parameters = tool_call['parameters'] | |
| response_content = result['llm_response'].content[0] | |
| if isinstance(response_content, text_block.TextBlock): | |
| intermediate_reply = response_content.text | |
| else: | |
| intermediate_reply = INTERMEDIATE_REPLY_HINTS[tool_name] | |
| dialog.info('LLM intermediate reply: %s', intermediate_reply) | |
| dialog.info('MCP: called %s', tool_name) | |
| tool_result = json.loads(result['tool_result'].content)['text'] | |
| prompt = prompts.OTHER_TOOL_PROMPT.substitute( | |
| user_query=user_query, | |
| prior_reply=prior_reply, | |
| intermediate_reply=intermediate_reply, | |
| tool_name=tool_name, | |
| tool_parameters=tool_parameters, | |
| tool_result=tool_result | |
| ) | |
| dialog.info('System: re-prompting LLM with return from %s call', tool_name) | |
| while True: | |
| reply = await other_call( | |
| prompt, | |
| bridge, | |
| dialog | |
| ) | |
| if 'final reply' in reply: | |
| final_reply = reply['final reply'] | |
| dialog.info('LLM final reply: %s ...', final_reply[:50]) | |
| output_queue.put(final_reply) | |
| break | |
| else: | |
| prompt = reply['new_prompt'] | |
| async def get_feed_call( | |
| user_query: str, | |
| result: list, | |
| bridge: AnthropicBridge, | |
| output_queue: queue.Queue, | |
| dialog: logging.Logger | |
| ) -> str: | |
| '''Re-prompts LLM after a call to get_feed(). | |
| Args: | |
| user_query: the original user input that provoked the tool call | |
| result: the complete model reply containing the tool call | |
| bridge: AnthropicBridge class instance | |
| output_queue: queue to send results back to Gradio UI | |
| dialog: logger instance to record intermediate responses and internal dialog | |
| ''' | |
| tool_call = result['tool_call'] | |
| tool_name = tool_call['name'] | |
| tool_parameters = tool_call['parameters'] | |
| website = tool_parameters['website'] | |
| response_content = result['llm_response'].content[0] | |
| if isinstance(response_content, text_block.TextBlock): | |
| intermediate_reply = response_content.text | |
| else: | |
| intermediate_reply = f'I Will check the {website} RSS feed for you' | |
| dialog.info('LLM intermediate reply: %s', intermediate_reply) | |
| dialog.info('MCP: called %s on %s', tool_name, website) | |
| articles = json.loads(result['tool_result'].content)['text'] | |
| prompt = prompts.GET_FEED_PROMPT.substitute( | |
| website=website, | |
| user_query=user_query, | |
| intermediate_reply=intermediate_reply, | |
| articles=articles | |
| ) | |
| input_message =[{ | |
| 'role': 'user', | |
| 'content': prompt | |
| }] | |
| dialog.info('System: re-prompting LLM with return from %s call', tool_name) | |
| result = await bridge.process_query( | |
| prompts.REPROMPTING_SYSTEM_PROMPT, | |
| input_message | |
| ) | |
| try: | |
| reply = result['llm_response'].content[0].text | |
| except (IndexError, AttributeError): | |
| reply = 'No final reply from model' | |
| dialog.info('LLM final reply: %s ...', reply[:50]) | |
| output_queue.put(reply) | |
| async def other_call( | |
| prompt: list[dict], | |
| bridge: AnthropicBridge, | |
| dialog: logging.Logger | |
| ) -> dict: | |
| '''Re-prompts LLM after a call to get_feed(). | |
| Args: | |
| prompt: prompt to to send the LLM | |
| result: the complete model reply containing the tool call | |
| bridge: AnthropicBridge class instance | |
| output_queue: queue to send results back to Gradio UI | |
| dialog: logger instance to record intermediate responses and internal dialog | |
| ''' | |
| input_message =[{ | |
| 'role': 'user', | |
| 'content': prompt | |
| }] | |
| result = await bridge.process_query( | |
| prompts.REPROMPTING_SYSTEM_PROMPT, | |
| input_message | |
| ) | |
| if result['tool_result']: | |
| tool_call = result['tool_call'] | |
| tool_name = tool_call['name'] | |
| tool_parameters = tool_call['parameters'] | |
| response_content = result['llm_response'].content[0] | |
| if isinstance(response_content, text_block.TextBlock): | |
| intermediate_reply = response_content.text | |
| else: | |
| intermediate_reply = INTERMEDIATE_REPLY_HINTS[tool_name] | |
| dialog.info('LLM intermediate reply: %s', intermediate_reply) | |
| dialog.info('MCP: called %s', tool_name) | |
| tool_result = json.loads(result['tool_result'].content)['text'] | |
| prompt += f'agent: {intermediate_reply}\n' | |
| prompt += f'function call: {tool_name}("{tool_parameters}")' | |
| prompt += f'function return: {tool_result}' | |
| dialog.info('System: re-prompting LLM with return from %s call', tool_name) | |
| return {'new_prompt': prompt} | |
| else: | |
| reply = result['llm_response'].content[0].text | |
| return {'final reply': reply} | |