vision-agent 0.2.78__py3-none-any.whl → 0.2.80__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- vision_agent/agent/vision_agent.py +10 -1
- vision_agent/utils/exceptions.py +42 -0
- vision_agent/utils/execute.py +65 -21
- vision_agent/utils/sim.py +3 -5
- vision_agent/utils/type_defs.py +2 -12
- {vision_agent-0.2.78.dist-info → vision_agent-0.2.80.dist-info}/METADATA +2 -2
- {vision_agent-0.2.78.dist-info → vision_agent-0.2.80.dist-info}/RECORD +9 -8
- {vision_agent-0.2.78.dist-info → vision_agent-0.2.80.dist-info}/LICENSE +0 -0
- {vision_agent-0.2.78.dist-info → vision_agent-0.2.80.dist-info}/WHEEL +0 -0
| @@ -471,6 +471,7 @@ class VisionAgent(Agent): | |
| 471 471 | 
             
                    tool_recommender: Optional[Sim] = None,
         | 
| 472 472 | 
             
                    verbosity: int = 0,
         | 
| 473 473 | 
             
                    report_progress_callback: Optional[Callable[[Dict[str, Any]], None]] = None,
         | 
| 474 | 
            +
                    code_sandbox_runtime: Optional[str] = None,
         | 
| 474 475 | 
             
                ) -> None:
         | 
| 475 476 | 
             
                    """Initialize the Vision Agent.
         | 
| 476 477 |  | 
| @@ -487,6 +488,11 @@ class VisionAgent(Agent): | |
| 487 488 | 
             
                            This is useful for streaming logs in a web application where multiple
         | 
| 488 489 | 
             
                            VisionAgent instances are running in parallel. This callback ensures
         | 
| 489 490 | 
             
                            that the progress are not mixed up.
         | 
| 491 | 
            +
                        code_sandbox_runtime: the code sandbox runtime to use. A code sandbox is
         | 
| 492 | 
            +
                             used to run the generated code. It can be one of the following
         | 
| 493 | 
            +
                             values: None, "local" or "e2b". If None, Vision Agent will read the
         | 
| 494 | 
            +
                             value from the environment variable CODE_SANDBOX_RUNTIME. If it's
         | 
| 495 | 
            +
                             also None, the local python runtime environment will be used.
         | 
| 490 496 | 
             
                    """
         | 
