content: import functools
  import re
  import traceback
  import json
  from typing import List, AsyncGenerator, Sequence, Dict, Any, Optional
  from dataclasses import dataclass
  from enum import Enum
  
  import anyio
  
  from pydantic_ai import Agent, Tool, RunContext
  from pydantic_ai.mcp import MCPServerStreamableHTTP
  from pydantic_ai.messages import (
      FunctionToolCallEvent,
      FunctionToolResultEvent,
      PartStartEvent,
      PartDeltaEvent,
      TextPartDelta,
      ModelResponse,
      TextPart,
      ImageUrl,
      UserContent,
      ModelMessage,
  )
  from pydantic_ai.exceptions import ModelRetry, AgentRunError, UserError
  from pydantic_ai.usage import UsageLimits
  from langchain_core.tools import StructuredTool
  
  from .tool_helpers import (
      get_tool_call_info_content,
      get_tool_response_message,
      get_tool_result_info_content,
      get_tool_run_message,
      get_delegation_call_message,
      get_delegation_response_message,
      get_delegation_info_content,
      get_delegation_result_content,
  )
  from app.modules.intelligence.provider.provider_service import (
      ProviderService,
  )
  from .agent_config import AgentConfig, TaskConfig
  from app.modules.utils.logger import setup_logger
  
  from ..chat_agent import (
      ChatAgent,
      ChatAgentResponse,
      ChatContext,
      ToolCallEventType,
      ToolCallResponse,
  )
  
  logger = setup_logger(__name__)
  
  
  class AgentType(Enum):
      """Types of specialized agents in the multi-agent system"""
  
      SUPERVISOR = "supervisor"
      THINK_EXECUTE = "think_execute"  # Generic Think and Execute Agent
  
  
  @dataclass
  class AgentDelegationResult:
      """Result from agent delegation"""
  
      agent_type: AgentType
      result: str
      success: bool
      error: Optional[str] = None
      usage: Optional[Dict[str, Any]] = None
  
  
  def handle_exception(tool_func):
      @functools.wraps(tool_func)
      def wrapper(*args, **kwargs):
          try:
              return tool_func(*args, **kwargs)
          except Exception:
              logger.exception("Exception in tool function", tool_name=tool_func.__name__)
              return "An internal error occurred. Please try again later."
  
      return wrapper
  
  
  def is_delegation_tool(tool_name: str) -> bool:
      """Check if a tool call is a delegation to a subagent"""
      return tool_name.startswith("delegate_to_")
  
  
  def extract_agent_type_from_delegation_tool(tool_name: str) -> str:
      """Extract agent type from delegation tool name"""
      if tool_name.startswith("delegate_to_"):
          return tool_name[12:]  # Remove "delegate_to_" prefix
      return tool_name
  
  
  def extract_task_result_from_response(response: str) -> str:
      """
      Extract the Task Result section from a subagent response.
      Returns the full Task Result without truncation - can include detailed content and code snippets.
      If no Task Result section is found, return the full response.
      Enhanced to handle error cases and provide better fallbacks.
      """
      import re
  
      if not response or not response.strip():
          logger.warning("Empty response provided to extract_task_result_from_response")
          return ""
  
      # Check for error indicators first
      error_indicators = [
          r"(?i)❌\s*error",
          r"(?i)⚠️\s*error",
          r"(?i)🚨\s*error",
          r"(?i)error\s*occurred",
          r"(?i)failed\s*to",
          r"(?i)exception",
          r"(?i)traceback",
      ]
  
      for error_pattern in error_indicators:
          if re.search(error_pattern, response):
              logger.info("Error indicators found in response, returning full response")
              return response
  
      # Pattern to match Task Result section (case insensitive)
      # Updated patterns to better capture the end of result sections
      patterns = [
          r"(?i)#{1,4}\s*task\s*result[:\s]*\n(.*?)(?=\n#{1,4}\s*(?!task\s*result)\w+|\Z)",
          r"(?i)\*\*task\s*result[:\s]*\*\*\n(.*?)(?=\n\*\*(?!task\s*result)\w+|\Z)",
          r"(?i)task\s*result[:\s]*\n(.*?)(?=\n\w+:|\n#{1,4}\s*\w+|\Z)",
          r"(?i)## result[:\s]*\n(.*?)(?=\n#{1,4}\s*(?!result)\w+|\Z)",
          r"(?i)\*\*result[:\s]*\*\*\n(.*?)(?=\n\*\*(?!result)\w+|\Z)",
      ]
  
      for pattern in patterns:
          match = re.search(pattern, response, re.DOTALL)
          if match:
              summary = match.group(1).strip()
              if summary:
                  logger.info(
                      f"Successfully extracted Task Result from subagent response (length: {len(summary)} chars)"
                  )
                  return summary
  
      # If no Task Result section is found, look for conclusion or final sections
      conclusion_patterns = [
          r"(?i)#{1,4}\s*conclusion[:\s]*\n(.*?)(?=\n#{1,4}\s*\w+|\Z)",
          r"(?i)#{1,4}\s*summary[:\s]*\n(.*?)(?=\n#{1,4}\s*\w+|\Z)",
          r"(?i)#{1,4}\s*findings[:\s]*\n(.*?)(?=\n#{1,4}\s*\w+|\Z)",
      ]
  
      for pattern in conclusion_patterns:
          match = re.search(pattern, response, re.DOTALL)
          if match:
              summary = match.group(1).strip()
              if summary:
                  logger.warning(
                      f"No Task Result found, but found conclusion/summary section (length: {len(summary)} chars)"
                  )
                  return summary
  
      # If still no structured section found, return the last meaningful paragraphs without truncation
      lines = response.strip().split("\n")
      if len(lines) > 10:  # If response is substantial, try to get the final content
          # Look for the last substantial paragraphs
          meaningful_lines = []
          for line in reversed(lines):
              line = line.strip()
              if line:  # Keep all non-empty lines including code blocks
                  meaningful_lines.append(line)
                  if len(meaningful_lines) >= 10:  # Get more content for detailed summary
                      break
  
          if meaningful_lines:
              summary = "\n".join(reversed(meaningful_lines))
              logger.warning(
                  f"No Task Summary section found, using last meaningful content as detailed summary (length: {len(summary)} chars)"
              )
              return summary
  
      # Final fallback: return full response without truncation
      logger.warning(
          f"No Task Summary section found, returning full response (length: {len(response)} chars)"
      )
      return response
  
  
  def create_tool_call_response(event: FunctionToolCallEvent) -> ToolCallResponse:
      """Create appropriate tool call response for regular or delegation tools"""
      tool_name = event.part.tool_name
  
      # Safely parse tool arguments with error handling for malformed JSON
      try:
          args_dict = event.part.args_as_dict()
      except (ValueError, json.JSONDecodeError) as json_error:
          # Handle incomplete/malformed JSON in tool arguments
          # This can happen when the model generates truncated JSON, often due to:
          # - Token limits during streaming
          # - Model stopping mid-generation
          # - Network issues interrupting the response
          raw_args = getattr(event.part, "args", "N/A")
          logger.error(
              f"JSON parsing error in tool call '{tool_name}': {json_error}. "
              f"Tool args (raw, first 300 chars): {str(raw_args)[:300]}. "
              f"This may cause issues when pydantic_ai tries to serialize the message history."
          )
          # Return empty args dict to allow processing to continue
          # Note: This won't prevent errors when pydantic_ai tries to serialize
          # the message history later, but it allows the current tool call to proceed
          args_dict = {}
  
      if is_delegation_tool(tool_name):
          agent_type = extract_agent_type_from_delegation_tool(tool_name)
          task_description = args_dict.get("task_description", "")
          context = args_dict.get("context", "")
  
          return ToolCallResponse(
              call_id=event.part.tool_call_id or "",
              event_type=ToolCallEventType.DELEGATION_CALL,
              tool_name=tool_name,
              tool_response=get_delegation_call_message(agent_type),
              tool_call_details={
                  "summary": get_delegation_info_content(
                      agent_type, task_description, context
                  )
              },
          )
      else:
          return ToolCallResponse(
              call_id=event.part.tool_call_id or "",
              event_type=ToolCallEventType.CALL,
              tool_name=tool_name,
              tool_response=get_tool_run_message(tool_name),
              tool_call_details={
                  "summary": get_tool_call_info_content(tool_name, args_dict)
              },
          )
  
  
  def create_tool_result_response(event: FunctionToolResultEvent) -> ToolCallResponse:
      """Create appropriate tool result response for regular or delegation tools"""
      tool_name = event.result.tool_name or "unknown tool"
  
      if is_delegation_tool(tool_name):
          agent_type = extract_agent_type_from_delegation_tool(tool_name)
          result_content = str(event.result.content) if event.result.content else ""
  
          return ToolCallResponse(
              call_id=event.result.tool_call_id or "",
              event_type=ToolCallEventType.DELEGATION_RESULT,
              tool_name=tool_name,
              tool_response=get_delegation_response_message(agent_type),
              tool_call_details={
                  "summary": get_delegation_result_content(agent_type, result_content)
              },
          )
      else:
          return ToolCallResponse(
              call_id=event.result.tool_call_id or "",
              event_type=ToolCallEventType.RESULT,
              tool_name=tool_name,
              tool_response=get_tool_response_message(tool_name),
              tool_call_details={
                  "summary": get_tool_result_info_content(tool_name, event.result.content)
              },
          )
  
  
  class PydanticMultiAgent(ChatAgent):
      """
      Multi-agent system using Pydantic AI with agent delegation patterns.
  
      This system consists of:
      1. A supervisor agent that coordinates tasks
      2. Specialized delegate agents for specific tasks
      3. Context passing between agents
      4. Usage tracking across all agents
      """
  
      def __init__(
          self,
          llm_provider: ProviderService,
          config: AgentConfig,
          tools: List[StructuredTool],
          mcp_servers: List[dict] | None = None,
          delegate_agents: Optional[Dict[AgentType, AgentConfig]] = None,
      ):
          """Initialize the multi-agent system with configuration and tools"""
  
          self.tasks = config.tasks
          self.max_iter = config.max_iter
          self.llm_provider = llm_provider
          self.tools = tools
          self.config = config
          self.mcp_servers = mcp_servers or []
  
          # Clean tool names (no spaces for pydantic agents)
          for i, tool in enumerate(tools):
              tools[i].name = re.sub(r" ", "", tool.name)
  
          # Initialize delegate agents
          self.delegate_agents = delegate_agents or self._create_default_delegate_agents()
  
          # Store agent instances
          self._agent_instances: Dict[AgentType, Agent] = {}
          self._supervisor_agent: Optional[Agent] = None
  
      # Constants for agent instructions
      DELEGATE_AGENT_INSTRUCTIONS = """You are a focused task execution agent with access to all available tools. Execute the assigned task efficiently and provide clear, concise results.
  
  **CODE MANAGEMENT:**
  - Use code changes tools (add_file_to_changes, update_file_lines, insert_lines, delete_lines) instead of including code in response text
  - Use show_updated_file and show_diff to display changes effectively
  - Keep responses concise and avoid large code blocks in your text
  
  **EXECUTION:**
  - Execute tasks completely without asking for clarification unless absolutely critical
  - Make reasonable assumptions and mention them
  - Use tools to gather information and perform actions
  - Return focused, actionable results"""
  
      # Tool name constants
      TOOL_NAME_SHOW_UPDATED_FILE = "show_updated_file"
      TOOL_NAME_SHOW_DIFF = "show_diff"
  
      @staticmethod
      def _create_error_response(message: str) -> ChatAgentResponse:
          """Create a standardized error response"""
          return ChatAgentResponse(
              response=f"\n\n{message}\n\n",
              tool_calls=[],
              citations=[],
          )
  
      @staticmethod
      async def _yield_text_stream_events(
          request_stream: Any, agent_type: str = "agent"
      ) -> AsyncGenerator[ChatAgentResponse, None]:
          """Yield text streaming events from a request stream"""
          async for event in request_stream:
              if isinstance(event, PartStartEvent) and isinstance(event.part, TextPart):
                  yield ChatAgentResponse(
                      response=event.part.content,
                      tool_calls=[],
                      citations=[],
                  )
              if isinstance(event, PartDeltaEvent) and isinstance(
                  event.delta, TextPartDelta
              ):
                  yield ChatAgentResponse(
                      response=event.delta.content_delta,
                      tool_calls=[],
                      citations=[],
                  )
  
      @staticmethod
      def _handle_stream_error(
          error: Exception, context: str = "model request stream"
      ) -> Optional[ChatAgentResponse]:
          """Handle streaming errors and return appropriate response"""
          if isinstance(error, (ModelRetry, AgentRunError, UserError)):
              logger.warning(f"Pydantic-ai error in {context}: {error}")
              return PydanticMultiAgent._create_error_response(
                  "*Encountered an issue while processing your request. Trying to recover...*"
              )
          elif isinstance(error, anyio.WouldBlock):
              logger.warning(f"{context} would block - continuing...")
              return None  # Signal to continue
          elif isinstance(error, ValueError):
              error_str = str(error)
              if (
                  "json" in error_str.lower()
                  or "parse" in error_str.lower()
                  or "EOF" in error_str
              ):
                  logger.error(
                      f"JSON parsing error in {context} (likely from malformed tool call in message history): {error}. "
                      f"This may indicate a truncated or incomplete tool call from a previous iteration. "
                      f"Full traceback:\n{traceback.format_exc()}"
                  )
                  return PydanticMultiAgent._create_error_response(
                      "*Encountered a parsing error. Skipping this step and continuing...*"
                  )
              else:
                  raise  # Re-raise if it's a different ValueError
          else:
              logger.exception("Unexpected error", context=context)
              if "json" in str(error).lower() or "parse" in str(error).lower():
                  return PydanticMultiAgent._create_error_response(
                      "*Encountered a parsing error. Skipping this step and continuing...*"
                  )
              return PydanticMultiAgent._create_error_response(
                  "*An unexpected error occurred. Continuing...*"
              )
  
      @staticmethod
      def _create_delegation_prompt(
          task_description: str, project_context: str, task_specific_context: str = ""
      ) -> str:
          """Create the delegation prompt for subagents"""
          full_context_parts = [project_context]
          if task_specific_context and task_specific_context.strip():
              full_context_parts.append(f"Task-specific context: {task_specific_context}")
  
          full_context = "\n\n".join(full_context_parts)
  
          return f"""Execute this focused task for the supervisor:
  
  **TASK:**
  {task_description}
  
  **PROJECT CONTEXT:**
  {full_context}
  
  **YOUR MISSION:**
  Execute the task above and return ONLY the specific, actionable result the supervisor needs.
  
  **OUTPUT FORMAT:**
  Start your response with "## Task Result" and then provide the focused answer.
  
  **CRITICAL GUIDELINES:**
  1. Use tools to gather information, analyze code, or perform actions as needed
  2. Be specific and concise - avoid broad explanations or context gathering
  3. Focus on answering the exact question or completing the exact task
  4. If you make code changes, use show_updated_file and show_diff to display them
  5. Don't restate the problem - just solve it and report the result
  
  **RESULT:** Should be specific, actionable, and immediately usable by the supervisor."""
  
      @staticmethod
      def _format_delegation_error(
          agent_type: AgentType,
          task_description: str,
          error_type: str,
          error_message: str,
          raw_response: str = "",
      ) -> str:
          """Format error responses for delegation failures"""
          if error_type == "no_result":
              return f"""
  ## Task Result
  
  ❌ **ERROR: No valid task result found**
  
  **Agent Type:** {agent_type.value}
  **Task:** {task_description}
  **Issue:** The subagent did not provide a properly formatted Task Result section
  
  **Raw Response (truncated):**
  {raw_response[:500]}{'...' if len(raw_response) > 500 else ''}
  
  **Recommendation:** The supervisor should retry the delegation with clearer instructions.
              """.strip()
          elif error_type == "empty_result":
              return f"""
  ## Task Result
  
  ❌ **ERROR: Empty or invalid result**
  
  **Agent Type:** {agent_type.value}
  **Task:** {task_description}
  **Issue:** The subagent returned no output or an invalid response
  
  **Recommendation:** The supervisor should retry the delegation or try a different approach.
              """.strip()
          else:  # exception
              return f"""
  ## Task Result
  
  ❌ **ERROR: Delegation failed**
  
  **Agent Type:** {agent_type.value}
  **Task:** {task_description}
  **Error:** {error_message}
  **Error Type:** {error_type}
  
  **Recommendation:** The supervisor should investigate the error and retry with a different approach or agent.
              """.strip()
  
      @staticmethod
      async def _collect_agent_streaming_response(
          agent: Agent, user_prompt: str, agent_type: str = "agent"
      ) -> str:
          """Collect streaming response from an agent run"""
          full_response = ""
  
          async with agent.iter(
              user_prompt=user_prompt,
              usage_limits=UsageLimits(request_limit=None),
          ) as run:
              async for node in run:
                  if Agent.is_model_request_node(node):
                      # Stream tokens from the model's request
                      async with node.stream(run.ctx) as request_stream:
                          async for event in request_stream:
                              if isinstance(event, PartStartEvent) and isinstance(
                                  event.part, TextPart
                              ):
                                  full_response += event.part.content
                                  logger.debug(
                                      f"[{agent_type}] Streaming chunk: {event.part.content[:100]}{'...' if len(event.part.content) > 100 else ''}"
                                  )
                              if isinstance(event, PartDeltaEvent) and isinstance(
                                  event.delta, TextPartDelta
                              ):
                                  full_response += event.delta.content_delta
                                  logger.debug(
                                      f"[{agent_type}] Streaming delta: {event.delta.content_delta[:100]}{'...' if len(event.delta.content_delta) > 100 else ''}"
                                  )
                  elif Agent.is_end_node(node):
                      break
  
          return full_response
  
      @staticmethod
      async def _yield_tool_result_event(
          event: FunctionToolResultEvent,
      ) -> AsyncGenerator[ChatAgentResponse, None]:
          """Yield appropriate response for tool result events"""
          tool_name = event.result.tool_name or "unknown"
          tool_result = create_tool_result_response(event)
  
          # For show_updated_file and show_diff, append content directly to response
          # instead of going through tool_result_info - these stream directly to user
          if tool_name in (
              PydanticMultiAgent.TOOL_NAME_SHOW_UPDATED_FILE,
              PydanticMultiAgent.TOOL_NAME_SHOW_DIFF,
          ):
              content = str(event.result.content) if event.result.content else ""
              yield ChatAgentResponse(
                  response=content,
                  tool_calls=[tool_result],
                  citations=[],
              )
          else:
              yield ChatAgentResponse(
                  response="",
                  tool_calls=[tool_result],
                  citations=[],
              )
  
      async def _process_agent_run_nodes(
          self, run: Any, context: str = "agent"
      ) -> AsyncGenerator[ChatAgentResponse, None]:
          """Process nodes from an agent run and yield responses"""
          async for node in run:
              if Agent.is_model_request_node(node):
                  # Stream tokens from the model's request
                  try:
                      async with node.stream(run.ctx) as request_stream:
                          async for chunk in self._yield_text_stream_events(
                              request_stream, context
                          ):
                              yield chunk
                  except Exception as e:
                      error_response = self._handle_stream_error(
                          e, f"{context} model request stream"
                      )
                      if error_response:
                          yield error_response
                      continue
  
              elif Agent.is_call_tools_node(node):
                  # Handle tool calls and results
                  async for response in self._process_tool_call_node(node, run.ctx):
                      yield response
  
              elif Agent.is_end_node(node):
                  logger.info(f"{context} result streamed successfully!!")
                  break
  
      async def _process_tool_call_node(
          self, node: Any, ctx: Any
      ) -> AsyncGenerator[ChatAgentResponse, None]:
          """Process tool call nodes and yield responses"""
          try:
              async with node.stream(ctx) as handle_stream:
                  async for event in handle_stream:
                      if isinstance(event, FunctionToolCallEvent):
                          yield ChatAgentResponse(
                              response="",
                              tool_calls=[create_tool_call_response(event)],
                              citations=[],
                          )
                      if isinstance(event, FunctionToolResultEvent):
                          async for response in self._yield_tool_result_event(event):
                              yield response
          except (
              ModelRetry,
              AgentRunError,
              UserError,
          ) as pydantic_error:
              logger.warning(f"Pydantic-ai error in tool call stream: {pydantic_error}")
              yield self._create_error_response(
                  "*Encountered an issue while calling tools. Trying to recover...*"
              )
          except anyio.WouldBlock:
              logger.warning("Tool call stream would block - continuing...")
          except Exception:
              logger.exception("Unexpected error in tool call stream")
              yield self._create_error_response(
                  "*An unexpected error occurred during tool execution. Continuing...*"
              )
  
      def _create_mcp_servers(self) -> List[MCPServerStreamableHTTP]:
          """Create MCP server instances from configuration"""
          mcp_toolsets: List[MCPServerStreamableHTTP] = []
          for mcp_server in self.mcp_servers:
              try:
                  mcp_server_instance = MCPServerStreamableHTTP(
                      url=mcp_server["link"], timeout=10.0
                  )
                  mcp_toolsets.append(mcp_server_instance)
                  logger.info(
                      f"Successfully created MCP server: {mcp_server.get('name', 'unknown')}"
                  )
              except Exception as e:
                  logger.warning(
                      f"Failed to create MCP server {mcp_server.get('name', 'unknown')}: {e}"
                  )
                  continue
          return mcp_toolsets
  
      def _wrap_structured_tools(self, tools: Sequence[Any]) -> List[Tool]:
          """Convert tool instances (StructuredTool or similar) to PydanticAI Tool instances"""
          return [
              Tool(
                  name=tool.name,
                  description=tool.description,
                  function=handle_exception(tool.func),  # type: ignore
              )
              for tool in tools
          ]
  
      def _build_delegate_agent_tools(self) -> List[Tool]:
          """Build the tool list for delegate agents"""
          return self._wrap_structured_tools(self.tools)
  
      def _build_supervisor_agent_tools(self) -> List[Tool]:
          """Build the tool list for supervisor agent including delegation, todo, and code changes tools"""
          # Import tools here to avoid circular imports
          from app.modules.intelligence.tools.todo_management_tool import (
              create_todo_management_tools,
          )
          from app.modules.intelligence.tools.code_changes_manager import (
              create_code_changes_management_tools,
          )
  
          todo_tools = create_todo_management_tools()
          code_changes_tools = create_code_changes_management_tools()
  
          # Create delegation tools
          delegation_tools = []
          for agent_type in self.delegate_agents.keys():
              if agent_type == AgentType.THINK_EXECUTE:
                  description = "🔨 DELEGATE TO TASK EXECUTION AGENT - Delegate focused work to save your context! Great for: information gathering, code searches, targeted implementations, debugging specific issues, analyzing code sections. The subagent will return clean, focused results. Use this liberally to break down complex tasks! IMPORTANT: Use the 'context' parameter to pass already-fetched information (file paths, code snippets, analysis results) to avoid redundant work - this is critical for efficiency!"
              else:
                  description = f"🤖 DELEGATE TO {agent_type.value.upper()} - Delegate focused work to save your context! The subagent will return clean, focused results. Use this liberally to break down complex tasks! IMPORTANT: Use the 'context' parameter to pass already-fetched information (file paths, code snippets, analysis results) to avoid redundant work - this is critical for efficiency!"
  
              delegation_tools.append(
                  Tool(
                      name=f"delegate_to_{agent_type.value}",
                      description=description,
                      function=self._create_delegation_function(agent_type),
                  )
              )
  
          return (
              self._wrap_structured_tools(self.tools)
              + delegation_tools
              + self._wrap_structured_tools(todo_tools)
              + self._wrap_structured_tools(code_changes_tools)
          )
  
      def _create_default_delegate_agents(self) -> Dict[AgentType, AgentConfig]:
          """Create default specialized agents if none provided"""
          return {
              AgentType.THINK_EXECUTE: AgentConfig(
                  role="Task Execution Specialist",
                  goal="Execute specific tasks with clear, actionable results",
                  backstory="""You are a focused task executor for specific, well-defined tasks.
  
  You receive tasks that have clear, specific expected outputs. Your job is to provide exactly what the supervisor needs - no more, no less.
  
  CRITICAL: Do ALL your work inside the "## Task Result" section.
  
  Your approach:
  1. Understand exactly what specific information is needed
  2. Start the "## Task Result" section immediately
  3. Provide the specific answer/information requested
  4. Keep results concise and focused
  5. Include only what the supervisor needs to make a decision
  
  You are used for specific lookups, small implementations, and focused tasks - not broad analysis or context gathering.""",
                  tasks=[
                      TaskConfig(
                          description="""Execute the specific, well-defined task assigned by the supervisor.
  
  This task has a clear expected output. Provide exactly what the supervisor needs.
  
  CRITICAL INSTRUCTIONS:
  - Do ALL your work inside the "## Task Result" section
  - Provide the specific information/answer requested
  - Keep results concise and focused
  - Don't provide broad analysis or context gathering
  - Be efficient - supervisor needs specific information
  
  TASK RESULT SECTION REQUIREMENTS:
  - Start with "## Task Result" immediately
  - Provide the specific answer/information requested
  - Include any code, files, or data needed
  - Keep it focused on what the supervisor asked for
  - End with the specific result requested
  
  Remember: You are used for specific lookups and focused tasks, not broad analysis.""",
                          expected_output="Specific task completion with concrete execution results and deliverables",
                      )
                  ],
                  max_iter=20,
              ),
          }
  
      def _create_agent(self, agent_type: AgentType, ctx: ChatContext) -> Agent:
          """Create a generic delegate agent with all tools for focused task execution"""
          if agent_type in self._agent_instances:
              return self._agent_instances[agent_type]
  
          agent = Agent(
              model=self.llm_provider.get_pydantic_model(),
              tools=self._build_delegate_agent_tools(),
              mcp_servers=self._create_mcp_servers(),
              # Delegate agents get minimal instructions - the full task context comes from delegation
              instructions=self.DELEGATE_AGENT_INSTRUCTIONS,
              # result_type=str,
              output_retries=3,
              output_type=str,
              defer_model_check=True,
              end_strategy="exhaustive",
              instrument=True,
          )
          self._agent_instances[agent_type] = agent
          return agent
  
      def _create_supervisor_agent(self, ctx: ChatContext) -> Agent:
          """Create the supervisor agent that coordinates other agents"""
          if self._supervisor_agent:
              return self._supervisor_agent
  
          # Prepare multimodal instructions if images are present
          multimodal_instructions = self._prepare_multimodal_instructions(ctx)
  
          supervisor_agent = Agent(
              model=self.llm_provider.get_pydantic_model(),
              tools=self._build_supervisor_agent_tools(),
              mcp_servers=self._create_mcp_servers(),
              instructions=f"""
              You are a problem-solving supervisor who orchestrates subagents to efficiently solve complex tasks.
  
              **🚀 MANDATORY PLANNING PHASE (DO THIS FIRST):**
              1. **Analyze:** Understand the request, identify objectives, dependencies, and constraints
              2. **Break down:** Split into logical, delegable chunks (self-contained, clear outcomes, minimal interdependencies)
              3. **Create TODOs:** Use `create_todo` for every step (main tasks → subtasks), mark dependencies, set status to "pending"
              4. **Plan delegation:** Identify what to delegate, determine execution order, plan context needs
              5. **Document:** Summarize problem, list chunks, explain strategy, note assumptions
  
              **📋 EXECUTION & ADAPTATION:**
              - Execute systematically: Follow your plan, delegate tasks with proper context
              - Track progress: Update todo status (pending → in_progress → completed), add notes as you learn
              - Adapt: Update plan and TODOs based on discoveries - your plan can evolve!
              - Verify: Ensure all TODOs complete and objective met
  
              **🎯 INTELLIGENT DELEGATION:**
              **Why delegate:** Subagents return clean results via "## Task Result" format, saving your context.
  
              **When to delegate:** targeted analysis, research, implementation slices etc.
              for information gathering pertaining to the problem don't delegate task since the gathered context might be useful later on aswell
  
              **How to delegate effectively:**
              - Break tasks into focused chunks with clear success criteria
              - **CRITICAL:** Pass already-fetched context via `context` parameter (file paths, code snippets, analysis results, config values)
              - Group related tasks to share context efficiently
              - Example context: "Main function in app/main.py:45-67 uses Config class from app/core/config.py with 'database_url' property. Error at line 52."
  
              **Code Management:**
              - **CRITICAL:** All your code changes for this session are tracked in the code changes manager - it persists throughout the conversation
  