support think tag on expert

This commit is contained in:
AI Christianson 2025-03-07 21:37:34 -05:00
parent cf150173aa
commit e49cce301f
3 changed files with 191 additions and 2 deletions

View File

@ -171,7 +171,7 @@ models_params = {
"supports_think_tag": True, "supports_think_tag": True,
"supports_temperature": True, "supports_temperature": True,
"latency_coefficient": DEFAULT_BASE_LATENCY, "latency_coefficient": DEFAULT_BASE_LATENCY,
"max_tokens": 64000, "max_tokens": 130000,
} }
}, },
"azure_openai": { "azure_openai": {

View File

@ -18,6 +18,8 @@ from ..llm import initialize_expert_llm
from ..model_formatters import format_key_facts_dict from ..model_formatters import format_key_facts_dict
from ..model_formatters.key_snippets_formatter import format_key_snippets_dict from ..model_formatters.key_snippets_formatter import format_key_snippets_dict
from ..model_formatters.research_notes_formatter import format_research_notes_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() console = Console()
_model = None _model = None
@ -231,10 +233,38 @@ def ask_expert(question: str) -> str:
# Get the content from the response # Get the content from the response
content = response.content 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) # Handle thinking mode responses (content is a list) or regular responses (content is a string)
try: 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 # Extract thinking content and response text from structured response
thinking_content = None thinking_content = None
response_text = None response_text = None
@ -245,12 +275,15 @@ def ask_expert(question: str) -> str:
# Extract thinking content # Extract thinking content
if item.get('type') == 'thinking' and 'thinking' in item: if item.get('type') == 'thinking' and 'thinking' in item:
thinking_content = item['thinking'] thinking_content = item['thinking']
logger.debug("Found structured thinking content")
# Extract response text # Extract response text
elif item.get('type') == 'text' and 'text' in item: elif item.get('type') == 'text' and 'text' in item:
response_text = item['text'] response_text = item['text']
logger.debug("Found structured response text")
# Display thinking content in a separate panel if available # Display thinking content in a separate panel if available
if thinking_content: if thinking_content:
logger.debug(f"Displaying structured thinking content ({len(thinking_content)} chars)")
console.print( console.print(
Panel(Markdown(thinking_content), title="Expert Thinking", border_style="yellow") Panel(Markdown(thinking_content), title="Expert Thinking", border_style="yellow")
) )
@ -260,6 +293,7 @@ def ask_expert(question: str) -> str:
content = response_text content = response_text
else: else:
# Fallback: join list items if structured extraction failed # 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) content = "\n".join(str(item) for item in content)
except Exception as e: except Exception as e:

View File

@ -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 = "<think>This is thinking content</think>This 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 = "<think>Line 1\nLine 2\nLine 3</think>This 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(
"<think>Here's my reasoning</think>Final 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(
"<think>Here's my reasoning</think>Final answer",
supports_think_tag=False
)
assert not thoughts_displayed
assert think_content is None
assert response == "<think>Here's my reasoning</think>Final 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(
"<think>Thinking with alternate parameter</think>Final 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 = "<think>Some thoughts</think>Response 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"