Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ The format is based on Keep a Changelog, and this project currently tracks chang

### Fixed

- React TUI spinner now stays visible throughout the entire agent turn: `assistant_complete` no longer resets `busy` state prematurely, and `tool_started` explicitly sets `busy=true` so the status bar remains active even when tool calls follow an assistant message. `line_complete` is the sole signal that ends the turn and clears the spinner.

- `BackendHostConfig` was missing the `cwd` field, causing `AttributeError: 'BackendHostConfig' object has no attribute 'cwd'` on startup when `oh` was run after the runtime refactor that added `cwd` support to `build_runtime`.
- Shell-escape `$ARGUMENTS` substitution in command hooks to prevent shell injection from payload values containing metacharacters like `$(...)` or backticks.
- Swarm `_READ_ONLY_TOOLS` now uses actual registered tool names (snake_case) instead of PascalCase, fixing read-only auto-approval in `handle_permission_request`.
Expand Down
11 changes: 7 additions & 4 deletions frontend/terminal/src/hooks/useBackendSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,21 +264,24 @@ export function useBackendSession(config: FrontendConfig, onExit: (code?: number
const text = event.message ?? assistantBufferRef.current;
setTranscript((items) => [...items, {role: 'assistant', text}]);
clearAssistantDelta();
setBusy(false);
// Do NOT reset busy here: tool calls may follow this event.
// busy is reset by line_complete (the true end-of-turn signal).
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new inline comment says busy is reset by line_complete (the “true end-of-turn signal”), but error events also call setBusy(false) earlier in this handler. Consider tweaking the wording to reflect that line_complete is the normal end-of-turn signal, with error/shutdown as exceptional early-termination paths, to avoid misleading future readers.

Suggested change
// busy is reset by line_complete (the true end-of-turn signal).
// line_complete is the normal end-of-turn signal; error/shutdown paths may clear busy earlier.

Copilot uses AI. Check for mistakes.
setBusyLabel(undefined);
return;
}
if (event.type === 'line_complete') {
// If the line ended without an assistant_complete (e.g. errors), make sure we
// don't leave stale streaming text on screen.
// Final end-of-turn: clear everything, stop spinner.
clearAssistantDelta();
setBusy(false);
setBusyLabel(undefined);
return;
}
if ((event.type === 'tool_started' || event.type === 'tool_completed') && event.item) {
if (event.type === 'tool_started') {
setBusyLabel(event.tool_name ? `Running ${event.tool_name}...` : 'Running...');
setBusy(true);
setBusyLabel(`Running ${event.tool_name ?? 'tool'}...`);
} else {
setBusyLabel('Processing...');
}
const enrichedItem: TranscriptItem = {
...event.item,
Expand Down
Loading