soothe-cli 0.4.6__tar.gz → 0.4.8__tar.gz
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.
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/PKG-INFO +1 -1
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/execution/daemon.py +2 -4
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/execution/headless_renderer.py +1 -1
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/stream/pipeline.py +2 -2
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/config/cli_config.py +0 -13
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/core/event_processor.py +2 -8
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/core/processor_state.py +2 -4
- soothe_cli-0.4.8/src/soothe_cli/shared/tools/__init__.py +96 -0
- soothe_cli-0.4.8/src/soothe_cli/shared/tools/_utils.py +30 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/message_processing.py +1 -1
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_card_payload.py +2 -2
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/execution.py +8 -14
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/fallback.py +2 -2
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/file_ops.py +57 -27
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/goal_formatter.py +6 -5
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/media.py +5 -4
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/subagent.py +2 -2
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/web.py +4 -3
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_output_formatter.py +3 -2
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/_session_stats.py +6 -3
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/app.py +20 -16
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/app.tcss +15 -5
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/textual_adapter.py +751 -253
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/tool_display.py +97 -1
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/loading.py +51 -18
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/message_store.py +31 -1
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/messages.py +1000 -98
- soothe_cli-0.4.6/src/soothe_cli/shared/presentation_engine.py +0 -5
- soothe_cli-0.4.6/src/soothe_cli/shared/renderer_base.py +0 -5
- soothe_cli-0.4.6/src/soothe_cli/shared/stream_accumulator.py +0 -13
- soothe_cli-0.4.6/src/soothe_cli/shared/subagent_routing.py +0 -15
- soothe_cli-0.4.6/src/soothe_cli/shared/tools/__init__.py +0 -3
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/.gitignore +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/README.md +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/pyproject.toml +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/commands/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/commands/autopilot_cmd.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/commands/loop_cmd.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/commands/thread_cmd.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/execution/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/execution/headless.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/execution/launcher.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/main.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/stream/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/stream/context.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/stream/display_line.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/stream/formatter.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/cli/stream/task_scope.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/config/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/plan/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/plan/rich_tree.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/commands/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/commands/command_router.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/commands/slash_commands.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/commands/subagent_routing.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/config_loader.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/core/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/core/presentation_engine.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/core/renderer_protocol.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/events/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/events/display_policy.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/events/essential_events.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/events/explore_task_display.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/events/stream_accumulator.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/events/tui_trace_log.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/rendering/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/rendering/async_renderer_protocol.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/rendering/renderer_base.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/rendering.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_call_resolution.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_card_visibility.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/base.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/structured.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_message_format.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/_ask_user_types.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/_cli_context.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/_env_vars.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/_version.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/command_registry.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/config.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/daemon_session.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/file_ops.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/formatting.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/hooks.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/input.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/media_utils.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/message_display_filter.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/model_config.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/output.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/preview_limits.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/project_utils.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/sessions.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/skills/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/skills/invocation.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/skills/load.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/theme.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/unicode_security.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/update_check.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/__init__.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/_links.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/approval.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/ask_user.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/autopilot_dashboard.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/autopilot_screen.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/clipboard.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/diff.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/editor.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/history.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/status.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/thread_selector.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/tool_renderers.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/tool_widgets.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/tools.py +0 -0
- {soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/tui/widgets/welcome.py +0 -0
|
@@ -20,8 +20,8 @@ from soothe_sdk.client import (
|
|
|
20
20
|
|
|
21
21
|
from soothe_cli.cli.execution.headless_renderer import HeadlessCliRenderer
|
|
22
22
|
from soothe_cli.shared import EventProcessor
|
|
23
|
-
from soothe_cli.shared.
|
|
24
|
-
from soothe_cli.shared.
|
|
23
|
+
from soothe_cli.shared.commands.subagent_routing import parse_subagent_from_input
|
|
24
|
+
from soothe_cli.shared.core.presentation_engine import PresentationEngine
|
|
25
25
|
|
|
26
26
|
logger = logging.getLogger(__name__)
|
|
27
27
|
|
|
@@ -47,7 +47,6 @@ async def run_headless_via_daemon(
|
|
|
47
47
|
|
|
48
48
|
ws_url = websocket_url_from_config(cfg)
|
|
49
49
|
client = WebSocketClient(url=ws_url)
|
|
50
|
-
final_output_mode = getattr(cfg, "final_output_mode", "streaming")
|
|
51
50
|
|
|
52
51
|
try:
|
|
53
52
|
await connect_websocket_with_retries(client)
|
|
@@ -85,7 +84,6 @@ async def run_headless_via_daemon(
|
|
|
85
84
|
renderer = HeadlessCliRenderer()
|
|
86
85
|
processor = EventProcessor(
|
|
87
86
|
renderer,
|
|
88
|
-
final_output_mode=final_output_mode,
|
|
89
87
|
presentation_engine=presentation,
|
|
90
88
|
headless_output=True,
|
|
91
89
|
)
|
|
@@ -30,13 +30,13 @@ from soothe_cli.cli.stream.formatter import (
|
|
|
30
30
|
format_subagent_done,
|
|
31
31
|
format_subagent_milestone,
|
|
32
32
|
)
|
|
33
|
-
from soothe_cli.shared.
|
|
33
|
+
from soothe_cli.shared.core.presentation_engine import PresentationEngine
|
|
34
|
+
from soothe_cli.shared.events.essential_events import (
|
|
34
35
|
LOOP_REASON_EVENT_TYPE,
|
|
35
36
|
is_goal_start_event_type,
|
|
36
37
|
is_step_complete_event_type,
|
|
37
38
|
is_step_start_event_type,
|
|
38
39
|
)
|
|
39
|
-
from soothe_cli.shared.presentation_engine import PresentationEngine
|
|
40
40
|
|
|
41
41
|
logger = logging.getLogger(__name__)
|
|
42
42
|
|
|
@@ -27,8 +27,6 @@ class CLIConfig:
|
|
|
27
27
|
# logging_level: DEBUG/INFO/… for ~/.soothe/logs/soothe-cli.log; None = default INFO.
|
|
28
28
|
logging_level: str | None = None
|
|
29
29
|
|
|
30
|
-
final_output_mode: str = "streaming"
|
|
31
|
-
|
|
32
30
|
# Output streaming overrides (RFC-614)
|
|
33
31
|
output_streaming_enabled: bool | None = None
|
|
34
32
|
"""Override daemon streaming enabled setting."""
|
|
@@ -107,26 +105,15 @@ class CLIConfig:
|
|
|
107
105
|
transports = daemon_section.get("transports", {})
|
|
108
106
|
websocket = transports.get("websocket", {})
|
|
109
107
|
websocket_legacy = data.get("websocket", {})
|
|
110
|
-
ui_section = data.get("ui", {})
|
|
111
108
|
|
|
112
109
|
raw_level = data.get("logging_level")
|
|
113
110
|
if raw_level is not None and not isinstance(raw_level, str):
|
|
114
111
|
raw_level = None
|
|
115
112
|
|
|
116
|
-
raw_final_output_mode = data.get("final_output_mode")
|
|
117
|
-
if raw_final_output_mode is None and isinstance(ui_section, dict):
|
|
118
|
-
raw_final_output_mode = ui_section.get("final_output_mode")
|
|
119
|
-
if not isinstance(raw_final_output_mode, str):
|
|
120
|
-
raw_final_output_mode = "streaming"
|
|
121
|
-
final_output_mode = raw_final_output_mode.strip().lower()
|
|
122
|
-
if final_output_mode not in {"streaming", "batch"}:
|
|
123
|
-
final_output_mode = "streaming"
|
|
124
|
-
|
|
125
113
|
return cls(
|
|
126
114
|
daemon_host=websocket.get("host", websocket_legacy.get("host", "127.0.0.1")),
|
|
127
115
|
daemon_port=websocket.get("port", websocket_legacy.get("port", 8765)),
|
|
128
116
|
logging_level=raw_level,
|
|
129
|
-
final_output_mode=final_output_mode,
|
|
130
117
|
soothe_home=Path(data.get("home", str(Path.home() / ".soothe"))),
|
|
131
118
|
)
|
|
132
119
|
|
|
@@ -82,7 +82,6 @@ class EventProcessor:
|
|
|
82
82
|
self,
|
|
83
83
|
renderer: RendererProtocol,
|
|
84
84
|
*,
|
|
85
|
-
final_output_mode: str = "streaming",
|
|
86
85
|
presentation_engine: PresentationEngine | None = None,
|
|
87
86
|
tui_debug: bool = False,
|
|
88
87
|
headless_output: bool = False,
|
|
@@ -98,9 +97,6 @@ class EventProcessor:
|
|
|
98
97
|
"""
|
|
99
98
|
self._renderer = renderer
|
|
100
99
|
self._headless_output = headless_output
|
|
101
|
-
self._final_output_mode = (
|
|
102
|
-
final_output_mode if final_output_mode in {"streaming", "batch"} else "streaming"
|
|
103
|
-
)
|
|
104
100
|
self._tui_debug = tui_debug
|
|
105
101
|
|
|
106
102
|
rebind = getattr(renderer, "_rebind_presentation", None)
|
|
@@ -1103,12 +1099,10 @@ class EventProcessor:
|
|
|
1103
1099
|
Dict with enabled, mode, and synthesis_streaming fields.
|
|
1104
1100
|
"""
|
|
1105
1101
|
# Use defaults - streaming is enabled by default per RFC-614
|
|
1106
|
-
#
|
|
1102
|
+
# Always use streaming mode
|
|
1107
1103
|
config = {
|
|
1108
1104
|
"enabled": True,
|
|
1109
|
-
"mode":
|
|
1110
|
-
if self._final_output_mode in {"streaming", "batch"}
|
|
1111
|
-
else "streaming",
|
|
1105
|
+
"mode": "streaming",
|
|
1112
1106
|
"synthesis_streaming": True,
|
|
1113
1107
|
}
|
|
1114
1108
|
|
|
@@ -13,7 +13,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
13
13
|
if TYPE_CHECKING:
|
|
14
14
|
from soothe_sdk.client.schemas import Plan
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
from soothe_cli.shared.events.stream_accumulator import StreamingTextAccumulator
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
@dataclass
|
|
@@ -56,9 +56,7 @@ class ProcessorState:
|
|
|
56
56
|
|
|
57
57
|
# Unified streaming text accumulator (RFC-614)
|
|
58
58
|
streaming_accumulator: StreamingTextAccumulator = field(
|
|
59
|
-
default_factory=
|
|
60
|
-
"soothe_cli.shared.stream_accumulator", fromlist=["StreamingTextAccumulator"]
|
|
61
|
-
).StreamingTextAccumulator()
|
|
59
|
+
default_factory=StreamingTextAccumulator
|
|
62
60
|
)
|
|
63
61
|
"""Unified streaming text accumulator with namespace isolation."""
|
|
64
62
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Tool call/result handling utilities."""
|
|
2
|
+
|
|
3
|
+
from soothe_cli.shared.tools.message_processing import (
|
|
4
|
+
accumulate_tool_call_chunks,
|
|
5
|
+
coerce_tool_call_args_to_dict,
|
|
6
|
+
extract_tool_args_dict,
|
|
7
|
+
extract_tool_brief,
|
|
8
|
+
finalize_pending_tool_call,
|
|
9
|
+
format_tool_call_args,
|
|
10
|
+
normalize_tool_calls_list,
|
|
11
|
+
strip_internal_tags,
|
|
12
|
+
tool_calls_have_any_arg_dict,
|
|
13
|
+
try_parse_pending_tool_call_args,
|
|
14
|
+
)
|
|
15
|
+
from soothe_cli.shared.tools.rendering import update_name_map_from_tool_calls
|
|
16
|
+
from soothe_cli.shared.tools.tool_call_resolution import (
|
|
17
|
+
build_streaming_args_overlay,
|
|
18
|
+
infer_tool_name_from_call_id,
|
|
19
|
+
materialize_ai_blocks_with_resolved_tools,
|
|
20
|
+
tool_args_meaningful,
|
|
21
|
+
)
|
|
22
|
+
from soothe_cli.shared.tools.tool_card_payload import (
|
|
23
|
+
ToolResultCardPayload,
|
|
24
|
+
extract_tool_result_card_payload,
|
|
25
|
+
infer_tool_output_suggests_error,
|
|
26
|
+
)
|
|
27
|
+
from soothe_cli.shared.tools.tool_card_visibility import (
|
|
28
|
+
should_elide_completed_tool_call_message,
|
|
29
|
+
should_elide_stream_tool_card_mount,
|
|
30
|
+
should_elide_tool_card_no_info,
|
|
31
|
+
)
|
|
32
|
+
from soothe_cli.shared.tools.tool_formatters import (
|
|
33
|
+
BaseFormatter,
|
|
34
|
+
ExecutionFormatter,
|
|
35
|
+
FallbackFormatter,
|
|
36
|
+
FileOpsFormatter,
|
|
37
|
+
GoalFormatter,
|
|
38
|
+
MediaFormatter,
|
|
39
|
+
StructuredFormatter,
|
|
40
|
+
SubagentFormatter,
|
|
41
|
+
WebFormatter,
|
|
42
|
+
)
|
|
43
|
+
from soothe_cli.shared.tools.tool_message_format import (
|
|
44
|
+
format_content_block_for_tool_display,
|
|
45
|
+
format_tool_message_content,
|
|
46
|
+
run_python_envelope_indicates_failure,
|
|
47
|
+
try_parse_run_python_result_envelope,
|
|
48
|
+
)
|
|
49
|
+
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief, ToolOutputFormatter
|
|
50
|
+
|
|
51
|
+
__all__ = [
|
|
52
|
+
# Message processing
|
|
53
|
+
"accumulate_tool_call_chunks",
|
|
54
|
+
"coerce_tool_call_args_to_dict",
|
|
55
|
+
"extract_tool_args_dict",
|
|
56
|
+
"extract_tool_brief",
|
|
57
|
+
"finalize_pending_tool_call",
|
|
58
|
+
"format_tool_call_args",
|
|
59
|
+
"normalize_tool_calls_list",
|
|
60
|
+
"strip_internal_tags",
|
|
61
|
+
"tool_calls_have_any_arg_dict",
|
|
62
|
+
"try_parse_pending_tool_call_args",
|
|
63
|
+
# Rendering
|
|
64
|
+
"update_name_map_from_tool_calls",
|
|
65
|
+
# Tool call resolution
|
|
66
|
+
"build_streaming_args_overlay",
|
|
67
|
+
"infer_tool_name_from_call_id",
|
|
68
|
+
"materialize_ai_blocks_with_resolved_tools",
|
|
69
|
+
"tool_args_meaningful",
|
|
70
|
+
# Tool card payload
|
|
71
|
+
"ToolResultCardPayload",
|
|
72
|
+
"extract_tool_result_card_payload",
|
|
73
|
+
"infer_tool_output_suggests_error",
|
|
74
|
+
# Tool card visibility
|
|
75
|
+
"should_elide_completed_tool_call_message",
|
|
76
|
+
"should_elide_stream_tool_card_mount",
|
|
77
|
+
"should_elide_tool_card_no_info",
|
|
78
|
+
# Tool message format
|
|
79
|
+
"format_content_block_for_tool_display",
|
|
80
|
+
"format_tool_message_content",
|
|
81
|
+
"run_python_envelope_indicates_failure",
|
|
82
|
+
"try_parse_run_python_result_envelope",
|
|
83
|
+
# Formatter
|
|
84
|
+
"ToolBrief",
|
|
85
|
+
"ToolOutputFormatter",
|
|
86
|
+
# Formatters
|
|
87
|
+
"BaseFormatter",
|
|
88
|
+
"ExecutionFormatter",
|
|
89
|
+
"FallbackFormatter",
|
|
90
|
+
"FileOpsFormatter",
|
|
91
|
+
"GoalFormatter",
|
|
92
|
+
"MediaFormatter",
|
|
93
|
+
"SubagentFormatter",
|
|
94
|
+
"StructuredFormatter",
|
|
95
|
+
"WebFormatter",
|
|
96
|
+
]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Internal utilities for tool formatting (not part of public API)."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def normalize_tool_name(tool_name: str) -> str:
|
|
5
|
+
"""Normalize tool name to snake_case for comparison and lookup.
|
|
6
|
+
|
|
7
|
+
Args:
|
|
8
|
+
tool_name: Raw tool name (may contain dashes or spaces).
|
|
9
|
+
|
|
10
|
+
Returns:
|
|
11
|
+
Lowercase snake_case name.
|
|
12
|
+
"""
|
|
13
|
+
return tool_name.lower().replace("-", "_").replace(" ", "_")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def text_looks_like_error(text: str) -> bool:
|
|
17
|
+
"""Return True if text content suggests a tool failure.
|
|
18
|
+
|
|
19
|
+
Checks for common error indicator substrings.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
text: Tool output text to inspect.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
True if any error indicator is found.
|
|
26
|
+
"""
|
|
27
|
+
if not text:
|
|
28
|
+
return False
|
|
29
|
+
lowered = text.lower()
|
|
30
|
+
return any(indicator in lowered for indicator in ("error", "failed", "exception", "traceback"))
|
|
@@ -392,7 +392,7 @@ def format_tool_call_args(tool_name: str, tool_call: dict[str, Any]) -> str:
|
|
|
392
392
|
def _is_path_arg_name(key: str) -> bool:
|
|
393
393
|
return _PATH_ARG_PATTERN.match(key) is not None
|
|
394
394
|
|
|
395
|
-
max_value_length =
|
|
395
|
+
max_value_length = 50 # Max length for displayed values
|
|
396
396
|
|
|
397
397
|
def _display_path_value(raw: str) -> str:
|
|
398
398
|
out = convert_and_abbreviate_path(raw)
|
|
@@ -13,6 +13,7 @@ from collections.abc import Mapping
|
|
|
13
13
|
from dataclasses import dataclass
|
|
14
14
|
from typing import Any
|
|
15
15
|
|
|
16
|
+
from soothe_cli.shared.tools._utils import text_looks_like_error
|
|
16
17
|
from soothe_cli.shared.tools.tool_call_resolution import infer_tool_name_from_call_id
|
|
17
18
|
from soothe_cli.shared.tools.tool_message_format import (
|
|
18
19
|
format_tool_message_content,
|
|
@@ -38,8 +39,7 @@ def infer_tool_output_suggests_error(output_display: str, _tool_name: str = "")
|
|
|
38
39
|
|
|
39
40
|
if not output_display:
|
|
40
41
|
return False
|
|
41
|
-
|
|
42
|
-
return any(indicator in lowered for indicator in ("error", "failed", "exception", "traceback"))
|
|
42
|
+
return text_looks_like_error(output_display)
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
@dataclass(frozen=True, slots=True)
|
{soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/execution.py
RENAMED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
+
from soothe_cli.shared.tools._utils import normalize_tool_name, text_looks_like_error
|
|
7
8
|
from soothe_cli.shared.tools.tool_formatters.base import BaseFormatter
|
|
8
9
|
from soothe_cli.shared.tools.tool_message_format import try_parse_run_python_result_envelope
|
|
9
10
|
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
@@ -37,10 +38,11 @@ class ExecutionFormatter(BaseFormatter):
|
|
|
37
38
|
'✓ Done'
|
|
38
39
|
"""
|
|
39
40
|
# Normalize tool name
|
|
40
|
-
normalized = tool_name
|
|
41
|
+
normalized = normalize_tool_name(tool_name)
|
|
41
42
|
|
|
42
43
|
# Route to specific formatter
|
|
43
|
-
|
|
44
|
+
# execute/shell/bash are aliases of run_command (per TOOL_REGISTRY)
|
|
45
|
+
if normalized in ("run_command", "execute", "shell", "bash"):
|
|
44
46
|
return self._format_run_command(result)
|
|
45
47
|
if normalized == "run_python":
|
|
46
48
|
return self._format_run_python(result)
|
|
@@ -83,9 +85,7 @@ class ExecutionFormatter(BaseFormatter):
|
|
|
83
85
|
)
|
|
84
86
|
|
|
85
87
|
# Check for other error patterns
|
|
86
|
-
|
|
87
|
-
result_lower = result.lower()
|
|
88
|
-
if any(indicator in result_lower for indicator in error_indicators):
|
|
88
|
+
if text_looks_like_error(result):
|
|
89
89
|
# Extract first line as error message
|
|
90
90
|
first_line = result.partition("\n")[0].strip()
|
|
91
91
|
return ToolBrief(
|
|
@@ -170,13 +170,7 @@ class ExecutionFormatter(BaseFormatter):
|
|
|
170
170
|
|
|
171
171
|
# Handle string result (fallback — not the standard run_python JSON envelope)
|
|
172
172
|
if isinstance(result, str):
|
|
173
|
-
|
|
174
|
-
if (
|
|
175
|
-
"traceback" in lowered
|
|
176
|
-
or "exception:" in lowered
|
|
177
|
-
or "failed:" in lowered
|
|
178
|
-
or result.startswith("Error:")
|
|
179
|
-
):
|
|
173
|
+
if text_looks_like_error(result) or result.startswith("Error:"):
|
|
180
174
|
return ToolBrief(
|
|
181
175
|
icon="✗",
|
|
182
176
|
summary="Execution failed",
|
|
@@ -240,7 +234,7 @@ class ExecutionFormatter(BaseFormatter):
|
|
|
240
234
|
|
|
241
235
|
# Handle string result (fallback)
|
|
242
236
|
if isinstance(result, str):
|
|
243
|
-
if
|
|
237
|
+
if text_looks_like_error(result):
|
|
244
238
|
return ToolBrief(
|
|
245
239
|
icon="✗",
|
|
246
240
|
summary="Start failed",
|
|
@@ -280,7 +274,7 @@ class ExecutionFormatter(BaseFormatter):
|
|
|
280
274
|
'Terminated PID 12345'
|
|
281
275
|
"""
|
|
282
276
|
# Check for error
|
|
283
|
-
if
|
|
277
|
+
if text_looks_like_error(result) or "not found" in result.lower():
|
|
284
278
|
return ToolBrief(
|
|
285
279
|
icon="✗",
|
|
286
280
|
summary="Termination failed",
|
{soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/fallback.py
RENAMED
|
@@ -6,6 +6,7 @@ from typing import Any
|
|
|
6
6
|
|
|
7
7
|
from soothe_sdk.client.protocol import preview_first
|
|
8
8
|
|
|
9
|
+
from soothe_cli.shared.tools._utils import text_looks_like_error
|
|
9
10
|
from soothe_cli.shared.tools.tool_formatters.base import BaseFormatter
|
|
10
11
|
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
11
12
|
|
|
@@ -40,8 +41,7 @@ class FallbackFormatter(BaseFormatter):
|
|
|
40
41
|
# Handle string results
|
|
41
42
|
if isinstance(result, str):
|
|
42
43
|
# Check for error indicators
|
|
43
|
-
|
|
44
|
-
is_error = any(indicator in result.lower() for indicator in error_indicators)
|
|
44
|
+
is_error = text_looks_like_error(result)
|
|
45
45
|
|
|
46
46
|
if is_error:
|
|
47
47
|
# Extract error message (first line or first 80 chars)
|
{soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/file_ops.py
RENAMED
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import re
|
|
6
6
|
from typing import Any
|
|
7
7
|
|
|
8
|
+
from soothe_cli.shared.tools._utils import normalize_tool_name, text_looks_like_error
|
|
8
9
|
from soothe_cli.shared.tools.tool_formatters.base import BaseFormatter
|
|
9
10
|
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
10
11
|
|
|
@@ -12,8 +13,8 @@ from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
|
12
13
|
class FileOpsFormatter(BaseFormatter):
|
|
13
14
|
"""Formatter for file operation tools.
|
|
14
15
|
|
|
15
|
-
Handles: read_file, write_file, delete_file, list_files, search_files,
|
|
16
|
-
grep, ls, file_info
|
|
16
|
+
Handles: read_file, write_file, edit_file, delete_file, list_files, search_files,
|
|
17
|
+
glob, grep, ls, file_info, edit_file_lines, insert_lines, delete_lines, apply_diff
|
|
17
18
|
|
|
18
19
|
Provides semantic summaries with size, line count, and item count metrics.
|
|
19
20
|
"""
|
|
@@ -38,13 +39,33 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
38
39
|
'✓ Read 12 B (2 lines)'
|
|
39
40
|
"""
|
|
40
41
|
# Normalize tool name
|
|
41
|
-
normalized = tool_name
|
|
42
|
+
normalized = normalize_tool_name(tool_name)
|
|
42
43
|
|
|
43
44
|
# Route to specific formatter
|
|
44
45
|
if normalized == "read_file":
|
|
45
46
|
return self._format_read_file(result)
|
|
46
47
|
if normalized == "write_file":
|
|
47
48
|
return self._format_write_file(result)
|
|
49
|
+
if normalized == "edit_file":
|
|
50
|
+
return self._format_file_mutation(
|
|
51
|
+
result, success_summary="Edited file", failure_summary="Edit failed"
|
|
52
|
+
)
|
|
53
|
+
if normalized == "edit_file_lines":
|
|
54
|
+
return self._format_file_mutation(
|
|
55
|
+
result, success_summary="Updated file", failure_summary="Line edit failed"
|
|
56
|
+
)
|
|
57
|
+
if normalized == "insert_lines":
|
|
58
|
+
return self._format_file_mutation(
|
|
59
|
+
result, success_summary="Inserted lines", failure_summary="Insert failed"
|
|
60
|
+
)
|
|
61
|
+
if normalized == "delete_lines":
|
|
62
|
+
return self._format_file_mutation(
|
|
63
|
+
result, success_summary="Deleted lines", failure_summary="Delete lines failed"
|
|
64
|
+
)
|
|
65
|
+
if normalized == "apply_diff":
|
|
66
|
+
return self._format_file_mutation(
|
|
67
|
+
result, success_summary="Applied patch", failure_summary="Patch failed"
|
|
68
|
+
)
|
|
48
69
|
if normalized == "delete_file":
|
|
49
70
|
return self._format_delete_file(result)
|
|
50
71
|
if normalized in ("list_files", "ls"):
|
|
@@ -142,6 +163,28 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
142
163
|
metrics={"size_bytes": size_bytes, "lines": lines},
|
|
143
164
|
)
|
|
144
165
|
|
|
166
|
+
def _format_file_mutation(
|
|
167
|
+
self,
|
|
168
|
+
result: str,
|
|
169
|
+
*,
|
|
170
|
+
success_summary: str,
|
|
171
|
+
failure_summary: str,
|
|
172
|
+
) -> ToolBrief:
|
|
173
|
+
"""Format success/error for tools that mutate file content (write, edit, patch, …)."""
|
|
174
|
+
if text_looks_like_error(result):
|
|
175
|
+
return ToolBrief(
|
|
176
|
+
icon="✗",
|
|
177
|
+
summary=failure_summary,
|
|
178
|
+
detail=self._truncate_text(result, 80),
|
|
179
|
+
metrics={"error": True},
|
|
180
|
+
)
|
|
181
|
+
return ToolBrief(
|
|
182
|
+
icon="✓",
|
|
183
|
+
summary=success_summary,
|
|
184
|
+
detail=None,
|
|
185
|
+
metrics={},
|
|
186
|
+
)
|
|
187
|
+
|
|
145
188
|
def _format_write_file(self, result: str) -> ToolBrief:
|
|
146
189
|
"""Format write_file result.
|
|
147
190
|
|
|
@@ -156,25 +199,10 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
156
199
|
Example:
|
|
157
200
|
>>> brief = formatter._format_write_file("Successfully wrote to file")
|
|
158
201
|
>>> brief.summary
|
|
159
|
-
'Wrote
|
|
202
|
+
'Wrote file'
|
|
160
203
|
"""
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
return ToolBrief(
|
|
164
|
-
icon="✗",
|
|
165
|
-
summary="Write failed",
|
|
166
|
-
detail=self._truncate_text(result, 80),
|
|
167
|
-
metrics={"error": True},
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
# Try to extract size from result (if available)
|
|
171
|
-
# Common patterns: "Wrote X bytes", "Successfully wrote X"
|
|
172
|
-
# For now, show simple success
|
|
173
|
-
return ToolBrief(
|
|
174
|
-
icon="✓",
|
|
175
|
-
summary="Wrote file",
|
|
176
|
-
detail=None,
|
|
177
|
-
metrics={},
|
|
204
|
+
return self._format_file_mutation(
|
|
205
|
+
result, success_summary="Wrote file", failure_summary="Write failed"
|
|
178
206
|
)
|
|
179
207
|
|
|
180
208
|
def _format_delete_file(self, result: str) -> ToolBrief:
|
|
@@ -194,7 +222,7 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
194
222
|
'Deleted'
|
|
195
223
|
"""
|
|
196
224
|
# Check for error
|
|
197
|
-
if
|
|
225
|
+
if text_looks_like_error(result):
|
|
198
226
|
return ToolBrief(
|
|
199
227
|
icon="✗",
|
|
200
228
|
summary="Delete failed",
|
|
@@ -226,7 +254,7 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
226
254
|
'Found 3 items'
|
|
227
255
|
"""
|
|
228
256
|
# Check for error
|
|
229
|
-
if
|
|
257
|
+
if text_looks_like_error(result):
|
|
230
258
|
return ToolBrief(
|
|
231
259
|
icon="✗",
|
|
232
260
|
summary="List failed",
|
|
@@ -265,7 +293,7 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
265
293
|
'Found 2 matches'
|
|
266
294
|
"""
|
|
267
295
|
# Check for error
|
|
268
|
-
if
|
|
296
|
+
if text_looks_like_error(result):
|
|
269
297
|
return ToolBrief(
|
|
270
298
|
icon="✗",
|
|
271
299
|
summary="Search failed",
|
|
@@ -311,12 +339,14 @@ class FileOpsFormatter(BaseFormatter):
|
|
|
311
339
|
>>> brief.summary
|
|
312
340
|
'Found 2 files'
|
|
313
341
|
"""
|
|
314
|
-
# Check for error
|
|
315
|
-
|
|
342
|
+
# Check for actual error message (not file paths containing error-like words)
|
|
343
|
+
# Glob results are newline-separated paths; errors start with "Error:"
|
|
344
|
+
if result.startswith("Error:"):
|
|
345
|
+
error_msg = result[6:].strip()
|
|
316
346
|
return ToolBrief(
|
|
317
347
|
icon="✗",
|
|
318
348
|
summary="Glob failed",
|
|
319
|
-
detail=self._truncate_text(
|
|
349
|
+
detail=self._truncate_text(error_msg, 80),
|
|
320
350
|
metrics={"error": True},
|
|
321
351
|
)
|
|
322
352
|
|
{soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/goal_formatter.py
RENAMED
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
+
from soothe_cli.shared.tools._utils import normalize_tool_name, text_looks_like_error
|
|
7
8
|
from soothe_cli.shared.tools.tool_formatters.base import BaseFormatter
|
|
8
9
|
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
9
10
|
|
|
@@ -36,7 +37,7 @@ class GoalFormatter(BaseFormatter):
|
|
|
36
37
|
'✓ Created goal g1'
|
|
37
38
|
"""
|
|
38
39
|
# Normalize tool name
|
|
39
|
-
normalized = tool_name
|
|
40
|
+
normalized = normalize_tool_name(tool_name)
|
|
40
41
|
|
|
41
42
|
# Route to specific formatter
|
|
42
43
|
if normalized == "create_goal":
|
|
@@ -100,7 +101,7 @@ class GoalFormatter(BaseFormatter):
|
|
|
100
101
|
|
|
101
102
|
# Handle string result (fallback)
|
|
102
103
|
if isinstance(result, str):
|
|
103
|
-
if
|
|
104
|
+
if text_looks_like_error(result):
|
|
104
105
|
return ToolBrief(
|
|
105
106
|
icon="✗",
|
|
106
107
|
summary="Create failed",
|
|
@@ -167,7 +168,7 @@ class GoalFormatter(BaseFormatter):
|
|
|
167
168
|
|
|
168
169
|
# Handle string result (fallback)
|
|
169
170
|
if isinstance(result, str):
|
|
170
|
-
if
|
|
171
|
+
if text_looks_like_error(result):
|
|
171
172
|
return ToolBrief(
|
|
172
173
|
icon="✗",
|
|
173
174
|
summary="List failed",
|
|
@@ -234,7 +235,7 @@ class GoalFormatter(BaseFormatter):
|
|
|
234
235
|
|
|
235
236
|
# Handle string result (fallback)
|
|
236
237
|
if isinstance(result, str):
|
|
237
|
-
if
|
|
238
|
+
if text_looks_like_error(result):
|
|
238
239
|
return ToolBrief(
|
|
239
240
|
icon="✗",
|
|
240
241
|
summary="Complete failed",
|
|
@@ -307,7 +308,7 @@ class GoalFormatter(BaseFormatter):
|
|
|
307
308
|
|
|
308
309
|
# Handle string result (fallback)
|
|
309
310
|
if isinstance(result, str):
|
|
310
|
-
if
|
|
311
|
+
if text_looks_like_error(result):
|
|
311
312
|
return ToolBrief(
|
|
312
313
|
icon="✗",
|
|
313
314
|
summary="Fail operation failed",
|
|
@@ -4,6 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
+
from soothe_cli.shared.tools._utils import normalize_tool_name, text_looks_like_error
|
|
7
8
|
from soothe_cli.shared.tools.tool_formatters.base import BaseFormatter
|
|
8
9
|
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
9
10
|
|
|
@@ -36,7 +37,7 @@ class MediaFormatter(BaseFormatter):
|
|
|
36
37
|
'✓ Transcribed 45.2s (en)'
|
|
37
38
|
"""
|
|
38
39
|
# Normalize tool name
|
|
39
|
-
normalized = tool_name
|
|
40
|
+
normalized = normalize_tool_name(tool_name)
|
|
40
41
|
|
|
41
42
|
# Route to specific formatter
|
|
42
43
|
if normalized == "transcribe_audio":
|
|
@@ -104,7 +105,7 @@ class MediaFormatter(BaseFormatter):
|
|
|
104
105
|
|
|
105
106
|
# Handle string result (fallback)
|
|
106
107
|
if isinstance(result, str):
|
|
107
|
-
if
|
|
108
|
+
if text_looks_like_error(result):
|
|
108
109
|
return ToolBrief(
|
|
109
110
|
icon="✗",
|
|
110
111
|
summary="Transcription failed",
|
|
@@ -182,7 +183,7 @@ class MediaFormatter(BaseFormatter):
|
|
|
182
183
|
|
|
183
184
|
# Handle string result (fallback)
|
|
184
185
|
if isinstance(result, str):
|
|
185
|
-
if
|
|
186
|
+
if text_looks_like_error(result):
|
|
186
187
|
return ToolBrief(
|
|
187
188
|
icon="✗",
|
|
188
189
|
summary="Video info failed",
|
|
@@ -267,7 +268,7 @@ class MediaFormatter(BaseFormatter):
|
|
|
267
268
|
|
|
268
269
|
# Handle string result (fallback)
|
|
269
270
|
if isinstance(result, str):
|
|
270
|
-
if
|
|
271
|
+
if text_looks_like_error(result):
|
|
271
272
|
return ToolBrief(
|
|
272
273
|
icon="✗",
|
|
273
274
|
summary="Image analysis failed",
|
{soothe_cli-0.4.6 → soothe_cli-0.4.8}/src/soothe_cli/shared/tools/tool_formatters/subagent.py
RENAMED
|
@@ -7,6 +7,7 @@ from __future__ import annotations
|
|
|
7
7
|
|
|
8
8
|
from typing import Any
|
|
9
9
|
|
|
10
|
+
from soothe_cli.shared.tools._utils import text_looks_like_error
|
|
10
11
|
from soothe_cli.shared.tools.tool_formatters.base import BaseFormatter
|
|
11
12
|
from soothe_cli.shared.tools.tool_output_formatter import ToolBrief
|
|
12
13
|
|
|
@@ -36,8 +37,7 @@ class SubagentFormatter(BaseFormatter):
|
|
|
36
37
|
# Handle string results
|
|
37
38
|
if isinstance(result, str):
|
|
38
39
|
# Check for error indicators
|
|
39
|
-
|
|
40
|
-
is_error = any(indicator in result.lower() for indicator in error_indicators)
|
|
40
|
+
is_error = text_looks_like_error(result)
|
|
41
41
|
|
|
42
42
|
if is_error:
|
|
43
43
|
# Extract first line of error
|