fast-agent-mcp 0.4.7__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.
- fast_agent/__init__.py +183 -0
- fast_agent/acp/__init__.py +19 -0
- fast_agent/acp/acp_aware_mixin.py +304 -0
- fast_agent/acp/acp_context.py +437 -0
- fast_agent/acp/content_conversion.py +136 -0
- fast_agent/acp/filesystem_runtime.py +427 -0
- fast_agent/acp/permission_store.py +269 -0
- fast_agent/acp/server/__init__.py +5 -0
- fast_agent/acp/server/agent_acp_server.py +1472 -0
- fast_agent/acp/slash_commands.py +1050 -0
- fast_agent/acp/terminal_runtime.py +408 -0
- fast_agent/acp/tool_permission_adapter.py +125 -0
- fast_agent/acp/tool_permissions.py +474 -0
- fast_agent/acp/tool_progress.py +814 -0
- fast_agent/agents/__init__.py +85 -0
- fast_agent/agents/agent_types.py +64 -0
- fast_agent/agents/llm_agent.py +350 -0
- fast_agent/agents/llm_decorator.py +1139 -0
- fast_agent/agents/mcp_agent.py +1337 -0
- fast_agent/agents/tool_agent.py +271 -0
- fast_agent/agents/workflow/agents_as_tools_agent.py +849 -0
- fast_agent/agents/workflow/chain_agent.py +212 -0
- fast_agent/agents/workflow/evaluator_optimizer.py +380 -0
- fast_agent/agents/workflow/iterative_planner.py +652 -0
- fast_agent/agents/workflow/maker_agent.py +379 -0
- fast_agent/agents/workflow/orchestrator_models.py +218 -0
- fast_agent/agents/workflow/orchestrator_prompts.py +248 -0
- fast_agent/agents/workflow/parallel_agent.py +250 -0
- fast_agent/agents/workflow/router_agent.py +353 -0
- fast_agent/cli/__init__.py +0 -0
- fast_agent/cli/__main__.py +73 -0
- fast_agent/cli/commands/acp.py +159 -0
- fast_agent/cli/commands/auth.py +404 -0
- fast_agent/cli/commands/check_config.py +783 -0
- fast_agent/cli/commands/go.py +514 -0
- fast_agent/cli/commands/quickstart.py +557 -0
- fast_agent/cli/commands/serve.py +143 -0
- fast_agent/cli/commands/server_helpers.py +114 -0
- fast_agent/cli/commands/setup.py +174 -0
- fast_agent/cli/commands/url_parser.py +190 -0
- fast_agent/cli/constants.py +40 -0
- fast_agent/cli/main.py +115 -0
- fast_agent/cli/terminal.py +24 -0
- fast_agent/config.py +798 -0
- fast_agent/constants.py +41 -0
- fast_agent/context.py +279 -0
- fast_agent/context_dependent.py +50 -0
- fast_agent/core/__init__.py +92 -0
- fast_agent/core/agent_app.py +448 -0
- fast_agent/core/core_app.py +137 -0
- fast_agent/core/direct_decorators.py +784 -0
- fast_agent/core/direct_factory.py +620 -0
- fast_agent/core/error_handling.py +27 -0
- fast_agent/core/exceptions.py +90 -0
- fast_agent/core/executor/__init__.py +0 -0
- fast_agent/core/executor/executor.py +280 -0
- fast_agent/core/executor/task_registry.py +32 -0
- fast_agent/core/executor/workflow_signal.py +324 -0
- fast_agent/core/fastagent.py +1186 -0
- fast_agent/core/logging/__init__.py +5 -0
- fast_agent/core/logging/events.py +138 -0
- fast_agent/core/logging/json_serializer.py +164 -0
- fast_agent/core/logging/listeners.py +309 -0
- fast_agent/core/logging/logger.py +278 -0
- fast_agent/core/logging/transport.py +481 -0
- fast_agent/core/prompt.py +9 -0
- fast_agent/core/prompt_templates.py +183 -0
- fast_agent/core/validation.py +326 -0
- fast_agent/event_progress.py +62 -0
- fast_agent/history/history_exporter.py +49 -0
- fast_agent/human_input/__init__.py +47 -0
- fast_agent/human_input/elicitation_handler.py +123 -0
- fast_agent/human_input/elicitation_state.py +33 -0
- fast_agent/human_input/form_elements.py +59 -0
- fast_agent/human_input/form_fields.py +256 -0
- fast_agent/human_input/simple_form.py +113 -0
- fast_agent/human_input/types.py +40 -0
- fast_agent/interfaces.py +310 -0
- fast_agent/llm/__init__.py +9 -0
- fast_agent/llm/cancellation.py +22 -0
- fast_agent/llm/fastagent_llm.py +931 -0
- fast_agent/llm/internal/passthrough.py +161 -0
- fast_agent/llm/internal/playback.py +129 -0
- fast_agent/llm/internal/silent.py +41 -0
- fast_agent/llm/internal/slow.py +38 -0
- fast_agent/llm/memory.py +275 -0
- fast_agent/llm/model_database.py +490 -0
- fast_agent/llm/model_factory.py +388 -0
- fast_agent/llm/model_info.py +102 -0
- fast_agent/llm/prompt_utils.py +155 -0
- fast_agent/llm/provider/anthropic/anthropic_utils.py +84 -0
- fast_agent/llm/provider/anthropic/cache_planner.py +56 -0
- fast_agent/llm/provider/anthropic/llm_anthropic.py +796 -0
- fast_agent/llm/provider/anthropic/multipart_converter_anthropic.py +462 -0
- fast_agent/llm/provider/bedrock/bedrock_utils.py +218 -0
- fast_agent/llm/provider/bedrock/llm_bedrock.py +2207 -0
- fast_agent/llm/provider/bedrock/multipart_converter_bedrock.py +84 -0
- fast_agent/llm/provider/google/google_converter.py +466 -0
- fast_agent/llm/provider/google/llm_google_native.py +681 -0
- fast_agent/llm/provider/openai/llm_aliyun.py +31 -0
- fast_agent/llm/provider/openai/llm_azure.py +143 -0
- fast_agent/llm/provider/openai/llm_deepseek.py +76 -0
- fast_agent/llm/provider/openai/llm_generic.py +35 -0
- fast_agent/llm/provider/openai/llm_google_oai.py +32 -0
- fast_agent/llm/provider/openai/llm_groq.py +42 -0
- fast_agent/llm/provider/openai/llm_huggingface.py +85 -0
- fast_agent/llm/provider/openai/llm_openai.py +1195 -0
- fast_agent/llm/provider/openai/llm_openai_compatible.py +138 -0
- fast_agent/llm/provider/openai/llm_openrouter.py +45 -0
- fast_agent/llm/provider/openai/llm_tensorzero_openai.py +128 -0
- fast_agent/llm/provider/openai/llm_xai.py +38 -0
- fast_agent/llm/provider/openai/multipart_converter_openai.py +561 -0
- fast_agent/llm/provider/openai/openai_multipart.py +169 -0
- fast_agent/llm/provider/openai/openai_utils.py +67 -0
- fast_agent/llm/provider/openai/responses.py +133 -0
- fast_agent/llm/provider_key_manager.py +139 -0
- fast_agent/llm/provider_types.py +34 -0
- fast_agent/llm/request_params.py +61 -0
- fast_agent/llm/sampling_converter.py +98 -0
- fast_agent/llm/stream_types.py +9 -0
- fast_agent/llm/usage_tracking.py +445 -0
- fast_agent/mcp/__init__.py +56 -0
- fast_agent/mcp/common.py +26 -0
- fast_agent/mcp/elicitation_factory.py +84 -0
- fast_agent/mcp/elicitation_handlers.py +164 -0
- fast_agent/mcp/gen_client.py +83 -0
- fast_agent/mcp/helpers/__init__.py +36 -0
- fast_agent/mcp/helpers/content_helpers.py +352 -0
- fast_agent/mcp/helpers/server_config_helpers.py +25 -0
- fast_agent/mcp/hf_auth.py +147 -0
- fast_agent/mcp/interfaces.py +92 -0
- fast_agent/mcp/logger_textio.py +108 -0
- fast_agent/mcp/mcp_agent_client_session.py +411 -0
- fast_agent/mcp/mcp_aggregator.py +2175 -0
- fast_agent/mcp/mcp_connection_manager.py +723 -0
- fast_agent/mcp/mcp_content.py +262 -0
- fast_agent/mcp/mime_utils.py +108 -0
- fast_agent/mcp/oauth_client.py +509 -0
- fast_agent/mcp/prompt.py +159 -0
- fast_agent/mcp/prompt_message_extended.py +155 -0
- fast_agent/mcp/prompt_render.py +84 -0
- fast_agent/mcp/prompt_serialization.py +580 -0
- fast_agent/mcp/prompts/__init__.py +0 -0
- fast_agent/mcp/prompts/__main__.py +7 -0
- fast_agent/mcp/prompts/prompt_constants.py +18 -0
- fast_agent/mcp/prompts/prompt_helpers.py +238 -0
- fast_agent/mcp/prompts/prompt_load.py +186 -0
- fast_agent/mcp/prompts/prompt_server.py +552 -0
- fast_agent/mcp/prompts/prompt_template.py +438 -0
- fast_agent/mcp/resource_utils.py +215 -0
- fast_agent/mcp/sampling.py +200 -0
- fast_agent/mcp/server/__init__.py +4 -0
- fast_agent/mcp/server/agent_server.py +613 -0
- fast_agent/mcp/skybridge.py +44 -0
- fast_agent/mcp/sse_tracking.py +287 -0
- fast_agent/mcp/stdio_tracking_simple.py +59 -0
- fast_agent/mcp/streamable_http_tracking.py +309 -0
- fast_agent/mcp/tool_execution_handler.py +137 -0
- fast_agent/mcp/tool_permission_handler.py +88 -0
- fast_agent/mcp/transport_tracking.py +634 -0
- fast_agent/mcp/types.py +24 -0
- fast_agent/mcp/ui_agent.py +48 -0
- fast_agent/mcp/ui_mixin.py +209 -0
- fast_agent/mcp_server_registry.py +89 -0
- fast_agent/py.typed +0 -0
- fast_agent/resources/examples/data-analysis/analysis-campaign.py +189 -0
- fast_agent/resources/examples/data-analysis/analysis.py +68 -0
- fast_agent/resources/examples/data-analysis/fastagent.config.yaml +41 -0
- fast_agent/resources/examples/data-analysis/mount-point/WA_Fn-UseC_-HR-Employee-Attrition.csv +1471 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_account_server.py +88 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_forms_server.py +297 -0
- fast_agent/resources/examples/mcp/elicitations/elicitation_game_server.py +164 -0
- fast_agent/resources/examples/mcp/elicitations/fastagent.config.yaml +35 -0
- fast_agent/resources/examples/mcp/elicitations/fastagent.secrets.yaml.example +17 -0
- fast_agent/resources/examples/mcp/elicitations/forms_demo.py +107 -0
- fast_agent/resources/examples/mcp/elicitations/game_character.py +65 -0
- fast_agent/resources/examples/mcp/elicitations/game_character_handler.py +256 -0
- fast_agent/resources/examples/mcp/elicitations/tool_call.py +21 -0
- fast_agent/resources/examples/mcp/state-transfer/agent_one.py +18 -0
- fast_agent/resources/examples/mcp/state-transfer/agent_two.py +18 -0
- fast_agent/resources/examples/mcp/state-transfer/fastagent.config.yaml +27 -0
- fast_agent/resources/examples/mcp/state-transfer/fastagent.secrets.yaml.example +15 -0
- fast_agent/resources/examples/researcher/fastagent.config.yaml +61 -0
- fast_agent/resources/examples/researcher/researcher-eval.py +53 -0
- fast_agent/resources/examples/researcher/researcher-imp.py +189 -0
- fast_agent/resources/examples/researcher/researcher.py +36 -0
- fast_agent/resources/examples/tensorzero/.env.sample +2 -0
- fast_agent/resources/examples/tensorzero/Makefile +31 -0
- fast_agent/resources/examples/tensorzero/README.md +56 -0
- fast_agent/resources/examples/tensorzero/agent.py +35 -0
- fast_agent/resources/examples/tensorzero/demo_images/clam.jpg +0 -0
- fast_agent/resources/examples/tensorzero/demo_images/crab.png +0 -0
- fast_agent/resources/examples/tensorzero/demo_images/shrimp.png +0 -0
- fast_agent/resources/examples/tensorzero/docker-compose.yml +105 -0
- fast_agent/resources/examples/tensorzero/fastagent.config.yaml +19 -0
- fast_agent/resources/examples/tensorzero/image_demo.py +67 -0
- fast_agent/resources/examples/tensorzero/mcp_server/Dockerfile +25 -0
- fast_agent/resources/examples/tensorzero/mcp_server/entrypoint.sh +35 -0
- fast_agent/resources/examples/tensorzero/mcp_server/mcp_server.py +31 -0
- fast_agent/resources/examples/tensorzero/mcp_server/pyproject.toml +11 -0
- fast_agent/resources/examples/tensorzero/simple_agent.py +25 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/system_schema.json +29 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/system_template.minijinja +11 -0
- fast_agent/resources/examples/tensorzero/tensorzero_config/tensorzero.toml +35 -0
- fast_agent/resources/examples/workflows/agents_as_tools_extended.py +73 -0
- fast_agent/resources/examples/workflows/agents_as_tools_simple.py +50 -0
- fast_agent/resources/examples/workflows/chaining.py +37 -0
- fast_agent/resources/examples/workflows/evaluator.py +77 -0
- fast_agent/resources/examples/workflows/fastagent.config.yaml +26 -0
- fast_agent/resources/examples/workflows/graded_report.md +89 -0
- fast_agent/resources/examples/workflows/human_input.py +28 -0
- fast_agent/resources/examples/workflows/maker.py +156 -0
- fast_agent/resources/examples/workflows/orchestrator.py +70 -0
- fast_agent/resources/examples/workflows/parallel.py +56 -0
- fast_agent/resources/examples/workflows/router.py +69 -0
- fast_agent/resources/examples/workflows/short_story.md +13 -0
- fast_agent/resources/examples/workflows/short_story.txt +19 -0
- fast_agent/resources/setup/.gitignore +30 -0
- fast_agent/resources/setup/agent.py +28 -0
- fast_agent/resources/setup/fastagent.config.yaml +65 -0
- fast_agent/resources/setup/fastagent.secrets.yaml.example +38 -0
- fast_agent/resources/setup/pyproject.toml.tmpl +23 -0
- fast_agent/skills/__init__.py +9 -0
- fast_agent/skills/registry.py +235 -0
- fast_agent/tools/elicitation.py +369 -0
- fast_agent/tools/shell_runtime.py +402 -0
- fast_agent/types/__init__.py +59 -0
- fast_agent/types/conversation_summary.py +294 -0
- fast_agent/types/llm_stop_reason.py +78 -0
- fast_agent/types/message_search.py +249 -0
- fast_agent/ui/__init__.py +38 -0
- fast_agent/ui/console.py +59 -0
- fast_agent/ui/console_display.py +1080 -0
- fast_agent/ui/elicitation_form.py +946 -0
- fast_agent/ui/elicitation_style.py +59 -0
- fast_agent/ui/enhanced_prompt.py +1400 -0
- fast_agent/ui/history_display.py +734 -0
- fast_agent/ui/interactive_prompt.py +1199 -0
- fast_agent/ui/markdown_helpers.py +104 -0
- fast_agent/ui/markdown_truncator.py +1004 -0
- fast_agent/ui/mcp_display.py +857 -0
- fast_agent/ui/mcp_ui_utils.py +235 -0
- fast_agent/ui/mermaid_utils.py +169 -0
- fast_agent/ui/message_primitives.py +50 -0
- fast_agent/ui/notification_tracker.py +205 -0
- fast_agent/ui/plain_text_truncator.py +68 -0
- fast_agent/ui/progress_display.py +10 -0
- fast_agent/ui/rich_progress.py +195 -0
- fast_agent/ui/streaming.py +774 -0
- fast_agent/ui/streaming_buffer.py +449 -0
- fast_agent/ui/tool_display.py +422 -0
- fast_agent/ui/usage_display.py +204 -0
- fast_agent/utils/__init__.py +5 -0
- fast_agent/utils/reasoning_stream_parser.py +77 -0
- fast_agent/utils/time.py +22 -0
- fast_agent/workflow_telemetry.py +261 -0
- fast_agent_mcp-0.4.7.dist-info/METADATA +788 -0
- fast_agent_mcp-0.4.7.dist-info/RECORD +261 -0
- fast_agent_mcp-0.4.7.dist-info/WHEEL +4 -0
- fast_agent_mcp-0.4.7.dist-info/entry_points.txt +7 -0
- fast_agent_mcp-0.4.7.dist-info/licenses/LICENSE +201 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""High performance truncation for plain text streaming displays."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import math
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PlainTextTruncator:
|
|
9
|
+
"""Trim plain text content to fit within a target terminal window."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, target_height_ratio: float = 0.7) -> None:
|
|
12
|
+
if not 0 < target_height_ratio <= 1:
|
|
13
|
+
raise ValueError("target_height_ratio must be between 0 and 1")
|
|
14
|
+
self.target_height_ratio = target_height_ratio
|
|
15
|
+
|
|
16
|
+
def truncate(self, text: str, *, terminal_height: int, terminal_width: int) -> str:
|
|
17
|
+
"""Return the most recent portion of text that fits the terminal window.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
text: Full text buffer accumulated during streaming.
|
|
21
|
+
terminal_height: Terminal height in rows.
|
|
22
|
+
terminal_width: Terminal width in columns.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
Tail portion of the text that fits within the target height ratio.
|
|
26
|
+
"""
|
|
27
|
+
if not text:
|
|
28
|
+
return text
|
|
29
|
+
|
|
30
|
+
if terminal_height <= 0 or terminal_width <= 0:
|
|
31
|
+
return text
|
|
32
|
+
|
|
33
|
+
target_rows = max(1, int(terminal_height * self.target_height_ratio))
|
|
34
|
+
width = max(1, terminal_width)
|
|
35
|
+
|
|
36
|
+
idx = len(text)
|
|
37
|
+
rows_used = 0
|
|
38
|
+
start_idx = 0
|
|
39
|
+
|
|
40
|
+
while idx > 0 and rows_used < target_rows:
|
|
41
|
+
prev_newline = text.rfind("\n", 0, idx)
|
|
42
|
+
line_start = prev_newline + 1 if prev_newline != -1 else 0
|
|
43
|
+
line = text[line_start:idx]
|
|
44
|
+
expanded = line.expandtabs()
|
|
45
|
+
line_len = len(expanded)
|
|
46
|
+
line_rows = max(1, math.ceil(line_len / width)) if line_len else 1
|
|
47
|
+
|
|
48
|
+
if rows_used + line_rows >= target_rows:
|
|
49
|
+
rows_remaining = target_rows - rows_used
|
|
50
|
+
if rows_remaining <= 0:
|
|
51
|
+
start_idx = idx
|
|
52
|
+
break
|
|
53
|
+
|
|
54
|
+
if line_rows <= rows_remaining:
|
|
55
|
+
start_idx = line_start
|
|
56
|
+
else:
|
|
57
|
+
approx_chars = width * rows_remaining
|
|
58
|
+
keep_chars = min(len(line), approx_chars)
|
|
59
|
+
start_idx = idx - keep_chars
|
|
60
|
+
break
|
|
61
|
+
|
|
62
|
+
rows_used += line_rows
|
|
63
|
+
start_idx = line_start
|
|
64
|
+
if prev_newline == -1:
|
|
65
|
+
break
|
|
66
|
+
idx = prev_newline
|
|
67
|
+
|
|
68
|
+
return text[start_idx:]
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Centralized progress display configuration for MCP Agent.
|
|
3
|
+
Provides a shared progress display instance for consistent progress handling.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from fast_agent.ui.console import console
|
|
7
|
+
from fast_agent.ui.rich_progress import RichProgressDisplay
|
|
8
|
+
|
|
9
|
+
# Main progress display instance - shared across the application
|
|
10
|
+
progress_display = RichProgressDisplay(console)
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"""Rich-based progress display for MCP Agent."""
|
|
2
|
+
|
|
3
|
+
import time
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
from rich.console import Console
|
|
8
|
+
from rich.progress import Progress, SpinnerColumn, TaskID, TextColumn
|
|
9
|
+
|
|
10
|
+
from fast_agent.event_progress import ProgressAction, ProgressEvent
|
|
11
|
+
from fast_agent.ui.console import console as default_console
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class RichProgressDisplay:
|
|
15
|
+
"""Rich-based display for progress events."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, console: Console | None = None) -> None:
|
|
18
|
+
"""Initialize the progress display."""
|
|
19
|
+
self.console = console or default_console
|
|
20
|
+
self._taskmap: dict[str, TaskID] = {}
|
|
21
|
+
self._progress = Progress(
|
|
22
|
+
SpinnerColumn(spinner_name="simpleDotsScrolling"),
|
|
23
|
+
TextColumn(
|
|
24
|
+
"[progress.description]{task.description}▎",
|
|
25
|
+
# table_column=Column(max_width=16),
|
|
26
|
+
),
|
|
27
|
+
TextColumn(text_format="{task.fields[target]:<16}", style="Bold Blue"),
|
|
28
|
+
TextColumn(text_format="{task.fields[details]}", style="white"),
|
|
29
|
+
console=self.console,
|
|
30
|
+
transient=False,
|
|
31
|
+
)
|
|
32
|
+
self._paused = False
|
|
33
|
+
|
|
34
|
+
def start(self) -> None:
|
|
35
|
+
"""start"""
|
|
36
|
+
|
|
37
|
+
self._progress.start()
|
|
38
|
+
|
|
39
|
+
def stop(self) -> None:
|
|
40
|
+
"""Stop and clear the progress display."""
|
|
41
|
+
# Hide all tasks before stopping (like pause does)
|
|
42
|
+
for task in self._progress.tasks:
|
|
43
|
+
task.visible = False
|
|
44
|
+
self._progress.stop()
|
|
45
|
+
self._paused = True
|
|
46
|
+
|
|
47
|
+
def pause(self) -> None:
|
|
48
|
+
"""Pause the progress display."""
|
|
49
|
+
if not self._paused:
|
|
50
|
+
self._paused = True
|
|
51
|
+
|
|
52
|
+
for task in self._progress.tasks:
|
|
53
|
+
task.visible = False
|
|
54
|
+
self._progress.stop()
|
|
55
|
+
|
|
56
|
+
def resume(self) -> None:
|
|
57
|
+
"""Resume the progress display."""
|
|
58
|
+
if self._paused:
|
|
59
|
+
for task in self._progress.tasks:
|
|
60
|
+
task.visible = True
|
|
61
|
+
self._paused = False
|
|
62
|
+
self._progress.start()
|
|
63
|
+
|
|
64
|
+
def hide_task(self, task_name: str) -> None:
|
|
65
|
+
"""Hide an existing task from the progress display by name."""
|
|
66
|
+
task_id = self._taskmap.get(task_name)
|
|
67
|
+
if task_id is None:
|
|
68
|
+
return
|
|
69
|
+
for task in self._progress.tasks:
|
|
70
|
+
if task.id == task_id:
|
|
71
|
+
task.visible = False
|
|
72
|
+
break
|
|
73
|
+
|
|
74
|
+
@contextmanager
|
|
75
|
+
def paused(self):
|
|
76
|
+
"""Context manager for temporarily pausing the display."""
|
|
77
|
+
self.pause()
|
|
78
|
+
try:
|
|
79
|
+
yield
|
|
80
|
+
finally:
|
|
81
|
+
self.resume()
|
|
82
|
+
|
|
83
|
+
def _get_action_style(self, action: ProgressAction) -> str:
|
|
84
|
+
"""Map actions to appropriate styles."""
|
|
85
|
+
return {
|
|
86
|
+
ProgressAction.STARTING: "bold yellow",
|
|
87
|
+
ProgressAction.LOADED: "dim green",
|
|
88
|
+
ProgressAction.INITIALIZED: "dim green",
|
|
89
|
+
ProgressAction.CHATTING: "bold blue",
|
|
90
|
+
ProgressAction.STREAMING: "bold green", # Assistant Colour
|
|
91
|
+
ProgressAction.THINKING: "bold yellow", # Assistant Colour
|
|
92
|
+
ProgressAction.ROUTING: "bold blue",
|
|
93
|
+
ProgressAction.PLANNING: "bold blue",
|
|
94
|
+
ProgressAction.READY: "dim green",
|
|
95
|
+
ProgressAction.CALLING_TOOL: "bold magenta",
|
|
96
|
+
ProgressAction.TOOL_PROGRESS: "bold magenta",
|
|
97
|
+
ProgressAction.FINISHED: "black on green",
|
|
98
|
+
ProgressAction.SHUTDOWN: "black on red",
|
|
99
|
+
ProgressAction.AGGREGATOR_INITIALIZED: "bold green",
|
|
100
|
+
ProgressAction.FATAL_ERROR: "black on red",
|
|
101
|
+
}.get(action, "white")
|
|
102
|
+
|
|
103
|
+
def update(self, event: ProgressEvent) -> None:
|
|
104
|
+
"""Update the progress display with a new event."""
|
|
105
|
+
task_name = event.agent_name or "default"
|
|
106
|
+
|
|
107
|
+
# Create new task if needed
|
|
108
|
+
if task_name not in self._taskmap:
|
|
109
|
+
task_id = self._progress.add_task(
|
|
110
|
+
"",
|
|
111
|
+
total=None,
|
|
112
|
+
target=event.target or task_name,
|
|
113
|
+
details=event.details or "",
|
|
114
|
+
task_name=task_name,
|
|
115
|
+
)
|
|
116
|
+
self._taskmap[task_name] = task_id
|
|
117
|
+
else:
|
|
118
|
+
task_id = self._taskmap[task_name]
|
|
119
|
+
|
|
120
|
+
# Ensure no None values in the update
|
|
121
|
+
# For streaming, use custom description immediately to avoid flashing
|
|
122
|
+
if (
|
|
123
|
+
event.action == ProgressAction.STREAMING or event.action == ProgressAction.THINKING
|
|
124
|
+
) and event.streaming_tokens:
|
|
125
|
+
# Account for [dim][/dim] tags (11 characters) in padding calculation
|
|
126
|
+
formatted_tokens = f"▎[dim]◀[/dim] {event.streaming_tokens.strip()}".ljust(17 + 11)
|
|
127
|
+
description = f"[{self._get_action_style(event.action)}]{formatted_tokens}"
|
|
128
|
+
elif event.action == ProgressAction.CHATTING:
|
|
129
|
+
# Add special formatting for chatting with dimmed arrow
|
|
130
|
+
formatted_text = f"▎[dim]▶[/dim] {event.action.value.strip()}".ljust(17 + 11)
|
|
131
|
+
description = f"[{self._get_action_style(event.action)}]{formatted_text}"
|
|
132
|
+
elif event.action == ProgressAction.CALLING_TOOL:
|
|
133
|
+
# Add special formatting for calling tool with dimmed arrow
|
|
134
|
+
formatted_text = f"▎[dim]◀[/dim] {event.action.value}".ljust(17 + 11)
|
|
135
|
+
description = f"[{self._get_action_style(event.action)}]{formatted_text}"
|
|
136
|
+
elif event.action == ProgressAction.TOOL_PROGRESS:
|
|
137
|
+
# Format similar to streaming - show progress numbers
|
|
138
|
+
if event.progress is not None:
|
|
139
|
+
if event.total is not None:
|
|
140
|
+
progress_display = f"{int(event.progress)}/{int(event.total)}"
|
|
141
|
+
else:
|
|
142
|
+
progress_display = str(int(event.progress))
|
|
143
|
+
else:
|
|
144
|
+
progress_display = "Processing"
|
|
145
|
+
formatted_text = f"▎[dim]▶[/dim] {progress_display}".ljust(17 + 11)
|
|
146
|
+
description = f"[{self._get_action_style(event.action)}]{formatted_text}"
|
|
147
|
+
else:
|
|
148
|
+
description = f"[{self._get_action_style(event.action)}]▎ {event.action.value:<15}"
|
|
149
|
+
|
|
150
|
+
# Update basic task information
|
|
151
|
+
update_kwargs: dict[str, Any] = {
|
|
152
|
+
"description": description,
|
|
153
|
+
"target": event.target or task_name, # Use task_name as fallback for target
|
|
154
|
+
"details": event.details or "",
|
|
155
|
+
"task_name": task_name,
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
# For TOOL_PROGRESS events, update progress if available
|
|
159
|
+
if event.action == ProgressAction.TOOL_PROGRESS and event.progress is not None:
|
|
160
|
+
if event.total is not None:
|
|
161
|
+
update_kwargs["completed"] = event.progress
|
|
162
|
+
update_kwargs["total"] = event.total
|
|
163
|
+
else:
|
|
164
|
+
# If no total, reset to indeterminate but keep other fields
|
|
165
|
+
self._progress.reset(task_id)
|
|
166
|
+
# Still need to update after reset to apply the fields
|
|
167
|
+
|
|
168
|
+
self._progress.update(task_id, **update_kwargs)
|
|
169
|
+
|
|
170
|
+
if (
|
|
171
|
+
event.action == ProgressAction.INITIALIZED
|
|
172
|
+
or event.action == ProgressAction.READY
|
|
173
|
+
or event.action == ProgressAction.LOADED
|
|
174
|
+
):
|
|
175
|
+
self._progress.update(task_id, completed=100, total=100)
|
|
176
|
+
elif event.action == ProgressAction.FINISHED:
|
|
177
|
+
self._progress.update(
|
|
178
|
+
task_id,
|
|
179
|
+
completed=100,
|
|
180
|
+
total=100,
|
|
181
|
+
target=event.target or task_name,
|
|
182
|
+
details=f" / Elapsed Time {time.strftime('%H:%M:%S', time.gmtime(self._progress.tasks[task_id].elapsed))}",
|
|
183
|
+
task_name=task_name,
|
|
184
|
+
)
|
|
185
|
+
elif event.action == ProgressAction.FATAL_ERROR:
|
|
186
|
+
self._progress.update(
|
|
187
|
+
task_id,
|
|
188
|
+
completed=100,
|
|
189
|
+
total=100,
|
|
190
|
+
target=event.target or task_name,
|
|
191
|
+
details=f" / {event.details}",
|
|
192
|
+
task_name=task_name,
|
|
193
|
+
)
|
|
194
|
+
else:
|
|
195
|
+
self._progress.reset(task_id)
|