refactor(agent): Refactor resource of agents (#1518)

This commit is contained in:
Fangyin Cheng
2024-05-15 09:57:19 +08:00
committed by GitHub
parent db4d318a5f
commit 559affe87d
102 changed files with 2633 additions and 2549 deletions

112
dbgpt/util/cache_utils.py Normal file
View File

@@ -0,0 +1,112 @@
"""Cache utils.
Adapted from https://github.com/hephex/asyncache/blob/master/asyncache/__init__.py.
It has stopped updating since 2022. So I copied the code here for future reference.
"""
import asyncio
import functools
from contextlib import AbstractContextManager
from typing import Any, Callable, MutableMapping, Optional, Protocol, TypeVar
from cachetools import keys
_KT = TypeVar("_KT")
_T = TypeVar("_T")
class IdentityFunction(Protocol): # pylint: disable=too-few-public-methods
"""
Type for a function returning the same type as the one it received.
"""
def __call__(self, __x: _T) -> _T:
...
class NullContext:
"""A class for noop context managers."""
def __enter__(self):
"""Return ``self`` upon entering the runtime context."""
return self
def __exit__(self, exc_type, exc_value, traceback):
"""Raise any exception triggered within the runtime context."""
return None
async def __aenter__(self):
"""Return ``self`` upon entering the runtime context."""
return self
async def __aexit__(self, exc_type, exc_value, traceback):
"""Raise any exception triggered within the runtime context."""
return None
def cached(
cache: Optional[MutableMapping[_KT, Any]],
# ignoring the mypy error to be consistent with the type used
# in https://github.com/python/typeshed/tree/master/stubs/cachetools
key: Callable[..., _KT] = keys.hashkey, # type:ignore
lock: Optional["AbstractContextManager[Any]"] = None,
) -> IdentityFunction:
"""
Decorator to wrap a function or a coroutine with a memoizing callable
that saves results in a cache.
When ``lock`` is provided for a standard function, it's expected to
implement ``__enter__`` and ``__exit__`` that will be used to lock
the cache when gets updated. If it wraps a coroutine, ``lock``
must implement ``__aenter__`` and ``__aexit__``.
"""
lock = lock or NullContext()
def decorator(func):
if asyncio.iscoroutinefunction(func):
async def wrapper(*args, **kwargs):
k = key(*args, **kwargs)
try:
async with lock:
return cache[k]
except KeyError:
pass # key not found
val = await func(*args, **kwargs)
try:
async with lock:
cache[k] = val
except ValueError:
pass # val too large
return val
else:
def wrapper(*args, **kwargs):
k = key(*args, **kwargs)
try:
with lock:
return cache[k]
except KeyError:
pass # key not found
val = func(*args, **kwargs)
try:
with lock:
cache[k] = val
except ValueError:
pass # val too large
return val
return functools.wraps(func)(wrapper)
return decorator

View File

@@ -1,9 +1,20 @@
import asyncio
import inspect
from functools import wraps
from typing import Any, get_args, get_origin, get_type_hints
from typing import (
Any,
Dict,
List,
Optional,
Union,
_UnionGenericAlias,
get_args,
get_origin,
get_type_hints,
)
from typeguard import check_type
from typing_extensions import Annotated, Doc, _AnnotatedAlias
def _is_typing(obj):
@@ -119,3 +130,61 @@ def rearrange_args_by_type(func):
return await func(*sorted_args, **sorted_kwargs)
return async_wrapper if asyncio.iscoroutinefunction(func) else sync_wrapper
def type_to_string(obj: Any, default_type: str = "unknown") -> str:
"""Convert a type to a string representation."""
type_map = {
int: "integer",
str: "string",
float: "float",
bool: "boolean",
Any: "any",
List: "array",
dict: "object",
}
# Check NoneType
if obj is type(None):
return "null"
# Get the origin of the type
origin = getattr(obj, "__origin__", None)
if origin:
if _is_typing(origin) and not isinstance(obj, _UnionGenericAlias):
obj = origin
origin = origin.__origin__
# Handle special cases like List[int]
if origin is Union and hasattr(obj, "__args__"):
subtypes = ", ".join(
type_to_string(t) for t in obj.__args__ if t is not type(None)
)
# return f"Optional[{subtypes}]"
return subtypes
elif origin is list or origin is List:
subtypes = ", ".join(type_to_string(t) for t in obj.__args__)
# return f"List[{subtypes}]"
return "array"
elif origin in [dict, Dict]:
key_type, value_type = (type_to_string(t) for t in obj.__args__)
# return f"Dict[{key_type}, {value_type}]"
return "object"
return type_map.get(origin, default_type)
else:
if hasattr(obj, "__args__"):
subtypes = ", ".join(
type_to_string(t) for t in obj.__args__ if t is not type(None)
)
return subtypes
return type_map.get(obj, default_type)
def parse_param_description(name: str, obj: Any) -> str:
default_type_title = name.replace("_", " ").title()
if isinstance(obj, _AnnotatedAlias):
metadata = obj.__metadata__
docs = [arg for arg in metadata if isinstance(arg, Doc)]
doc_str = docs[0].documentation if docs else default_type_title
else:
doc_str = default_type_title
return doc_str

View File

@@ -104,6 +104,9 @@ class BaseParameters:
"""
return _dict_to_command_args(asdict(self), args_prefix=args_prefix)
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
def _get_dataclass_print_str(obj):
class_name = obj.__class__.__name__