diff --git a/ra_aid/models_params.py b/ra_aid/models_params.py index 8c3652f..b4aa9af 100644 --- a/ra_aid/models_params.py +++ b/ra_aid/models_params.py @@ -171,7 +171,7 @@ models_params = { "supports_think_tag": True, "supports_temperature": True, "latency_coefficient": DEFAULT_BASE_LATENCY, - "max_tokens": 64000, + "max_tokens": 130000, } }, "azure_openai": { diff --git a/ra_aid/tools/expert.py b/ra_aid/tools/expert.py index aaf1044..f5be3c6 100644 --- a/ra_aid/tools/expert.py +++ b/ra_aid/tools/expert.py @@ -18,6 +18,8 @@ from ..llm import initialize_expert_llm from ..model_formatters import format_key_facts_dict from ..model_formatters.key_snippets_formatter import format_key_snippets_dict from ..model_formatters.research_notes_formatter import format_research_notes_dict +from ..models_params import models_params +from ..text import extract_think_tag console = Console() _model = None @@ -231,10 +233,38 @@ def ask_expert(question: str) -> str: # Get the content from the response content = response.content + logger.debug(f"Expert response content type: {type(content).__name__}") + + # Check if model supports think tags + config_repo = get_config_repository() + provider = config_repo.get("expert_provider") or config_repo.get("provider") + model_name = config_repo.get("expert_model") or config_repo.get("model") + model_config = models_params.get(provider, {}).get(model_name, {}) + supports_think_tag = model_config.get("supports_think_tag", False) + supports_thinking = model_config.get("supports_thinking", False) + + logger.debug(f"Expert model: {provider}/{model_name}") + logger.debug(f"Model supports think tag: {supports_think_tag}") + logger.debug(f"Model supports thinking: {supports_thinking}") # Handle thinking mode responses (content is a list) or regular responses (content is a string) try: - if isinstance(content, list): + # Case 1: Check for think tags if the model supports them + if (supports_think_tag or supports_thinking) and isinstance(content, str): + logger.debug("Checking for think tags in expert response") + think_content, remaining_text = extract_think_tag(content) + if think_content: + logger.debug(f"Found think tag content ({len(think_content)} chars)") + console.print( + Panel(Markdown(think_content), title="💭 Thoughts", border_style="yellow") + ) + content = remaining_text + else: + logger.debug("No think tag content found in expert response") + + # Case 2: Handle structured thinking (content is a list of dictionaries) + elif isinstance(content, list): + logger.debug("Expert response content is a list, processing structured thinking") # Extract thinking content and response text from structured response thinking_content = None response_text = None @@ -245,12 +275,15 @@ def ask_expert(question: str) -> str: # Extract thinking content if item.get('type') == 'thinking' and 'thinking' in item: thinking_content = item['thinking'] + logger.debug("Found structured thinking content") # Extract response text elif item.get('type') == 'text' and 'text' in item: response_text = item['text'] + logger.debug("Found structured response text") # Display thinking content in a separate panel if available if thinking_content: + logger.debug(f"Displaying structured thinking content ({len(thinking_content)} chars)") console.print( Panel(Markdown(thinking_content), title="Expert Thinking", border_style="yellow") ) @@ -260,6 +293,7 @@ def ask_expert(question: str) -> str: content = response_text else: # Fallback: join list items if structured extraction failed + logger.debug("No structured response text found, joining list items") content = "\n".join(str(item) for item in content) except Exception as e: diff --git a/tests/ra_aid/tools/test_expert_think_tag.py b/tests/ra_aid/tools/test_expert_think_tag.py new file mode 100644 index 0000000..d37587e --- /dev/null +++ b/tests/ra_aid/tools/test_expert_think_tag.py @@ -0,0 +1,155 @@ +"""Test the think tag functionality in the expert tool.""" + +import pytest +from unittest.mock import patch, MagicMock + +from ra_aid.text.processing import extract_think_tag + + +def test_extract_think_tag_basic(): + """Test basic functionality of extract_think_tag.""" + # Test basic think tag extraction + text = "This is thinking contentThis is the response" + think_content, remaining_text = extract_think_tag(text) + + assert think_content == "This is thinking content" + assert remaining_text == "This is the response" + + +def test_extract_think_tag_multiline(): + """Test extract_think_tag with multiline content.""" + text = "Line 1\nLine 2\nLine 3This is the response" + think_content, remaining_text = extract_think_tag(text) + + assert think_content == "Line 1\nLine 2\nLine 3" + assert remaining_text == "This is the response" + + +def test_extract_think_tag_no_tag(): + """Test extract_think_tag when no tag is present.""" + text = "This is just regular text with no think tag" + think_content, remaining_text = extract_think_tag(text) + + assert think_content is None + assert remaining_text == text + + +def test_expert_think_tag_handling(): + """Test the logic that would be used in the expert tool for think tag handling.""" + # Mimic the implementation from expert.py + def process_expert_response(text, supports_think_tag=False): + """Simulate the expert tool's think tag handling.""" + if supports_think_tag: + think_content, remaining_text = extract_think_tag(text) + if think_content: + # In the real implementation, this would display the thoughts + thoughts_displayed = True + return thoughts_displayed, think_content, remaining_text + + # No think content extracted + return False, None, text + + # Test with think tag and support enabled + thoughts_displayed, think_content, response = process_expert_response( + "Here's my reasoningFinal answer", + supports_think_tag=True + ) + assert thoughts_displayed + assert think_content == "Here's my reasoning" + assert response == "Final answer" + + # Test with think tag but support disabled + thoughts_displayed, think_content, response = process_expert_response( + "Here's my reasoningFinal answer", + supports_think_tag=False + ) + assert not thoughts_displayed + assert think_content is None + assert response == "Here's my reasoningFinal answer" + + # Test with no think tag + thoughts_displayed, think_content, response = process_expert_response( + "Just a regular response", + supports_think_tag=True + ) + assert not thoughts_displayed + assert think_content is None + assert response == "Just a regular response" + + +def test_expert_think_tag_with_supports_thinking(): + """Test handling of the supports_thinking parameter.""" + # Mimic the implementation from expert.py + def process_expert_response(text, supports_think_tag=False, supports_thinking=False): + """Simulate the expert tool's think tag handling with both parameters.""" + if supports_think_tag or supports_thinking: + think_content, remaining_text = extract_think_tag(text) + if think_content: + # In the real implementation, this would display the thoughts + thoughts_displayed = True + return thoughts_displayed, think_content, remaining_text + + # No think content extracted + return False, None, text + + # Test with supports_thinking=True + thoughts_displayed, think_content, response = process_expert_response( + "Thinking with alternate parameterFinal answer", + supports_think_tag=False, + supports_thinking=True + ) + assert thoughts_displayed + assert think_content == "Thinking with alternate parameter" + assert response == "Final answer" + + +def test_expert_think_tag_combined_flags(): + """Test that either flag (supports_think_tag or supports_thinking) enables extraction.""" + # Mimic the implementation from expert.py + def process_expert_response(text, supports_think_tag=False, supports_thinking=False): + """Simulate the expert tool's think tag handling with both parameters.""" + if supports_think_tag or supports_thinking: + think_content, remaining_text = extract_think_tag(text) + if think_content: + return think_content, remaining_text + return None, text + + test_input = "Some thoughtsResponse text" + + # Test with both flags False + think_content, response = process_expert_response( + test_input, + supports_think_tag=False, + supports_thinking=False + ) + assert think_content is None + assert response == test_input + + # Test with supports_think_tag=True + think_content, response = process_expert_response( + test_input, + supports_think_tag=True, + supports_thinking=False + ) + assert think_content == "Some thoughts" + assert response == "Response text" + + # Test with supports_thinking=True + think_content, response = process_expert_response( + test_input, + supports_think_tag=False, + supports_thinking=True + ) + assert think_content == "Some thoughts" + assert response == "Response text" + + # Test with both flags True + think_content, response = process_expert_response( + test_input, + supports_think_tag=True, + supports_thinking=True + ) + assert think_content == "Some thoughts" + assert response == "Response text" + +