| 1069 | # ─── permission handler (worker thread; BLOCKS) ──────────────────────── |
| 1070 | |
| 1071 | def permission_handler(self, request: Any) -> Any: |
| 1072 | from src.permissions.types import PermissionAskReply |
| 1073 | |
| 1074 | request_id = str(_uuid.uuid4()) |
| 1075 | pending = _Pending(event=threading.Event()) |
| 1076 | with self._lock: |
| 1077 | self._pending[request_id] = pending |
| 1078 | |
| 1079 | self._emit({ |
| 1080 | "type": "control_request", |
| 1081 | "request_id": request_id, |
| 1082 | "request": { |
| 1083 | "subtype": "can_use_tool", |
| 1084 | "tool_name": getattr(request, "tool_name", ""), |
| 1085 | "input": getattr(request, "tool_input", None) or {}, |
| 1086 | "tool_use_id": None, |
| 1087 | }, |
| 1088 | }) |
| 1089 | |
| 1090 | got = pending.event.wait(timeout=self.config.permission_timeout_s) |
| 1091 | with self._lock: |
| 1092 | self._pending.pop(request_id, None) |
| 1093 | |
| 1094 | if not got: |
| 1095 | return PermissionAskReply( |
| 1096 | behavior="deny", message="permission request timed out" |
| 1097 | ) |
| 1098 | reply = pending.reply or {"behavior": "deny"} |
| 1099 | behavior = reply.get("behavior") |
| 1100 | if behavior == "allow": |
| 1101 | updated = reply.get("updatedInput") |
| 1102 | if not isinstance(updated, dict): |
| 1103 | updated = reply.get("updated_input") |
| 1104 | return PermissionAskReply( |
| 1105 | behavior="allow", |
| 1106 | updated_input=updated if isinstance(updated, dict) else None, |
| 1107 | ) |
| 1108 | return PermissionAskReply( |
| 1109 | behavior="deny", message=str(reply.get("message", "")) or "denied by user" |
| 1110 | ) |
| 1111 | |
| 1112 | # ─── worker thread (runs query() turns) ──────────────────────────────── |
| 1113 | |