Skip to content

Commit cdc5aa0

Browse files
Ambient Code Botclaude
andcommitted
fix: address CodeRabbit critical & accessibility feedback
- **CRITICAL**: Fix race condition in bridge.py by scoping halt state per-thread - Added `_halted_by_thread` dict to track halt state separately for each thread_id - Prevents concurrent runs from interfering with each other's halt detection - Clears thread-specific halt flag after worker interrupt - **Fix**: Clear in-flight tool-call state on halt in adapter.py - Prevents duplicate ToolCallEndEvent emission in finally block - Resets current_tool_call_id and related state when halting - **Accessibility**: Add keyboard support to "Other" option in ask-user-question - Added onKeyDown handler for Enter/Space keys - Added tabIndex and role="button" for keyboard navigation - Ensures compliance with a11y requirements Addresses CodeRabbit review feedback from PR #871. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent c674b9d commit cdc5aa0

3 files changed

Lines changed: 26 additions & 1 deletion

File tree

components/frontend/src/components/session/ask-user-question.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,14 @@ export const AskUserQuestionMessage: React.FC<AskUserQuestionMessageProps> = ({
215215
disabled && "cursor-default opacity-60"
216216
)}
217217
onClick={() => !disabled && handleOtherToggle(q.question)}
218+
onKeyDown={(e) => {
219+
if (!disabled && (e.key === "Enter" || e.key === " ")) {
220+
e.preventDefault();
221+
handleOtherToggle(q.question);
222+
}
223+
}}
224+
tabIndex={disabled ? -1 : 0}
225+
role="button"
218226
>
219227
<div className={cn(
220228
"aspect-square h-4 w-4 rounded-full border border-primary flex items-center justify-center flex-shrink-0",

components/runners/ambient-runner/ag_ui_claude_sdk/adapter.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,14 @@ def flush_pending_msg():
919919
self._halted = True
920920
self._halted_tool_call_id = current_tool_call_id
921921
halt_event_stream = True
922+
923+
# Clear in-flight tool call state to prevent duplicate
924+
# ToolCallEndEvent emission in the finally block
925+
current_tool_call_id = None
926+
current_tool_call_name = None
927+
current_tool_display_name = None
928+
accumulated_tool_json = ""
929+
922930
# Continue consuming remaining events for cleanup
923931
continue
924932

components/runners/ambient-runner/ambient_runner/bridges/claude/bridge.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ def __init__(self) -> None:
5656
self._allowed_tools: list[str] = []
5757
self._system_prompt: dict = {}
5858
self._stderr_lines: list[str] = []
59+
# Per-thread halt tracking to avoid race conditions on shared adapter
60+
self._halted_by_thread: dict[str, bool] = {}
5961

6062
# ------------------------------------------------------------------
6163
# PlatformBridge interface
@@ -121,15 +123,21 @@ async def run(self, input_data: RunAgentInput) -> AsyncIterator[BaseEvent]:
121123
async for event in wrapped_stream:
122124
yield event
123125

126+
# Capture halt state for this thread to avoid race conditions
127+
# with concurrent runs modifying the shared adapter's halted flag
128+
self._halted_by_thread[thread_id] = self._adapter.halted
129+
124130
# If the adapter halted (frontend tool or built-in HITL tool like
125131
# AskUserQuestion), interrupt the worker to prevent the SDK from
126132
# auto-approving the tool call with a placeholder result.
127-
if self._adapter.halted:
133+
if self._halted_by_thread.get(thread_id, False):
128134
logger.info(
129135
f"Adapter halted for thread={thread_id}, "
130136
"interrupting worker to await user input"
131137
)
132138
await worker.interrupt()
139+
# Clear the halt flag for this thread
140+
self._halted_by_thread.pop(thread_id, None)
133141

134142
self._first_run = False
135143

@@ -176,6 +184,7 @@ def mark_dirty(self) -> None:
176184
self._ready = False
177185
self._first_run = True
178186
self._adapter = None
187+
self._halted_by_thread.clear()
179188
if self._session_manager:
180189
manager = self._session_manager
181190
self._session_manager = None

0 commit comments

Comments
 (0)