-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Open
Labels
Issue/PR - TriageNew issue. Needs quick review to confirm validity and assign labels.New issue. Needs quick review to confirm validity and assign labels.bugSomething isn't workingSomething isn't working
Description
Problem (one or two sentences)
Messages indicates Tool calls seems broken with Roocode update version 3.37.1 . Worked before the last update.
Context (who is affected and when)
Happens when trying to use any NVIDIA API models --> at least with the two I used)
Reproduction steps
- use NVIDIA API https://integrate.api.nvidia.com/v1 as a OpenAI compatible endpoint
- use a model, for example deepseek/deepseek-v3.2 or mistralai/devstral-2-123b-instruct-2512
3.send a message in 'Ask' or 'Code' mode, for example "do a flowchart mermaid of the Agent class"
Expected result
The model should return a response without error
Actual result
Throw error in dialogbox, and (for deepseek) XML function call in conversation
Variations tried (optional)
Tried with deepseek and mistralai models. error messages are not the same.
App Version
v3.37.1
API Provider (optional)
Not Applicable / Other
Model Used (optional)
devstral-2-123b-instruct-2512, deepseek/deepseek-v3.2
Roo Code Task Links (optional)
No response
Relevant logs or errors (optional)
I'll create a flowchart Mermaid diagram of the Agent class. First, let me examine the Agent class file to understand its structure and flow.
<function_calls>
<invoke name="read_file">{
"files": [
{
"path": "core/agent.py"
}
]
invoke>
</function_calls>
API Request
$0.0000
Roo said
<function_calls>
<invoke name="read_file">{
"files": [
{
"path": "core/agent.py"
}
]
invoke>
</function_calls>
Model Response Incomplete
The model failed to use any tools in its response. This typically happens when the model provides only text/reasoning without calling the required tools to complete the task.Details
**OR (different flavor of error, with mistral model)**
Provider Error · 400
The provider couldn't process the request as made. Stop the task and try a different approach.Details
// Please share this file with Roo Code Support ([email protected]) to diagnose the issue faster
// Just make sure you're OK sharing the contents of the conversation below.
{
"error": {
"timestamp": "2025-12-26T16:44:25.879Z",
"version": "3.37.1",
"provider": "openai",
"model": "mistralai/devstral-2-123b-instruct-2512",
"details": "400\nOpenAI completion error: 400 Unexpected role 'user' after role 'tool' Unexpected role 'user' after role 'tool'"
},
"history": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "<task>\ndo a flowchart mermaid of the Agent class\n</task>"
},
{
"type": "text",
"text": "<environment_details>\n# VSCode Visible Files\ncore/message_manager.py\n\n# VSCode Open Tabs\ncore/message_manager.py,core/agent.py\n\n# Current Time\nCurrent time in ISO 8601 UTC format: 2025-12-26T16:42:11.800Z\nUser time zone: Europe/Paris, UTC+1:00\n\n# Current Cost\n$0.00\n\n# Current Mode\n<slug>ask</slug>\n<name>❓ Ask</name>\n<model>mistralai/devstral-2-123b-instruct-2512</model>\n<tool_format>native</tool_format>\n\n\n# Current Workspace Directory (/home/seb/ComfyUI_Dev/custom_nodes/lm_agent) Files\ndebug_edge_case.py\ndebug_full_context.py\ndebug_line_endings.py\ndebug_message_manager_issue.py\ndebug_repetition_issue.py\ndebug_summary_logic.py\ndebug_test_chat.py\nfile_tool_usage_examples.py\nFIX_SUMMARY.md\nMessageManager_Analysis.md\npelican.svg\npelican2.svg\npelican3.svg\nREPETITION_FIX_SUMMARY.md\nrequirements.txt\nroo-code-settings_VSCODE.json\nstrot.txt\nStrut.txt\ntest_agent_integration.py\ntest_compaction.py\ntest_context_compaction.py\ntest_different_limits.py\ntest_enhanced_file_tool.py\ntest_enhanced_message_manager.py\ntest_file_tool_compatibility.py\ntest_file_tool_line_endings.py\ntest_final_fix_3000.py\ntest_final_fix.py\ntest_message_manager_comprehensive.py\ntest_message_manager_real.py\ntest_message_manager_simple.py\ntest_multiple_compactions.py\ntest_proxy_system.py\ntest_real_conversation.py\ntest_realistic_scenario.py\ntest_rss_tool.py\nTODO enhancing crawling using undetected ch.md\nUsing tor with python - duck.ai.md\n_OLD/\n_OLD/calculator_tool._py\n_OLD/comprehensive_test.py\n_OLD/debug_tool_test.py\n_OLD/gpt_oss_20b_fix_summary.md\n_OLD/OLD_agent.py\n_OLD/test_no_tools.py\n_OLD/test_results_summary.md\n_OLD/test.json\n.zencoder/\n.zenflow/\ncore/\ncore/agent.py\ncore/history_log.txt\ncore/llm_client.py\ncore/message_manager.py\ncore/monde_rss_articles.json\ncore/super_camarche.txt\ncore/test_agent.py\ncore/test_chat.py\ncore/test_multiagent.py\ncore/test_summary_logging.py\ncore/tools/\ncore/tools/agent_tool.py\ncore/tools/calculator_tool.py\ncore/tools/duck_search_tool.py\ncore/tools/extract_web_content_tool.py\ncore/tools/factory.py\ncore/tools/file_tool.py\ncore/tools/news_search_tool.py\ncore/tools/python_ast_tool.py\ncore/tools/python_tool.py\ncore/tools/registry.py\ncore/tools/rss_tool.py\ncore/tools/tool.py\ncore/tools/weather_tool.py\ncore/tools/wikimedia_tool.py\ncore/tools/web_tools/\ncore/tools/web_tools/__init__.py\ncore/tools/web_tools/_extract._py\ncore/tools/web_tools/extract.py\ncore/tools/web_tools/headers.py\ncore/tools/web_tools/http_client.py\ncore/tools/web_tools/models.py\ncore/tools/web_tools/proxy_config.json\ncore/tools/web_tools/proxy.py\ncore/tools/web_tools/search.py\ncore/tools/web_tools/tools.___json\ncore/tools/web_tools/parsers/\ncore/tools/web_tools/parsers/__init__.py\ncore/tools/web_tools/parsers/html_parser.py\ncore/tools/web_tools/parsers/results_parser.py\nmermaid and flowcharts/\nmermaid and flowcharts/Agent_loop_211225.mmd\nplans/\nplans/file_tool_analysis_comparison.md\nplans/file_tool_architecture_diagram.md\nplans/file_tool_code_examples.md\nplans/file_tool_executive_summary.md\nplans/file_tool_final_recommendations.md\nplans/file_tool_immediate_improvements.md\nplans/file_tool_implementation_plan.md\nplans/file_tool_improved_example.py\nplans/file_tool_migration_plan.md\nplans/file_tool_risk_assessment.md\nYou have not created a todo list yet. Create one with `update_todo_list` if your task is complicated or involves multiple steps.\n</environment_details>"
}
],
"ts": 1766767331831
},
{
"role": "assistant",
"content": [
{
"type": "text",
"text": "To create a flowchart of the Agent class, I need to first examine the contents of the `core/agent.py` file to understand its structure and methods. Let me read the file to gather the necessary information."
},
{
"type": "tool_use",
"id": "YvzMG28qB",
"name": "read_file",
"input": {
"files": [
{
"path": "core/agent.py"
}
]
}
}
],
"ts": 1766767334403
},
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": "YvzMG28qB",
"content": "File: core/agent.py\nLines 1-389:\n 1 | import os\n 2 | import re\n 3 | import json\n 4 | import time\n 5 | from datetime import date, datetime\n 6 | from typing import Optional, Dict, Any, List\n 7 | from llm_client import LLMClient\n 8 | from tools.tool import ToolRegistry\n 9 | from tools.factory import build_tools\n 10 | from message_manager import MessageManager\n 11 | \n 12 | \n 13 | BLUE = \"\\033[38;5;68m\"\n 14 | GREEN = \"\\033[38;5;77m\"\n 15 | BGGREEN = \"\\033[48;5;77m\"\n 16 | RED = \"\\033[38;5;1m\"\n 17 | BGRED = \"\\033[48;5;1m\"\n 18 | GRAY = \"\\033[38;5;240m\"\n 19 | BGGRAY = \"\\033[48;5;240m\"\n 20 | YELLOW = \"\\033[33m\"\n 21 | RESET = \"\\033[0m\"\n 22 | ITALIC = \"\\033[3m\"\n 23 | \n 24 | CONTEXT_LENGTH = 10000 # Default context length\n 25 | \n 26 | # calculate 45*3, then calculate 5+2, everytime using the calculator tool \n 27 | # what do you think of happiness ?\n 28 | \n 29 | class Agent:\n 30 | \"\"\"A simple AI agent that can answer questions\"\"\"\n 31 | \n 32 | # Regex pattern for XML-style tool calls\n 33 | TOOL_CALL_PATTERN = r'<\\|channel\\|>commentary to=functions\\.(\\w+).*?<\\|message\\|>(\\{.*?\\})'\n 34 | \n 35 | # def __init__(self, tools=None):\n 36 | def __init__(self, \n 37 | model: Optional[str] = None,\n 38 | client: Optional[LLMClient] = None,\n 39 | system_message: Optional[str] = None,\n 40 | tools=None):\n 41 | \n 42 | # self.model = model or \"gpt-oss-20b-derestricted\"\n 43 | # self.model = \"qwen3-coder-30b-a3b-instruct\"\n 44 | self.model = model or \"devstral-small-2-24b-instruct-2512\"\n 45 | \n 46 | # self.model = model or \"janhq/jan-v1-4b-gguf/jan-v1-4b-q4_k_m.gguf\"\n 47 | # self.model = model or \"ministral-3-3b-instruct-2512@q4_k_m\"\n 48 | # self.model = model or \"qwen3-4b-instruct-2507\"\n 49 | \n 50 | self.client = client or LLMClient(api_key=\"\", base_url=\"http://localhost:8000/v1/chat/completions\")\n 51 | # self.client = LLMClient(api_key=\"sk-6950ac51a4c2659fc527313e5edd5655\", base_url=\"https://apis.iflow.cn/v1/chat/completions\")\n 52 | \n 53 | # self.system_message = f\"\"\"You are a helpful assistant that breaks down problems into steps and solves them systematically.\n 54 | # IMPORTANT: When solving mathematical or logical problems, you MUST:\n 55 | # 1. Break down complex calculations into individual, separate steps\n 56 | # 2. Use only ONE calculation per tool call\n 57 | # 3. Show intermediate results before proceeding to the next step\n 58 | # 4. Think step-by-step and explain your reasoning for each calculation\n 59 | \n 60 | # When using the extract_web_content tool:\n 61 | # 1. Always return readable content for article and news\n 62 | # 2. Use the 'search' action to find specific information first\n 63 | # 3. Load large content limit on first call to allow using content from cache on subsequent calls\n 64 | # 4. If content is incomplete, use pagination with start_char/end_char.\n 65 | \n 66 | # Today's date is {date.today().isoformat()}.\"\"\"\n 67 | \n 68 | self.system_message = system_message if system_message is not None else f\"\"\"\n 69 | You are a helpful assistant that breaks down problems, you can use tools, \n 70 | think step-by-step and explain your reasoning. \n 71 | Today's date is {date.today().isoformat()}.\n 72 | \"\"\"\n 73 | self.system_message += \"\"\"\n 74 | IMPORTANT: When using tools, ALWAYS format arguments as valid JSON:\n 75 | - Use proper double quotes for all strings\n 76 | - No newline characters (\\n) inside JSON values\n 77 | - No HTML tags or XML markers in JSON\n 78 | - Example: {{\"url\": \"https://example.com\", \"action\": \"search\", \"query\": \"test\"}}\n 79 | \n 80 | Tool Usage\n 81 | \n 82 | Use tools for retrieval, not for facts within training.\n 83 | \n 84 | <use_tools_when>\n 85 | Information may have changed after December 2024\n 86 | User references specific URLs, documents, or current data\n 87 | Niche/local information that benefits from live sources\n 88 | High accuracy stakes (library versions, event dates, prices)\n 89 | </use_tools_when>\n 90 | \n 91 | <do_not_use_tools_for>\n 92 | Well-established facts, historical events, stable concepts\n 93 | General knowledge questions you can answer confidently\n 94 | Conceptual explanations already in your training\n 95 | </do_not_use_tools_for>\n 96 | \n 97 | When tools are appropriate, use them decisively and do multiple searches if breadth is needed.\n 98 | \"\"\".strip()\n 99 | \n100 | self.message_manager = MessageManager(\n101 | max_tokens=CONTEXT_LENGTH, # Optimized for prompt_tokens management\n102 | summary_callback=self.create_conversation_summary\n103 | )\n104 | tool_instances = build_tools(tools)\n105 | self.registry = ToolRegistry(tool_instances)\n106 | \n107 | # ---------- Core loop ----------\n108 | \n109 | def run_agent(self, \n110 | message, \n111 | debug: bool = False,\n112 | top_p: float = 1.0,\n113 | top_k: int = 0,\n114 | max_tokens: int = 2048,\n115 | temperature: float = 0.1,\n116 | **kwargs):\n117 | \"\"\"Process a user message with proper tool use loop logic\"\"\"\n118 | \n119 | logic_start_time = time.time()\n120 | \n121 | self.message_manager.add_message(\"user\", message)\n122 | # print(f\"user{YELLOW}{message}{RESET}\") # DEBUG\n123 | \n124 | max_turns = 10\n125 | for i in range(1, max_turns + 1):\n126 | if debug:\n127 | print(f\"\\n=== Iteration {i} ===\")\n128 | \n129 | response = self.client.messages.create(\n130 | model=self.model,\n131 | messages=self.message_manager.get_messages(),\n132 | tools=self.registry.schemas(),\n133 | top_p=top_p,\n134 | top_k=top_k,\n135 | max_tokens=max_tokens,\n136 | system=self.system_message,\n137 | temperature=temperature,\n138 | debug=debug,\n139 | **kwargs\n140 | )\n141 | \n142 | # Update message manager with actual API response token usage\n143 | self.message_manager.update_from_api_response(response)\n144 | \n145 | message = response[\"choices\"][0][\"message\"]\n146 | tool_calls = self._extract_tool_calls(message)\n147 | \n148 | content, reasoning = self._extract_reason_and_content(message)\n149 | \n150 | if tool_calls:\n151 | self.message_manager.add_message(\"assistant\", reasoning,\n152 | {\"tool_calls\": tool_calls})\n153 | # print(f\"Assistant{YELLOW}{reasoning}{RESET}\") # DEBUG\n154 | # print(f\"tool_calls{YELLOW}{tool_calls}{RESET}\") # DEBUG\n155 | \n156 | for call in tool_calls:\n157 | tool_start_time = time.time()\n158 | result = self.registry.execute(call)\n159 | tool_exec_time = time.time() - tool_start_time\n160 | self.message_manager.add_message(\"tool\", json.dumps(result),\n161 | {\"tool_call_id\": call[\"id\"],\n162 | \"tool_name\": call[\"function\"][\"name\"]})\n163 | # print(f\"tool{YELLOW}{json.dumps(result)}{RESET}\") # DEBUG\n164 | # print(f\"tool_call_id{YELLOW}{call[\"id\"]}{RESET}\") # DEBUG\n165 | # print(f\"tool_name{YELLOW}{call[\"function\"][\"name\"]}{RESET}\") # DEBUG\n166 | \n167 | func = f\"{BGGRAY}⏱️ {ITALIC}{call[\"function\"][\"name\"]} {RESET}\" # 💤 💬 🗨️ 👾 🛠️\n168 | if result.get(\"error\"):\n169 | print (f\"{func}{BGRED}{ITALIC} Error: {result[\"error\"]} {RESET} ({tool_exec_time:.1f}s)\")\n170 | else:\n171 | print (f\"{func}{BGGREEN}{ITALIC} Success {RESET} ({tool_exec_time:.1f}s)\")\n172 | continue\n173 | \n174 | return self._finalize_response(content, reasoning, logic_start_time)\n175 | \n176 | # fallback if max iterations reached, we try to formulate a final answer # previously return \"Maximum iterations reached. Please try again.\"\n177 | content = \"I apologize, but I was unable to find the requested information after multiple attempts. Could you please rephrase your question or provide more specific details?\"\n178 | reasoning = f\"\"\"Maximum iterations reached without a conclusive answer to the user's query : '{message}'.\"\"\"\n179 | return self._finalize_response(content, reasoning, logic_start_time)\n180 | \n181 | def _finalize_response(self, content: str, reasoning: str, logic_start_time: float) -> str:\n182 | \"\"\"Finalize and return the assistant response with proper logging and message storage\"\"\"\n183 | logic_exec_time = time.time() - logic_start_time\n184 | completion_tokens = self.message_manager.last_completion_tokens\n185 | total_tokens = self.message_manager.last_total_tokens\n186 | tokens_per_second = completion_tokens / logic_exec_time if logic_exec_time > 0 else 0\n187 | \n188 | print(f\"{GRAY}{ITALIC}{reasoning}{RESET} (⏱️ Total: {logic_exec_time:.1f}s ({tokens_per_second:.1f} t/s)- {completion_tokens}/{total_tokens} tokens)\")\n189 | if reasoning:\n190 | self.message_manager.add_message(\"assistant\", content, {\"reasoning\": reasoning})\n191 | else:\n192 | self.message_manager.add_message(\"assistant\", content)\n193 | \n194 | # print(f\"assistant{YELLOW}{content}{RESET}\") # DEBUG\n195 | return content\n196 | \n197 | # ---------- Parsing helpers ----------\n198 | \n199 | def _strip_xml_tool_syntax(self, content: str) -> str:\n200 | \"\"\"\n201 | Remove XML-style tool call syntax from content.\n202 | Used to clean up content field when models emit both formats.\n203 | \"\"\"\n204 | if not content:\n205 | return \"\"\n206 | \n207 | # Remove the entire XML tool call pattern\n208 | content = re.sub(self.TOOL_CALL_PATTERN, '', content, flags=re.DOTALL)\n209 | \n210 | # Remove any remaining <|...> tags\n211 | content = re.sub(r'<\\|[^>]+\\|>', '', content)\n212 | \n213 | return content.strip()\n214 | \n215 | def _extract_reason_and_content(self, message: Dict[str, Any]) -> tuple[str, str]:\n216 | \"\"\"Extract reasoning and content from the assistant's message, cleaning XML artifacts\"\"\"\n217 | \n218 | # raw_reason = message.get(\"reasoning_content\", \"\") or message.get(\"reasoning\", \"\") or \"\"\n219 | raw_reason = message.get(\"reasoning\", \"\")\n220 | raw_content = message.get(\"content\", \"\")\n221 | \n222 | # Always strip XML tool syntax first (defensive cleaning)\n223 | raw_content = self._strip_xml_tool_syntax(raw_content)\n224 | \n225 | # If reasoning is in a separate field, return as-is\n226 | if raw_reason:\n227 | return raw_content, raw_reason\n228 | \n229 | # Extract <think> tags from content\n230 | reason_match = re.search(r'<think>(.*?)</think>', raw_content, re.DOTALL)\n231 | if reason_match:\n232 | reason = reason_match.group(1).strip()\n233 | content = re.sub(r'<think>.*?</think>', '', raw_content, flags=re.DOTALL).strip()\n234 | return content, reason\n235 | \n236 | return raw_content, \"\"\n237 | \n238 | def _extract_tool_calls(self, message: Dict[str, Any]) -> List[Dict[str, Any]]:\n239 | \"\"\" Extract tool calls from the assistant's message \"\"\"\n240 | \n241 | # Standard OpenAI format\n242 | if message.get(\"tool_calls\"):\n243 | return message[\"tool_calls\"]\n244 | \n245 | # XML format parsing (legacy/alternative models)\n246 | content = message.get(\"content\", \"\")\n247 | if not content:\n248 | return []\n249 | \n250 | matches = re.findall(self.TOOL_CALL_PATTERN, content, re.DOTALL)\n251 | if not matches:\n252 | return []\n253 | \n254 | tool_calls = []\n255 | for i, (name, args_json) in enumerate(matches):\n256 | try:\n257 | args = json.loads(args_json)\n258 | tool_calls.append({\n259 | \"id\": f\"call_{i}_{name}\",\n260 | \"type\": \"function\",\n261 | \"function\": {\n262 | \"name\": name,\n263 | \"arguments\": json.dumps(args), # args, # respecting opennai's format\n264 | }\n265 | })\n266 | except json.JSONDecodeError:\n267 | continue\n268 | \n269 | return tool_calls\n270 | \n271 | # ---------- Conversation summarization ----------\n272 | \n273 | def create_conversation_summary(self, messages_to_summarize: List[Dict]) -> str:\n274 | \"\"\"Create a summary of old conversation messages\"\"\"\n275 | if not messages_to_summarize:\n276 | return \"\"\n277 | \n278 | # Build a summary prompt with the messages to summarize\n279 | summary_prompt = self._build_summary_prompt(messages_to_summarize)\n280 | \n281 | try:\n282 | # Create a temporary message manager for summary generation\n283 | temp_manager = MessageManager(max_tokens=CONTEXT_LENGTH*0.5) # Smaller limit for summary\n284 | temp_manager.add_message(\"system\", \"You are a helpful assistant that creates concise summaries of conversations.\")\n285 | temp_manager.add_message(\"user\", summary_prompt)\n286 | \n287 | # Generate summary using the LLM with all required parameters\n288 | response = self.client.messages.create(\n289 | model=self.model,\n290 | messages=temp_manager.get_messages(),\n291 | tools=[], # No tools needed for summary\n292 | top_p=1.0,\n293 | top_k=0,\n294 | max_tokens=CONTEXT_LENGTH*0.2 , # Keep summary concise\n295 | temperature=0.3,\n296 | system=\"Create a consolidated summary of the entire conversation. If an existing summary is provided, MERGE the new information into it. Ensure no key topics, requests, or events from the past are lost. Keep the output concise but comprehensive.\",\n297 | debug=False\n298 | )\n299 | \n300 | if response and response.get(\"choices\"):\n301 | summary = response[\"choices\"][0][\"message\"].get(\"content\", \"\")\n302 | \n303 | # Clean up any potential \"Summary:\" or \"**Summary:**\" prefix from the LLM if they are redundant\n304 | summary = re.sub(r'^(?:\\*\\*)?Summary:(?:\\*\\*)?\\s*', '', summary, flags=re.IGNORECASE).strip()\n305 | summary = re.sub(r'^(?:\\*\\*)?Consolidated Summary:(?:\\*\\*)?\\s*', '', summary, flags=re.IGNORECASE).strip()\n306 | \n307 | print(f\"📝 Successfully created summary: {summary[:100].replace('\\n', '')}...\")\n308 | \n309 | # Log the event for inspection\n310 | self._log_summarization_event(messages_to_summarize, summary_prompt, summary)\n311 | \n312 | return summary.strip()\n313 | \n314 | except Exception as e:\n315 | print(f\"Error creating conversation summary: {e}\")\n316 | return \"\"\n317 | \n318 | return \"\"\n319 | \n320 | def _build_summary_prompt(self, messages: List[Dict]) -> str:\n321 | \"\"\"Build the summary prompt from conversation messages\"\"\"\n322 | prompt_parts = [\n323 | \"You are tasked with summarizing the following conversation history.\",\n324 | \"Please create a consolidated, comprehensive summary that includes all key topics, requests, and tool outputs.\",\n325 | \"IMPORTANT: If there is a 'PREVIOUS SUMMARY' below, merge the new messages into it to maintain a continuous record. Do not lose information from the previous summary.\\n\",\n326 | \"### CONVERSATION HISTORY TO SUMMARIZE:\\n\"\n327 | ]\n328 | \n329 | for msg in messages:\n330 | role = msg[\"role\"].upper()\n331 | content = msg[\"content\"]\n332 | \n333 | # Identify if this is a previous summary\n334 | is_summary = msg.get(\"metadata\", {}).get(\"is_summary\", False)\n335 | if not is_summary and \"[Previous conversation summary:\" in content:\n336 | is_summary = True\n337 | content = content.replace(\"[Previous conversation summary: \", \"\").rstrip(\"]\")\n338 | \n339 | if is_summary:\n340 | prompt_parts.append(f\"[[ PREVIOUS SUMMARY ]]\\n{content}\\n\")\n341 | else:\n342 | # Truncate very long messages for summary (NOT ideal, but practical) TODO: better handling\n343 | if len(content) > 2000:\n344 | content = content[:2000] + \"...\"\n345 | \n346 | # Handle tool calls in history\n347 | meta = msg.get(\"metadata\", {})\n348 | if meta.get(\"tool_calls\"):\n349 | tool_calls = json.dumps(meta[\"tool_calls\"])\n350 | prompt_parts.append(f\"{role} (calls tools): {tool_calls}\")\n351 | elif role == \"TOOL\":\n352 | name = meta.get(\"tool_name\", \"unknown\")\n353 | prompt_parts.append(f\"TOOL ({name} result): {content}\")\n354 | else:\n355 | prompt_parts.append(f\"{role}: {content}\")\n356 | \n357 | prompt_parts.append(\"\\n### INSTRUCTIONS:\")\n358 | prompt_parts.append(\"- Provide the summary directly, without any introductory phrases like 'The user requested...' or 'Here is the summary'.\")\n359 | prompt_parts.append(\"- Focus strictly on the conversation content.\")\n360 | prompt_parts.append(\"- Output should be a single coherent text block.\")\n361 | \n362 | return \"\\n\".join(prompt_parts)\n363 | \n364 | def _log_summarization_event(self, messages: List[Dict], prompt: str, summary: str):\n365 | \"\"\"Log the summarization event to a file for inspection\"\"\"\n366 | log_file = \"history_log.txt\"\n367 | timestamp = datetime.now().strftime(\"%Y-%m-%d %H:%M:%S\")\n368 | \n369 | with open(log_file, \"a\", encoding=\"utf-8\") as f:\n370 | f.write(\"\\n\" + \"=\"*80 + \"\\n\")\n371 | f.write(f\"SUMMARIZATION EVENT - {timestamp}\\n\")\n372 | f.write(\"=\"*80 + \"\\n\\n\")\n373 | \n374 | f.write(\"--- MESSAGES USED FOR SUMMARY ---\\n\")\n375 | for msg in messages:\n376 | role = msg.get(\"role\", \"unknown\").upper()\n377 | content = msg.get(\"content\", \"\")\n378 | f.write(f\"[{role}]: {content}\\n\")\n379 | if msg.get(\"metadata\"):\n380 | f.write(f\" (Metadata: {json.dumps(msg['metadata'])})\\n\")\n381 | \n382 | f.write(\"\\n--- GENERATED SUMMARY PROMPT ---\\n\")\n383 | f.write(prompt)\n384 | f.write(\"\\n\\n\")\n385 | \n386 | f.write(\"--- RESULTING SUMMARY ---\\n\")\n387 | f.write(summary)\n388 | f.write(\"\\n\\n\")\n389 | f.write(\"=\"*80 + \"\\n\\n\")\n"
},
{
"type": "text",
"text": "<environment_details>\n# VSCode Visible Files\ncore/message_manager.py\n\n# VSCode Open Tabs\ncore/message_manager.py,core/agent.py\n\n# Current Time\nCurrent time in ISO 8601 UTC format: 2025-12-26T16:42:14.437Z\nUser time zone: Europe/Paris, UTC+1:00\n\n# Current Cost\n$0.00\n\n# Current Mode\n<slug>ask</slug>\n<name>❓ Ask</name>\n<model>mistralai/devstral-2-123b-instruct-2512</model>\n<tool_format>native</tool_format>\nYou have not created a todo list yet. Create one with `update_todo_list` if your task is complicated or involves multiple steps.\n</environment_details>"
}
],
"ts": 1766767334442
}
]
}Metadata
Metadata
Assignees
Labels
Issue/PR - TriageNew issue. Needs quick review to confirm validity and assign labels.New issue. Needs quick review to confirm validity and assign labels.bugSomething isn't workingSomething isn't working
Type
Projects
Status
Triage