Handle an incoming message (response or notification)
(self, message: dict)
| 355 | return json.loads(content) |
| 356 | |
| 357 | def _handle_message(self, message: dict): |
| 358 | """Handle an incoming message (response or notification)""" |
| 359 | # Check if it's a response to our request |
| 360 | if "id" in message: |
| 361 | with self._pending_lock: |
| 362 | future = self.pending_requests.get(message["id"]) |
| 363 | inline_cb = self._pending_inline_callbacks.pop(message["id"], None) |
| 364 | |
| 365 | if future is not None: |
| 366 | loop = future.get_loop() |
| 367 | |
| 368 | if "error" in message: |
| 369 | error = message["error"] |
| 370 | exc = JsonRpcError( |
| 371 | error.get("code", -1), |
| 372 | error.get("message", "Unknown error"), |
| 373 | error.get("data"), |
| 374 | ) |
| 375 | loop.call_soon_threadsafe(future.set_exception, exc) |
| 376 | elif "result" in message: |
| 377 | result = message["result"] |
| 378 | # Invoke the inline callback synchronously in the reader |
| 379 | # thread so any state it mutates is visible before the next |
| 380 | # message (e.g. a session.event notification) is dispatched. |
| 381 | if inline_cb is not None: |
| 382 | try: |
| 383 | inline_cb(result) |
| 384 | except Exception as exc: # pylint: disable=broad-except |
| 385 | logger.warning( |
| 386 | "Inline response callback for request %s raised", |
| 387 | message["id"], |
| 388 | exc_info=True, |
| 389 | ) |
| 390 | loop.call_soon_threadsafe(future.set_exception, exc) |
| 391 | return |
| 392 | loop.call_soon_threadsafe(future.set_result, result) |
| 393 | else: |
| 394 | exc = ValueError("Invalid JSON-RPC response") |
| 395 | loop.call_soon_threadsafe(future.set_exception, exc) |
| 396 | return |
| 397 | |
| 398 | # Check if it's a notification from the server |
| 399 | if "method" in message and "id" not in message: |
| 400 | if self.notification_handler and self._loop: |
| 401 | method = message["method"] |
| 402 | params = message.get("params", {}) |
| 403 | # Schedule notification handler on the event loop for thread safety |
| 404 | self._loop.call_soon_threadsafe(self.notification_handler, method, params) |
| 405 | return |
| 406 | |
| 407 | # Otherwise handle as incoming request (tool.call, etc.) |
| 408 | if "method" in message and "id" in message: |
| 409 | self._handle_request(message) |
| 410 | |
| 411 | def _handle_request(self, message: dict): |
| 412 | method = message.get("method", "") |
no test coverage detected