mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
bad05a2bdc
* Add initial harness console for python * Add textual to project * Add planning and approval flows with list selector * Address PR comments * Fix list selection bug * Fix PR #6312 round 2 review comments - Escape untrusted agent text with rich.markup.escape() in observers (text_output, planning_output, reasoning_display) to prevent markup injection - Remove non-functional 'Always approve' choices from tool_approval.py (framework lacks CreateAlwaysApproveToolResponse support) - Remove textual from root pyproject.toml dev deps (sample-specific) - Add PEP 723 inline script metadata to harness_research.py - Narrow except Exception to except NoMatches in list_selection.py Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix build error * Fix build errors --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
81 lines
2.5 KiB
Python
81 lines
2.5 KiB
Python
# Copyright (c) Microsoft. All rights reserved.
|
|
|
|
"""Reasoning display observer for showing thinking content."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import TYPE_CHECKING, Any
|
|
|
|
from rich.markup import escape
|
|
|
|
from .base import ConsoleObserver
|
|
|
|
if TYPE_CHECKING:
|
|
from agent_framework import Agent, Content
|
|
|
|
from ..state_driver import IUXStateDriver
|
|
|
|
|
|
class ReasoningDisplayObserver(ConsoleObserver):
|
|
"""Displays reasoning/thinking content from the agent.
|
|
|
|
Some models (like o1) provide reasoning steps that show their
|
|
internal thought process. This observer displays them with a 💠prefix
|
|
in a dimmed style.
|
|
"""
|
|
|
|
async def on_content(
|
|
self,
|
|
ux: IUXStateDriver,
|
|
content: Content,
|
|
agent: Agent,
|
|
session: Any,
|
|
) -> None:
|
|
"""Display reasoning content.
|
|
|
|
Args:
|
|
ux: The UX state driver for UI updates.
|
|
content: The content item to check for reasoning.
|
|
agent: The AI agent.
|
|
session: The agent session.
|
|
"""
|
|
reasoning_text = self._extract_reasoning(content)
|
|
if reasoning_text:
|
|
# Display reasoning in dim style to differentiate from main output
|
|
ux.append_info_line(f"💠{escape(reasoning_text)}", "dim")
|
|
|
|
def _extract_reasoning(self, content: Content) -> str | None:
|
|
"""Extract reasoning text from content.
|
|
|
|
Args:
|
|
content: The content item to extract reasoning from.
|
|
|
|
Returns:
|
|
The reasoning text, or None if no reasoning is present.
|
|
"""
|
|
# Check for reasoning content type
|
|
if hasattr(content, "type") and content.type in {"text_reasoning", "reasoning"}:
|
|
if hasattr(content, "text"):
|
|
return content.text
|
|
content_attr = getattr(content, "content", None)
|
|
if content_attr:
|
|
return str(content_attr)
|
|
|
|
# Check for reasoning attribute
|
|
reasoning = getattr(content, "reasoning", None)
|
|
if reasoning is not None:
|
|
if isinstance(reasoning, str):
|
|
return reasoning
|
|
if hasattr(reasoning, "text"):
|
|
return reasoning.text
|
|
|
|
# Check for thinking attribute (alternative name)
|
|
thinking = getattr(content, "thinking", None)
|
|
if thinking is not None:
|
|
if isinstance(thinking, str):
|
|
return thinking
|
|
if hasattr(thinking, "text"):
|
|
return thinking.text
|
|
|
|
return None
|