soothe-cli 0.7.9__tar.gz → 0.7.11__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.7.9 → soothe_cli-0.7.11}/PKG-INFO +1 -1
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/policy/display_policy.py +3 -3
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/state/step_router.py +2 -3
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/preview_limits.py +1 -1
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/textual_adapter.py +80 -97
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_step.py +2 -37
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_step_activity.py +0 -17
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/.gitignore +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/README.md +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/pyproject.toml +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/autopilot_cmd.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/config_cmd.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/cron_cmd.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/loop_cmd.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/run_cmd.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/commands/status_cmd.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/execution/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/execution/daemon.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/execution/daemon_errors.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/execution/headless.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/execution/headless_renderer.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/execution/launcher.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/cli/main.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/config/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/config/cli_config.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/config/loader.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/config/logging_setup.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/headless/processor.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/headless/processor_state.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/parse/message_processing.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/parse/tool_call_resolution.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/parse/tool_result.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/policy/essential_events.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/policy/tui_trace_log.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/duration_format.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/engine.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/renderer_base.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/renderer_protocol.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/subagent_task_display.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/state/file_tracker.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/state/session_stats.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/state/stream_accumulator.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/state/transcript.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/transport/session.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/turn/pipeline.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/turn/prepare.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/wire/chunk_filter.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/wire/message_text.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/wire/messages.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/_cli_context.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/_env_vars.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/_version.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_app.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_execution.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_history.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_messages_mixin.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_model.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_module_init.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_startup.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/_ui.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/app/app.tcss +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/binding.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/command_registry.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/commands/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/commands/command_router.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/commands/slash_commands.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/commands/subagent_routing.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/config.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/file_change_notify.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/file_change_renderers.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/hooks.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/input.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/markdown_theme.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/media_utils.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/model_config.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/path_utils.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/project_utils.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/sessions.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/shell_color.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/skills/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/skills/invocation.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/skills/load.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/spinner_labels.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/theme.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/tips.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/tool_display.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/unicode_security.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/update_check.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/_links.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/autocomplete.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/chat_input.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/clipboard.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/context_viewer.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/diff.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/editor.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/file_change_preview.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/help_screen.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/history.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/loading.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/loop_selector.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/mcp_viewer.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/message_store.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/__init__.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/_helpers.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/app.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/assistant.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/clarification.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_goal_tree.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_reason.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_subagent.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/diff_message.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/error.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/skill.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/user.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/model_selector.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/notification_settings.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/plan_quick_view_overlay.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/status.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/theme_selector.py +0 -0
- {soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/welcome.py +0 -0
|
@@ -134,9 +134,9 @@ class DisplayPolicy:
|
|
|
134
134
|
"""Check if this is a plan-related event."""
|
|
135
135
|
return event_type.startswith("soothe.cognition.plan.")
|
|
136
136
|
|
|
137
|
-
def
|
|
138
|
-
"""Check if this is a
|
|
139
|
-
return event_type.startswith("soothe.subagent.
|
|
137
|
+
def is_subagent_wire_event(self, event_type: str) -> bool:
|
|
138
|
+
"""Check if this is a curated subagent wire event."""
|
|
139
|
+
return event_type.startswith("soothe.subagent.")
|
|
140
140
|
|
|
141
141
|
def is_internal_event(self, event_type: str) -> bool:
|
|
142
142
|
"""Check if this is an internal (never-shown) event."""
|
|
@@ -174,9 +174,8 @@ class StepTaskRouter:
|
|
|
174
174
|
) -> None:
|
|
175
175
|
"""Promote a pending step card to running only when it is executing (RFC-628).
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
the active step is allowed only while no sibling step card is already running.
|
|
177
|
+
Future steps are not pre-mounted in the message list; only the active step
|
|
178
|
+
may transition to ``running`` before ``step.started`` when tools arrive early.
|
|
180
179
|
"""
|
|
181
180
|
if getattr(step_w, "_status", "") != "pending":
|
|
182
181
|
return
|
|
@@ -15,7 +15,7 @@ from typing import Final
|
|
|
15
15
|
STEP_CARD_SHOW_TOOL_ROW_DETAILS: Final[bool] = False
|
|
16
16
|
|
|
17
17
|
# Latest per-tool invocation lines on step and SubAgent cards (shared activity tree).
|
|
18
|
-
STEP_CARD_TOOL_ACTIVITY_PREVIEW_COUNT: Final[int] =
|
|
18
|
+
STEP_CARD_TOOL_ACTIVITY_PREVIEW_COUNT: Final[int] = 2
|
|
19
19
|
|
|
20
20
|
# Optional manual full tool-list folding threshold (not auto-collapse).
|
|
21
21
|
STEP_TASK_CARD_COLLAPSE_LINE_THRESHOLD: Final[int] = 3
|
|
@@ -52,6 +52,11 @@ from soothe_sdk.ux.loop_stream import (
|
|
|
52
52
|
is_stream_terminal,
|
|
53
53
|
)
|
|
54
54
|
from soothe_sdk.ux.stream_tool_wire import STREAM_TOOL_CALL_UPDATE, TOOL_CALL_UPDATES_BATCH
|
|
55
|
+
from soothe_sdk.ux.subagent_wire_display import (
|
|
56
|
+
SubagentWireRenderKind,
|
|
57
|
+
classify_subagent_wire_render,
|
|
58
|
+
subagent_wire_row_params,
|
|
59
|
+
)
|
|
55
60
|
from soothe_sdk.ux.task_namespace import (
|
|
56
61
|
TaskScope,
|
|
57
62
|
is_inner_subgraph_task_tool_id,
|
|
@@ -293,9 +298,6 @@ class TextualUIAdapter:
|
|
|
293
298
|
self._execute_wave_completed: int = 0
|
|
294
299
|
"""Completed steps in the current execute batch."""
|
|
295
300
|
|
|
296
|
-
self._successful_step_ids: set[str] = set()
|
|
297
|
-
"""Step ids that finished successfully this loop (survives plan=keep replays)."""
|
|
298
|
-
|
|
299
301
|
self._clarification_input_by_step: dict[str, ClarificationInputMessage] = {}
|
|
300
302
|
"""Active inline ``ClarificationInputMessage`` widgets keyed by step id.
|
|
301
303
|
|
|
@@ -401,7 +403,7 @@ def _stream_end_pending_error_message(
|
|
|
401
403
|
if is_daemon_worker_thread_lost(err_msg) or is_daemon_worker_subprocess_lost(err_msg):
|
|
402
404
|
return "Worker stopped during stream"
|
|
403
405
|
if end_state == "idle" and any(
|
|
404
|
-
getattr(widget, "_status", "")
|
|
406
|
+
getattr(widget, "_status", "") == "running"
|
|
405
407
|
for widget in adapter._current_step_messages.values()
|
|
406
408
|
):
|
|
407
409
|
return "Stream ended before steps completed"
|
|
@@ -951,34 +953,6 @@ def _ingest_wire_step_on_subagent_card(
|
|
|
951
953
|
subagent_card.set_tool_success(row_id, "", duration_ms=duration_ms)
|
|
952
954
|
|
|
953
955
|
|
|
954
|
-
def _subagent_wire_step_params(
|
|
955
|
-
event_type: str,
|
|
956
|
-
data: dict[str, Any],
|
|
957
|
-
) -> tuple[str, dict[str, Any], str, int] | None:
|
|
958
|
-
"""Map curated subagent wire events to SubAgent card row fields."""
|
|
959
|
-
et = str(event_type or "").strip()
|
|
960
|
-
if et.endswith(".gather.summary"):
|
|
961
|
-
query = str(data.get("query_preview", "") or "").strip()
|
|
962
|
-
rc = int(data.get("result_count", 0) or 0)
|
|
963
|
-
st = int(data.get("sources_touched", 0) or 0)
|
|
964
|
-
preview = query
|
|
965
|
-
if rc or st:
|
|
966
|
-
tail = f"{rc} hits, {st} sources"
|
|
967
|
-
preview = f"{query} → {tail}" if query else tail
|
|
968
|
-
return "WebSearch", {"query": preview or query}, "success", 0
|
|
969
|
-
if et.endswith(".step.completed"):
|
|
970
|
-
tool_name = str(data.get("tool_name", "") or "").strip() or "Step"
|
|
971
|
-
args_preview = str(data.get("args_preview", "") or "").strip()
|
|
972
|
-
status = str(data.get("status", "done") or "done").strip().lower()
|
|
973
|
-
phase = "success" if status in ("done", "success", "complete") else "running"
|
|
974
|
-
if status in ("error", "failed"):
|
|
975
|
-
phase = "error"
|
|
976
|
-
duration_ms = int(data.get("duration_ms", 0) or 0)
|
|
977
|
-
args = {"preview": args_preview} if args_preview else {}
|
|
978
|
-
return tool_name, args, phase, duration_ms
|
|
979
|
-
return None
|
|
980
|
-
|
|
981
|
-
|
|
982
956
|
def _apply_subagent_wire_step_event(
|
|
983
957
|
adapter: TextualUIAdapter,
|
|
984
958
|
*,
|
|
@@ -986,8 +960,8 @@ def _apply_subagent_wire_step_event(
|
|
|
986
960
|
data: dict[str, Any],
|
|
987
961
|
task_scope: TaskScope,
|
|
988
962
|
) -> bool:
|
|
989
|
-
"""Render
|
|
990
|
-
params =
|
|
963
|
+
"""Render row-style subagent wire events on the SubAgent (TASK) card."""
|
|
964
|
+
params = subagent_wire_row_params(event_type, data)
|
|
991
965
|
if params is None:
|
|
992
966
|
return False
|
|
993
967
|
tool_name, args, phase, duration_ms = params
|
|
@@ -1011,6 +985,29 @@ def _apply_subagent_wire_step_event(
|
|
|
1011
985
|
return True
|
|
1012
986
|
|
|
1013
987
|
|
|
988
|
+
def _apply_subagent_wire_activity_event(
|
|
989
|
+
adapter: TextualUIAdapter,
|
|
990
|
+
*,
|
|
991
|
+
event_type: str,
|
|
992
|
+
data: dict[str, Any],
|
|
993
|
+
task_scope: TaskScope,
|
|
994
|
+
) -> bool:
|
|
995
|
+
"""Render note-style subagent wire events on the SubAgent card."""
|
|
996
|
+
from soothe_sdk.ux.subagent_progress import summarize_subagent_wire_activity
|
|
997
|
+
|
|
998
|
+
line = summarize_subagent_wire_activity(str(event_type or "").strip(), data).strip()
|
|
999
|
+
if not line:
|
|
1000
|
+
return False
|
|
1001
|
+
step_id = task_scope_step_id(task_scope)
|
|
1002
|
+
if not step_id:
|
|
1003
|
+
return True
|
|
1004
|
+
subagent_card = _ensure_subagent_card_for_task_scope(adapter, task_scope)
|
|
1005
|
+
if subagent_card is None:
|
|
1006
|
+
return True
|
|
1007
|
+
subagent_card.append_subagent_activity(line)
|
|
1008
|
+
return True
|
|
1009
|
+
|
|
1010
|
+
|
|
1014
1011
|
def _apply_subagent_wire_lifecycle_event(
|
|
1015
1012
|
adapter: TextualUIAdapter,
|
|
1016
1013
|
*,
|
|
@@ -1021,7 +1018,7 @@ def _apply_subagent_wire_lifecycle_event(
|
|
|
1021
1018
|
"""Handle subagent ``*.completed`` / ``*.failed`` wire events (RFC-628, IG-513)."""
|
|
1022
1019
|
et = str(event_type or "").strip()
|
|
1023
1020
|
if not (et.endswith(".completed") or et.endswith(".failed")):
|
|
1024
|
-
return
|
|
1021
|
+
return False
|
|
1025
1022
|
step_id = task_scope_step_id(task_scope)
|
|
1026
1023
|
task_idx = task_scope_task_idx(task_scope, step_id)
|
|
1027
1024
|
card = adapter._subagent_cards_by_key.get(_subagent_registry_key(step_id, task_idx))
|
|
@@ -1048,6 +1045,39 @@ def _apply_subagent_wire_lifecycle_event(
|
|
|
1048
1045
|
return True
|
|
1049
1046
|
|
|
1050
1047
|
|
|
1048
|
+
def _route_subagent_wire_event(
|
|
1049
|
+
adapter: TextualUIAdapter,
|
|
1050
|
+
*,
|
|
1051
|
+
event_type: str,
|
|
1052
|
+
data: dict[str, Any],
|
|
1053
|
+
task_scope: TaskScope,
|
|
1054
|
+
) -> bool:
|
|
1055
|
+
"""Route a curated subagent wire event to the unified display protocol handlers."""
|
|
1056
|
+
kind = classify_subagent_wire_render(event_type)
|
|
1057
|
+
if kind is SubagentWireRenderKind.ACTIVITY_ROW:
|
|
1058
|
+
return _apply_subagent_wire_step_event(
|
|
1059
|
+
adapter,
|
|
1060
|
+
event_type=event_type,
|
|
1061
|
+
data=data,
|
|
1062
|
+
task_scope=task_scope,
|
|
1063
|
+
)
|
|
1064
|
+
if kind is SubagentWireRenderKind.ACTIVITY_NOTE:
|
|
1065
|
+
return _apply_subagent_wire_activity_event(
|
|
1066
|
+
adapter,
|
|
1067
|
+
event_type=event_type,
|
|
1068
|
+
data=data,
|
|
1069
|
+
task_scope=task_scope,
|
|
1070
|
+
)
|
|
1071
|
+
if kind is SubagentWireRenderKind.LIFECYCLE_END:
|
|
1072
|
+
return _apply_subagent_wire_lifecycle_event(
|
|
1073
|
+
adapter,
|
|
1074
|
+
event_type=event_type,
|
|
1075
|
+
data=data,
|
|
1076
|
+
task_scope=task_scope,
|
|
1077
|
+
)
|
|
1078
|
+
return False
|
|
1079
|
+
|
|
1080
|
+
|
|
1051
1081
|
def _route_subgraph_tool_call(
|
|
1052
1082
|
adapter: TextualUIAdapter,
|
|
1053
1083
|
router: StepTaskRouter,
|
|
@@ -1415,12 +1445,16 @@ async def _ensure_goal_tree_message(
|
|
|
1415
1445
|
return widget
|
|
1416
1446
|
|
|
1417
1447
|
|
|
1418
|
-
async def
|
|
1448
|
+
async def cleanup_stale_plan_step_cards(
|
|
1419
1449
|
adapter: TextualUIAdapter,
|
|
1420
1450
|
*,
|
|
1421
1451
|
steps: list[dict[str, Any]],
|
|
1422
1452
|
) -> None:
|
|
1423
|
-
"""
|
|
1453
|
+
"""Drop stale pending step cards after replan; do not mount future steps.
|
|
1454
|
+
|
|
1455
|
+
Planned and queued steps appear only in the Ctrl+T plan quick view (goal tree).
|
|
1456
|
+
Step cards mount in the message list when ``step_started`` fires.
|
|
1457
|
+
"""
|
|
1424
1458
|
planned_ids = {
|
|
1425
1459
|
str(row.get("id", "")).strip()
|
|
1426
1460
|
for row in steps
|
|
@@ -1435,23 +1469,6 @@ async def sync_pending_step_cards_from_plan(
|
|
|
1435
1469
|
if bound is widget:
|
|
1436
1470
|
adapter._step_by_namespace.pop(ns, None)
|
|
1437
1471
|
|
|
1438
|
-
for row in steps:
|
|
1439
|
-
if not isinstance(row, dict):
|
|
1440
|
-
continue
|
|
1441
|
-
sid = str(row.get("id", "")).strip()
|
|
1442
|
-
if not sid or sid in adapter._current_step_messages:
|
|
1443
|
-
continue
|
|
1444
|
-
if _is_successful_step_id(adapter, sid):
|
|
1445
|
-
continue
|
|
1446
|
-
desc = str(row.get("description", "")).strip() or "(step)"
|
|
1447
|
-
step_widget = CognitionStepMessage(
|
|
1448
|
-
step_id=sid,
|
|
1449
|
-
description=desc,
|
|
1450
|
-
id=f"step-{uuid.uuid4().hex[:8]}",
|
|
1451
|
-
)
|
|
1452
|
-
await adapter._mount_message(step_widget)
|
|
1453
|
-
adapter._current_step_messages[sid] = step_widget
|
|
1454
|
-
|
|
1455
1472
|
|
|
1456
1473
|
def _step_card_lookup_keys(step_id: str) -> list[str]:
|
|
1457
1474
|
"""Return dict lookup keys for a step id (canonical and wire variants)."""
|
|
@@ -1468,17 +1485,6 @@ def _step_card_lookup_keys(step_id: str) -> list[str]:
|
|
|
1468
1485
|
return keys
|
|
1469
1486
|
|
|
1470
1487
|
|
|
1471
|
-
def _register_successful_step_id(adapter: TextualUIAdapter, step_id: str) -> None:
|
|
1472
|
-
"""Remember a step that completed successfully so plan=keep does not remount it."""
|
|
1473
|
-
for key in _step_card_lookup_keys(step_id):
|
|
1474
|
-
adapter._successful_step_ids.add(key)
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
def _is_successful_step_id(adapter: TextualUIAdapter, step_id: str) -> bool:
|
|
1478
|
-
"""True when this step already succeeded earlier in the current loop."""
|
|
1479
|
-
return any(key in adapter._successful_step_ids for key in _step_card_lookup_keys(step_id))
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
1488
|
def _lookup_step_card(
|
|
1483
1489
|
adapter: TextualUIAdapter,
|
|
1484
1490
|
step_id: str,
|
|
@@ -2823,7 +2829,6 @@ async def execute_task_textual(
|
|
|
2823
2829
|
router.reset_turn()
|
|
2824
2830
|
adapter._execute_wave_total = 0
|
|
2825
2831
|
adapter._execute_wave_completed = 0
|
|
2826
|
-
adapter._successful_step_ids.clear()
|
|
2827
2832
|
ui_coalesce = TurnToolUiCoalescer()
|
|
2828
2833
|
adapter._goal_completion_mounted_this_turn = False
|
|
2829
2834
|
adapter._goal_tree_message = None
|
|
@@ -3832,7 +3837,7 @@ async def execute_task_textual(
|
|
|
3832
3837
|
done_steps,
|
|
3833
3838
|
len(raw_steps),
|
|
3834
3839
|
)
|
|
3835
|
-
await
|
|
3840
|
+
await cleanup_stale_plan_step_cards(
|
|
3836
3841
|
adapter,
|
|
3837
3842
|
steps=raw_steps,
|
|
3838
3843
|
)
|
|
@@ -3850,26 +3855,13 @@ async def execute_task_textual(
|
|
|
3850
3855
|
if event_type == STRANGE_LOOP_STEP_QUEUED:
|
|
3851
3856
|
step_id = str(data.get("step_id", "")).strip()
|
|
3852
3857
|
description = str(data.get("description", "")).strip()
|
|
3853
|
-
if step_id:
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
)
|
|
3861
|
-
await adapter._mount_message(step_widget)
|
|
3862
|
-
adapter._current_step_messages[step_id] = step_widget
|
|
3863
|
-
elif description:
|
|
3864
|
-
step_widget.set_description(description)
|
|
3865
|
-
step_widget.set_queued()
|
|
3866
|
-
if not ns_key:
|
|
3867
|
-
_sync_goal_tree_step_phase(
|
|
3868
|
-
adapter,
|
|
3869
|
-
step_id,
|
|
3870
|
-
"queued",
|
|
3871
|
-
description=description,
|
|
3872
|
-
)
|
|
3858
|
+
if step_id and not ns_key:
|
|
3859
|
+
_sync_goal_tree_step_phase(
|
|
3860
|
+
adapter,
|
|
3861
|
+
step_id,
|
|
3862
|
+
"queued",
|
|
3863
|
+
description=description,
|
|
3864
|
+
)
|
|
3873
3865
|
continue
|
|
3874
3866
|
|
|
3875
3867
|
if event_type == STRANGE_LOOP_STEP_STARTED:
|
|
@@ -3985,8 +3977,6 @@ async def execute_task_textual(
|
|
|
3985
3977
|
pending_text_by_namespace[ns_key] = ""
|
|
3986
3978
|
assistant_message_by_namespace.pop(ns_key, None)
|
|
3987
3979
|
success = bool(data.get("success", True))
|
|
3988
|
-
if success:
|
|
3989
|
-
_register_successful_step_id(adapter, step_id)
|
|
3990
3980
|
duration_ms = int(data.get("duration_ms", 0))
|
|
3991
3981
|
tool_call_count = int(data.get("tool_call_count", 0))
|
|
3992
3982
|
summary = str(
|
|
@@ -4172,20 +4162,13 @@ async def execute_task_textual(
|
|
|
4172
4162
|
and event_type.startswith("soothe.subagent.")
|
|
4173
4163
|
and is_allowlisted_subagent_event_type(event_type)
|
|
4174
4164
|
):
|
|
4175
|
-
if
|
|
4165
|
+
if _route_subagent_wire_event(
|
|
4176
4166
|
adapter,
|
|
4177
4167
|
event_type=event_type,
|
|
4178
4168
|
data=data,
|
|
4179
4169
|
task_scope=task_scope,
|
|
4180
4170
|
):
|
|
4181
4171
|
continue
|
|
4182
|
-
_apply_subagent_wire_lifecycle_event(
|
|
4183
|
-
adapter,
|
|
4184
|
-
event_type=event_type,
|
|
4185
|
-
data=data,
|
|
4186
|
-
task_scope=task_scope,
|
|
4187
|
-
)
|
|
4188
|
-
continue
|
|
4189
4172
|
finally:
|
|
4190
4173
|
await ui_coalesce.after_chunk()
|
|
4191
4174
|
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_step.py
RENAMED
|
@@ -135,7 +135,7 @@ class CognitionStepMessage(Vertical):
|
|
|
135
135
|
super().__init__(**kwargs)
|
|
136
136
|
self._step_id = step_id
|
|
137
137
|
self._description = description.strip()
|
|
138
|
-
self._status = "pending" # pending |
|
|
138
|
+
self._status = "pending" # pending | running | success | error
|
|
139
139
|
self._spinner_position = 0
|
|
140
140
|
self._start_time: float | None = None
|
|
141
141
|
self._animation_timer: Timer | None = None
|
|
@@ -217,7 +217,7 @@ class CognitionStepMessage(Vertical):
|
|
|
217
217
|
return
|
|
218
218
|
self._input_tokens += input_tokens
|
|
219
219
|
self._output_tokens += output_tokens
|
|
220
|
-
if self._status in ("running", "pending"
|
|
220
|
+
if self._status in ("running", "pending"):
|
|
221
221
|
self._sync_running_status_line()
|
|
222
222
|
|
|
223
223
|
def _token_budget_suffix(self) -> str:
|
|
@@ -283,8 +283,6 @@ class CognitionStepMessage(Vertical):
|
|
|
283
283
|
return
|
|
284
284
|
if self._status == "running":
|
|
285
285
|
self._ensure_running_ui()
|
|
286
|
-
elif self._status == "queued":
|
|
287
|
-
self._sync_step_card_surface()
|
|
288
286
|
elif self._status == "pending":
|
|
289
287
|
self._sync_step_card_surface()
|
|
290
288
|
|
|
@@ -466,8 +464,6 @@ class CognitionStepMessage(Vertical):
|
|
|
466
464
|
self._sync_running_status_text(index)
|
|
467
465
|
elif self._status == "pending":
|
|
468
466
|
self._refresh_pending_display(index)
|
|
469
|
-
elif self._status == "queued":
|
|
470
|
-
self._refresh_queued_display(index)
|
|
471
467
|
|
|
472
468
|
if STEP_CARD_SHOW_TOOL_ROW_DETAILS:
|
|
473
469
|
self._refresh_tools_display()
|
|
@@ -1156,37 +1152,6 @@ class CognitionStepMessage(Vertical):
|
|
|
1156
1152
|
)
|
|
1157
1153
|
self._status_widget.display = True
|
|
1158
1154
|
|
|
1159
|
-
def _refresh_queued_display(self, index: StepRowIndex | None = None) -> None:
|
|
1160
|
-
"""Show ready steps waiting for a concurrency slot (``max_parallel_steps``)."""
|
|
1161
|
-
if self._status != "queued" or self._status_widget is None:
|
|
1162
|
-
return
|
|
1163
|
-
if index is None:
|
|
1164
|
-
index = self._build_row_index()
|
|
1165
|
-
try:
|
|
1166
|
-
colors = theme.get_theme_colors(self)
|
|
1167
|
-
except Exception: # noqa: BLE001
|
|
1168
|
-
colors = theme.DARK_COLORS
|
|
1169
|
-
g = get_glyphs()
|
|
1170
|
-
gutter = f"{g.output_prefix} "
|
|
1171
|
-
self._status_widget.update(
|
|
1172
|
-
StepCardStatusLine.footer_queued(
|
|
1173
|
-
gutter=gutter,
|
|
1174
|
-
circle_empty=g.circle_empty,
|
|
1175
|
-
stats_suffix=stats_title_suffix(index),
|
|
1176
|
-
token_suffix=self._token_budget_suffix(),
|
|
1177
|
-
colors=colors,
|
|
1178
|
-
)
|
|
1179
|
-
)
|
|
1180
|
-
self._status_widget.display = True
|
|
1181
|
-
|
|
1182
|
-
def set_queued(self) -> None:
|
|
1183
|
-
"""Mark a ready step as waiting for an execute batch slot."""
|
|
1184
|
-
if self._status in ("running", "success", "error"):
|
|
1185
|
-
return
|
|
1186
|
-
self._status = "queued"
|
|
1187
|
-
self._refresh_header_title()
|
|
1188
|
-
self._sync_step_card_surface()
|
|
1189
|
-
|
|
1190
1155
|
def _maybe_start_running_timer(self) -> None:
|
|
1191
1156
|
"""Start the spinner timer when the step is running and mounted."""
|
|
1192
1157
|
if self._status != "running":
|
|
@@ -458,23 +458,6 @@ class StepCardStatusLine:
|
|
|
458
458
|
parts.append(Content.styled(tail, theme.SECONDARY_TEXT_STYLE))
|
|
459
459
|
return Content.assemble(*parts)
|
|
460
460
|
|
|
461
|
-
@staticmethod
|
|
462
|
-
def footer_queued(
|
|
463
|
-
*,
|
|
464
|
-
gutter: str,
|
|
465
|
-
circle_empty: str,
|
|
466
|
-
stats_suffix: str,
|
|
467
|
-
token_suffix: str = "",
|
|
468
|
-
colors: Any,
|
|
469
|
-
) -> Content:
|
|
470
|
-
"""Step card footer for ready steps waiting for a concurrency slot."""
|
|
471
|
-
head = f"{gutter}{circle_empty} Queued..."
|
|
472
|
-
tail = f"{stats_suffix}{token_suffix}"
|
|
473
|
-
parts: list[object] = [Content.styled(head, colors.cognition)]
|
|
474
|
-
if tail:
|
|
475
|
-
parts.append(Content.styled(tail, theme.SECONDARY_TEXT_STYLE))
|
|
476
|
-
return Content.assemble(*parts)
|
|
477
|
-
|
|
478
461
|
|
|
479
462
|
# Activity tree renderer
|
|
480
463
|
# ---------------------------------------------------------------------------
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/duration_format.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/renderer_protocol.py
RENAMED
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/runtime/presentation/subagent_task_display.py
RENAMED
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_goal_tree.py
RENAMED
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_reason.py
RENAMED
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/messages/cognition_subagent.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{soothe_cli-0.7.9 → soothe_cli-0.7.11}/src/soothe_cli/tui/widgets/plan_quick_view_overlay.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|