| 491 497 |  | 
| 492 498 | 
             
                    self.planner = (
         | 
| @@ -506,6 +512,7 @@ class VisionAgent(Agent): | |
| 506 512 | 
             
                    self.verbosity = verbosity
         | 
| 507 513 | 
             
                    self.max_retries = 2
         | 
| 508 514 | 
             
                    self.report_progress_callback = report_progress_callback
         | 
| 515 | 
            +
                    self.code_sandbox_runtime = code_sandbox_runtime
         | 
| 509 516 |  | 
| 510 517 | 
             
                def __call__(
         | 
| 511 518 | 
             
                    self,
         | 
| @@ -560,7 +567,9 @@ class VisionAgent(Agent): | |
| 560 567 | 
             
                        raise ValueError("Chat cannot be empty.")
         | 
| 561 568 |  | 
| 562 569 | 
             
                    # NOTE: each chat should have a dedicated code interpreter instance to avoid concurrency issues
         | 
| 563 | 
            -
                    with CodeInterpreterFactory.new_instance( | 
| 570 | 
            +
                    with CodeInterpreterFactory.new_instance(
         | 
| 571 | 
            +
                        code_sandbox_runtime=self.code_sandbox_runtime
         | 
| 572 | 
            +
                    ) as code_interpreter:
         | 
| 564 573 | 
             
                        chat = copy.deepcopy(chat)
         | 
| 565 574 | 
             
                        media_list = []
         | 
| 566 575 | 
             
                        for chat_i in chat:
         | 
| @@ -0,0 +1,42 @@ | |
| 1 | 
            +
            """Vision Agent exceptions."""
         | 
| 2 | 
            +
             | 
| 3 | 
            +
             | 
| 4 | 
            +
            class InvalidApiKeyError(Exception):
         | 
| 5 | 
            +
                """Exception raised when the an invalid API key is provided. This error could be raised from any SDK code, not limited to a HTTP client."""
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def __init__(self, message: str):
         | 
| 8 | 
            +
                    self.message = f"""{message}
         | 
| 9 | 
            +
            For more information, see https://landing-ai.github.io/landingai-python/landingai.html#manage-api-credentials"""
         | 
| 10 | 
            +
                    super().__init__(self.message)
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def __str__(self) -> str:
         | 
| 13 | 
            +
                    return self.message
         | 
| 14 | 
            +
             | 
| 15 | 
            +
             | 
| 16 | 
            +
            class RemoteSandboxError(Exception):
         | 
| 17 | 
            +
                """Exception related to remote sandbox."""
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                is_retryable = False
         | 
| 20 | 
            +
             | 
| 21 | 
            +
             | 
| 22 | 
            +
            class RemoteSandboxCreationError(RemoteSandboxError):
         | 
| 23 | 
            +
                """Exception raised when failed to create a remote sandbox.
         | 
| 24 | 
            +
                This could be due to the remote sandbox service is unavailable.
         | 
| 25 | 
            +
                """
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                is_retryable = False
         | 
| 28 | 
            +
             | 
| 29 | 
            +
             | 
| 30 | 
            +
            class RemoteSandboxExecutionError(RemoteSandboxError):
         | 
| 31 | 
            +
                """Exception raised when failed in a remote sandbox code execution."""
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                is_retryable = False
         | 
| 34 | 
            +
             | 
| 35 | 
            +
             | 
| 36 | 
            +
            class RemoteSandboxClosedError(RemoteSandboxError):
         | 
| 37 | 
            +
                """Exception raised when a remote sandbox is dead.
         | 
| 38 | 
            +
                This is retryable in the sense that the user can try again with a new sandbox. Can't be retried in the same sandbox.
         | 
| 39 | 
            +
                When this error is raised, the user should retry by create a new VisionAgent (i.e. a new sandbox).
         | 
| 40 | 
            +
                """
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                is_retryable = True
         | 
    
        vision_agent/utils/execute.py
    CHANGED
    
    | @@ -1,5 +1,4 @@ | |
| 1 1 | 
             
            import abc
         | 
| 2 | 
            -
            import atexit
         | 
| 3 2 | 
             
            import base64
         | 
| 4 3 | 
             
            import copy
         | 
| 5 4 | 
             
            import logging
         | 
| @@ -18,7 +17,6 @@ from typing import Any, Dict, Iterable, List, Optional, Union | |
| 18 17 | 
             
            import nbformat
         | 
| 19 18 | 
             
            import tenacity
         | 
| 20 19 | 
             
            from dotenv import load_dotenv
         | 
| 21 | 
            -
            from e2b.api.v2.client.exceptions import ServiceException
         | 
| 22 20 | 
             
            from e2b_code_interpreter import CodeInterpreter as E2BCodeInterpreterImpl
         | 
| 23 21 | 
             
            from e2b_code_interpreter import Execution as E2BExecution
         | 
| 24 22 | 
             
            from e2b_code_interpreter import Result as E2BResult
         | 
| @@ -30,9 +28,15 @@ from nbformat.v4 import new_code_cell | |
| 30 28 | 
             
            from pydantic import BaseModel, field_serializer
         | 
| 31 29 | 
             
            from typing_extensions import Self
         | 
| 32 30 |  | 
| 31 | 
            +
            from vision_agent.utils.exceptions import (
         | 
| 32 | 
            +
                RemoteSandboxClosedError,
         | 
| 33 | 
            +
                RemoteSandboxCreationError,
         | 
| 34 | 
            +
                RemoteSandboxExecutionError,
         | 
| 35 | 
            +
            )
         | 
| 36 | 
            +
             | 
| 33 37 | 
             
            load_dotenv()
         | 
| 34 38 | 
             
            _LOGGER = logging.getLogger(__name__)
         | 
| 35 | 
            -
            _SESSION_TIMEOUT =  | 
| 39 | 
            +
            _SESSION_TIMEOUT = 600  # 10 minutes
         | 
| 36 40 |  | 
| 37 41 |  | 
| 38 42 | 
             
            class MimeType(str, Enum):
         | 
| @@ -108,6 +112,11 @@ class Result: | |
| 108 112 | 
             
                    self.raw = copy.deepcopy(data)
         | 
| 109 113 |  | 
| 110 114 | 
             
                    self.text = data.pop(MimeType.TEXT_PLAIN, None)
         | 
| 115 | 
            +
                    if self.text and (self.text.startswith("'") and self.text.endswith("'")):
         | 
| 116 | 
            +
                        # This is a workaround for the issue that str result is wrapped with single quotes by notebook.
         | 
| 117 | 
            +
                        # E.g. input text: "'flower'". what we want: "flower"
         | 
| 118 | 
            +
                        self.text = self.text[1:-1]
         | 
| 119 | 
            +
             | 
| 111 120 | 
             
                    self.html = data.pop(MimeType.TEXT_HTML, None)
         | 
| 112 121 | 
             
                    self.markdown = data.pop(MimeType.TEXT_MARKDOWN, None)
         | 
| 113 122 | 
             
                    self.svg = data.pop(MimeType.IMAGE_SVG, None)
         | 
| @@ -417,7 +426,15 @@ class E2BCodeInterpreter(CodeInterpreter): | |
| 417 426 | 
             
                def __init__(self, *args: Any, **kwargs: Any) -> None:
         | 
| 418 427 | 
             
                    super().__init__(*args, **kwargs)
         | 
| 419 428 | 
             
                    assert os.getenv("E2B_API_KEY"), "E2B_API_KEY environment variable must be set"
         | 
| 420 | 
            -
                     | 
| 429 | 
            +
                    try:
         | 
| 430 | 
            +
                        self.interpreter = E2BCodeInterpreter._new_e2b_interpreter_impl(
         | 
| 431 | 
            +
                            *args, **kwargs
         | 
| 432 | 
            +
                        )
         | 
| 433 | 
            +
                    except Exception as e:
         | 
| 434 | 
            +
                        raise RemoteSandboxCreationError(
         | 
| 435 | 
            +
                            f"Failed to create a remote sandbox due to {e}"
         | 
| 436 | 
            +
                        ) from e
         | 
| 437 | 
            +
             | 
| 421 438 | 
             
                    result = self.exec_cell(
         | 
| 422 439 | 
             
                        """
         | 
| 423 440 | 
             
            import platform
         | 
| @@ -433,27 +450,40 @@ print(f"Vision Agent version: {va_version}")""" | |
| 433 450 | 
             
                    _LOGGER.info(f"E2BCodeInterpreter initialized:\n{sys_versions}")
         | 
| 434 451 |  | 
| 435 452 | 
             
                def close(self, *args: Any, **kwargs: Any) -> None:
         | 
| 436 | 
            -
                     | 
| 437 | 
            -
             | 
| 453 | 
            +
                    try:
         | 
| 454 | 
            +
                        self.interpreter.notebook.close()
         | 
| 455 | 
            +
                        self.interpreter.kill(request_timeout=2)
         | 
| 456 | 
            +
                        _LOGGER.info(
         | 
| 457 | 
            +
                            f"The sandbox {self.interpreter.sandbox_id} is closed successfully."
         | 
| 458 | 
            +
                        )
         | 
| 459 | 
            +
                    except Exception as e:
         | 
| 460 | 
            +
                        _LOGGER.warn(
         | 
| 461 | 
            +
                            f"Failed to close the remote sandbox ({self.interpreter.sandbox_id}) due to {e}. This is not an issue. It's likely that the sandbox is already closed due to timeout."
         | 
| 462 | 
            +
                        )
         | 
| 438 463 |  | 
| 439 464 | 
             
                def restart_kernel(self) -> None:
         | 
| 465 | 
            +
                    self._check_sandbox_liveness()
         | 
| 440 466 | 
             
                    self.interpreter.notebook.restart_kernel()
         | 
| 441 467 |  | 
| 442 468 | 
             
                @tenacity.retry(
         | 
| 443 469 | 
             
                    wait=tenacity.wait_exponential_jitter(),
         | 
| 444 470 | 
             
                    stop=tenacity.stop_after_attempt(2),
         | 
| 471 | 
            +
                    # TODO: change TimeoutError to a more specific exception when e2b team provides more granular retryable exceptions
         | 
| 445 472 | 
             
                    retry=tenacity.retry_if_exception_type(TimeoutError),
         | 
| 446 473 | 
             
                )
         | 
| 447 474 | 
             
                def exec_cell(self, code: str) -> Execution:
         | 
| 448 | 
            -
                     | 
| 449 | 
            -
                        raise ConnectionResetError(
         | 
| 450 | 
            -
                            "Remote sandbox is closed unexpectedly. Please retry the operation."
         | 
| 451 | 
            -
                        )
         | 
| 475 | 
            +
                    self._check_sandbox_liveness()
         | 
| 452 476 | 
             
                    self.interpreter.set_timeout(_SESSION_TIMEOUT)  # Extend the life of the sandbox
         | 
| 453 | 
            -
                     | 
| 454 | 
            -
             | 
| 477 | 
            +
                    try:
         | 
| 478 | 
            +
                        execution = self.interpreter.notebook.exec_cell(code, timeout=self.timeout)
         | 
| 479 | 
            +
                        return Execution.from_e2b_execution(execution)
         | 
| 480 | 
            +
                    except Exception as e:
         | 
| 481 | 
            +
                        raise RemoteSandboxExecutionError(
         | 
| 482 | 
            +
                            f"Failed executing code in remote sandbox due to {e}: {code}"
         | 
| 483 | 
            +
                        ) from e
         | 
| 455 484 |  | 
| 456 485 | 
             
                def upload_file(self, file: Union[str, Path]) -> str:
         | 
| 486 | 
            +
                    self._check_sandbox_liveness()
         | 
| 457 487 | 
             
                    file_name = Path(file).name
         | 
| 458 488 | 
             
                    remote_path = f"/home/user/{file_name}"
         | 
| 459 489 | 
             
                    with open(file, "rb") as f:
         | 
| @@ -462,17 +492,26 @@ print(f"Vision Agent version: {va_version}")""" | |
| 462 492 | 
             
                        return remote_path
         | 
| 463 493 |  | 
| 464 494 | 
             
                def download_file(self, file_path: str) -> Path:
         | 
| 495 | 
            +
                    self._check_sandbox_liveness()
         | 
| 465 496 | 
             
                    with tempfile.NamedTemporaryFile(mode="w+b", delete=False) as file:
         | 
| 466 497 | 
             
                        file.write(self.interpreter.files.read(path=file_path, format="bytes"))
         | 
| 467 498 | 
             
                        _LOGGER.info(f"File ({file_path}) is downloaded to: {file.name}")
         | 
| 468 499 | 
             
                        return Path(file.name)
         | 
| 469 500 |  | 
| 501 | 
            +
                def _check_sandbox_liveness(self) -> None:
         | 
| 502 | 
            +
                    try:
         | 
| 503 | 
            +
                        alive = self.interpreter.is_running(request_timeout=2)
         | 
| 504 | 
            +
                    except Exception as e:
         | 
| 505 | 
            +
                        _LOGGER.error(
         | 
| 506 | 
            +
                            f"Failed to check the health of the remote sandbox ({self.interpreter.sandbox_id}) due to {e}. Consider the sandbox as dead."
         | 
| 507 | 
            +
                        )
         | 
| 508 | 
            +
                        alive = False
         | 
| 509 | 
            +
                    if not alive:
         | 
| 510 | 
            +
                        raise RemoteSandboxClosedError(
         | 
| 511 | 
            +
                            "Remote sandbox is closed unexpectedly. Please start a new VisionAgent instance."
         | 
| 512 | 
            +
                        )
         | 
| 513 | 
            +
             | 
| 470 514 | 
             
                @staticmethod
         | 
| 471 | 
            -
                @tenacity.retry(
         | 
| 472 | 
            -
                    wait=tenacity.wait_exponential_jitter(),
         | 
| 473 | 
            -
                    stop=tenacity.stop_after_delay(60),
         | 
| 474 | 
            -
                    retry=tenacity.retry_if_exception_type(ServiceException),
         | 
| 475 | 
            -
                )
         | 
| 476 515 | 
             
                def _new_e2b_interpreter_impl(*args, **kwargs) -> E2BCodeInterpreterImpl:  # type: ignore
         | 
| 477 516 | 
             
                    return E2BCodeInterpreterImpl(template="va-sandbox", *args, **kwargs)
         | 
| 478 517 |  | 
| @@ -564,12 +603,17 @@ class CodeInterpreterFactory: | |
| 564 603 | 
             
                    return instance
         | 
| 565 604 |  | 
| 566 605 | 
             
                @staticmethod
         | 
| 567 | 
            -
                def new_instance() -> CodeInterpreter:
         | 
| 568 | 
            -
                    if  | 
| 606 | 
            +
                def new_instance(code_sandbox_runtime: Optional[str] = None) -> CodeInterpreter:
         | 
| 607 | 
            +
                    if not code_sandbox_runtime:
         | 
| 608 | 
            +
                        code_sandbox_runtime = os.getenv("CODE_SANDBOX_RUNTIME", "local")
         | 
| 609 | 
            +
                    if code_sandbox_runtime == "e2b":
         | 
| 569 610 | 
             
                        instance: CodeInterpreter = E2BCodeInterpreter(timeout=_SESSION_TIMEOUT)
         | 
| 570 | 
            -
                     | 
| 611 | 
            +
                    elif code_sandbox_runtime == "local":
         | 
| 571 612 | 
             
                        instance = LocalCodeInterpreter(timeout=_SESSION_TIMEOUT)
         | 
| 572 | 
            -
                     | 
| 613 | 
            +
                    else:
         | 
| 614 | 
            +
                        raise ValueError(
         | 
| 615 | 
            +
                            f"Unsupported code sandbox runtime: {code_sandbox_runtime}. Supported runtimes: e2b, local"
         | 
| 616 | 
            +
                        )
         | 
| 573 617 | 
             
                    return instance
         | 
| 574 618 |  | 
| 575 619 |  | 
    
        vision_agent/utils/sim.py
    CHANGED
    
    | @@ -1,4 +1,5 @@ | |
| 1 1 | 
             
            import os
         | 
| 2 | 
            +
            from functools import lru_cache
         | 
| 2 3 | 
             
            from pathlib import Path
         | 
| 3 4 | 
             
            from typing import Dict, List, Optional, Sequence, Union
         | 
| 4 5 |  | 
| @@ -33,11 +34,7 @@ class Sim: | |
| 33 34 | 
             
                        model: str: The model to use for embeddings.
         | 
| 34 35 | 
             
                    """
         | 
| 35 36 | 
             
                    self.df = df
         | 
| 36 | 
            -
                     | 
| 37 | 
            -
                        self.client = OpenAI()
         | 
| 38 | 
            -
                    else:
         | 
| 39 | 
            -
                        self.client = OpenAI(api_key=api_key)
         | 
| 40 | 
            -
             | 
| 37 | 
            +
                    self.client = OpenAI(api_key=api_key)
         | 
| 41 38 | 
             
                    self.model = model
         | 
| 42 39 | 
             
                    if "embs" not in df.columns and sim_key is None:
         | 
| 43 40 | 
             
                        raise ValueError("key is required if no column 'embs' is present.")
         | 
| @@ -57,6 +54,7 @@ class Sim: | |
| 57 54 | 
             
                    df = df.drop("embs", axis=1)
         | 
| 58 55 | 
             
                    df.to_csv(sim_file / "df.csv", index=False)
         | 
| 59 56 |  | 
| 57 | 
            +
                @lru_cache(maxsize=256)
         | 
| 60 58 | 
             
                def top_k(
         | 
| 61 59 | 
             
                    self, query: str, k: int = 5, thresh: Optional[float] = None
         | 
| 62 60 | 
             
                ) -> Sequence[Dict]:
         | 
    
        vision_agent/utils/type_defs.py
    CHANGED
    
    | @@ -1,6 +1,8 @@ | |
| 1 1 | 
             
            from pydantic import Field, field_validator
         | 
| 2 2 | 
             
            from pydantic_settings import BaseSettings
         | 
| 3 3 |  | 
| 4 | 
            +
            from vision_agent.utils.exceptions import InvalidApiKeyError
         | 
| 5 | 
            +
             | 
| 4 6 |  | 
| 5 7 | 
             
            class LandingaiAPIKey(BaseSettings):
         | 
| 6 8 | 
             
                """The API key of a user in a particular organization in LandingLens.
         | 
| @@ -34,15 +36,3 @@ class LandingaiAPIKey(BaseSettings): | |
| 34 36 | 
             
                    env_prefix = "landingai_"
         | 
| 35 37 | 
             
                    case_sensitive = False
         | 
| 36 38 | 
             
                    extra = "ignore"
         | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
            class InvalidApiKeyError(Exception):
         | 
| 40 | 
            -
                """Exception raised when the an invalid API key is provided. This error could be raised from any SDK code, not limited to a HTTP client."""
         | 
| 41 | 
            -
             | 
| 42 | 
            -
                def __init__(self, message: str):
         | 
| 43 | 
            -
                    self.message = f"""{message}
         | 
| 44 | 
            -
            For more information, see https://landing-ai.github.io/landingai-python/landingai.html#manage-api-credentials"""
         | 
| 45 | 
            -
                    super().__init__(self.message)
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                def __str__(self) -> str:
         | 
| 48 | 
            -
                    return self.message
         | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            Metadata-Version: 2.1
         | 
| 2 2 | 
             
            Name: vision-agent
         | 
| 3 | 
            -
            Version: 0.2. | 
| 3 | 
            +
            Version: 0.2.80
         | 
| 4 4 | 
             
            Summary: Toolset for Vision Agent
         | 
| 5 5 | 
             
            Author: Landing AI
         | 
| 6 6 | 
             
            Author-email: dev@landing.ai
         | 
| @@ -10,7 +10,7 @@ Classifier: Programming Language :: Python :: 3.9 | |
| 10 10 | 
             
            Classifier: Programming Language :: Python :: 3.10
         | 
| 11 11 | 
             
            Classifier: Programming Language :: Python :: 3.11
         | 
| 12 12 | 
             
            Requires-Dist: e2b (>=0.17.1,<0.18.0)
         | 
| 13 | 
            -
            Requires-Dist: e2b-code-interpreter (==0.0. | 
| 13 | 
            +
            Requires-Dist: e2b-code-interpreter (==0.0.11a2)
         | 
| 14 14 | 
             
            Requires-Dist: ipykernel (>=6.29.4,<7.0.0)
         | 
| 15 15 | 
             
            Requires-Dist: langsmith (>=0.1.58,<0.2.0)
         | 
| 16 16 | 
             
            Requires-Dist: moviepy (>=1.0.0,<2.0.0)
         | 
| @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            vision_agent/__init__.py,sha256=EAb4-f9iyuEYkBrX4ag1syM8Syx8118_t0R6_C34M9w,57
         | 
| 2 2 | 
             
            vision_agent/agent/__init__.py,sha256=IUwfbPMcT8X_rnXMLmI8gJ4ltsHy_XSs9eLiKURJxeY,81
         | 
| 3 3 | 
             
            vision_agent/agent/agent.py,sha256=ZK-5lOtd9-eD9aWcXssJpnOyvZuO7_5hAmnb-6sWVe8,569
         | 
| 4 | 
            -
            vision_agent/agent/vision_agent.py,sha256= | 
| 4 | 
            +
            vision_agent/agent/vision_agent.py,sha256=n3IALoZZIqmosOw8TkfkfVD9NXIPkf9sMhGTN9elFFU,26305
         | 
| 5 5 | 
             
            vision_agent/agent/vision_agent_prompts.py,sha256=jpGJjrxDrxZej5SSgsTEK1sSYttgkTiZqxZAU1jWfvk,8656
         | 
| 6 6 | 
             
            vision_agent/fonts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
         | 
| 7 7 | 
             
            vision_agent/fonts/default_font_ch_en.ttf,sha256=1YM0Z3XqLDjSNbF7ihQFSAIUdjF9m1rtHiNC_6QosTE,1594400
         | 
| @@ -12,12 +12,13 @@ vision_agent/tools/prompts.py,sha256=V1z4YJLXZuUl_iZ5rY0M5hHc_2tmMEUKr0WocXKGt4E | |
| 12 12 | 
             
            vision_agent/tools/tool_utils.py,sha256=6z0jrvUnesJEFqDHZoAvbXPic8rzh0KfILL07tu0uRo,2205
         | 
| 13 13 | 
             
            vision_agent/tools/tools.py,sha256=TkZqNYX-ocwdaCdXd6c6tysSa_HX2y6Nrgl4JKni4IQ,43661
         | 
| 14 14 | 
             
            vision_agent/utils/__init__.py,sha256=CW84HnhqI6XQVuxf2KifkLnSuO7EOhmuL09-gAymAak,219
         | 
| 15 | 
            -
            vision_agent/utils/ | 
| 15 | 
            +
            vision_agent/utils/exceptions.py,sha256=JGiFPLAYnPpEvHfueQuJotv3rCkS-A7UAwEym56MmHM,1359
         | 
| 16 | 
            +
            vision_agent/utils/execute.py,sha256=wt7YNVn4jEzU-9ljQg2RYTcFV8qNSrS30QN3tNDRct4,23326
         | 
| 16 17 | 
             
            vision_agent/utils/image_utils.py,sha256=_cdiS5YrLzqkq_ZgFUO897m5M4_SCIThwUy4lOklfB8,7700
         | 
| 17 | 
            -
            vision_agent/utils/sim.py,sha256= | 
| 18 | 
            -
            vision_agent/utils/type_defs.py,sha256= | 
| 18 | 
            +
            vision_agent/utils/sim.py,sha256=1HTaiVaBiKeyXIy21IYGXlPw0TipOyw9FPOJDfyLI94,4409
         | 
| 19 | 
            +
            vision_agent/utils/type_defs.py,sha256=QeQRRIlklZMWzxROcCn5ELxP89nYdXGydy1rAiSpZZw,1384
         | 
| 19 20 | 
             
            vision_agent/utils/video.py,sha256=rNmU9KEIkZB5-EztZNlUiKYN0mm_55A_2VGUM0QpqLA,8779
         | 
| 20 | 
            -
            vision_agent-0.2. | 
| 21 | 
            -
            vision_agent-0.2. | 
| 22 | 
            -
            vision_agent-0.2. | 
| 23 | 
            -
            vision_agent-0.2. | 
| 21 | 
            +
            vision_agent-0.2.80.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
         | 
| 22 | 
            +
            vision_agent-0.2.80.dist-info/METADATA,sha256=xflnjK1RKkn82YM_yR21jEvLqlq0RpOm1JEgETYZXos,9433
         | 
| 23 | 
            +
            vision_agent-0.2.80.dist-info/WHEEL,sha256=7Z8_27uaHI_UZAc4Uox4PpBhQ9Y5_modZXWMxtUi4NU,88
         | 
| 24 | 
            +
            vision_agent-0.2.80.dist-info/RECORD,,
         | 
| 
            File without changes
         | 
| 
            File without changes
         |