feat: bump version to 1.51.0

feat: add reasoning extraction and cleaning
feat: update autonomous mode to handle reasoning and task completion markers
refactor: extract reasoning and clean content in assistant
docs: update system message to include reasoning and task completion instructions
fix: improve task completion detection by lowercasing content
This commit is contained in:
retoor 2025-11-10 10:29:27 +01:00
parent ea7fadd76b
commit f33867bb12
4 changed files with 56 additions and 7 deletions

View File

@ -8,7 +8,12 @@ def is_task_complete(response, iteration):
if "choices" not in response or not response["choices"]: if "choices" not in response or not response["choices"]:
return True return True
message = response["choices"][0]["message"] message = response["choices"][0]["message"]
content = message.get("content", "").lower() content = message.get("content", "")
if "[TASK_COMPLETE]" in content:
return True
content_lower = content.lower()
completion_keywords = [ completion_keywords = [
"task complete", "task complete",
"task is complete", "task is complete",
@ -36,9 +41,9 @@ def is_task_complete(response, iteration):
"what can i do for you", "what can i do for you",
] ]
has_tool_calls = "tool_calls" in message and message["tool_calls"] has_tool_calls = "tool_calls" in message and message["tool_calls"]
mentions_completion = any((keyword in content for keyword in completion_keywords)) mentions_completion = any((keyword in content_lower for keyword in completion_keywords))
mentions_error = any((keyword in content for keyword in error_keywords)) mentions_error = any((keyword in content_lower for keyword in error_keywords))
is_simple_response = any((keyword in content for keyword in simple_response_keywords)) is_simple_response = any((keyword in content_lower for keyword in simple_response_keywords))
if mentions_error: if mentions_error:
return True return True
if mentions_completion and (not has_tool_calls): if mentions_completion and (not has_tool_calls):

View File

@ -13,6 +13,29 @@ from rp.ui.progress import ProgressIndicator
logger = logging.getLogger("rp") logger = logging.getLogger("rp")
def extract_reasoning_and_clean_content(content):
"""
Extract reasoning from content and strip the [TASK_COMPLETE] marker.
Returns:
tuple: (reasoning, cleaned_content)
"""
reasoning = None
lines = content.split('\n')
cleaned_lines = []
for line in lines:
if line.strip().startswith('REASONING:'):
reasoning = line.strip()[10:].strip()
else:
cleaned_lines.append(line)
cleaned_content = '\n'.join(cleaned_lines)
cleaned_content = cleaned_content.replace('[TASK_COMPLETE]', '').strip()
return reasoning, cleaned_content
def sanitize_for_json(obj): def sanitize_for_json(obj):
if isinstance(obj, bytes): if isinstance(obj, bytes):
return base64.b64encode(obj).decode("utf-8") return base64.b64encode(obj).decode("utf-8")
@ -131,9 +154,15 @@ def process_response_autonomous(assistant, response):
print(f"{Colors.YELLOW}💰 Cost: ${cost:.4f} | Total: ${total_cost:.4f}{Colors.RESET}") print(f"{Colors.YELLOW}💰 Cost: ${cost:.4f} | Total: ${total_cost:.4f}{Colors.RESET}")
return process_response_autonomous(assistant, follow_up) return process_response_autonomous(assistant, follow_up)
content = message.get("content", "") content = message.get("content", "")
reasoning, cleaned_content = extract_reasoning_and_clean_content(content)
if reasoning:
print(f"{Colors.BLUE}💭 Reasoning: {reasoning}{Colors.RESET}")
from rp.ui import render_markdown from rp.ui import render_markdown
return render_markdown(content, assistant.syntax_highlighting) return render_markdown(cleaned_content, assistant.syntax_highlighting)
def execute_single_tool(assistant, func_name, arguments): def execute_single_tool(assistant, func_name, arguments):

View File

@ -336,9 +336,16 @@ class Assistant:
) )
return self.process_response(follow_up) return self.process_response(follow_up)
content = message.get("content", "") content = message.get("content", "")
from rp.autonomous.mode import extract_reasoning_and_clean_content
reasoning, cleaned_content = extract_reasoning_and_clean_content(content)
if reasoning:
print(f"{Colors.BLUE}💭 Reasoning: {reasoning}{Colors.RESET}")
with ProgressIndicator("Updating memory..."): with ProgressIndicator("Updating memory..."):
self.graph_memory.populate_from_text(content) self.graph_memory.populate_from_text(cleaned_content)
return render_markdown(content, self.syntax_highlighting) return render_markdown(cleaned_content, self.syntax_highlighting)
def signal_handler(self, signum, frame): def signal_handler(self, signum, frame):
if self.autonomous_mode: if self.autonomous_mode:

View File

@ -87,6 +87,14 @@ def init_system_message(args):
"Prefer standard Unix utilities over complex scripts.", "Prefer standard Unix utilities over complex scripts.",
"Use run_command_interactive for commands requiring user input (vim, nano, etc.).", "Use run_command_interactive for commands requiring user input (vim, nano, etc.).",
"Use the knowledge base to answer questions and store important user preferences or information when relevant. Avoid storing simple greetings or casual conversation.", "Use the knowledge base to answer questions and store important user preferences or information when relevant. Avoid storing simple greetings or casual conversation.",
"",
"IMPORTANT RESPONSE FORMAT:",
"When you have completed a task or answered a question, include [TASK_COMPLETE] at the end of your response.",
"The [TASK_COMPLETE] marker will not be shown to the user, so include it only when the task is truly finished.",
"Before your main response, include your reasoning on a separate line prefixed with 'REASONING: '.",
"Example format:",
"REASONING: The user asked about their favorite beer. I found 'westmalle' in the knowledge base.",
"Your favorite beer is Westmalle. [TASK_COMPLETE]",
] ]
max_context_size = 10000 max_context_size = 10000