fast-agent-mcp 0.2.57__py3-none-any.whl → 0.3.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of fast-agent-mcp might be problematic. Click here for more details.

Files changed (234) hide show
  1. fast_agent/__init__.py +127 -0
  2. fast_agent/agents/__init__.py +36 -0
  3. {mcp_agent/core → fast_agent/agents}/agent_types.py +2 -1
  4. fast_agent/agents/llm_agent.py +217 -0
  5. fast_agent/agents/llm_decorator.py +486 -0
  6. mcp_agent/agents/base_agent.py → fast_agent/agents/mcp_agent.py +377 -385
  7. fast_agent/agents/tool_agent.py +168 -0
  8. {mcp_agent → fast_agent}/agents/workflow/chain_agent.py +43 -33
  9. {mcp_agent → fast_agent}/agents/workflow/evaluator_optimizer.py +31 -35
  10. {mcp_agent → fast_agent}/agents/workflow/iterative_planner.py +56 -47
  11. {mcp_agent → fast_agent}/agents/workflow/orchestrator_models.py +4 -4
  12. {mcp_agent → fast_agent}/agents/workflow/parallel_agent.py +34 -41
  13. {mcp_agent → fast_agent}/agents/workflow/router_agent.py +54 -39
  14. {mcp_agent → fast_agent}/cli/__main__.py +5 -3
  15. {mcp_agent → fast_agent}/cli/commands/check_config.py +95 -66
  16. {mcp_agent → fast_agent}/cli/commands/go.py +20 -11
  17. {mcp_agent → fast_agent}/cli/commands/quickstart.py +4 -4
  18. {mcp_agent → fast_agent}/cli/commands/server_helpers.py +1 -1
  19. {mcp_agent → fast_agent}/cli/commands/setup.py +64 -134
  20. {mcp_agent → fast_agent}/cli/commands/url_parser.py +9 -8
  21. {mcp_agent → fast_agent}/cli/main.py +36 -16
  22. {mcp_agent → fast_agent}/cli/terminal.py +2 -2
  23. {mcp_agent → fast_agent}/config.py +13 -2
  24. fast_agent/constants.py +8 -0
  25. {mcp_agent → fast_agent}/context.py +24 -19
  26. {mcp_agent → fast_agent}/context_dependent.py +9 -5
  27. fast_agent/core/__init__.py +17 -0
  28. {mcp_agent → fast_agent}/core/agent_app.py +39 -36
  29. fast_agent/core/core_app.py +135 -0
  30. {mcp_agent → fast_agent}/core/direct_decorators.py +12 -26
  31. {mcp_agent → fast_agent}/core/direct_factory.py +95 -73
  32. {mcp_agent → fast_agent/core}/executor/executor.py +4 -5
  33. {mcp_agent → fast_agent}/core/fastagent.py +32 -32
  34. fast_agent/core/logging/__init__.py +5 -0
  35. {mcp_agent → fast_agent/core}/logging/events.py +3 -3
  36. {mcp_agent → fast_agent/core}/logging/json_serializer.py +1 -1
  37. {mcp_agent → fast_agent/core}/logging/listeners.py +85 -7
  38. {mcp_agent → fast_agent/core}/logging/logger.py +7 -7
  39. {mcp_agent → fast_agent/core}/logging/transport.py +10 -11
  40. fast_agent/core/prompt.py +9 -0
  41. {mcp_agent → fast_agent}/core/validation.py +4 -4
  42. fast_agent/event_progress.py +61 -0
  43. fast_agent/history/history_exporter.py +44 -0
  44. {mcp_agent → fast_agent}/human_input/__init__.py +9 -12
  45. {mcp_agent → fast_agent}/human_input/elicitation_handler.py +26 -8
  46. {mcp_agent → fast_agent}/human_input/elicitation_state.py +7 -7
  47. {mcp_agent → fast_agent}/human_input/simple_form.py +6 -4
  48. {mcp_agent → fast_agent}/human_input/types.py +1 -18
  49. fast_agent/interfaces.py +228 -0
  50. fast_agent/llm/__init__.py +9 -0
  51. mcp_agent/llm/augmented_llm.py → fast_agent/llm/fastagent_llm.py +128 -218
  52. fast_agent/llm/internal/passthrough.py +137 -0
  53. mcp_agent/llm/augmented_llm_playback.py → fast_agent/llm/internal/playback.py +29 -25
  54. mcp_agent/llm/augmented_llm_silent.py → fast_agent/llm/internal/silent.py +10 -17
  55. fast_agent/llm/internal/slow.py +38 -0
  56. {mcp_agent → fast_agent}/llm/memory.py +40 -30
  57. {mcp_agent → fast_agent}/llm/model_database.py +35 -2
  58. {mcp_agent → fast_agent}/llm/model_factory.py +103 -77
  59. fast_agent/llm/model_info.py +126 -0
  60. {mcp_agent/llm/providers → fast_agent/llm/provider/anthropic}/anthropic_utils.py +7 -7
  61. fast_agent/llm/provider/anthropic/llm_anthropic.py +603 -0
  62. {mcp_agent/llm/providers → fast_agent/llm/provider/anthropic}/multipart_converter_anthropic.py +79 -86
  63. fast_agent/llm/provider/bedrock/bedrock_utils.py +218 -0
  64. fast_agent/llm/provider/bedrock/llm_bedrock.py +2192 -0
  65. {mcp_agent/llm/providers → fast_agent/llm/provider/google}/google_converter.py +66 -14
  66. fast_agent/llm/provider/google/llm_google_native.py +431 -0
  67. mcp_agent/llm/providers/augmented_llm_aliyun.py → fast_agent/llm/provider/openai/llm_aliyun.py +6 -7
  68. mcp_agent/llm/providers/augmented_llm_azure.py → fast_agent/llm/provider/openai/llm_azure.py +4 -4
  69. mcp_agent/llm/providers/augmented_llm_deepseek.py → fast_agent/llm/provider/openai/llm_deepseek.py +10 -11
  70. mcp_agent/llm/providers/augmented_llm_generic.py → fast_agent/llm/provider/openai/llm_generic.py +4 -4
  71. mcp_agent/llm/providers/augmented_llm_google_oai.py → fast_agent/llm/provider/openai/llm_google_oai.py +4 -4
  72. mcp_agent/llm/providers/augmented_llm_groq.py → fast_agent/llm/provider/openai/llm_groq.py +14 -16
  73. mcp_agent/llm/providers/augmented_llm_openai.py → fast_agent/llm/provider/openai/llm_openai.py +133 -206
  74. mcp_agent/llm/providers/augmented_llm_openrouter.py → fast_agent/llm/provider/openai/llm_openrouter.py +6 -6
  75. mcp_agent/llm/providers/augmented_llm_tensorzero_openai.py → fast_agent/llm/provider/openai/llm_tensorzero_openai.py +17 -16
  76. mcp_agent/llm/providers/augmented_llm_xai.py → fast_agent/llm/provider/openai/llm_xai.py +6 -6
  77. {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/multipart_converter_openai.py +125 -63
  78. {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/openai_multipart.py +12 -12
  79. {mcp_agent/llm/providers → fast_agent/llm/provider/openai}/openai_utils.py +18 -16
  80. {mcp_agent → fast_agent}/llm/provider_key_manager.py +2 -2
  81. {mcp_agent → fast_agent}/llm/provider_types.py +2 -0
  82. {mcp_agent → fast_agent}/llm/sampling_converter.py +15 -12
  83. {mcp_agent → fast_agent}/llm/usage_tracking.py +23 -5
  84. fast_agent/mcp/__init__.py +43 -0
  85. {mcp_agent → fast_agent}/mcp/elicitation_factory.py +3 -3
  86. {mcp_agent → fast_agent}/mcp/elicitation_handlers.py +19 -10
  87. {mcp_agent → fast_agent}/mcp/gen_client.py +3 -3
  88. fast_agent/mcp/helpers/__init__.py +36 -0
  89. fast_agent/mcp/helpers/content_helpers.py +183 -0
  90. {mcp_agent → fast_agent}/mcp/helpers/server_config_helpers.py +8 -8
  91. {mcp_agent → fast_agent}/mcp/hf_auth.py +25 -23
  92. fast_agent/mcp/interfaces.py +93 -0
  93. {mcp_agent → fast_agent}/mcp/logger_textio.py +4 -4
  94. {mcp_agent → fast_agent}/mcp/mcp_agent_client_session.py +49 -44
  95. {mcp_agent → fast_agent}/mcp/mcp_aggregator.py +66 -115
  96. {mcp_agent → fast_agent}/mcp/mcp_connection_manager.py +16 -23
  97. {mcp_agent/core → fast_agent/mcp}/mcp_content.py +23 -15
  98. {mcp_agent → fast_agent}/mcp/mime_utils.py +39 -0
  99. fast_agent/mcp/prompt.py +159 -0
  100. mcp_agent/mcp/prompt_message_multipart.py → fast_agent/mcp/prompt_message_extended.py +27 -20
  101. {mcp_agent → fast_agent}/mcp/prompt_render.py +21 -19
  102. {mcp_agent → fast_agent}/mcp/prompt_serialization.py +46 -46
  103. fast_agent/mcp/prompts/__main__.py +7 -0
  104. {mcp_agent → fast_agent}/mcp/prompts/prompt_helpers.py +31 -30
  105. {mcp_agent → fast_agent}/mcp/prompts/prompt_load.py +8 -8
  106. {mcp_agent → fast_agent}/mcp/prompts/prompt_server.py +11 -19
  107. {mcp_agent → fast_agent}/mcp/prompts/prompt_template.py +18 -18
  108. {mcp_agent → fast_agent}/mcp/resource_utils.py +1 -1
  109. {mcp_agent → fast_agent}/mcp/sampling.py +31 -26
  110. {mcp_agent/mcp_server → fast_agent/mcp/server}/__init__.py +1 -1
  111. {mcp_agent/mcp_server → fast_agent/mcp/server}/agent_server.py +5 -6
  112. fast_agent/mcp/ui_agent.py +48 -0
  113. fast_agent/mcp/ui_mixin.py +209 -0
  114. fast_agent/mcp_server_registry.py +90 -0
  115. {mcp_agent → fast_agent}/resources/examples/data-analysis/analysis-campaign.py +5 -4
  116. {mcp_agent → fast_agent}/resources/examples/data-analysis/analysis.py +1 -1
  117. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_forms_server.py +25 -3
  118. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/forms_demo.py +3 -3
  119. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/game_character.py +2 -2
  120. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/game_character_handler.py +1 -1
  121. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/tool_call.py +1 -1
  122. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/agent_one.py +1 -1
  123. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/agent_two.py +1 -1
  124. {mcp_agent → fast_agent}/resources/examples/researcher/researcher-eval.py +1 -1
  125. {mcp_agent → fast_agent}/resources/examples/researcher/researcher-imp.py +1 -1
  126. {mcp_agent → fast_agent}/resources/examples/researcher/researcher.py +1 -1
  127. {mcp_agent → fast_agent}/resources/examples/tensorzero/agent.py +2 -2
  128. {mcp_agent → fast_agent}/resources/examples/tensorzero/image_demo.py +3 -3
  129. {mcp_agent → fast_agent}/resources/examples/tensorzero/simple_agent.py +1 -1
  130. {mcp_agent → fast_agent}/resources/examples/workflows/chaining.py +1 -1
  131. {mcp_agent → fast_agent}/resources/examples/workflows/evaluator.py +3 -3
  132. {mcp_agent → fast_agent}/resources/examples/workflows/human_input.py +5 -3
  133. {mcp_agent → fast_agent}/resources/examples/workflows/orchestrator.py +1 -1
  134. {mcp_agent → fast_agent}/resources/examples/workflows/parallel.py +2 -2
  135. {mcp_agent → fast_agent}/resources/examples/workflows/router.py +5 -2
  136. fast_agent/resources/setup/.gitignore +24 -0
  137. fast_agent/resources/setup/agent.py +18 -0
  138. fast_agent/resources/setup/fastagent.config.yaml +44 -0
  139. fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
  140. fast_agent/tools/elicitation.py +369 -0
  141. fast_agent/types/__init__.py +32 -0
  142. fast_agent/types/llm_stop_reason.py +77 -0
  143. fast_agent/ui/__init__.py +38 -0
  144. fast_agent/ui/console_display.py +1005 -0
  145. {mcp_agent/human_input → fast_agent/ui}/elicitation_form.py +56 -39
  146. mcp_agent/human_input/elicitation_forms.py → fast_agent/ui/elicitation_style.py +1 -1
  147. {mcp_agent/core → fast_agent/ui}/enhanced_prompt.py +96 -25
  148. {mcp_agent/core → fast_agent/ui}/interactive_prompt.py +330 -125
  149. fast_agent/ui/mcp_ui_utils.py +224 -0
  150. {mcp_agent → fast_agent/ui}/progress_display.py +2 -2
  151. {mcp_agent/logging → fast_agent/ui}/rich_progress.py +4 -4
  152. {mcp_agent/core → fast_agent/ui}/usage_display.py +3 -8
  153. {fast_agent_mcp-0.2.57.dist-info → fast_agent_mcp-0.3.0.dist-info}/METADATA +7 -7
  154. fast_agent_mcp-0.3.0.dist-info/RECORD +202 -0
  155. fast_agent_mcp-0.3.0.dist-info/entry_points.txt +5 -0
  156. fast_agent_mcp-0.2.57.dist-info/RECORD +0 -192
  157. fast_agent_mcp-0.2.57.dist-info/entry_points.txt +0 -6
  158. mcp_agent/__init__.py +0 -114
  159. mcp_agent/agents/agent.py +0 -92
  160. mcp_agent/agents/workflow/__init__.py +0 -1
  161. mcp_agent/agents/workflow/orchestrator_agent.py +0 -597
  162. mcp_agent/app.py +0 -175
  163. mcp_agent/core/__init__.py +0 -26
  164. mcp_agent/core/prompt.py +0 -191
  165. mcp_agent/event_progress.py +0 -134
  166. mcp_agent/human_input/handler.py +0 -81
  167. mcp_agent/llm/__init__.py +0 -2
  168. mcp_agent/llm/augmented_llm_passthrough.py +0 -232
  169. mcp_agent/llm/augmented_llm_slow.py +0 -53
  170. mcp_agent/llm/providers/__init__.py +0 -8
  171. mcp_agent/llm/providers/augmented_llm_anthropic.py +0 -717
  172. mcp_agent/llm/providers/augmented_llm_bedrock.py +0 -1788
  173. mcp_agent/llm/providers/augmented_llm_google_native.py +0 -495
  174. mcp_agent/llm/providers/sampling_converter_anthropic.py +0 -57
  175. mcp_agent/llm/providers/sampling_converter_openai.py +0 -26
  176. mcp_agent/llm/sampling_format_converter.py +0 -37
  177. mcp_agent/logging/__init__.py +0 -0
  178. mcp_agent/mcp/__init__.py +0 -50
  179. mcp_agent/mcp/helpers/__init__.py +0 -25
  180. mcp_agent/mcp/helpers/content_helpers.py +0 -187
  181. mcp_agent/mcp/interfaces.py +0 -266
  182. mcp_agent/mcp/prompts/__init__.py +0 -0
  183. mcp_agent/mcp/prompts/__main__.py +0 -10
  184. mcp_agent/mcp_server_registry.py +0 -343
  185. mcp_agent/tools/tool_definition.py +0 -14
  186. mcp_agent/ui/console_display.py +0 -790
  187. mcp_agent/ui/console_display_legacy.py +0 -401
  188. {mcp_agent → fast_agent}/agents/workflow/orchestrator_prompts.py +0 -0
  189. {mcp_agent/agents → fast_agent/cli}/__init__.py +0 -0
  190. {mcp_agent → fast_agent}/cli/constants.py +0 -0
  191. {mcp_agent → fast_agent}/core/error_handling.py +0 -0
  192. {mcp_agent → fast_agent}/core/exceptions.py +0 -0
  193. {mcp_agent/cli → fast_agent/core/executor}/__init__.py +0 -0
  194. {mcp_agent → fast_agent/core}/executor/task_registry.py +0 -0
  195. {mcp_agent → fast_agent/core}/executor/workflow_signal.py +0 -0
  196. {mcp_agent → fast_agent}/human_input/form_fields.py +0 -0
  197. {mcp_agent → fast_agent}/llm/prompt_utils.py +0 -0
  198. {mcp_agent/core → fast_agent/llm}/request_params.py +0 -0
  199. {mcp_agent → fast_agent}/mcp/common.py +0 -0
  200. {mcp_agent/executor → fast_agent/mcp/prompts}/__init__.py +0 -0
  201. {mcp_agent → fast_agent}/mcp/prompts/prompt_constants.py +0 -0
  202. {mcp_agent → fast_agent}/py.typed +0 -0
  203. {mcp_agent → fast_agent}/resources/examples/data-analysis/fastagent.config.yaml +0 -0
  204. {mcp_agent → fast_agent}/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +0 -0
  205. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_account_server.py +0 -0
  206. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/elicitation_game_server.py +0 -0
  207. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/fastagent.config.yaml +0 -0
  208. {mcp_agent → fast_agent}/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +0 -0
  209. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/fastagent.config.yaml +0 -0
  210. {mcp_agent → fast_agent}/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +0 -0
  211. {mcp_agent → fast_agent}/resources/examples/researcher/fastagent.config.yaml +0 -0
  212. {mcp_agent → fast_agent}/resources/examples/tensorzero/.env.sample +0 -0
  213. {mcp_agent → fast_agent}/resources/examples/tensorzero/Makefile +0 -0
  214. {mcp_agent → fast_agent}/resources/examples/tensorzero/README.md +0 -0
  215. {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
  216. {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/crab.png +0 -0
  217. {mcp_agent → fast_agent}/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
  218. {mcp_agent → fast_agent}/resources/examples/tensorzero/docker-compose.yml +0 -0
  219. {mcp_agent → fast_agent}/resources/examples/tensorzero/fastagent.config.yaml +0 -0
  220. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/Dockerfile +0 -0
  221. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/entrypoint.sh +0 -0
  222. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/mcp_server.py +0 -0
  223. {mcp_agent → fast_agent}/resources/examples/tensorzero/mcp_server/pyproject.toml +0 -0
  224. {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/system_schema.json +0 -0
  225. {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +0 -0
  226. {mcp_agent → fast_agent}/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +0 -0
  227. {mcp_agent → fast_agent}/resources/examples/workflows/fastagent.config.yaml +0 -0
  228. {mcp_agent → fast_agent}/resources/examples/workflows/graded_report.md +0 -0
  229. {mcp_agent → fast_agent}/resources/examples/workflows/short_story.md +0 -0
  230. {mcp_agent → fast_agent}/resources/examples/workflows/short_story.txt +0 -0
  231. {mcp_agent → fast_agent/ui}/console.py +0 -0
  232. {mcp_agent/core → fast_agent/ui}/mermaid_utils.py +0 -0
  233. {fast_agent_mcp-0.2.57.dist-info → fast_agent_mcp-0.3.0.dist-info}/WHEEL +0 -0
  234. {fast_agent_mcp-0.2.57.dist-info → fast_agent_mcp-0.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,401 +0,0 @@
1
- from typing import Optional, Union
2
-
3
- from mcp.types import CallToolResult
4
- from rich.panel import Panel
5
- from rich.text import Text
6
-
7
- from mcp_agent import console
8
- from mcp_agent.mcp.common import SEP
9
- from mcp_agent.mcp.mcp_aggregator import MCPAggregator
10
-
11
- # Constants
12
- HUMAN_INPUT_TOOL_NAME = "__human_input__"
13
-
14
-
15
- class ConsoleDisplay:
16
- """
17
- Handles displaying formatted messages, tool calls, and results to the console.
18
- This centralizes the UI display logic used by LLM implementations.
19
- """
20
-
21
- def __init__(self, config=None) -> None:
22
- """
23
- Initialize the console display handler.
24
-
25
- Args:
26
- config: Configuration object containing display preferences
27
- """
28
- self.config = config
29
- self._markup = config.logger.enable_markup if config else True
30
-
31
- def show_tool_result(self, result: CallToolResult, name: Optional[str] = None) -> None:
32
- """Display a tool result in a formatted panel."""
33
- if not self.config or not self.config.logger.show_tools:
34
- return
35
-
36
- style = "red" if result.isError else "magenta"
37
-
38
- panel = Panel(
39
- Text(str(result.content), overflow="..."),
40
- title=f"[TOOL RESULT]{f' ({name})' if name else ''}",
41
- title_align="right",
42
- style=style,
43
- border_style="white",
44
- padding=(1, 2),
45
- )
46
-
47
- if self.config and self.config.logger.truncate_tools:
48
- if len(str(result.content)) > 360:
49
- panel.height = 8
50
-
51
- console.console.print(panel, markup=self._markup)
52
- console.console.print("\n")
53
-
54
- def show_tool_call(
55
- self, available_tools, tool_name, tool_args, name: Optional[str] = None
56
- ) -> None:
57
- """Display a tool call in a formatted panel."""
58
- if not self.config or not self.config.logger.show_tools:
59
- return
60
-
61
- display_tool_list = self._format_tool_list(available_tools, tool_name)
62
-
63
- panel = Panel(
64
- Text(str(tool_args), overflow="ellipsis"),
65
- title=f"[TOOL CALL]{f' ({name})' if name else ''}",
66
- title_align="left",
67
- style="magenta",
68
- border_style="white",
69
- subtitle=display_tool_list,
70
- subtitle_align="left",
71
- padding=(1, 2),
72
- )
73
-
74
- if self.config and self.config.logger.truncate_tools:
75
- if len(str(tool_args)) > 360:
76
- panel.height = 8
77
-
78
- console.console.print(panel, markup=self._markup)
79
- console.console.print("\n")
80
-
81
- async def show_tool_update(self, aggregator: MCPAggregator | None, updated_server: str) -> None:
82
- """Show a tool update for a server"""
83
- if not self.config or not self.config.logger.show_tools:
84
- return
85
-
86
- display_server_list = Text()
87
-
88
- if aggregator:
89
- for server_name in await aggregator.list_servers():
90
- style = "green" if updated_server == server_name else "dim white"
91
- display_server_list.append(f"[{server_name}] ", style)
92
-
93
- panel = Panel(
94
- f"[dim green]Updating tools for server {updated_server}[/]",
95
- title="[TOOL UPDATE]",
96
- title_align="left",
97
- style="green",
98
- border_style="white",
99
- padding=(1, 2),
100
- subtitle=display_server_list,
101
- subtitle_align="left",
102
- )
103
- console.console.print("\n")
104
- console.console.print(panel, markup=self._markup)
105
- console.console.print("\n")
106
-
107
- def _format_tool_list(self, available_tools, selected_tool_name):
108
- """Format the list of available tools, highlighting the selected one."""
109
- display_tool_list = Text()
110
- for display_tool in available_tools:
111
- # Handle both OpenAI and Anthropic tool formats
112
- if isinstance(display_tool, dict):
113
- if "function" in display_tool:
114
- # OpenAI format
115
- tool_call_name = display_tool["function"]["name"]
116
- else:
117
- # Anthropic format
118
- tool_call_name = display_tool["name"]
119
- else:
120
- # Handle potential object format (e.g., Pydantic models)
121
- tool_call_name = (
122
- display_tool.function.name
123
- if hasattr(display_tool, "function")
124
- else display_tool.name
125
- )
126
-
127
- parts = (
128
- tool_call_name.split(SEP)
129
- if SEP in tool_call_name
130
- else [tool_call_name, tool_call_name]
131
- )
132
-
133
- if selected_tool_name.split(SEP)[0] == parts[0]:
134
- style = "magenta" if tool_call_name == selected_tool_name else "dim white"
135
- shortened_name = parts[1] if len(parts[1]) <= 12 else parts[1][:11] + "…"
136
- display_tool_list.append(f"[{shortened_name}] ", style)
137
-
138
- return display_tool_list
139
-
140
- async def show_assistant_message(
141
- self,
142
- message_text: Union[str, Text],
143
- aggregator=None,
144
- highlight_namespaced_tool: str = "",
145
- title: str = "ASSISTANT",
146
- name: Optional[str] = None,
147
- ) -> None:
148
- """Display an assistant message in a formatted panel."""
149
- if not self.config or not self.config.logger.show_chat:
150
- return
151
-
152
- display_server_list = Text()
153
-
154
- if aggregator:
155
- # Add human input tool if available
156
- tools = await aggregator.list_tools()
157
- if any(tool.name == HUMAN_INPUT_TOOL_NAME for tool in tools.tools):
158
- style = (
159
- "green" if highlight_namespaced_tool == HUMAN_INPUT_TOOL_NAME else "dim white"
160
- )
161
- display_server_list.append("[human] ", style)
162
-
163
- # Add all available servers
164
- mcp_server_name = (
165
- highlight_namespaced_tool.split(SEP)[0]
166
- if SEP in highlight_namespaced_tool
167
- else highlight_namespaced_tool
168
- )
169
-
170
- for server_name in await aggregator.list_servers():
171
- style = "green" if server_name == mcp_server_name else "dim white"
172
- display_server_list.append(f"[{server_name}] ", style)
173
-
174
- panel = Panel(
175
- message_text,
176
- title=f"[{title}]{f' ({name})' if name else ''}",
177
- title_align="left",
178
- style="green",
179
- border_style="white",
180
- padding=(1, 2),
181
- subtitle=display_server_list,
182
- subtitle_align="left",
183
- )
184
- console.console.print(panel, markup=self._markup)
185
- console.console.print("\n")
186
-
187
- def show_user_message(
188
- self, message, model: Optional[str], chat_turn: int, name: Optional[str] = None
189
- ) -> None:
190
- """Display a user message in a formatted panel."""
191
- if not self.config or not self.config.logger.show_chat:
192
- return
193
-
194
- subtitle_text = Text(f"{model or 'unknown'}", style="dim white")
195
- if chat_turn > 0:
196
- subtitle_text.append(f" turn {chat_turn}", style="dim white")
197
-
198
- panel = Panel(
199
- message,
200
- title=f"{f'({name}) [USER]' if name else '[USER]'}",
201
- title_align="right",
202
- style="blue",
203
- border_style="white",
204
- padding=(1, 2),
205
- subtitle=subtitle_text,
206
- subtitle_align="left",
207
- )
208
- console.console.print(panel, markup=self._markup)
209
- console.console.print("\n")
210
-
211
- async def show_prompt_loaded(
212
- self,
213
- prompt_name: str,
214
- description: Optional[str] = None,
215
- message_count: int = 0,
216
- agent_name: Optional[str] = None,
217
- aggregator=None,
218
- arguments: Optional[dict[str, str]] = None,
219
- ) -> None:
220
- """
221
- Display information about a loaded prompt template.
222
-
223
- Args:
224
- prompt_name: The name of the prompt that was loaded (should be namespaced)
225
- description: Optional description of the prompt
226
- message_count: Number of messages added to the conversation history
227
- agent_name: Name of the agent using the prompt
228
- aggregator: Optional aggregator instance to use for server highlighting
229
- arguments: Optional dictionary of arguments passed to the prompt template
230
- """
231
- if not self.config or not self.config.logger.show_tools:
232
- return
233
-
234
- # Get server name from the namespaced prompt_name
235
- mcp_server_name = None
236
- if SEP in prompt_name:
237
- # Extract the server from the namespaced prompt name
238
- mcp_server_name = prompt_name.split(SEP)[0]
239
- elif aggregator and aggregator.server_names:
240
- # Fallback to first server if not namespaced
241
- mcp_server_name = aggregator.server_names[0]
242
-
243
- # Build the server list with highlighting
244
- display_server_list = Text()
245
- if aggregator:
246
- for server_name in await aggregator.list_servers():
247
- style = "green" if server_name == mcp_server_name else "dim white"
248
- display_server_list.append(f"[{server_name}] ", style)
249
-
250
- # Create content text
251
- content = Text()
252
- messages_phrase = f"Loaded {message_count} message{'s' if message_count != 1 else ''}"
253
- content.append(f"{messages_phrase} from template ", style="cyan italic")
254
- content.append(f"'{prompt_name}'", style="cyan bold italic")
255
-
256
- if agent_name:
257
- content.append(f" for {agent_name}", style="cyan italic")
258
-
259
- # Add template arguments if provided
260
- if arguments:
261
- content.append("\n\nArguments:", style="cyan")
262
- for key, value in arguments.items():
263
- content.append(f"\n {key}: ", style="cyan bold")
264
- content.append(value, style="white")
265
-
266
- if description:
267
- content.append("\n\n", style="default")
268
- content.append(description, style="dim white")
269
-
270
- # Create panel
271
- panel = Panel(
272
- content,
273
- title="[PROMPT LOADED]",
274
- title_align="right",
275
- style="cyan",
276
- border_style="white",
277
- padding=(1, 2),
278
- subtitle=display_server_list,
279
- subtitle_align="left",
280
- )
281
-
282
- console.console.print(panel, markup=self._markup)
283
- console.console.print("\n")
284
-
285
- def show_parallel_results(self, parallel_agent) -> None:
286
- """Display parallel agent results in a clean, organized format.
287
-
288
- Args:
289
- parallel_agent: The parallel agent containing fan_out_agents with results
290
- """
291
- from rich.markdown import Markdown
292
- from rich.text import Text
293
-
294
- if self.config and not self.config.logger.show_chat:
295
- return
296
-
297
- if not parallel_agent or not hasattr(parallel_agent, "fan_out_agents"):
298
- return
299
-
300
- # Collect results and agent information
301
- agent_results = []
302
-
303
- for agent in parallel_agent.fan_out_agents:
304
- # Get the last response text from this agent
305
- message_history = agent.message_history
306
- if not message_history:
307
- continue
308
-
309
- last_message = message_history[-1]
310
- content = last_message.last_text()
311
-
312
- # Get model name
313
- model = "unknown"
314
- if (
315
- hasattr(agent, "_llm")
316
- and agent._llm
317
- and hasattr(agent._llm, "default_request_params")
318
- ):
319
- model = getattr(agent._llm.default_request_params, "model", "unknown")
320
-
321
- # Get usage information
322
- tokens = 0
323
- tool_calls = 0
324
- if hasattr(agent, "usage_accumulator") and agent.usage_accumulator:
325
- summary = agent.usage_accumulator.get_summary()
326
- tokens = summary.get("cumulative_input_tokens", 0) + summary.get(
327
- "cumulative_output_tokens", 0
328
- )
329
- tool_calls = summary.get("cumulative_tool_calls", 0)
330
-
331
- agent_results.append(
332
- {
333
- "name": agent.name,
334
- "model": model,
335
- "content": content,
336
- "tokens": tokens,
337
- "tool_calls": tool_calls,
338
- }
339
- )
340
-
341
- if not agent_results:
342
- return
343
-
344
- # Display header
345
- console.console.print()
346
- console.console.print("[dim]Parallel execution complete[/dim]")
347
- console.console.print()
348
-
349
- # Display results for each agent
350
- for i, result in enumerate(agent_results):
351
- if i > 0:
352
- # Simple full-width separator
353
- console.console.print()
354
- console.console.print("─" * console.console.size.width, style="dim")
355
- console.console.print()
356
-
357
- # Two column header: model name (green) + usage info (dim)
358
- left = f"[green]▎[/green] [bold green]{result['model']}[/bold green]"
359
-
360
- # Build right side with tokens and tool calls if available
361
- right_parts = []
362
- if result["tokens"] > 0:
363
- right_parts.append(f"{result['tokens']:,} tokens")
364
- if result["tool_calls"] > 0:
365
- right_parts.append(f"{result['tool_calls']} tools")
366
-
367
- right = f"[dim]{' • '.join(right_parts) if right_parts else 'no usage data'}[/dim]"
368
-
369
- # Calculate padding to right-align usage info
370
- width = console.console.size.width
371
- left_text = Text.from_markup(left)
372
- right_text = Text.from_markup(right)
373
- padding = max(1, width - left_text.cell_len - right_text.cell_len)
374
-
375
- console.console.print(left + " " * padding + right, markup=self._markup)
376
- console.console.print()
377
-
378
- # Display content as markdown if it looks like markdown, otherwise as text
379
- content = result["content"]
380
- if any(marker in content for marker in ["##", "**", "*", "`", "---", "###"]):
381
- md = Markdown(content)
382
- console.console.print(md, markup=self._markup)
383
- else:
384
- console.console.print(content, markup=self._markup)
385
-
386
- # Summary
387
- console.console.print()
388
- console.console.print("─" * console.console.size.width, style="dim")
389
-
390
- total_tokens = sum(result["tokens"] for result in agent_results)
391
- total_tools = sum(result["tool_calls"] for result in agent_results)
392
-
393
- summary_parts = [f"{len(agent_results)} models"]
394
- if total_tokens > 0:
395
- summary_parts.append(f"{total_tokens:,} tokens")
396
- if total_tools > 0:
397
- summary_parts.append(f"{total_tools} tools")
398
-
399
- summary_text = " • ".join(summary_parts)
400
- console.console.print(f"[dim]{summary_text}[/dim]")
401
- console.console.print()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes