Skip to content

No handling for 4xx response #262

@rchl

Description

@rchl

Been testing a bit and used all my quota/tokens. Now the response is 402 Payment Required which is not communicated anywhere in the UI. The chat just doesn't reply with anything.

:: [22:33:24.346] --> LSP-copilot conversation/turn (7): {'conversationId': '7639ba5e-da11-4fcb-a8eb-6119adbd14c5', 'message': 'can python decorators use generic type arguments?', 'workDoneToken': 'copilot_chat://10', 'doc': {'source': 'from __future__ import annotations\nfrom .interface import ClientHandlerInterface\nfrom typing import Any, Callable, List, TypeVar, Union\nimport inspect\n\n__all__ = [\n    "notification_handler",\n    "request_handler",\n    "register_decorated_handlers",\n]\n\nT = TypeVar(\'T\')\n# the first argument is always "self"\nNotificationHandler = Callable[[Any, Any], None]\nRequestHandler = Callable[[Any, Any, Callable[[Any], None]], None]\nMessageMethods = Union[str, List[str]]\n\n_HANDLER_MARKS = {\n    "notification": "__handle_notification_message_methods",\n    "request": "__handle_request_message_methods",\n}\n\nclass ApiWrapper(ApiWrapperInterface):\n    def __init__(self, plugin: \'ref[AbstractPlugin]\'):\n        self.__plugin = plugin\n\n    def __session(self) -> Session | None:\n        plugin = self.__plugin()\n        return plugin.weaksession() if plugin else None\n\n    # --- ApiWrapperInterface -----------------------------------------------------------------------------------------\n\n    @override\n    def on_notification(self, method: str, handler: ApiNotificationHandler) -> None:\n        def handle_notification(weak_handler: WeakMethod[ApiNotificationHandler], params: Any) -> None:\n            if handler := weak_handler():\n                handler(params)\n\n        plugin = self.__plugin()\n        if plugin:\n            setattr(plugin, method2attr(method), partial(handle_notification, WeakMethod(handler)))\n\n    @override\n    def on_request(self, method: str, handler: ApiRequestHandler) -> None:\n        def send_response(request_id: Any, result: Any) -> None:\n            session = self.__session()\n            if session:\n                session.send_response(Response(request_id, result))\n\n        def on_response(weak_handler: WeakMethod[ApiRequestHandler], params: Any, request_id: Any) -> None:\n            if handler := weak_handler():\n                handler(params, lambda result: send_response(request_id, result))\n\n        plugin = self.__plugin()\n        if plugin:\n            setattr(plugin, method2attr(method), partial(on_response, WeakMethod(handler)))\n\n    @override\n    def send_notification(self, method: str, params: Any) -> None:\n        session = self.__session()\n        if session:\n            session.send_notification(Notification(method, params))\n\n    @override\n    def send_request(self, method: str, params: Any, handler: Callable[[Any, bool], None]) -> None:\n        session = self.__session()\n        if session:\n            request: Request[Any, Any] = Request(method, params)\n            session.send_request(request, lambda result: handler(result, False), lambda result: handler(result, True))\n        else:\n            handler(None, True)\n\n\ndef notification_handler(method: str) -> Callable[[NotificationHandler], NotificationHandler]:\n    """\n    Marks the decorated function as a "notification" message handler.\n\n    On server sending the notification, the decorated function will be called with the `params` argument which contains\n    the payload.\n    """\n\n    return _create_handler("notification", notification_methods)\n\n\ndef request_handler(method: str) -> Callable[[RequestHandler], RequestHandler]:\n    """\n    Marks the decorated function as a "request" message handler.\n\n    On server sending the request, the decorated function will be called with two arguments (`params` and `respond`).\n    The first argument (`params`) is the payload of the request and the second argument (`respond`) is the function that\n    must be used to respond to the request. The `respond` function takes any data that should be sent back to the\n    server.\n    """\n\n    return _create_handler("request", request_methods)\n\n\ndef _create_handler(client_event: str, message_methods: MessageMethods) -> Callable[[T], T]:\n    """ Marks the decorated function as a message handler. """\n\n    message_methods = [message_methods] if isinstance(message_methods, str) else message_methods\n\n    def decorator(func: T) -> T:\n        setattr(func, _HANDLER_MARKS[client_event], message_methods)\n        return func\n\n    return decorator\n\n\ndef register_decorated_handlers(client_handler: ClientHandlerInterface, api: ApiWrapperInterface) -> None:\n    """\n    Register decorator-style custom message handlers.\n\n    This method works as following:\n\n    1. Scan through all methods of `client_handler`.\n    2. If a method is decorated, it will have a "handler mark" attribute which is set by the decorator.\n    3. Register the method with wanted message methods, which are stored in the "handler mark" attribute.\n\n    :param client_handler: The instance of the client handler.\n    :param api: The API instance for interacting with the server.\n    """\n    for _, func in inspect.getmembers(client_handler, predicate=inspect.isroutine):\n        for client_event, handler_mark in _HANDLER_MARKS.items():\n            message_methods: list[str] | None = getattr(func, handler_mark, None)\n            if message_methods is None:\n                continue\n            event_registrator = getattr(api, "on_" + client_event, None)\n            if callable(event_registrator):\n                for message_method in message_methods:\n                    event_registrator(message_method, func)\n                # it makes no sense that a handler handles both "notification" and "request"\n                # so we do early break once we\'ve registered a handler\n                break\n', 'tabSize': 4, 'indentSize': 1, 'insertSpaces': True, 'path': '/usr/local/workspace/sublime-packages/LSP/plugin/api_decorator.py', 'uri': 'file:///usr/local/workspace/sublime-packages/LSP/plugin/api_decorator.py', 'relativePath': 'plugin/api_decorator.py', 'languageId': 'python', 'position': {'line': 72, 'character': 0}, 'version': 0}, 'computeSuggestions': True, 'references': [], 'source': 'panel'}
:: [22:33:24.348] <-  LSP-copilot $/progress: {'token': 'copilot_chat://10', 'value': {'kind': 'begin', 'title': 'Conversation 7639ba5e-da11-4fcb-a8eb-6119adbd14c5 Turn be587115-c5ff-405d-a7f4-8039d66dd8df', 'conversationId': '7639ba5e-da11-4fcb-a8eb-6119adbd14c5', 'turnId': 'be587115-c5ff-405d-a7f4-8039d66dd8df'}}
:: [22:33:24.373] <-  LSP-copilot window/logMessage: {'type': 3, 'message': '[agentPrompt] Reusing cached global context from first turn for conversation/turn 7639ba5e-da11-4fcb-a8eb-6119adbd14c5/be587115-c5ff-405d-a7f4-8039d66dd8df'}
:: [22:33:24.501] <-  LSP-copilot window/logMessage: {'type': 3, 'message': '[fetchChat] Request a12f47a1-2ee1-45a4-9d4f-1889f91a849a at <https://api.individual.githubcopilot.com/chat/completions> finished with 402 status after 140.4438749999972ms'}
:: [22:33:24.501] <-  LSP-copilot window/logMessage: {'type': 1, 'message': '[toolCallingLoop] Fetch failed: {\n  type: \'failed\',\n  reason: "You\'ve reached your monthly chat messages quota. Upgrade to Copilot Pro (30-day free trial) or wait for your allowance to renew.",\n  requestId: \'a12f47a1-2ee1-45a4-9d4f-1889f91a849a\',\n  code: 402\n}'}
:: [22:33:24.501] <-  LSP-copilot $/progress: {'token': 'copilot_chat://10', 'value': {'kind': 'end', 'conversationId': '7639ba5e-da11-4fcb-a8eb-6119adbd14c5', 'turnId': 'be587115-c5ff-405d-a7f4-8039d66dd8df', 'error': {'message': "You've reached your monthly chat messages quota. Upgrade to Copilot Pro (30-day free trial) or wait for your allowance to renew. Request ID: a12f47a1-2ee1-45a4-9d4f-1889f91a849a", 'code': 402}}}
:: [22:33:24.511] <<< LSP-copilot (7) (duration: 165ms): {'conversationId': '7639ba5e-da11-4fcb-a8eb-6119adbd14c5', 'turnId': 'be587115-c5ff-405d-a7f4-8039d66dd8df', 'modelName': 'GPT-4o', 'billingMultiplier': 1}

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions