Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hotfix(agent): Wrong indentation preventing tool calls #47

Merged
merged 1 commit into from
Feb 24, 2025

Conversation

RezaRahemtola
Copy link
Member

What does this PR do?

Hotfix for an issue that prevented tool calls in certain cases

Before submitting

  • This PR fixes a typo or improves the docs (you can dismiss the other checks if that's the case).
  • Did you read the contributor guideline,
    Pull Request section?
  • Was this discussed/approved via a Github issue or Telegram? Please add a link
    to it if that's the case.
  • Did you write any new necessary tests?

@RezaRahemtola RezaRahemtola added the bug Something isn't working label Feb 24, 2025
@RezaRahemtola RezaRahemtola self-assigned this Feb 24, 2025
@RezaRahemtola RezaRahemtola marked this pull request as ready for review February 24, 2025 14:39
@RezaRahemtola RezaRahemtola enabled auto-merge (squash) February 24, 2025 14:39
Copy link

codecov bot commented Feb 24, 2025

❌ 1 Tests Failed:

Tests completed Failed Passed Skipped
17 1 16 0
View the top 1 failed test(s) by shortest run time
tests.test_agents::test_create_chat_agent_double_tool
Stack Traces | 10.4s run time
self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x7efe9e923a60>
conn = <urllib3.connection.HTTPSConnection object at 0x7efe9e9e2560>
method = 'GET'
url = '.../resolve/main/tokenizer.json'
body = None
headers = {'user-agent': 'unknown/None; hf_hub/0.26.5; python/3.10.16; transformers/4.48.0; session_id/f77190582b5549aaa46f767c1...horization': 'Bearer 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', 'X-Amzn-Trace-Id': '6939b33e-e2f2-4e03-a7d5-28f4d0bd02c1'}
retries = Retry(total=0, connect=None, read=False, redirect=None, status=None)
timeout = Timeout(connect=10, read=10, total=None), chunked = False
response_conn = <urllib3.connection.HTTPSConnection object at 0x7efe9e9e2560>
preload_content = False, decode_content = False, enforce_content_length = True

    def _make_request(
        self,
        conn: BaseHTTPConnection,
        method: str,
        url: str,
        body: _TYPE_BODY | None = None,
        headers: typing.Mapping[str, str] | None = None,
        retries: Retry | None = None,
        timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
        chunked: bool = False,
        response_conn: BaseHTTPConnection | None = None,
        preload_content: bool = True,
        decode_content: bool = True,
        enforce_content_length: bool = True,
    ) -> BaseHTTPResponse:
        """
        Perform a request on a given urllib connection object taken from our
        pool.
    
        :param conn:
            a connection from one of our connection pools
    
        :param method:
            HTTP request method (such as GET, POST, PUT, etc.)
    
        :param url:
            The URL to perform the request on.
    
        :param body:
            Data to send in the request body, either :class:`str`, :class:`bytes`,
            an iterable of :class:`str`/:class:`bytes`, or a file-like object.
    
        :param headers:
            Dictionary of custom headers to send, such as User-Agent,
            If-None-Match, etc. If None, pool headers are used. If provided,
            these headers completely replace any pool-specific headers.
    
        :param retries:
            Configure the number of retries to allow before raising a
            :class:`~urllib3.exceptions.MaxRetryError` exception.
    
            Pass ``None`` to retry until you receive a response. Pass a
            :class:`~urllib3.util.retry.Retry` object for fine-grained control
            over different types of retries.
            Pass an integer number to retry connection errors that many times,
            but no other types of errors. Pass zero to never retry.
    
            If ``False``, then retries are disabled and any exception is raised
            immediately. Also, instead of raising a MaxRetryError on redirects,
            the redirect response will be returned.
    
        :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
    
        :param timeout:
            If specified, overrides the default timeout for this one
            request. It may be a float (in seconds) or an instance of
            :class:`urllib3.util.Timeout`.
    
        :param chunked:
            If True, urllib3 will send the body using chunked transfer
            encoding. Otherwise, urllib3 will send the body using the standard
            content-length form. Defaults to False.
    
        :param response_conn:
            Set this to ``None`` if you will handle releasing the connection or
            set the connection to have the response release it.
    
        :param preload_content:
          If True, the response's body will be preloaded during construction.
    
        :param decode_content:
            If True, will attempt to decode the body based on the
            'content-encoding' header.
    
        :param enforce_content_length:
            Enforce content length checking. Body returned by server must match
            value of Content-Length header, if present. Otherwise, raise error.
        """
        self.num_requests += 1
    
        timeout_obj = self._get_timeout(timeout)
        timeout_obj.start_connect()
        conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)
    
        try:
            # Trigger any extra validation we need to do.
            try:
                self._validate_conn(conn)
            except (SocketTimeout, BaseSSLError) as e:
                self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)
                raise
    
        # _validate_conn() starts the connection to an HTTPS proxy
        # so we need to wrap errors with 'ProxyError' here too.
        except (
            OSError,
            NewConnectionError,
            TimeoutError,
            BaseSSLError,
            CertificateError,
            SSLError,
        ) as e:
            new_e: Exception = e
            if isinstance(e, (BaseSSLError, CertificateError)):
                new_e = SSLError(e)
            # If the connection didn't successfully connect to it's proxy
            # then there
            if isinstance(
                new_e, (OSError, NewConnectionError, TimeoutError, SSLError)
            ) and (conn and conn.proxy and not conn.has_connected_to_proxy):
                new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
            raise new_e
    
        # conn.request() calls http.client.*.request, not the method in
        # urllib3.request. It also calls makefile (recv) on the socket.
        try:
            conn.request(
                method,
                url,
                body=body,
                headers=headers,
                chunked=chunked,
                preload_content=preload_content,
                decode_content=decode_content,
                enforce_content_length=enforce_content_length,
            )
    
        # We are swallowing BrokenPipeError (errno.EPIPE) since the server is
        # legitimately able to close the connection after sending a valid response.
        # With this behaviour, the received response is still readable.
        except BrokenPipeError:
            pass
        except OSError as e:
            # MacOS/Linux
            # EPROTOTYPE and ECONNRESET are needed on macOS
            # https://erickt.github..../11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
            # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.
            if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:
                raise
    
        # Reset the timeout for the recv() on the socket
        read_timeout = timeout_obj.read_timeout
    
        if not conn.is_closed:
            # In Python 3 socket.py will catch EAGAIN and return None when you
            # try and read into the file pointer created by http.client, which
            # instead raises a BadStatusLine exception. Instead of catching
            # the exception and assuming all BadStatusLine exceptions are read
            # timeouts, check for a zero timeout before making the request.
            if read_timeout == 0:
                raise ReadTimeoutError(
                    self, url, f"Read timed out. (read timeout={read_timeout})"
                )
            conn.timeout = read_timeout
    
        # Receive the response from the server
        try:
>           response = conn.getresponse()

../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/urllib3/connectionpool.py:536: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../site-packages/urllib3/connection.py:507: in getresponse
    httplib_response = super().getresponse()
.../hostedtoolcache/Python/3.10.16................../x64/lib/python3.10/http/client.py:1375: in getresponse
    response.begin()
.../hostedtoolcache/Python/3.10.16................../x64/lib/python3.10/http/client.py:318: in begin
    version, status, reason = self._read_status()
.../hostedtoolcache/Python/3.10.16................../x64/lib/python3.10/http/client.py:279: in _read_status
    line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
.../hostedtoolcache/Python/3.10.16................../x64/lib/python3.10/socket.py:717: in readinto
    return self._sock.recv_into(b)
.../hostedtoolcache/Python/3.10.16................../x64/lib/python3.10/ssl.py:1307: in recv_into
    return self.read(nbytes, buffer)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <ssl.SSLSocket [closed] fd=-1, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6>
len = 8192, buffer = <memory at 0x7efe9e6e0400>

    def read(self, len=1024, buffer=None):
        """Read up to LEN bytes and return them.
        Return zero-length string on EOF."""
    
        self._checkClosed()
        if self._sslobj is None:
            raise ValueError("Read on closed or unwrapped SSL socket.")
        try:
            if buffer is not None:
>               return self._sslobj.read(len, buffer)
E               TimeoutError: The read operation timed out

.../hostedtoolcache/Python/3.10.16................../x64/lib/python3.10/ssl.py:1163: TimeoutError

The above exception was the direct cause of the following exception:

self = <huggingface_hub.utils._http.UniqueRequestIdAdapter object at 0x7efe9e9e28f0>
request = <PreparedRequest [GET]>, stream = True
timeout = Timeout(connect=10, read=10, total=None), verify = True, cert = None
proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
>           resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )

../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10....../site-packages/requests/adapters.py:667: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/urllib3/connectionpool.py:843: in urlopen
    retries = retries.increment(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../urllib3/util/retry.py:474: in increment
    raise reraise(type(error), error, _stacktrace)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../urllib3/util/util.py:39: in reraise
    raise value
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/urllib3/connectionpool.py:789: in urlopen
    response = self._make_request(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/urllib3/connectionpool.py:538: in _make_request
    self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <urllib3.connectionpool.HTTPSConnectionPool object at 0x7efe9e923a60>
err = TimeoutError('The read operation timed out')
url = '.../resolve/main/tokenizer.json'
timeout_value = 10

    def _raise_timeout(
        self,
        err: BaseSSLError | OSError | SocketTimeout,
        url: str,
        timeout_value: _TYPE_TIMEOUT | None,
    ) -> None:
        """Is the error actually a timeout? Will raise a ReadTimeout or pass"""
    
        if isinstance(err, SocketTimeout):
>           raise ReadTimeoutError(
                self, url, f"Read timed out. (read timeout={timeout_value})"
            ) from err
E           urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host='huggingface.co', port=443): Read timed out. (read timeout=10)

../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/urllib3/connectionpool.py:369: ReadTimeoutError

During handling of the above exception, another exception occurred:

fake_get_temperature_tool = <function fake_get_temperature_tool.<locals>.get_current_temperature at 0x7efe9e6bb640>

    def test_create_chat_agent_double_tool(fake_get_temperature_tool):
        with pytest.raises(ValueError):
            _agent = ChatAgent(
>               model=get_model(get_random_model_id(), get_hf_token()),
                tools=[
                    Tool.from_function(fake_get_temperature_tool),
                    Tool.from_function(fake_get_temperature_tool),
                ],
            )

tests/test_agents.py:54: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
libertai_agents/models/models.py:64: in get_model
    return full_config.constructor(
libertai_agents/models/mistral.py:11: in __init__
    super().__init__(
libertai_agents/models/base.py:41: in __init__
    self.tokenizer = AutoTokenizer.from_pretrained(model_id)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../models/auto/tokenization_auto.py:934: in from_pretrained
    return tokenizer_class.from_pretrained(pretrained_model_name_or_path, *inputs, **kwargs)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../site-packages/transformers/tokenization_utils_base.py:1992: in from_pretrained
    resolved_vocab_files[file_id] = cached_file(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../transformers/utils/hub.py:403: in cached_file
    resolved_file = hf_hub_download(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../huggingface_hub/utils/_validators.py:114: in _inner_fn
    return fn(*args, **kwargs)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/huggingface_hub/file_download.py:862: in hf_hub_download
    return _hf_hub_download_to_cache_dir(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/huggingface_hub/file_download.py:1011: in _hf_hub_download_to_cache_dir
    _download_to_tmp_and_move(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/huggingface_hub/file_download.py:1545: in _download_to_tmp_and_move
    http_get(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/huggingface_hub/file_download.py:368: in http_get
    r = _request_wrapper(
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.............../site-packages/huggingface_hub/file_download.py:300: in _request_wrapper
    response = get_session().request(method=method, url=url, **params)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10....../site-packages/requests/sessions.py:589: in request
    resp = self.send(prep, **send_kwargs)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10....../site-packages/requests/sessions.py:703: in send
    r = adapter.send(request, **kwargs)
../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10.../huggingface_hub/utils/_http.py:93: in send
    return super().send(request, *args, **kwargs)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <huggingface_hub.utils._http.UniqueRequestIdAdapter object at 0x7efe9e9e28f0>
request = <PreparedRequest [GET]>, stream = True
timeout = Timeout(connect=10, read=10, total=None), verify = True, cert = None
proxies = OrderedDict()

    def send(
        self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
    ):
        """Sends PreparedRequest object. Returns Response object.
    
        :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
        :param stream: (optional) Whether to stream the request content.
        :param timeout: (optional) How long to wait for the server to send
            data before giving up, as a float, or a :ref:`(connect timeout,
            read timeout) <timeouts>` tuple.
        :type timeout: float or tuple or urllib3 Timeout object
        :param verify: (optional) Either a boolean, in which case it controls whether
            we verify the server's TLS certificate, or a string, in which case it
            must be a path to a CA bundle to use
        :param cert: (optional) Any user-provided SSL certificate to be trusted.
        :param proxies: (optional) The proxies dictionary to apply to the request.
        :rtype: requests.Response
        """
    
        try:
            conn = self.get_connection_with_tls_context(
                request, verify, proxies=proxies, cert=cert
            )
        except LocationValueError as e:
            raise InvalidURL(e, request=request)
    
        self.cert_verify(conn, request.url, verify, cert)
        url = self.request_url(request, proxies)
        self.add_headers(
            request,
            stream=stream,
            timeout=timeout,
            verify=verify,
            cert=cert,
            proxies=proxies,
        )
    
        chunked = not (request.body is None or "Content-Length" in request.headers)
    
        if isinstance(timeout, tuple):
            try:
                connect, read = timeout
                timeout = TimeoutSauce(connect=connect, read=read)
            except ValueError:
                raise ValueError(
                    f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
                    f"or a single float to set both timeouts to the same value."
                )
        elif isinstance(timeout, TimeoutSauce):
            pass
        else:
            timeout = TimeoutSauce(connect=timeout, read=timeout)
    
        try:
            resp = conn.urlopen(
                method=request.method,
                url=url,
                body=request.body,
                headers=request.headers,
                redirect=False,
                assert_same_host=False,
                preload_content=False,
                decode_content=False,
                retries=self.max_retries,
                timeout=timeout,
                chunked=chunked,
            )
    
        except (ProtocolError, OSError) as err:
            raise ConnectionError(err, request=request)
    
        except MaxRetryError as e:
            if isinstance(e.reason, ConnectTimeoutError):
                # TODO: Remove this in 3.0.0: see #2811
                if not isinstance(e.reason, NewConnectionError):
                    raise ConnectTimeout(e, request=request)
    
            if isinstance(e.reason, ResponseError):
                raise RetryError(e, request=request)
    
            if isinstance(e.reason, _ProxyError):
                raise ProxyError(e, request=request)
    
            if isinstance(e.reason, _SSLError):
                # This branch is for urllib3 v1.22 and later.
                raise SSLError(e, request=request)
    
            raise ConnectionError(e, request=request)
    
        except ClosedPoolError as e:
            raise ConnectionError(e, request=request)
    
        except _ProxyError as e:
            raise ProxyError(e)
    
        except (_SSLError, _HTTPError) as e:
            if isinstance(e, _SSLError):
                # This branch is for urllib3 versions earlier than v1.22
                raise SSLError(e, request=request)
            elif isinstance(e, ReadTimeoutError):
>               raise ReadTimeout(e, request=request)
E               requests.exceptions.ReadTimeout: (ReadTimeoutError("HTTPSConnectionPool(host='huggingface.co', port=443): Read timed out. (read timeout=10)"), '(Request ID: 6939b33e-e2f2-4e03-a7d5-28f4d0bd02c1)')

../../../../..../pypoetry/virtualenvs/libertai-agents-cGTlWRjZ-py3.10/lib/python3.10....../site-packages/requests/adapters.py:713: ReadTimeout

To view more test analytics, go to the Test Analytics Dashboard
📋 Got 3 mins? Take this short survey to help us improve Test Analytics.

@RezaRahemtola RezaRahemtola merged commit 9e8b37c into main Feb 24, 2025
8 checks passed
@RezaRahemtola RezaRahemtola deleted the reza/hotfix-tool-calls branch February 24, 2025 14:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant