Skip to content

Commit 9c9d119

Browse files
committed
fix: better handling for tool denials
1 parent 338c83b commit 9c9d119

File tree

5 files changed

+42
-17
lines changed

5 files changed

+42
-17
lines changed

src/agent_chat_cli/components/user_input.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ async def on_input_submitted(self, event: Input.Submitted) -> None:
5555
# Run agent query in background
5656
asyncio.create_task(self.query_agent(user_message))
5757

58+
async def on_input_blurred(self, event: Input.Blurred) -> None:
59+
if self.display:
60+
input_widget = self.query_one(Input)
61+
input_widget.focus()
62+
5863
async def query_agent(self, user_input: str) -> None:
5964
thinking_indicator = self.app.query_one(ThinkingIndicator)
6065
thinking_indicator.is_thinking = True

src/agent_chat_cli/system/actions.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,24 @@ async def respond_to_tool_permission(self, response: str) -> None:
5151

5252
await self.agent_loop.permission_response_queue.put(response)
5353

54-
thinking_indicator = self.app.query_one(ThinkingIndicator)
55-
thinking_indicator.is_thinking = True
56-
5754
permission_prompt = self.app.query_one(ToolPermissionPrompt)
5855
permission_prompt.is_visible = False
5956

6057
user_input = self.app.query_one(UserInput)
6158
user_input.display = True
6259
input_widget = user_input.query_one(Input)
6360
input_widget.focus()
61+
62+
# Check if it's a deny or custom response (anything except yes/allow)
63+
normalized = response.lower().strip()
64+
if normalized not in ["y", "yes", "allow", ""]:
65+
# Handle like a normal user query
66+
thinking_indicator = self.app.query_one(ThinkingIndicator)
67+
thinking_indicator.is_thinking = True
68+
input_widget.cursor_blink = False
69+
70+
if normalized in ["n", "no", "deny"]:
71+
denial_message = "The user has denied the tool"
72+
await self.query(denial_message)
73+
else:
74+
await self.query(response)

src/agent_chat_cli/system/agent_loop.py

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -259,30 +259,21 @@ async def _can_use_tool(
259259
)
260260
)
261261

262-
await self.on_message(
263-
AgentMessage(
264-
type=AgentMessageType.ASSISTANT,
265-
data="What should we do differently?",
266-
)
267-
)
268-
269262
return PermissionResultDeny(
270263
behavior="deny",
271264
message="User denied permission",
272265
interrupt=True,
273266
)
274267

275268
# If a user instead typed in a message (instead of confirming or denying)
276-
# forward this on to the agent.
269+
# post it to chat. actions.respond_to_tool_permission will handle querying.
277270
await self.on_message(
278271
AgentMessage(
279-
type=AgentMessageType.SYSTEM,
280-
data=f"Custom response for {tool_name}: {user_response}",
272+
type=AgentMessageType.USER,
273+
data=user_response,
281274
)
282275
)
283276

284-
await self.client.query(user_response)
285-
286277
return PermissionResultDeny(
287278
behavior="deny",
288279
message=user_response,

src/agent_chat_cli/system/message_bus.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@
1818
from agent_chat_cli.utils.logger import log_json
1919

2020
if TYPE_CHECKING:
21-
from textual.app import App
21+
from agent_chat_cli.app import AgentChatCLIApp
2222

2323

2424
class MessageBus:
25-
def __init__(self, app: "App") -> None:
25+
def __init__(self, app: "AgentChatCLIApp") -> None:
2626
self.app = app
2727
self.current_agent_message: AgentMessageWidget | None = None
2828
self.current_response_text = ""
@@ -38,6 +38,9 @@ async def handle_agent_message(self, message: AgentMessage) -> None:
3838
case AgentMessageType.SYSTEM:
3939
await self._handle_system(message)
4040

41+
case AgentMessageType.USER:
42+
await self._handle_user(message)
43+
4144
case AgentMessageType.TOOL_PERMISSION_REQUEST:
4245
await self._handle_tool_permission_request(message)
4346

@@ -109,6 +112,15 @@ async def _handle_system(self, message: AgentMessage) -> None:
109112

110113
await self._scroll_to_bottom()
111114

115+
async def _handle_user(self, message: AgentMessage) -> None:
116+
user_content = (
117+
message.data if isinstance(message.data, str) else str(message.data)
118+
)
119+
120+
self.app.post_message(MessagePosted(Message.user(user_content)))
121+
122+
await self._scroll_to_bottom()
123+
112124
async def _handle_tool_permission_request(self, message: AgentMessage) -> None:
113125
log_json(
114126
{
@@ -131,6 +143,11 @@ async def _handle_tool_permission_request(self, message: AgentMessage) -> None:
131143
await self._scroll_to_bottom()
132144

133145
async def _handle_result(self) -> None:
146+
# Check if there's a queued message (e.g., from custom permission response)
147+
if not self.app.agent_loop.query_queue.empty():
148+
# Don't turn off thinking - there's more work to do
149+
return
150+
134151
thinking_indicator = self.app.query_one(ThinkingIndicator)
135152
thinking_indicator.is_thinking = False
136153

src/agent_chat_cli/utils/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class AgentMessageType(Enum):
88
STREAM_EVENT = "stream_event"
99
SYSTEM = "system"
1010
TOOL_PERMISSION_REQUEST = "tool_permission_request"
11+
USER = "user"
1112

1213

1314
class ContentType(Enum):

0 commit comments

Comments
 (0)