增加环绕侦察场景适配
This commit is contained in:
0
backend_service/venv/bin/Activate.ps1
Executable file → Normal file
0
backend_service/venv/bin/Activate.ps1
Executable file → Normal file
4
backend_service/venv/bin/activate
Executable file → Normal file
4
backend_service/venv/bin/activate
Executable file → Normal file
@@ -41,12 +41,12 @@ case "$(uname)" in
|
||||
CYGWIN*|MSYS*|MINGW*)
|
||||
# transform D:\path\to\venv to /d/path/to/venv on MSYS and MINGW
|
||||
# and to /cygdrive/d/path/to/venv on Cygwin
|
||||
VIRTUAL_ENV=$(cygpath /home/huangfukk/DronePlanning/backend_service/venv)
|
||||
VIRTUAL_ENV=$(cygpath /home/a/DronePlanning/backend_service/venv)
|
||||
export VIRTUAL_ENV
|
||||
;;
|
||||
*)
|
||||
# use the path as-is
|
||||
export VIRTUAL_ENV=/home/huangfukk/DronePlanning/backend_service/venv
|
||||
export VIRTUAL_ENV=/home/a/DronePlanning/backend_service/venv
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
2
backend_service/venv/bin/activate.csh
Executable file → Normal file
2
backend_service/venv/bin/activate.csh
Executable file → Normal file
@@ -9,7 +9,7 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV /home/huangfukk/DronePlanning/backend_service/venv
|
||||
setenv VIRTUAL_ENV /home/a/DronePlanning/backend_service/venv
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
|
||||
|
||||
2
backend_service/venv/bin/activate.fish
Executable file → Normal file
2
backend_service/venv/bin/activate.fish
Executable file → Normal file
@@ -33,7 +33,7 @@ end
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx VIRTUAL_ENV /home/huangfukk/DronePlanning/backend_service/venv
|
||||
set -gx VIRTUAL_ENV /home/a/DronePlanning/backend_service/venv
|
||||
|
||||
set -gx _OLD_VIRTUAL_PATH $PATH
|
||||
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from chromadb.cli.cli import app
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from coloredlogs.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from dashscope.cli import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from distro.distro import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from dotenv.__main__ import cli
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from numpy.f2py.f2py2e import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from fastapi.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from huggingface_hub.cli.hf import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from httpx import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from humanfriendly.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from isympy import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from json_repair.__main__ import cli
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from jsonschema.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from markdown_it.cli.parse import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from mcp.cli import app
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(app())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from charset_normalizer.cli import cli_detect
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from numpy._configtool import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from onnxruntime.tools.onnxruntime_test import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from openai.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pybase64.__main__ import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from pygments.cmdline import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from json5.tool import main
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(main())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from build.__main__ import entrypoint
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import decrypt
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import encrypt
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import keygen
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.util import private_to_public
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import sign
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from rsa.cli import verify
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1 +1 @@
|
||||
/home/huangfukk/miniconda3/bin/python3
|
||||
/home/a/miniconda3/bin/python3
|
||||
@@ -1,7 +0,0 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from shortuuid.cli import cli
|
||||
if __name__ == '__main__':
|
||||
if sys.argv[0].endswith('.exe'):
|
||||
sys.argv[0] = sys.argv[0][:-4]
|
||||
sys.exit(cli())
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from huggingface_hub.inference._mcp.cli import app
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from tqdm.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from typer.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from uvicorn.main import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from watchfiles.cli import cli
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from websockets.cli import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/home/huangfukk/DronePlanning/backend_service/venv/bin/python3
|
||||
#!/home/a/DronePlanning/backend_service/venv/bin/python3
|
||||
import sys
|
||||
from websocket._wsdump import main
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
Copyright (c) 2011, Stavros Korokithakis
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of Stochastic Technologies nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@@ -1,7 +0,0 @@
|
||||
Authors
|
||||
=======
|
||||
|
||||
``pyjwt`` is currently written and maintained by `Jose Padilla <https://github.com/jpadilla>`_.
|
||||
Originally written and maintained by `Jeff Lindsay <https://github.com/progrium>`_.
|
||||
|
||||
A full list of contributors can be found on GitHub’s `overview <https://github.com/jpadilla/pyjwt/graphs/contributors>`_.
|
||||
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2022 José Padilla
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,106 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: PyJWT
|
||||
Version: 2.10.1
|
||||
Summary: JSON Web Token implementation in Python
|
||||
Author-email: Jose Padilla <hello@jpadilla.com>
|
||||
License: MIT
|
||||
Project-URL: Homepage, https://github.com/jpadilla/pyjwt
|
||||
Keywords: json,jwt,security,signing,token,web
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Classifier: Programming Language :: Python :: 3.13
|
||||
Classifier: Topic :: Utilities
|
||||
Requires-Python: >=3.9
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
License-File: AUTHORS.rst
|
||||
Provides-Extra: crypto
|
||||
Requires-Dist: cryptography>=3.4.0; extra == "crypto"
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: coverage[toml]==5.0.4; extra == "dev"
|
||||
Requires-Dist: cryptography>=3.4.0; extra == "dev"
|
||||
Requires-Dist: pre-commit; extra == "dev"
|
||||
Requires-Dist: pytest<7.0.0,>=6.0.0; extra == "dev"
|
||||
Requires-Dist: sphinx; extra == "dev"
|
||||
Requires-Dist: sphinx-rtd-theme; extra == "dev"
|
||||
Requires-Dist: zope.interface; extra == "dev"
|
||||
Provides-Extra: docs
|
||||
Requires-Dist: sphinx; extra == "docs"
|
||||
Requires-Dist: sphinx-rtd-theme; extra == "docs"
|
||||
Requires-Dist: zope.interface; extra == "docs"
|
||||
Provides-Extra: tests
|
||||
Requires-Dist: coverage[toml]==5.0.4; extra == "tests"
|
||||
Requires-Dist: pytest<7.0.0,>=6.0.0; extra == "tests"
|
||||
|
||||
PyJWT
|
||||
=====
|
||||
|
||||
.. image:: https://github.com/jpadilla/pyjwt/workflows/CI/badge.svg
|
||||
:target: https://github.com/jpadilla/pyjwt/actions?query=workflow%3ACI
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/pyjwt.svg
|
||||
:target: https://pypi.python.org/pypi/pyjwt
|
||||
|
||||
.. image:: https://codecov.io/gh/jpadilla/pyjwt/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/jpadilla/pyjwt
|
||||
|
||||
.. image:: https://readthedocs.org/projects/pyjwt/badge/?version=stable
|
||||
:target: https://pyjwt.readthedocs.io/en/stable/
|
||||
|
||||
A Python implementation of `RFC 7519 <https://tools.ietf.org/html/rfc7519>`_. Original implementation was written by `@progrium <https://github.com/progrium>`_.
|
||||
|
||||
Sponsor
|
||||
-------
|
||||
|
||||
.. |auth0-logo| image:: https://github.com/user-attachments/assets/ee98379e-ee76-4bcb-943a-e25c4ea6d174
|
||||
:width: 160px
|
||||
|
||||
+--------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
| |auth0-logo| | If you want to quickly add secure token-based authentication to Python projects, feel free to check Auth0's Python SDK and free plan at `auth0.com/signup <https://auth0.com/signup?utm_source=external_sites&utm_medium=pyjwt&utm_campaign=devn_signup>`_. |
|
||||
+--------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
|
||||
|
||||
Installing
|
||||
----------
|
||||
|
||||
Install with **pip**:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install PyJWT
|
||||
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code-block:: pycon
|
||||
|
||||
>>> import jwt
|
||||
>>> encoded = jwt.encode({"some": "payload"}, "secret", algorithm="HS256")
|
||||
>>> print(encoded)
|
||||
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg
|
||||
>>> jwt.decode(encoded, "secret", algorithms=["HS256"])
|
||||
{'some': 'payload'}
|
||||
|
||||
Documentation
|
||||
-------------
|
||||
|
||||
View the full docs online at https://pyjwt.readthedocs.io/en/stable/
|
||||
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
You can run tests from the project root after cloning with:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ tox
|
||||
@@ -1,32 +0,0 @@
|
||||
PyJWT-2.10.1.dist-info/AUTHORS.rst,sha256=klzkNGECnu2_VY7At89_xLBF3vUSDruXk3xwgUBxzwc,322
|
||||
PyJWT-2.10.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
PyJWT-2.10.1.dist-info/LICENSE,sha256=eXp6ICMdTEM-nxkR2xcx0GtYKLmPSZgZoDT3wPVvXOU,1085
|
||||
PyJWT-2.10.1.dist-info/METADATA,sha256=EkewF6D6KU8SGaaQzVYfxUUU1P_gs_dp1pYTkoYvAx8,3990
|
||||
PyJWT-2.10.1.dist-info/RECORD,,
|
||||
PyJWT-2.10.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
|
||||
PyJWT-2.10.1.dist-info/top_level.txt,sha256=RP5DHNyJbMq2ka0FmfTgoSaQzh7e3r5XuCWCO8a00k8,4
|
||||
jwt/__init__.py,sha256=VB2vFKuboTjcDGeZ8r-UqK_dz3NsQSQEqySSICby8Xg,1711
|
||||
jwt/__pycache__/__init__.cpython-313.pyc,,
|
||||
jwt/__pycache__/algorithms.cpython-313.pyc,,
|
||||
jwt/__pycache__/api_jwk.cpython-313.pyc,,
|
||||
jwt/__pycache__/api_jws.cpython-313.pyc,,
|
||||
jwt/__pycache__/api_jwt.cpython-313.pyc,,
|
||||
jwt/__pycache__/exceptions.cpython-313.pyc,,
|
||||
jwt/__pycache__/help.cpython-313.pyc,,
|
||||
jwt/__pycache__/jwk_set_cache.cpython-313.pyc,,
|
||||
jwt/__pycache__/jwks_client.cpython-313.pyc,,
|
||||
jwt/__pycache__/types.cpython-313.pyc,,
|
||||
jwt/__pycache__/utils.cpython-313.pyc,,
|
||||
jwt/__pycache__/warnings.cpython-313.pyc,,
|
||||
jwt/algorithms.py,sha256=cKr-XEioe0mBtqJMCaHEswqVOA1Z8Purt5Sb3Bi-5BE,30409
|
||||
jwt/api_jwk.py,sha256=6F1r7rmm8V5qEnBKA_xMjS9R7VoANe1_BL1oD2FrAjE,4451
|
||||
jwt/api_jws.py,sha256=aM8vzqQf6mRrAw7bRy-Moj_pjWsKSVQyYK896AfMjJU,11762
|
||||
jwt/api_jwt.py,sha256=OGT4hok1l5A6FH_KdcrU5g6u6EQ8B7em0r9kGM9SYgA,14512
|
||||
jwt/exceptions.py,sha256=bUIOJ-v9tjopTLS-FYOTc3kFx5WP5IZt7ksN_HE1G9Q,1211
|
||||
jwt/help.py,sha256=vFdNzjQoAch04XCMYpCkyB2blaqHAGAqQrtf9nSPkdk,1808
|
||||
jwt/jwk_set_cache.py,sha256=hBKmN-giU7-G37L_XKgc_OZu2ah4wdbj1ZNG_GkoSE8,959
|
||||
jwt/jwks_client.py,sha256=p9b-IbQqo2tEge9Zit3oSPBFNePqwho96VLbnUrHUWs,4259
|
||||
jwt/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
jwt/types.py,sha256=VnhGv_VFu5a7_mrPoSCB7HaNLrJdhM8Sq1sSfEg0gLU,99
|
||||
jwt/utils.py,sha256=hxOjvDBheBYhz-RIPiEz7Q88dSUSTMzEdKE_Ww2VdJw,3640
|
||||
jwt/warnings.py,sha256=50XWOnyNsIaqzUJTk6XHNiIDykiL763GYA92MjTKmok,59
|
||||
@@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (75.6.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
jwt
|
||||
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
@@ -1 +0,0 @@
|
||||
pip
|
||||
@@ -1,547 +0,0 @@
|
||||
Metadata-Version: 2.4
|
||||
Name: agentscope
|
||||
Version: 1.0.7
|
||||
Summary: AgentScope: A Flexible yet Robust Multi-Agent Platform.
|
||||
Author-email: SysML team of Alibaba Tongyi Lab <gaodawei.gdw@alibaba-inc.com>
|
||||
License-Expression: Apache-2.0
|
||||
Project-URL: Homepage, https://github.com/agentscope-ai/agentscope
|
||||
Project-URL: Documentation, https://doc.agentscope.io/
|
||||
Project-URL: Repository, https://github.com/agentscope-ai/agentscope
|
||||
Keywords: deep-learning,multi agents,agents
|
||||
Classifier: Development Status :: 4 - Beta
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: Intended Audience :: Science/Research
|
||||
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
||||
Requires-Python: >=3.10
|
||||
Description-Content-Type: text/markdown
|
||||
License-File: LICENSE
|
||||
Requires-Dist: aioitertools
|
||||
Requires-Dist: anthropic
|
||||
Requires-Dist: dashscope
|
||||
Requires-Dist: docstring_parser
|
||||
Requires-Dist: json5
|
||||
Requires-Dist: json_repair
|
||||
Requires-Dist: mcp>=1.13
|
||||
Requires-Dist: numpy
|
||||
Requires-Dist: openai
|
||||
Requires-Dist: python-datauri
|
||||
Requires-Dist: opentelemetry-api
|
||||
Requires-Dist: opentelemetry-sdk
|
||||
Requires-Dist: opentelemetry-exporter-otlp
|
||||
Requires-Dist: python-socketio
|
||||
Requires-Dist: shortuuid
|
||||
Requires-Dist: tiktoken
|
||||
Requires-Dist: sounddevice
|
||||
Provides-Extra: full
|
||||
Requires-Dist: ollama>=0.5.4; extra == "full"
|
||||
Requires-Dist: google-genai; extra == "full"
|
||||
Requires-Dist: Pillow; extra == "full"
|
||||
Requires-Dist: transformers; extra == "full"
|
||||
Requires-Dist: jinja2; extra == "full"
|
||||
Requires-Dist: ray; extra == "full"
|
||||
Requires-Dist: mem0ai; extra == "full"
|
||||
Requires-Dist: packaging; extra == "full"
|
||||
Requires-Dist: pypdf; extra == "full"
|
||||
Requires-Dist: python-docx; extra == "full"
|
||||
Requires-Dist: nltk; extra == "full"
|
||||
Requires-Dist: qdrant-client; extra == "full"
|
||||
Provides-Extra: dev
|
||||
Requires-Dist: agentscope[full]; extra == "dev"
|
||||
Requires-Dist: pre-commit; extra == "dev"
|
||||
Requires-Dist: pytest; extra == "dev"
|
||||
Requires-Dist: sphinx-gallery; extra == "dev"
|
||||
Requires-Dist: furo; extra == "dev"
|
||||
Requires-Dist: myst_parser; extra == "dev"
|
||||
Requires-Dist: matplotlib; extra == "dev"
|
||||
Requires-Dist: pymilvus[milvus_lite]; extra == "dev"
|
||||
Requires-Dist: reme-ai>=0.1.10.7; python_full_version >= "3.12" and extra == "dev"
|
||||
Dynamic: license-file
|
||||
|
||||
[**中文主页**](https://github.com/agentscope-ai/agentscope/blob/main/README_zh.md) | [**Tutorial**](https://doc.agentscope.io/) | [**Roadmap**](https://github.com/agentscope-ai/agentscope/blob/main/docs/roadmap.md) | [**FAQ**](https://doc.agentscope.io/tutorial/faq.html)
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
src="https://img.alicdn.com/imgextra/i1/O1CN01nTg6w21NqT5qFKH1u_!!6000000001621-55-tps-550-550.svg"
|
||||
alt="AgentScope Logo"
|
||||
width="200"
|
||||
/>
|
||||
</p>
|
||||
|
||||
<h2 align="center">AgentScope: Agent-Oriented Programming for Building LLM Applications</h2>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://arxiv.org/abs/2402.14034">
|
||||
<img
|
||||
src="https://img.shields.io/badge/cs.MA-2402.14034-B31C1C?logo=arxiv&logoColor=B31C1C"
|
||||
alt="arxiv"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://pypi.org/project/agentscope/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/python-3.10+-blue?logo=python"
|
||||
alt="pypi"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://pypi.org/project/agentscope/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fpypi.org%2Fpypi%2Fagentscope%2Fjson&query=%24.info.version&prefix=v&logo=pypi&label=version"
|
||||
alt="pypi"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://doc.agentscope.io/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/Docs-English%7C%E4%B8%AD%E6%96%87-blue?logo=markdown"
|
||||
alt="docs"
|
||||
/>
|
||||
</a>
|
||||
<a href="https://agentscope.io/">
|
||||
<img
|
||||
src="https://img.shields.io/badge/GUI-AgentScope_Studio-blue?logo=look&logoColor=green&color=dark-green"
|
||||
alt="workstation"
|
||||
/>
|
||||
</a>
|
||||
<a href="./LICENSE">
|
||||
<img
|
||||
src="https://img.shields.io/badge/license-Apache--2.0-black"
|
||||
alt="license"
|
||||
/>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="https://trendshift.io/api/badge/repositories/10079" alt="modelscope%2Fagentscope | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/>
|
||||
</p>
|
||||
|
||||
## ✨ Why AgentScope?
|
||||
|
||||
Easy for beginners, powerful for experts.
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/images/agentscope_v1_0822.png" alt="AgentScope Framework" width="80%"/>
|
||||
</p>
|
||||
|
||||
- **Transparent to Developers**: Transparent is our **FIRST principle**. Prompt engineering, API invocation, agent building, workflow orchestration, all are visible and controllable for developers. No deep encapsulation or implicit magic.
|
||||
- **[Realtime Steering](https://doc.agentscope.io/tutorial/task_agent.html#realtime-steering)**: Native support for realtime interruption and customized handling.
|
||||
- **More Agentic**: Support [agentic tools management](https://doc.agentscope.io/tutorial/task_tool.html), [agentic long-term memory control](https://doc.agentscope.io/tutorial/task_long_term_memory.html) and agentic RAG, etc.
|
||||
- **Model Agnostic**: Programming once, run with all models.
|
||||
- **LEGO-style Agent Building**: All components are **modular** and **independent**.
|
||||
- **Multi-Agent Oriented**: Designed for **multi-agent**, **explicit** message passing and workflow orchestration, NO deep encapsulation.
|
||||
- **Highly Customizable**: Tools, prompt, agent, workflow, third-party libs & visualization, customization is encouraged everywhere.
|
||||
|
||||
Quick overview of important features in **AgentScope 1.0**:
|
||||
|
||||
| Module | Feature | Tutorial |
|
||||
|------------|------------------------------------------------------------------------------------|-------------------------------------------------------------------------|
|
||||
| model | Support async invocation | [Model](https://doc.agentscope.io/tutorial/task_model.html) |
|
||||
| | Support reasoning model | |
|
||||
| | Support streaming/non-streaming returns | |
|
||||
| tool | Support async/sync tool functions | [Tool](https://doc.agentscope.io/tutorial/task_tool.html) |
|
||||
| | Support streaming/non-streaming returns | |
|
||||
| | Support user interruption | |
|
||||
| | Support post-processing | |
|
||||
| | Support group-wise tools management | |
|
||||
| | Support agentic tools management by meta tool | |
|
||||
| MCP | Support streamable HTTP/SSE/StdIO transport | [MCP](https://doc.agentscope.io/tutorial/task_mcp.html) |
|
||||
| | Support both **stateful** and **stateless** mode MCP Client | |
|
||||
| | Support client- & function-level fine-grained control | |
|
||||
| agent | Support async execution | |
|
||||
| | Support parallel tool calls | |
|
||||
| | Support realtime steering interruption and customized handling | |
|
||||
| | Support automatic state management | |
|
||||
| | Support agent-controlled long-term memory | |
|
||||
| | Support agent hooks | |
|
||||
| tracing | Support OpenTelemetry-based tracing in LLM, tools, agent and formatter | [Tracing](https://doc.agentscope.io/tutorial/task_tracing.html) |
|
||||
| | Support connecting to third-party tracing platforms (e.g. Arize-Phoenix, Langfuse) | |
|
||||
| memory | Support long-term memory | [Memory](https://doc.agentscope.io/tutorial/task_long_term_memory.html) |
|
||||
| session | Provide session/application-level automatic state management | [Session](https://doc.agentscope.io/tutorial/task_state.html) |
|
||||
| evaluation | Provide distributed and parallel evaluation | [Evaluation](https://doc.agentscope.io/tutorial/task_eval.html) |
|
||||
| formatter | Support multi-agent prompt formatting with tools API | [Prompt Formatter](https://doc.agentscope.io/tutorial/task_prompt.html) |
|
||||
| | Support truncation-based formatter strategy | |
|
||||
| plan | Support ReAct-based long-term planning | [Plan](https://doc.agentscope.io/tutorial/task_plan.html) |
|
||||
| | Support manual plan specification | |
|
||||
| RAG | Support agentic RAG | [RAG](https://doc.agentscope.io/tutorial/task_rag.html) |
|
||||
| | Support multimodal RAG | |
|
||||
| ... | | |
|
||||
|
||||
## 📢 News
|
||||
- **[2025-11]** [Contributing Guide](./CONTRIBUTING.md) is online now! Welcome to contribute to AgentScope.
|
||||
- **[2025-09]** **RAG** module in AgentScope 1.0 is online now! Check our [tutorial](https://doc.agentscope.io/tutorial/task_rag.html) and [example](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/rag) for more details.
|
||||
- **[2025-09]** **Voice agent** is online! `ReActAgent` supports Qwen-Omni and GPT-Audio natively now, check our [new example](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/voice_agent) and [roadmap](https://github.com/agentscope-ai/agentscope/issues/773).
|
||||
- **[2025-09]** A new powerful 📋**Plan** module is online now! Check out the [tutorial](https://doc.agentscope.io/tutorial/task_plan.html) for more details.
|
||||
- **[2025-09]** **AgentScope Runtime** is open-sourced now! Enabling effective agent deployment with sandboxed tool execution for production-ready AI applications. Check out the [GitHub repo](https://github.com/agentscope-ai/agentscope-runtime).
|
||||
- **[2025-09]** **AgentScope Studio** is open-sourced now! Check out the [GitHub repo](https://github.com/agentscope-ai/agentscope-studio).
|
||||
- **[2025-08]** The new tutorial of v1 is online now! Check out the [tutorial](https://doc.agentscope.io) for more details.
|
||||
- **[2025-08]** 🎉🎉 AgentScope v1 is released now! This version fully embraces the asynchronous execution, providing many new features and improvements. Check out [changelog](https://github.com/agentscope-ai/agentscope/blob/main/docs/changelog.md) for detailed changes.
|
||||
|
||||
## 💬 Contact
|
||||
|
||||
Welcome to join our community on
|
||||
|
||||
| [Discord](https://discord.gg/eYMpfnkG8h) | DingTalk |
|
||||
|----------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| <img src="https://gw.alicdn.com/imgextra/i1/O1CN01hhD1mu1Dd3BWVUvxN_!!6000000000238-2-tps-400-400.png" width="100" height="100"> | <img src="https://img.alicdn.com/imgextra/i1/O1CN01LxzZha1thpIN2cc2E_!!6000000005934-2-tps-497-477.png" width="100" height="100"> |
|
||||
|
||||
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
|
||||
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
|
||||
## 📑 Table of Contents
|
||||
|
||||
- [🚀 Quickstart](#-quickstart)
|
||||
- [💻 Installation](#-installation)
|
||||
- [🛠️ From source](#-from-source)
|
||||
- [🔄 Using uv (recommended for faster installs)](#-using-uv-recommended-for-faster-installs)
|
||||
- [📦 From PyPi](#-from-pypi)
|
||||
- [📝 Example](#-example)
|
||||
- [👋 Hello AgentScope!](#-hello-agentscope)
|
||||
- [🎯 Realtime Steering](#-realtime-steering)
|
||||
- [🛠️ Fine-Grained MCP Control](#-fine-grained-mcp-control)
|
||||
- [🧑🤝🧑 Multi-Agent Conversation](#-multi-agent-conversation)
|
||||
- [💻 AgentScope Studio](#-agentscope-studio)
|
||||
- [📖 Documentation](#-documentation)
|
||||
- [🤝 Contributing](#-contributing)
|
||||
- [⚖️ License](#-license)
|
||||
- [📚 Publications](#-publications)
|
||||
- [✨ Contributors](#-contributors)
|
||||
|
||||
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
|
||||
|
||||
## 🚀 Quickstart
|
||||
|
||||
### 💻 Installation
|
||||
|
||||
> AgentScope requires **Python 3.10** or higher.
|
||||
|
||||
#### 🛠️ From source
|
||||
|
||||
```bash
|
||||
# Pull the source code from GitHub
|
||||
git clone -b main https://github.com/agentscope-ai/agentscope.git
|
||||
|
||||
# Install the package in editable mode
|
||||
cd agentscope
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
#### 🔄 Using uv (recommended for faster installs)
|
||||
|
||||
[uv](https://github.com/astral-sh/uv) is a fast Python package installer and resolver, written in Rust.
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone -b main https://github.com/agentscope-ai/agentscope.git
|
||||
cd agentscope
|
||||
|
||||
# Install with uv
|
||||
uv pip install -e .
|
||||
```
|
||||
|
||||
#### 📦 From PyPi
|
||||
|
||||
```bash
|
||||
pip install agentscope
|
||||
```
|
||||
|
||||
Or with uv:
|
||||
|
||||
```bash
|
||||
uv pip install agentscope
|
||||
```
|
||||
|
||||
## 📝 Example
|
||||
|
||||
### 👋 Hello AgentScope!
|
||||
|
||||
Start with a conversation between user and a ReAct agent 🤖 named "Friday"!
|
||||
|
||||
```python
|
||||
from agentscope.agent import ReActAgent, UserAgent
|
||||
from agentscope.model import DashScopeChatModel
|
||||
from agentscope.formatter import DashScopeChatFormatter
|
||||
from agentscope.memory import InMemoryMemory
|
||||
from agentscope.tool import Toolkit, execute_python_code, execute_shell_command
|
||||
import os, asyncio
|
||||
|
||||
|
||||
async def main():
|
||||
toolkit = Toolkit()
|
||||
toolkit.register_tool_function(execute_python_code)
|
||||
toolkit.register_tool_function(execute_shell_command)
|
||||
|
||||
agent = ReActAgent(
|
||||
name="Friday",
|
||||
sys_prompt="You're a helpful assistant named Friday.",
|
||||
model=DashScopeChatModel(
|
||||
model_name="qwen-max",
|
||||
api_key=os.environ["DASHSCOPE_API_KEY"],
|
||||
stream=True,
|
||||
),
|
||||
memory=InMemoryMemory(),
|
||||
formatter=DashScopeChatFormatter(),
|
||||
toolkit=toolkit,
|
||||
)
|
||||
|
||||
user = UserAgent(name="user")
|
||||
|
||||
msg = None
|
||||
while True:
|
||||
msg = await agent(msg)
|
||||
msg = await user(msg)
|
||||
if msg.get_text_content() == "exit":
|
||||
break
|
||||
|
||||
asyncio.run(main())
|
||||
```
|
||||
|
||||
### 🎯 Realtime Steering
|
||||
|
||||
Natively support **realtime interruption** in ``ReActAgent`` with robust memory preservation, and convert interruption into an **observable event** for agent to seamlessly resume conversations.
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/images/realtime_steering_zh.gif" alt="Realtime Steering" width="49%"/>
|
||||
<img src="./assets/images/realtime_steering_en.gif" alt="Realtime Steering" width="49%"/>
|
||||
</p>
|
||||
|
||||
### 🛠️ Fine-Grained MCP Control
|
||||
|
||||
Developers can obtain the MCP tool as a **local callable function**, and use it anywhere (e.g. call directly, pass to agent, wrap into a more complex tool, etc.)
|
||||
|
||||
```python
|
||||
from agentscope.mcp import HttpStatelessClient
|
||||
from agentscope.tool import Toolkit
|
||||
import os
|
||||
|
||||
async def fine_grained_mcp_control():
|
||||
# Initialize the MCP client
|
||||
client = HttpStatelessClient(
|
||||
name="gaode_mcp",
|
||||
transport="streamable_http",
|
||||
url=f"https://mcp.amap.com/mcp?key={os.environ['GAODE_API_KEY']}",
|
||||
)
|
||||
|
||||
# Obtain the MCP tool as a **local callable function**, and use it anywhere
|
||||
func = await client.get_callable_function(func_name="maps_geo")
|
||||
|
||||
# Option 1: Call directly
|
||||
await func(address="Tiananmen Square", city="Beijing")
|
||||
|
||||
# Option 2: Pass to agent as a tool
|
||||
toolkit = Toolkit()
|
||||
toolkit.register_tool_function(func)
|
||||
# ...
|
||||
|
||||
# Option 3: Wrap into a more complex tool
|
||||
# ...
|
||||
```
|
||||
|
||||
### 🧑🤝🧑 Multi-Agent Conversation
|
||||
|
||||
AgentScope provides ``MsgHub`` and pipelines to streamline multi-agent conversations, offering efficient message routing and seamless information sharing
|
||||
|
||||
```python
|
||||
from agentscope.pipeline import MsgHub, sequential_pipeline
|
||||
from agentscope.message import Msg
|
||||
import asyncio
|
||||
|
||||
async def multi_agent_conversation():
|
||||
# Create agents
|
||||
agent1 = ...
|
||||
agent2 = ...
|
||||
agent3 = ...
|
||||
agent4 = ...
|
||||
|
||||
# Create a message hub to manage multi-agent conversation
|
||||
async with MsgHub(
|
||||
participants=[agent1, agent2, agent3],
|
||||
announcement=Msg("Host", "Introduce yourselves.", "assistant")
|
||||
) as hub:
|
||||
# Speak in a sequential manner
|
||||
await sequential_pipeline([agent1, agent2, agent3])
|
||||
# Dynamic manage the participants
|
||||
hub.add(agent4)
|
||||
hub.delete(agent3)
|
||||
await hub.broadcast(Msg("Host", "Goodbye!", "assistant"))
|
||||
|
||||
asyncio.run(multi_agent_conversation())
|
||||
```
|
||||
|
||||
### 💻 AgentScope Studio
|
||||
|
||||
Use the following command to install and start AgentScope Studio, to trace and visualize your agent application.
|
||||
|
||||
```bash
|
||||
npm install -g @agentscope/studio
|
||||
|
||||
as_studio
|
||||
```
|
||||
|
||||
<p align="center">
|
||||
<img
|
||||
src="./assets/images/home.gif"
|
||||
width="49%"
|
||||
alt="home"
|
||||
/>
|
||||
<img
|
||||
src="./assets/images/projects.gif"
|
||||
width="49%"
|
||||
alt="projects"
|
||||
/>
|
||||
<img
|
||||
src="./assets/images/runtime.gif"
|
||||
width="49%"
|
||||
alt="runtime"
|
||||
/>
|
||||
<img
|
||||
src="./assets/images/friday.gif"
|
||||
width="49%"
|
||||
alt="friday"
|
||||
/>
|
||||
</p>
|
||||
|
||||
|
||||
## 📖 Documentation
|
||||
|
||||
- Tutorial
|
||||
- [Installation](https://doc.agentscope.io/tutorial/quickstart_installation.html)
|
||||
- [Key Concepts](https://doc.agentscope.io/tutorial/quickstart_key_concept.html)
|
||||
- [Create Message](https://doc.agentscope.io/tutorial/quickstart_message.html)
|
||||
- [ReAct Agent](https://doc.agentscope.io/tutorial/quickstart_agent.html)
|
||||
- Workflow
|
||||
- [Conversation](https://doc.agentscope.io/tutorial/workflow_conversation.html)
|
||||
- [Multi-Agent Debate](https://doc.agentscope.io/tutorial/workflow_multiagent_debate.html)
|
||||
- [Concurrent Agents](https://doc.agentscope.io/tutorial/workflow_concurrent_agents.html)
|
||||
- [Routing](https://doc.agentscope.io/tutorial/workflow_routing.html)
|
||||
- [Handoffs](https://doc.agentscope.io/tutorial/workflow_handoffs.html)
|
||||
- FAQ
|
||||
- [FAQ](https://doc.agentscope.io/tutorial/faq.html)
|
||||
- Task Guides
|
||||
- [Model](https://doc.agentscope.io/tutorial/task_model.html)
|
||||
- [Prompt Formatter](https://doc.agentscope.io/tutorial/task_prompt.html)
|
||||
- [Tool](https://doc.agentscope.io/tutorial/task_tool.html)
|
||||
- [Memory](https://doc.agentscope.io/tutorial/task_memory.html)
|
||||
- [Long-Term Memory](https://doc.agentscope.io/tutorial/task_long_term_memory.html)
|
||||
- [Agent](https://doc.agentscope.io/tutorial/task_agent.html)
|
||||
- [Pipeline](https://doc.agentscope.io/tutorial/task_pipeline.html)
|
||||
- [Plan](https://doc.agentscope.io/tutorial/task_plan.html)
|
||||
- [State/Session Management](https://doc.agentscope.io/tutorial/task_state.html)
|
||||
- [Agent Hooks](https://doc.agentscope.io/tutorial/task_hook.html)
|
||||
- [MCP](https://doc.agentscope.io/tutorial/task_mcp.html)
|
||||
- [AgentScope Studio](https://doc.agentscope.io/tutorial/task_studio.html)
|
||||
- [Tracing](https://doc.agentscope.io/tutorial/task_tracing.html)
|
||||
- [Evaluation](https://doc.agentscope.io/tutorial/task_eval.html)
|
||||
- [Embedding](https://doc.agentscope.io/tutorial/task_embedding.html)
|
||||
- [Token](https://doc.agentscope.io/tutorial/task_token.html)
|
||||
- API
|
||||
- [API Docs](https://doc.agentscope.io/api/agentscope.html)
|
||||
- [Examples](https://github.com/agentscope-ai/agentscope/tree/main/examples)
|
||||
- Functionality
|
||||
- [MCP](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/mcp)
|
||||
- [Plan](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/plan)
|
||||
- [Structured Output](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/structured_output)
|
||||
- [RAG](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/rag)
|
||||
- [Long-Term Memory](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/long_term_memory)
|
||||
- [Session with SQLite](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/session_with_sqlite)
|
||||
- [Stream Printing Messages](https://github.com/agentscope-ai/agentscope/tree/main/examples/functionality/stream_printing_messages)
|
||||
- Agent
|
||||
- [ReAct Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/react_agent)
|
||||
- [Voice Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/voice_agent)
|
||||
- [Deep Research Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/deep_research_agent)
|
||||
- [Browser-use Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/browser_agent)
|
||||
- [Meta Planner Agent](https://github.com/agentscope-ai/agentscope/tree/main/examples/agent/meta_planner_agent)
|
||||
- Game
|
||||
- [Nine-player Werewolves](https://github.com/agentscope-ai/agentscope/tree/main/examples/game/werewolves)
|
||||
- Workflow
|
||||
- [Multi-agent Debate](https://github.com/agentscope-ai/agentscope/tree/main/examples/workflows/multiagent_debate)
|
||||
- [Multi-agent Conversation](https://github.com/agentscope-ai/agentscope/tree/main/examples/workflows/multiagent_conversation)
|
||||
- [Multi-agent Concurrent](https://github.com/agentscope-ai/agentscope/tree/main/examples/workflows/multiagent_concurrent)
|
||||
- Evaluation
|
||||
- [ACEBench](https://github.com/agentscope-ai/agentscope/tree/main/examples/evaluation/ace_bench)
|
||||
- Training
|
||||
- [Reinforcement learning (RL) with Trinity-RFT](https://github.com/agentscope-ai/agentscope/tree/main/examples/training/react_agent)
|
||||
|
||||
|
||||
## 🤝 Contributing
|
||||
|
||||
We welcome contributions from the community! Please refer to our [CONTRIBUTING.md](./CONTRIBUTING.md) for guidelines
|
||||
on how to contribute.
|
||||
|
||||
## ⚖️ License
|
||||
|
||||
AgentScope is released under Apache License 2.0.
|
||||
|
||||
## 📚 Publications
|
||||
|
||||
If you find our work helpful for your research or application, please cite our papers.
|
||||
|
||||
- [AgentScope 1.0: A Developer-Centric Framework for Building Agentic Applications](https://arxiv.org/abs/2508.16279)
|
||||
|
||||
- [AgentScope: A Flexible yet Robust Multi-Agent Platform](https://arxiv.org/abs/2402.14034)
|
||||
|
||||
```
|
||||
@article{agentscope_v1,
|
||||
author = {
|
||||
Dawei Gao,
|
||||
Zitao Li,
|
||||
Yuexiang Xie,
|
||||
Weirui Kuang,
|
||||
Liuyi Yao,
|
||||
Bingchen Qian,
|
||||
Zhijian Ma,
|
||||
Yue Cui,
|
||||
Haohao Luo,
|
||||
Shen Li,
|
||||
Lu Yi,
|
||||
Yi Yu,
|
||||
Shiqi He,
|
||||
Zhiling Luo,
|
||||
Wenmeng Zhou,
|
||||
Zhicheng Zhang,
|
||||
Xuguang He,
|
||||
Ziqian Chen,
|
||||
Weikai Liao,
|
||||
Farruh Isakulovich Kushnazarov,
|
||||
Yaliang Li,
|
||||
Bolin Ding,
|
||||
Jingren Zhou}
|
||||
title = {AgentScope 1.0: A Developer-Centric Framework for Building Agentic Applications},
|
||||
journal = {CoRR},
|
||||
volume = {abs/2508.16279},
|
||||
year = {2025},
|
||||
}
|
||||
|
||||
@article{agentscope,
|
||||
author = {
|
||||
Dawei Gao,
|
||||
Zitao Li,
|
||||
Xuchen Pan,
|
||||
Weirui Kuang,
|
||||
Zhijian Ma,
|
||||
Bingchen Qian,
|
||||
Fei Wei,
|
||||
Wenhao Zhang,
|
||||
Yuexiang Xie,
|
||||
Daoyuan Chen,
|
||||
Liuyi Yao,
|
||||
Hongyi Peng,
|
||||
Zeyu Zhang,
|
||||
Lin Zhu,
|
||||
Chen Cheng,
|
||||
Hongzhu Shi,
|
||||
Yaliang Li,
|
||||
Bolin Ding,
|
||||
Jingren Zhou}
|
||||
title = {AgentScope: A Flexible yet Robust Multi-Agent Platform},
|
||||
journal = {CoRR},
|
||||
volume = {abs/2402.14034},
|
||||
year = {2024},
|
||||
}
|
||||
```
|
||||
|
||||
## ✨ Contributors
|
||||
|
||||
All thanks to our contributors:
|
||||
|
||||
<a href="https://github.com/agentscope-ai/agentscope/graphs/contributors">
|
||||
<img src="https://contrib.rocks/image?repo=agentscope-ai/agentscope&max=999&columns=12&anon=1" />
|
||||
</a>
|
||||
@@ -1,315 +0,0 @@
|
||||
agentscope-1.0.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
agentscope-1.0.7.dist-info/METADATA,sha256=HD2a1imJIVJ1oFh55nhcZTP0Li5q-9o1ZDg-K73SVh8,25920
|
||||
agentscope-1.0.7.dist-info/RECORD,,
|
||||
agentscope-1.0.7.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
agentscope-1.0.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
||||
agentscope-1.0.7.dist-info/licenses/LICENSE,sha256=QYa8rfNYxgCABgMJdp22sqNScg1zU9gnu1dMYA_umRM,20637
|
||||
agentscope-1.0.7.dist-info/top_level.txt,sha256=uYSDqkiAOqFFfMz9DGnkhn0_nNVwo1uaFYZQikHbWNM,11
|
||||
agentscope/__init__.py,sha256=MkP1MQ4hMFmRQF8qeUUVuBcCGvLS4fa-eqvogl8aj84,3220
|
||||
agentscope/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/__pycache__/_config.cpython-313.pyc,,
|
||||
agentscope/__pycache__/_logging.cpython-313.pyc,,
|
||||
agentscope/__pycache__/_version.cpython-313.pyc,,
|
||||
agentscope/_config.py,sha256=W1Y2lQbTXj1esxwm_sK2yFqztacz-L1OzRJsaei04GM,767
|
||||
agentscope/_logging.py,sha256=XzcUTb7MfRZkc-B3N1IV-jpHaZG0yFirZyfuGa7HOA4,1223
|
||||
agentscope/_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
agentscope/_utils/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/_utils/__pycache__/_common.cpython-313.pyc,,
|
||||
agentscope/_utils/__pycache__/_mixin.cpython-313.pyc,,
|
||||
agentscope/_utils/_common.py,sha256=ghJITFirhNAwTl_ifi9cI6Oc_Fsvlimiv_sxwi4JXZE,8169
|
||||
agentscope/_utils/_mixin.py,sha256=9co2GJyiShSq6HiQ1KwGABr3mfYw2tyvlzCMgI8L0-w,219
|
||||
agentscope/_version.py,sha256=KpA_lRRXOAnkM0n8CqdbV0FanoevNyEft5-YZ-i1-wI,80
|
||||
agentscope/agent/__init__.py,sha256=fxBL1RmxC__kHPRVYkEj03EJ1mYO32vKsbY5wDIV_x8,496
|
||||
agentscope/agent/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_agent_base.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_agent_meta.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_react_agent.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_react_agent_base.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_user_agent.cpython-313.pyc,,
|
||||
agentscope/agent/__pycache__/_user_input.cpython-313.pyc,,
|
||||
agentscope/agent/_agent_base.py,sha256=gxF0tuQN0XebkWR-uVM-a_RTR6eKoJnJOvJT90UegKI,24299
|
||||
agentscope/agent/_agent_meta.py,sha256=Ilda4Fonq29oeQ3kUDTIs8db655MQqWIhzvxGiGUrSw,5730
|
||||
agentscope/agent/_react_agent.py,sha256=zQKd9L19k3hjJmCRZYp2GjqedHh5-A45k-8xWcGSDoI,28676
|
||||
agentscope/agent/_react_agent_base.py,sha256=haWRx93D7A_zmhVVJLlJ_YD8I2pCM7g77vok761DOug,3707
|
||||
agentscope/agent/_user_agent.py,sha256=50kYNXWSfYE7L0x8D1Vmzsl1-mg20nSaCDYROzEusPI,4219
|
||||
agentscope/agent/_user_input.py,sha256=oXtHQ8XapV0ov_8S40MAt2EWDHmvC-_zAEZsR9lUt8g,13105
|
||||
agentscope/embedding/__init__.py,sha256=aiGzcY4qzX7a-ieseIH86_8zhry5yaII5Wdkg-hKjXY,871
|
||||
agentscope/embedding/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_cache_base.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_dashscope_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_dashscope_multimodal_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_embedding_base.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_embedding_response.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_embedding_usage.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_file_cache.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_gemini_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_ollama_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/__pycache__/_openai_embedding.cpython-313.pyc,,
|
||||
agentscope/embedding/_cache_base.py,sha256=QV_D9Q1Rbtts1BporJVomFwaLyG6nsy9GxhLQNxh4lY,1800
|
||||
agentscope/embedding/_dashscope_embedding.py,sha256=r0qbxhs1kfNgPkgWIvcPXKDdKfVFhKKERpqW9DyfRtM,5905
|
||||
agentscope/embedding/_dashscope_multimodal_embedding.py,sha256=XQ3Dx7sXC18fTXW6kkudhMwJKqiVSfrPOJrGeYpXFEg,8682
|
||||
agentscope/embedding/_embedding_base.py,sha256=sgt_GsFGiuzSCt1-gzhLKJ3Cn4usYbGfHqliHIWMZg8,1191
|
||||
agentscope/embedding/_embedding_response.py,sha256=naEqlewn6J5UyteBewwknH6HlZVTo2SRhN714JhOk2U,1093
|
||||
agentscope/embedding/_embedding_usage.py,sha256=Z1q5yPXuGR8BpB7yUxcn-vPfmRP7gqnGmBjsSGC2f1w,579
|
||||
agentscope/embedding/_file_cache.py,sha256=2MZpiurcVgqkCTIq2U_8Z0n_D0I1Z87owXY0K-Fqfvk,7126
|
||||
agentscope/embedding/_gemini_embedding.py,sha256=5WgGi9iJK6OSbCO_2mG_JbgSxUotR44grNo9CF6yaL0,3549
|
||||
agentscope/embedding/_ollama_embedding.py,sha256=XRAicJgcD8DDHHy0W5du_Jsio4JC3L6pqvctexUOFKA,3379
|
||||
agentscope/embedding/_openai_embedding.py,sha256=ZWcyLR_a9DuekdmHkxD93ck6Hk3ZmytNsLYognCFacE,3491
|
||||
agentscope/evaluate/__init__.py,sha256=8FWPPEnQh95u9TxN8Forj8-b-in2a4_yxn_5F-yMeV8,861
|
||||
agentscope/evaluate/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_benchmark_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_metric_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_solution.cpython-313.pyc,,
|
||||
agentscope/evaluate/__pycache__/_task.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__init__.py,sha256=ZtgAiBvYaSJOmUPXX2P5hf_cJdECxJiMgEtyt99pI38,331
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/_ace_benchmark.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/_ace_metric.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/__pycache__/_ace_tools_zh.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_benchmark.py,sha256=8MV9V0FMSV3YfymVKd_ybJRt_dzybKBTJMeivZ393FI,8151
|
||||
agentscope/evaluate/_ace_benchmark/_ace_metric.py,sha256=6_VBBJ50v7aL6OdwJXRRUrqx2gdWtnpM6jlcZMHP6cQ,4225
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__init__.py,sha256=DFWSvwmPolmgqEbqwmkvO05mTr2QNoneO_eXFjEw7ac,327
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_food_platform_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_message_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_reminder_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_shared_state.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/__pycache__/_travel_api.cpython-313.pyc,,
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_food_platform_api.py,sha256=TUQD6gR2VzjtUDK9pZKoWr-H9U0opKcUjvqRmP3q58c,9871
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_message_api.py,sha256=oJcSfj5Kw_BIMI3eC3LsxB5ZI_nN4o_wd0jOX6OXPGA,11784
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_reminder_api.py,sha256=ObmgAI4UnpoZmgiRpGvqwXL2Bs5YH1KQG1JVBM9AXmM,7082
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_shared_state.py,sha256=sLkWasNv57-YxeMEj-GIj6mB6LN0RmsIpOaL3fjImmg,551
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_api/_travel_api.py,sha256=aa5ixysqx6mO3Msueyv_vrJ3yJbdMBKkBmyaKoozJoU,28644
|
||||
agentscope/evaluate/_ace_benchmark/_ace_tools_zh.py,sha256=f10Vu8N82BYe5aBVo8hi2FkC1f0VKMqrNouWEG8DsQM,4052
|
||||
agentscope/evaluate/_benchmark_base.py,sha256=YqFeDn6G-e8njE48Yso5-tRSeE5dZzDRhwvJKCnriQQ,1263
|
||||
agentscope/evaluate/_evaluator/__init__.py,sha256=2g3K8cHhugTwf64ywiF-yLFihpvlrBMX01bUNTQ-yik,280
|
||||
agentscope/evaluate/_evaluator/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/__pycache__/_evaluator_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/__pycache__/_general_evaluator.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/__pycache__/_ray_evaluator.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator/_evaluator_base.py,sha256=Y7LWZDTLmKyiq4WvpLj6dSMJSZw4N80ty-BFEAg5Wxg,7317
|
||||
agentscope/evaluate/_evaluator/_general_evaluator.py,sha256=GSMdijP5a8KPVvc6QrAqOI7pRFyXhd-n3yKekgqSHB0,3817
|
||||
agentscope/evaluate/_evaluator/_ray_evaluator.py,sha256=CS_Hng_j2lY5nlaN5Fb1Uq5hL99dcNyzu2OaGl_HLk0,6075
|
||||
agentscope/evaluate/_evaluator_storage/__init__.py,sha256=bSdhxI83A-2OVMX6L-ZO8EwYytyBQy6XwGIFQbdTod4,262
|
||||
agentscope/evaluate/_evaluator_storage/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator_storage/__pycache__/_evaluator_storage_base.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator_storage/__pycache__/_file_evaluator_storage.cpython-313.pyc,,
|
||||
agentscope/evaluate/_evaluator_storage/_evaluator_storage_base.py,sha256=IW4A6WkBGf43uGj59f7Eu5ySTiX1rmPbpjX1iYjCl8A,5459
|
||||
agentscope/evaluate/_evaluator_storage/_file_evaluator_storage.py,sha256=xPBZ6GXCSL3YMJJNsqH0-bzCxo4_FhZDEqLJcGXLexA,11096
|
||||
agentscope/evaluate/_metric_base.py,sha256=ksYBDhjmE8vTv8cMy31HBhbvkGgIYhUBiC8Qw4zpOAE,2663
|
||||
agentscope/evaluate/_solution.py,sha256=CDbGtYOerCd_o2WgKMnFUPrzF51tXeAcMRu2-poyyho,1194
|
||||
agentscope/evaluate/_task.py,sha256=RJw6GbBTZmYN7bZY3DR6qEDKB4bgV3zwNbWt5vZZEhU,1585
|
||||
agentscope/exception/__init__.py,sha256=eaWWszusA4Lm3CaPmyZCpLBkjwxc17IAPq0MioznbQQ,361
|
||||
agentscope/exception/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/exception/__pycache__/_exception_base.cpython-313.pyc,,
|
||||
agentscope/exception/__pycache__/_tool.cpython-313.pyc,,
|
||||
agentscope/exception/_exception_base.py,sha256=o0VAg5seb9GnJNs_eZMrlmxqbI7UEyzwr7B1gwA48oQ,660
|
||||
agentscope/exception/_tool.py,sha256=AsCWmwM7HF5fFKD6JhI6ohRGMZG7i8H1cwWj3xfiPUc,512
|
||||
agentscope/formatter/__init__.py,sha256=mgg0ZCZsk-beTELeVU9HVaU9T38w3u5gMyA4LT-wwag,1184
|
||||
agentscope/formatter/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_anthropic_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_dashscope_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_deepseek_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_formatter_base.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_gemini_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_ollama_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_openai_formatter.cpython-313.pyc,,
|
||||
agentscope/formatter/__pycache__/_truncated_formatter_base.cpython-313.pyc,,
|
||||
agentscope/formatter/_anthropic_formatter.py,sha256=yJMg6IZX538aKmC6JqYzddhVeLSGz92X9ubjg9MNvaA,8226
|
||||
agentscope/formatter/_dashscope_formatter.py,sha256=FWkX2_zHXCaq4sK_o6NH5b_qcXin_tODDhFqAk0x78A,14548
|
||||
agentscope/formatter/_deepseek_formatter.py,sha256=5Ewi8c99qYL5ZCyE6oKek1x3cqNMfHDtXay43Goohi0,8143
|
||||
agentscope/formatter/_formatter_base.py,sha256=FQKf_3KrydfzuAIL5m5YbC36pfz7lXjnnjG_VI25Cm0,3690
|
||||
agentscope/formatter/_gemini_formatter.py,sha256=n6okME8L623zoLayNXG1uf-UEDgB3xydmpuWipUm4kY,13036
|
||||
agentscope/formatter/_ollama_formatter.py,sha256=fqGKIdhPyMizYSBLj-YwtcbIPBriXolEvrPQuR-ZeiY,10290
|
||||
agentscope/formatter/_openai_formatter.py,sha256=6wrcmO7mqba1X-VWMbYEGjWIv7NfhW-4nctLqvuDaU0,13214
|
||||
agentscope/formatter/_truncated_formatter_base.py,sha256=xKqBL-qiDZSLaHq1ls9fUZZY8xSikdpLqC85hVSWbDM,10211
|
||||
agentscope/hooks/__init__.py,sha256=gn0gD6IUtvlN8fGSy9YZRcS3ANpewvyPjQZuHo2SylU,670
|
||||
agentscope/hooks/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/hooks/__pycache__/_studio_hooks.cpython-313.pyc,,
|
||||
agentscope/hooks/_studio_hooks.py,sha256=fxGjYIwqQ1vs0Yr3zrcfAwO1ZWLyoSvG_0MCmjLnBog,1143
|
||||
agentscope/mcp/__init__.py,sha256=8_x7Loaxt1PVh5h5ubr_RdnyF9wRJOhSsBYMHWaPFRw,587
|
||||
agentscope/mcp/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_client_base.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_http_stateful_client.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_http_stateless_client.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_mcp_function.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_stateful_client_base.cpython-313.pyc,,
|
||||
agentscope/mcp/__pycache__/_stdio_stateful_client.cpython-313.pyc,,
|
||||
agentscope/mcp/_client_base.py,sha256=XzYjrxwSzIEbAVO5IzUlbKTtzdr41fTfBtSUnISpGvY,3274
|
||||
agentscope/mcp/_http_stateful_client.py,sha256=Ekwd1KUJ2RX9oWvv3ZEqDy1FQaXa-hZbSp019K_eR_M,3186
|
||||
agentscope/mcp/_http_stateless_client.py,sha256=LotK9FgzXtSi7VSSGxF0PwYagARBd72P2derYe2Itmg,5223
|
||||
agentscope/mcp/_mcp_function.py,sha256=b_bK9chwTriE7pbncuzG3j46HZkG8BSugvpBr8Z90bI,2604
|
||||
agentscope/mcp/_stateful_client_base.py,sha256=l01VBdAsPNtwR50TnJtwx7NqcIB89V6xpiSN-QUFBeU,5206
|
||||
agentscope/mcp/_stdio_stateful_client.py,sha256=IjDjvha_82RCJgQ8eOitQfPnBVdWzy-ljzzYxnpAgvo,2950
|
||||
agentscope/memory/__init__.py,sha256=PlElb2Rt9lL9JcNZ6ADCvCJwaMPlhPdZIaaBkUlOHfs,555
|
||||
agentscope/memory/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_in_memory_memory.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_long_term_memory_base.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_mem0_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_mem0_utils.cpython-313.pyc,,
|
||||
agentscope/memory/__pycache__/_memory_base.cpython-313.pyc,,
|
||||
agentscope/memory/_in_memory_memory.py,sha256=wEpxEqJ0rKui4AVrPz4Bs7JYLc4FmZmp6brUxm9U9nw,3694
|
||||
agentscope/memory/_long_term_memory_base.py,sha256=PQj1W7cLZVyO6gEbaqCeJm_uGG4oa6kRb_3PNgtwbBA,2976
|
||||
agentscope/memory/_mem0_long_term_memory.py,sha256=UsETvCSdwdaP59CphU5SB_BmOvCUHVkmDdFd0POFScs,21243
|
||||
agentscope/memory/_mem0_utils.py,sha256=9cKMy6KUKfAT5CF5oaIrJp90-qFaOZRMbLVg1VZvyMA,7617
|
||||
agentscope/memory/_memory_base.py,sha256=HcM23pIsXULYX6lT1DsGODG72ZWo3EA2TE6kbJEXQG4,1218
|
||||
agentscope/memory/_reme/__init__.py,sha256=mIuY8wRbVVYrQk_S05RBLivY0cnWDfq7Ere-oASf0G0,364
|
||||
agentscope/memory/_reme/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_long_term_memory_base.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_personal_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_task_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/__pycache__/_reme_tool_long_term_memory.cpython-313.pyc,,
|
||||
agentscope/memory/_reme/_reme_long_term_memory_base.py,sha256=o9bvTq1Zz4OESBifog0rX-Pax1N4dkcEgbxMknLCnz4,13747
|
||||
agentscope/memory/_reme/_reme_personal_long_term_memory.py,sha256=y4BpRymoNjw4ZHTYE6ThflwDgKroeHOLotgrpCNd5n8,13818
|
||||
agentscope/memory/_reme/_reme_task_long_term_memory.py,sha256=QHqLJojl98JO9Gv4Q6QrJGtyUvffRAIOkY0w0zNkcVo,14324
|
||||
agentscope/memory/_reme/_reme_tool_long_term_memory.py,sha256=DyKOJQYKm5eAhiqd91Xb7bBl23RO6jf0_k98P_AuK7Q,17675
|
||||
agentscope/message/__init__.py,sha256=Bxh_L9v-eHVe4_vrhXhMfaNsk5TN45i0PwuKiIju1I0,519
|
||||
agentscope/message/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/message/__pycache__/_message_base.cpython-313.pyc,,
|
||||
agentscope/message/__pycache__/_message_block.cpython-313.pyc,,
|
||||
agentscope/message/_message_base.py,sha256=sYw8MiuErVEcqaS6mPAoqTwsrJAyb9UqP-hZyqltNYY,6895
|
||||
agentscope/message/_message_block.py,sha256=oJQsnqm2exxIZjUn3j6CV77rlwL-QIbSf15PCGiTOgg,2651
|
||||
agentscope/model/__init__.py,sha256=BrUp6U4Tn7GwuaKvJ4rC3GIwrNXZe9jxBYxftJV7OZA,603
|
||||
agentscope/model/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_anthropic_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_dashscope_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_gemini_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_model_base.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_model_response.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_model_usage.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_ollama_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_openai_model.cpython-313.pyc,,
|
||||
agentscope/model/__pycache__/_trinity_model.cpython-313.pyc,,
|
||||
agentscope/model/_anthropic_model.py,sha256=DPPI6WF1MD6ApSpu-tFXjM620GE8X3NqF4fpfuquA6U,18902
|
||||
agentscope/model/_dashscope_model.py,sha256=dCY6Z8xYyyMU2Y3HBUHaNaesBBCUW1FDBy_11VIm7dE,19329
|
||||
agentscope/model/_gemini_model.py,sha256=KUCZZelXec7ZXAo_XM8nyjrus7ATY2OYxXRPX0Uze5Y,17453
|
||||
agentscope/model/_model_base.py,sha256=9lRp9WT-NyOsoHLw2pKvr-aBOqsoFp_PLziXz9Jvsho,2039
|
||||
agentscope/model/_model_response.py,sha256=aER8B2-rg_Uu0MRSxknTIO_J0Q5yzyvH1aKfNdaW35k,1295
|
||||
agentscope/model/_model_usage.py,sha256=o9OvCM4CwYqqfa_w2oz80poIU8a2x9tf4jrkynr0g3o,560
|
||||
agentscope/model/_ollama_model.py,sha256=1l2fSIs2AakdZCV6rFVHANpokpZ0ZjAUFheY4sy6Eq0,12319
|
||||
agentscope/model/_openai_model.py,sha256=DA3LspB1X_Z-z9HNsZK_-df6oJjwvUNso1GzpgiRwhw,20201
|
||||
agentscope/model/_trinity_model.py,sha256=aq0pCGcDZfd3OX2bqM0RLhcsD2Dguom2QrwcB3CRjMw,2362
|
||||
agentscope/module/__init__.py,sha256=zhS2IA0PzSZalXiyu1jUXnz32ESQNn7RJKJJuSInE5o,130
|
||||
agentscope/module/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/module/__pycache__/_state_module.cpython-313.pyc,,
|
||||
agentscope/module/_state_module.py,sha256=nI1cm1Sa2ycFiFxs_tpo9aOnxWSqXGr8gVCTlRw5bVI,5644
|
||||
agentscope/pipeline/__init__.py,sha256=KwzeVx8Ugl0Ljk9B_ziRrR-5YfBHtDW5fjdM3CVJmgc,496
|
||||
agentscope/pipeline/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/pipeline/__pycache__/_class.cpython-313.pyc,,
|
||||
agentscope/pipeline/__pycache__/_functional.cpython-313.pyc,,
|
||||
agentscope/pipeline/__pycache__/_msghub.cpython-313.pyc,,
|
||||
agentscope/pipeline/_class.py,sha256=NQS56cj3eOK2j5F28-V3Sdh1cMaOT3N68y10hqH24MY,2594
|
||||
agentscope/pipeline/_functional.py,sha256=lVtm7UijSV7qyJ9C-aR_4dpmTON88nxZ8oUKxpvOoyU,5903
|
||||
agentscope/pipeline/_msghub.py,sha256=P2QqwvwJeiSE82eI_NDszeKHRHV4bOseisTnLwVUT34,5227
|
||||
agentscope/plan/__init__.py,sha256=TZ48k6DSZh5t9piWMl90R-gCBnY0ipLe875ZMfDtKts,418
|
||||
agentscope/plan/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_in_memory_storage.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_plan_model.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_plan_notebook.cpython-313.pyc,,
|
||||
agentscope/plan/__pycache__/_storage_base.cpython-313.pyc,,
|
||||
agentscope/plan/_in_memory_storage.py,sha256=I32B4nJCu7BYyb1Tgm4QLRI_K0Q27kMNRt96N-y0wLM,2094
|
||||
agentscope/plan/_plan_model.py,sha256=yb4KK_JL1C3QVoX4gCeiSghHFaE39ijq4lxbGm_viZI,6418
|
||||
agentscope/plan/_plan_notebook.py,sha256=LmZOJxQj862Bp4TR_gZU_lqF14uhPHVnENjVLVIOVas,32621
|
||||
agentscope/plan/_storage_base.py,sha256=M1BFqDIiHthFJQFi3gDZNaO12S9FZ_snTFMbqtTipIw,725
|
||||
agentscope/rag/__init__.py,sha256=ZCXDDkeHqYGyl-HuPpWzVj_5mP24fUXSDLpHRc0Hz-U,674
|
||||
agentscope/rag/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/rag/__pycache__/_document.cpython-313.pyc,,
|
||||
agentscope/rag/__pycache__/_knowledge_base.cpython-313.pyc,,
|
||||
agentscope/rag/__pycache__/_simple_knowledge.cpython-313.pyc,,
|
||||
agentscope/rag/_document.py,sha256=9UvKeKu0WBz2nwNj3cgvx6fouVzBa7LJFcDvpVXxw8A,1199
|
||||
agentscope/rag/_knowledge_base.py,sha256=pswLgq1VPKD9UiHns1I_dlI0m6A-9GNyAI67Pm_aJ2A,4441
|
||||
agentscope/rag/_reader/__init__.py,sha256=IvJ2FAphm5CgWoaI1CEPmJPArveQtZv5-Shfkf3yitg,413
|
||||
agentscope/rag/_reader/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_image_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_pdf_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_reader_base.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_text_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/__pycache__/_word_reader.cpython-313.pyc,,
|
||||
agentscope/rag/_reader/_image_reader.py,sha256=kY-jLuzaUyILsviOaO4Fzejupa7I_OJGCRVheo-D0YA,1902
|
||||
agentscope/rag/_reader/_pdf_reader.py,sha256=auptyMvJ6CFDOHqF-Z8s6gHoYtA5mldnQsz3k7AfSv8,2758
|
||||
agentscope/rag/_reader/_reader_base.py,sha256=qY5xkACT1H28lWLjUUFB-Dn_xqpUexPwJu-pMViTmVI,900
|
||||
agentscope/rag/_reader/_text_reader.py,sha256=Loq0fFMhj53mhZPcezG_hxIx3LQSD5FaTsxQmXDqZos,5046
|
||||
agentscope/rag/_reader/_word_reader.py,sha256=0eh_7d_Fa5_6g5xsMq7koSWz4Uv6y3fCPY3LoZ958TI,17385
|
||||
agentscope/rag/_simple_knowledge.py,sha256=rMqMEy6QInrjUOX85g8NRlG7LHSrip4hkYVcv17lOMA,2580
|
||||
agentscope/rag/_store/__init__.py,sha256=u7qAWDjacgKxfzIPD7LeDXb9pbvWX6WjgDrdvMyQzJM,305
|
||||
agentscope/rag/_store/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/rag/_store/__pycache__/_milvuslite_store.cpython-313.pyc,,
|
||||
agentscope/rag/_store/__pycache__/_qdrant_store.cpython-313.pyc,,
|
||||
agentscope/rag/_store/__pycache__/_store_base.cpython-313.pyc,,
|
||||
agentscope/rag/_store/_milvuslite_store.py,sha256=1FUs6zlVoOjwz3YLc-oFqyXqSQjEdKD_uNhCDjURqHI,9059
|
||||
agentscope/rag/_store/_qdrant_store.py,sha256=04Xsfr9WM7g7MNRyPO1hEd_-hbIqPkvexYKMY9ukR80,6250
|
||||
agentscope/rag/_store/_store_base.py,sha256=RaXNmcGu6kZMJjM7pfSjVWcv4iCxMt9LMbJpSMrI0ZM,1658
|
||||
agentscope/session/__init__.py,sha256=GY2Skir_T7y19pnywNVBZ3H3ePqsnShva-ljgeiCLiQ,196
|
||||
agentscope/session/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/session/__pycache__/_json_session.cpython-313.pyc,,
|
||||
agentscope/session/__pycache__/_session_base.cpython-313.pyc,,
|
||||
agentscope/session/_json_session.py,sha256=4NvJPK4qplKdASSHeu7BugpCSxO8BNHRbSNPzna6g-s,3820
|
||||
agentscope/session/_session_base.py,sha256=pKbEHnOHJuxaccGobPo2z984W3OrZS3Rl9oCwrpibMY,859
|
||||
agentscope/token/__init__.py,sha256=0PyydmrOKp-Al3CUqM_1WiCSZc9hSR3XEXV7mXCv48k,487
|
||||
agentscope/token/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_anthropic_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_gemini_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_huggingface_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_openai_token_counter.cpython-313.pyc,,
|
||||
agentscope/token/__pycache__/_token_base.cpython-313.pyc,,
|
||||
agentscope/token/_anthropic_token_counter.py,sha256=-1c-OrsfaNvSCEHzgRNSFL7HUQCAuoe9q3nNEk4J9YE,1853
|
||||
agentscope/token/_gemini_token_counter.py,sha256=vcWHo8iHR1JLhDTM3pS6-mpxEUWCKceVll_ypq7mKhU,1385
|
||||
agentscope/token/_huggingface_token_counter.py,sha256=ksxFpqPde16VptiSV8RmHasgld1bp_fz16j6t4baWtk,2846
|
||||
agentscope/token/_openai_token_counter.py,sha256=Aq2YCnCOvPUOfr4r5OeQqqom_VRAPyUdckqIbx3giiQ,11365
|
||||
agentscope/token/_token_base.py,sha256=ukxfNg8nBL_MLd9rzkpy5aP8s-uqEKbeZGtAYZyCBzA,388
|
||||
agentscope/tool/__init__.py,sha256=lXMHKD91iPK2rSY53cDg39kMXwQsedG-rf39gFRd0Go,1020
|
||||
agentscope/tool/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_async_wrapper.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_registered_tool_function.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_response.cpython-313.pyc,,
|
||||
agentscope/tool/__pycache__/_toolkit.cpython-313.pyc,,
|
||||
agentscope/tool/_async_wrapper.py,sha256=tfv6edszdHC03IsL0Z3EvVAII0zEdYavD3wBI__L-zM,3474
|
||||
agentscope/tool/_coding/__init__.py,sha256=e_XNdZZo6-gS7EvY_AEM2h0q3XtYm1voCKbojypfwn4,232
|
||||
agentscope/tool/_coding/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/_coding/__pycache__/_python.cpython-313.pyc,,
|
||||
agentscope/tool/_coding/__pycache__/_shell.cpython-313.pyc,,
|
||||
agentscope/tool/_coding/_python.py,sha256=FwnidjGPYBRsLGX0FPICjlApISg7eL4GZoVBvFrObik,2714
|
||||
agentscope/tool/_coding/_shell.py,sha256=pgivhc2CSs8mBWSh5ax9NgWI07q_b7WoKV7hdI8h448,2266
|
||||
agentscope/tool/_multi_modality/__init__.py,sha256=H9VpqWCV0V7WXvqqYWjbpwmafJHtq_pDm-RV7P3vG0s,678
|
||||
agentscope/tool/_multi_modality/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/_multi_modality/__pycache__/_dashscope_tools.cpython-313.pyc,,
|
||||
agentscope/tool/_multi_modality/__pycache__/_openai_tools.cpython-313.pyc,,
|
||||
agentscope/tool/_multi_modality/_dashscope_tools.py,sha256=6piJ5fjVaQTYaq4w3UQXGS0ANY29lkCqyc3_keomlbY,8908
|
||||
agentscope/tool/_multi_modality/_openai_tools.py,sha256=UaZOHHAWEi7Y_uG_n23Q8OTh45Cb-hD4t5-oR6o4K_Q,20873
|
||||
agentscope/tool/_registered_tool_function.py,sha256=jI8VMSeWlj-EGq7IKlydBQcC2jjOZEDQTdnkxEm7jng,3449
|
||||
agentscope/tool/_response.py,sha256=3WdPFj1uRdxvkrECfMlUjzPVg-PseeSVNF5SWn1dCOs,938
|
||||
agentscope/tool/_text_file/__init__.py,sha256=tnQP6RCS1wHff65ycZkXE4Fxcw5OXZe50_6dD5hfa9o,276
|
||||
agentscope/tool/_text_file/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/__pycache__/_utils.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/__pycache__/_view_text_file.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/__pycache__/_write_text_file.cpython-313.pyc,,
|
||||
agentscope/tool/_text_file/_utils.py,sha256=vizy7C6rNmp8z5aiNbrrsMdoeX8bws4FnnyEixlo0jU,2645
|
||||
agentscope/tool/_text_file/_view_text_file.py,sha256=MHq0eiNiBMSDY7Dne8Ch6-YqIS0i8alP3dX2gzxi-nA,2280
|
||||
agentscope/tool/_text_file/_write_text_file.py,sha256=zZcafaRg53o2DT1Q1t9en4Z8sRxaRwREAbsfdLfSpOI,7333
|
||||
agentscope/tool/_toolkit.py,sha256=2iSCpI9zRmNgD_g_PVE-N8K060_DU4S9NDzQ7tvnW30,34654
|
||||
agentscope/tracing/__init__.py,sha256=R7Xegg62pD5UDey0w4ZyAJ6LVt6_qSkjlrOIoV3mHpk,382
|
||||
agentscope/tracing/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_attributes.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_setup.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_trace.cpython-313.pyc,,
|
||||
agentscope/tracing/__pycache__/_types.cpython-313.pyc,,
|
||||
agentscope/tracing/_attributes.py,sha256=-R_z4rI17u4pOyK9RWtWPmKX0uEL1YmffcJhAEJanvM,1774
|
||||
agentscope/tracing/_setup.py,sha256=QwhHf_NyR-4lBJChNa616pze7CV7HPFq0mNoWxUnCQg,874
|
||||
agentscope/tracing/_trace.py,sha256=Iclrx0Uxpjq4OwrGfCvl_TADn7eSm85R2ZhJiwYdG-w,21677
|
||||
agentscope/tracing/_types.py,sha256=EE-Y6btCihsNuC27XiLlTdqLy1C4CCoENthPDerw8mU,528
|
||||
agentscope/tune/__init__.py,sha256=VpKbNhHLr6GAQ4zJJ-hEy9IOCqLB7YQTNt3DKQKbq0g,195
|
||||
agentscope/tune/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/tune/__pycache__/_tune.cpython-313.pyc,,
|
||||
agentscope/tune/__pycache__/_workflow.cpython-313.pyc,,
|
||||
agentscope/tune/_tune.py,sha256=elVcwVuRRlPghcaYQZAYhiwchV4VqIL-PDb86HaV_ws,2520
|
||||
agentscope/tune/_workflow.py,sha256=TLrri2aRfVamTzDK8FaeHUDDSZZnfhos8JvseeFoHiU,2125
|
||||
agentscope/types/__init__.py,sha256=_AX5wH9fPHkNEwCOQb2ycdh62J6IRXqYYcplJOcWjFQ,408
|
||||
agentscope/types/__pycache__/__init__.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_hook.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_json.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_object.cpython-313.pyc,,
|
||||
agentscope/types/__pycache__/_tool.cpython-313.pyc,,
|
||||
agentscope/types/_hook.py,sha256=st--2oBVuLwNaNk5DQXkYA7xp8X4HaqTaXf2lVDAPM0,427
|
||||
agentscope/types/_json.py,sha256=MXTFO_TufiyRy0X_OuEfuoPqWLRUYRRwurKu-o-m5oI,308
|
||||
agentscope/types/_object.py,sha256=dHR84mJvBFesbYj46mQO9ssw38dPuKpJaCbySprLWZE,111
|
||||
agentscope/types/_tool.py,sha256=J22DtLNDoMTZp_cOkGfrjpmG-qFPWgqaKhcXsyomC58,845
|
||||
@@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (80.9.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@@ -1,391 +0,0 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2024 Alibaba
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
||||
Some codes of tests/run.py is modified from
|
||||
https://github.com/alibaba/FederatedScope/blob/master/tests/run.py, which is
|
||||
also licensed under the terms of the Apache 2.0.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/socket.io.js is adapted from
|
||||
https://cdnjs.cloudflare.com/ajax/libs/socket.io/3.1.3/socket.io.js (MIT License)
|
||||
|
||||
Copyright (c) 2014-2021 Guillermo Rauch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/jquery-3.3.1.min.js is adapted from
|
||||
https://code.jquery.com/jquery-3.3.1.min.js (MIT License)
|
||||
|
||||
Copyright (c) JS Foundation and other contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/bootstrap.bundle.min.js is adapted from
|
||||
https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/js/bootstrap.bundle.min.js
|
||||
(MIT License)
|
||||
|
||||
Copyright (c) 2011-2019 The Bootstrap Authors (https://github
|
||||
.com/twbs/bootstrap/graphs/contributors)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/js/bootstrap-table.min.js is adapted from
|
||||
https://unpkg.com/bootstrap-table@1.18.0/dist/bootstrap-table.min.js (MIT
|
||||
License)
|
||||
|
||||
Copyright (c) wenzhixin <wenzhixin2010@gmail.com> (http://wenzhixin.net.cn/)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Code in src/agentscope/web/static/css/bootstrap.min.css is adapted from
|
||||
https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css (MIT
|
||||
License)
|
||||
|
||||
Copyright 2011-2019 The Bootstrap Authors
|
||||
Copyright 2011-2019 Twitter, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Fonts in src/agentscope/web/static/fonts/KRYPTON.ttf is adapted from
|
||||
https://github.com/githubnext/monaspace (SIL Open Font License 1.1). These
|
||||
fonts are distributed with their original license. See https://github
|
||||
.com/githubnext/monaspace/blob/main/LICENSE for the full text of the license.
|
||||
The following font families are included:
|
||||
|
||||
- Monaspace (with subfamilies: Krypton)
|
||||
|
||||
Copyright (c) 2023, GitHub https://github.com/githubnext/monaspace
|
||||
with Reserved Font Name "Monaspace", including subfamilies: "Argon", "Neon",
|
||||
"Xenon", "Radon", and "Krypton"
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
Fonts in src/agentscope/web/static/fonts/OSWALD.ttf is adapted from
|
||||
https://fonts.google.com/specimen/Oswald (SIL Open Font License 1.1). These
|
||||
fonts are distributed with their original license. See https://github
|
||||
.com/googlefonts/OswaldFont/blob/main/OFL.txt for the full text of the license.
|
||||
|
||||
Copyright 2016 The Oswald Project Authors (https://github
|
||||
.com/googlefonts/OswaldFont)
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
@@ -1 +0,0 @@
|
||||
agentscope
|
||||
@@ -1,133 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agentscope serialization module"""
|
||||
import os
|
||||
|
||||
import requests
|
||||
|
||||
from . import exception
|
||||
from . import module
|
||||
from . import message
|
||||
from . import model
|
||||
from . import tool
|
||||
from . import formatter
|
||||
from . import memory
|
||||
from . import agent
|
||||
from . import session
|
||||
from . import embedding
|
||||
from . import token
|
||||
from . import evaluate
|
||||
from . import pipeline
|
||||
from . import tracing
|
||||
from . import rag
|
||||
|
||||
from ._logging import (
|
||||
logger,
|
||||
setup_logger,
|
||||
)
|
||||
from .hooks import _equip_as_studio_hooks
|
||||
from ._version import __version__
|
||||
|
||||
|
||||
def init(
|
||||
project: str | None = None,
|
||||
name: str | None = None,
|
||||
logging_path: str | None = None,
|
||||
logging_level: str = "INFO",
|
||||
studio_url: str | None = None,
|
||||
tracing_url: str | None = None,
|
||||
) -> None:
|
||||
"""Initialize the agentscope library.
|
||||
|
||||
Args:
|
||||
project (`str | None`, optional):
|
||||
The project name.
|
||||
name (`str | None`, optional):
|
||||
The name of the run.
|
||||
logging_path (`str | None`, optional):
|
||||
The path to saving the log file. If not provided, logs will not be
|
||||
saved.
|
||||
logging_level (`str | None`, optional):
|
||||
The logging level. Defaults to "INFO".
|
||||
studio_url (`str | None`, optional):
|
||||
The URL of the AgentScope Studio to connect to.
|
||||
tracing_url (`str | None`, optional):
|
||||
The URL of the tracing endpoint, which can connect to third-party
|
||||
OpenTelemetry tracing platforms like Arize-Phoenix and Langfuse.
|
||||
If not provided and `studio_url` is provided, it will send traces
|
||||
to the AgentScope Studio's tracing endpoint.
|
||||
"""
|
||||
|
||||
from . import _config
|
||||
|
||||
if project:
|
||||
_config.project = project
|
||||
|
||||
if name:
|
||||
_config.name = name
|
||||
|
||||
setup_logger(logging_level, logging_path)
|
||||
|
||||
if studio_url:
|
||||
# Register the run
|
||||
data = {
|
||||
"id": _config.run_id,
|
||||
"project": _config.project,
|
||||
"name": _config.name,
|
||||
"timestamp": _config.created_at,
|
||||
"pid": os.getpid(),
|
||||
"status": "running",
|
||||
# Deprecated fields
|
||||
"run_dir": "",
|
||||
}
|
||||
response = requests.post(
|
||||
url=f"{studio_url}/trpc/registerRun",
|
||||
json=data,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
from .agent import UserAgent, StudioUserInput
|
||||
|
||||
UserAgent.override_class_input_method(
|
||||
StudioUserInput(
|
||||
studio_url=studio_url,
|
||||
run_id=_config.run_id,
|
||||
max_retries=3,
|
||||
),
|
||||
)
|
||||
|
||||
_equip_as_studio_hooks(studio_url)
|
||||
|
||||
if tracing_url:
|
||||
endpoint = tracing_url
|
||||
else:
|
||||
endpoint = studio_url.strip("/") + "/v1/traces" if studio_url else None
|
||||
|
||||
if endpoint:
|
||||
from .tracing import setup_tracing
|
||||
|
||||
setup_tracing(endpoint=endpoint)
|
||||
|
||||
|
||||
__all__ = [
|
||||
# modules
|
||||
"exception",
|
||||
"module",
|
||||
"message",
|
||||
"model",
|
||||
"tool",
|
||||
"formatter",
|
||||
"memory",
|
||||
"agent",
|
||||
"session",
|
||||
"logger",
|
||||
"embedding",
|
||||
"token",
|
||||
"evaluate",
|
||||
"pipeline",
|
||||
"tracing",
|
||||
"rag",
|
||||
# functions
|
||||
"init",
|
||||
"setup_logger",
|
||||
"__version__",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,23 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The runtime configuration in agentscope.
|
||||
|
||||
.. note:: You should import this module as ``import ._config``, then use the
|
||||
variables defined in this module, instead of ``from ._config import xxx``.
|
||||
Because when the variables are changed, the changes will not be reflected in
|
||||
the imported module.
|
||||
"""
|
||||
from datetime import datetime
|
||||
|
||||
import shortuuid
|
||||
|
||||
|
||||
def _generate_random_suffix(length: int) -> str:
|
||||
"""Generate a random suffix."""
|
||||
return shortuuid.uuid()[:length]
|
||||
|
||||
|
||||
project = "UnnamedProject_At" + datetime.now().strftime("%Y%m%d")
|
||||
name = datetime.now().strftime("%H%M%S_") + _generate_random_suffix(4)
|
||||
run_id: str = shortuuid.uuid()
|
||||
created_at: str = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
trace_enabled: bool = False
|
||||
@@ -1,47 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The logger for agentscope."""
|
||||
|
||||
import logging
|
||||
|
||||
|
||||
_DEFAULT_FORMAT = (
|
||||
"%(asctime)s | %(levelname)-7s | "
|
||||
"%(module)s:%(funcName)s:%(lineno)s - %(message)s"
|
||||
)
|
||||
|
||||
logger = logging.getLogger("as")
|
||||
|
||||
|
||||
def setup_logger(
|
||||
level: str,
|
||||
filepath: str | None = None,
|
||||
) -> None:
|
||||
"""Set up the agentscope logger.
|
||||
|
||||
Args:
|
||||
level (`str`):
|
||||
The logging level, chosen from "INFO", "DEBUG", "WARNING",
|
||||
"ERROR", "CRITICAL".
|
||||
filepath (`str | None`, optional):
|
||||
The filepath to save the logging output.
|
||||
"""
|
||||
if level not in ["INFO", "DEBUG", "WARNING", "ERROR", "CRITICAL"]:
|
||||
raise ValueError(
|
||||
f"Invalid logging level: {level}. Must be one of "
|
||||
f"'INFO', 'DEBUG', 'WARNING', 'ERROR', 'CRITICAL'.",
|
||||
)
|
||||
logger.handlers.clear()
|
||||
logger.setLevel(level)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(logging.Formatter(_DEFAULT_FORMAT))
|
||||
logger.addHandler(handler)
|
||||
|
||||
if filepath:
|
||||
handler = logging.FileHandler(filepath)
|
||||
handler.setFormatter(logging.Formatter(_DEFAULT_FORMAT))
|
||||
logger.addHandler(handler)
|
||||
|
||||
logger.propagate = False
|
||||
|
||||
|
||||
setup_logger("INFO")
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,285 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The common utilities for agentscope library."""
|
||||
import asyncio
|
||||
import base64
|
||||
import functools
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import types
|
||||
import typing
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
from typing import Union, Any, Callable, Type, Dict
|
||||
|
||||
import requests
|
||||
from json_repair import repair_json
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .._logging import logger
|
||||
|
||||
if typing.TYPE_CHECKING:
|
||||
from mcp.types import Tool
|
||||
else:
|
||||
Tool = "mcp.types.Tool"
|
||||
|
||||
|
||||
def _json_loads_with_repair(
|
||||
json_str: str,
|
||||
) -> Union[dict, list, str, float, int, bool, None]:
|
||||
"""The given json_str maybe incomplete, e.g. '{"key', so we need to
|
||||
repair and load it into a Python object.
|
||||
"""
|
||||
repaired = json_str
|
||||
try:
|
||||
repaired = repair_json(json_str)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
return json.loads(repaired)
|
||||
except json.JSONDecodeError as e:
|
||||
raise ValueError(
|
||||
f"Failed to decode JSON string `{json_str}` after repairing it "
|
||||
f"into `{repaired}`. Error: {e}",
|
||||
) from e
|
||||
|
||||
|
||||
def _is_accessible_local_file(url: str) -> bool:
|
||||
"""Check if the given URL is a local URL."""
|
||||
return os.path.isfile(url)
|
||||
|
||||
|
||||
def _get_timestamp(add_random_suffix: bool = False) -> str:
|
||||
"""Get the current timestamp in the format YYYY-MM-DD HH:MM:SS.sss."""
|
||||
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
|
||||
|
||||
if add_random_suffix:
|
||||
# Add a random suffix to the timestamp
|
||||
timestamp += f"_{os.urandom(3).hex()}"
|
||||
|
||||
return timestamp
|
||||
|
||||
|
||||
async def _is_async_func(func: Callable) -> bool:
|
||||
"""Check if the given function is an async function, including
|
||||
coroutine functions, async generators, and coroutine objects.
|
||||
"""
|
||||
|
||||
return (
|
||||
inspect.iscoroutinefunction(func)
|
||||
or inspect.isasyncgenfunction(func)
|
||||
or isinstance(func, types.CoroutineType)
|
||||
or isinstance(func, types.GeneratorType)
|
||||
and asyncio.iscoroutine(func)
|
||||
or isinstance(func, functools.partial)
|
||||
and await _is_async_func(func.func)
|
||||
)
|
||||
|
||||
|
||||
async def _execute_async_or_sync_func(
|
||||
func: Callable,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""Execute an async or sync function based on its type.
|
||||
|
||||
Args:
|
||||
func (`Callable`):
|
||||
The function to be executed, which can be either async or sync.
|
||||
*args (`Any`):
|
||||
Positional arguments to be passed to the function.
|
||||
**kwargs (`Any`):
|
||||
Keyword arguments to be passed to the function.
|
||||
|
||||
Returns:
|
||||
`Any`:
|
||||
The result of the function execution.
|
||||
"""
|
||||
|
||||
if await _is_async_func(func):
|
||||
return await func(*args, **kwargs)
|
||||
|
||||
return func(*args, **kwargs)
|
||||
|
||||
|
||||
def _get_bytes_from_web_url(
|
||||
url: str,
|
||||
max_retries: int = 3,
|
||||
) -> str:
|
||||
"""Get the bytes from a given URL.
|
||||
|
||||
Args:
|
||||
url (`str`):
|
||||
The URL to fetch the bytes from.
|
||||
max_retries (`int`, defaults to `3`):
|
||||
The maximum number of retries.
|
||||
"""
|
||||
for _ in range(max_retries):
|
||||
try:
|
||||
response = requests.get(url)
|
||||
response.raise_for_status()
|
||||
return response.content.decode("utf-8")
|
||||
|
||||
except UnicodeDecodeError:
|
||||
return base64.b64encode(response.content).decode("ascii")
|
||||
|
||||
except Exception as e:
|
||||
logger.info(
|
||||
"Failed to fetch bytes from URL %s. Error %s. Retrying...",
|
||||
url,
|
||||
str(e),
|
||||
)
|
||||
|
||||
raise RuntimeError(
|
||||
f"Failed to fetch bytes from URL `{url}` after {max_retries} retries.",
|
||||
)
|
||||
|
||||
|
||||
def _save_base64_data(
|
||||
media_type: str,
|
||||
base64_data: str,
|
||||
) -> str:
|
||||
"""Save the base64 data to a temp file and return the file path. The
|
||||
extension is guessed from the MIME type.
|
||||
|
||||
Args:
|
||||
media_type (`str`):
|
||||
The MIME type of the data, e.g. "image/png", "audio/mpeg".
|
||||
base64_data (`str):
|
||||
The base64 data to be saved.
|
||||
"""
|
||||
extension = "." + media_type.split("/")[-1]
|
||||
|
||||
with tempfile.NamedTemporaryFile(
|
||||
suffix=f".{extension}",
|
||||
delete=False,
|
||||
) as temp_file:
|
||||
decoded_data = base64.b64decode(base64_data)
|
||||
temp_file.write(decoded_data)
|
||||
temp_file.close()
|
||||
return temp_file.name
|
||||
|
||||
|
||||
def _extract_json_schema_from_mcp_tool(tool: Tool) -> dict[str, Any]:
|
||||
"""Extract JSON schema from MCP tool."""
|
||||
|
||||
return {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool.name,
|
||||
"description": tool.description,
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": tool.inputSchema.get(
|
||||
"properties",
|
||||
{},
|
||||
),
|
||||
"required": tool.inputSchema.get(
|
||||
"required",
|
||||
[],
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _remove_title_field(schema: dict) -> None:
|
||||
"""Remove the title field from the JSON schema to avoid
|
||||
misleading the LLM."""
|
||||
# The top level title field
|
||||
if "title" in schema:
|
||||
schema.pop("title")
|
||||
|
||||
# properties
|
||||
if "properties" in schema:
|
||||
for prop in schema["properties"].values():
|
||||
if isinstance(prop, dict):
|
||||
_remove_title_field(prop)
|
||||
|
||||
# items
|
||||
if "items" in schema and isinstance(schema["items"], dict):
|
||||
_remove_title_field(schema["items"])
|
||||
|
||||
# additionalProperties
|
||||
if "additionalProperties" in schema and isinstance(
|
||||
schema["additionalProperties"],
|
||||
dict,
|
||||
):
|
||||
_remove_title_field(
|
||||
schema["additionalProperties"],
|
||||
)
|
||||
|
||||
|
||||
def _create_tool_from_base_model(
|
||||
structured_model: Type[BaseModel],
|
||||
tool_name: str = "generate_structured_output",
|
||||
) -> Dict[str, Any]:
|
||||
"""Create a function tool definition from a Pydantic BaseModel.
|
||||
This function converts a Pydantic BaseModel class into a tool definition
|
||||
that can be used with function calling API. The resulting tool
|
||||
definition includes the model's JSON schema as parameters, enabling
|
||||
structured output generation by forcing the model to call this function
|
||||
with properly formatted data.
|
||||
|
||||
Args:
|
||||
structured_model (`Type[BaseModel]`):
|
||||
A Pydantic BaseModel class that defines the expected structure
|
||||
for the tool's output.
|
||||
tool_name (`str`, default `"generate_structured_output"`):
|
||||
The tool name that used to force the LLM to generate structured
|
||||
output by calling this function.
|
||||
|
||||
Returns:
|
||||
`Dict[str, Any]`: A tool definition dictionary compatible with
|
||||
function calling API, containing type ("function") and
|
||||
function dictionary with name, description, and parameters
|
||||
(JSON schema).
|
||||
|
||||
.. code-block:: python
|
||||
:caption: Example usage
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
class PersonInfo(BaseModel):
|
||||
name: str
|
||||
age: int
|
||||
email: str
|
||||
|
||||
tool = _create_tool_from_base_model(PersonInfo, "extract_person")
|
||||
print(tool["function"]["name"]) # extract_person
|
||||
print(tool["type"]) # function
|
||||
|
||||
.. note:: The function automatically removes the 'title' field from
|
||||
the JSON schema to ensure compatibility with function calling
|
||||
format. This is handled by the internal ``_remove_title_field()``
|
||||
function.
|
||||
"""
|
||||
schema = structured_model.model_json_schema()
|
||||
|
||||
_remove_title_field(schema)
|
||||
tool_definition = {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool_name,
|
||||
"description": "Generate the required structured output with "
|
||||
"this function",
|
||||
"parameters": schema,
|
||||
},
|
||||
}
|
||||
return tool_definition
|
||||
|
||||
|
||||
def _map_text_to_uuid(text: str) -> str:
|
||||
"""Map the given text to a deterministic UUID string.
|
||||
|
||||
Args:
|
||||
text (`str`):
|
||||
The input text to be mapped to a UUID.
|
||||
|
||||
Returns:
|
||||
`str`:
|
||||
A deterministic UUID string derived from the input text.
|
||||
"""
|
||||
return str(uuid.uuid3(uuid.NAMESPACE_DNS, text))
|
||||
@@ -1,9 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The mixin for agentscope."""
|
||||
|
||||
|
||||
class DictMixin(dict):
|
||||
"""The dictionary mixin that allows attribute-style access."""
|
||||
|
||||
__setattr__ = dict.__setitem__
|
||||
__getattr__ = dict.__getitem__
|
||||
@@ -1,4 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The version of agentscope."""
|
||||
|
||||
__version__ = "1.0.7"
|
||||
@@ -1,24 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agent base class."""
|
||||
from ._agent_base import AgentBase
|
||||
from ._react_agent_base import ReActAgentBase
|
||||
from ._react_agent import ReActAgent
|
||||
from ._user_input import (
|
||||
UserInputBase,
|
||||
UserInputData,
|
||||
TerminalUserInput,
|
||||
StudioUserInput,
|
||||
)
|
||||
from ._user_agent import UserAgent
|
||||
|
||||
|
||||
__all__ = [
|
||||
"AgentBase",
|
||||
"ReActAgentBase",
|
||||
"ReActAgent",
|
||||
"UserInputData",
|
||||
"UserInputBase",
|
||||
"TerminalUserInput",
|
||||
"StudioUserInput",
|
||||
"UserAgent",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,703 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The agent base class in agentscope."""
|
||||
import asyncio
|
||||
import io
|
||||
import json
|
||||
from asyncio import Task, Queue
|
||||
from collections import OrderedDict
|
||||
from copy import deepcopy
|
||||
from typing import Callable, Any
|
||||
import base64
|
||||
import shortuuid
|
||||
import numpy as np
|
||||
from typing_extensions import deprecated
|
||||
|
||||
from ._agent_meta import _AgentMeta
|
||||
from .._logging import logger
|
||||
from ..module import StateModule
|
||||
from ..message import (
|
||||
Msg,
|
||||
AudioBlock,
|
||||
ToolUseBlock,
|
||||
ToolResultBlock,
|
||||
ImageBlock,
|
||||
VideoBlock,
|
||||
)
|
||||
from ..types import AgentHookTypes
|
||||
|
||||
|
||||
class AgentBase(StateModule, metaclass=_AgentMeta):
|
||||
"""Base class for asynchronous agents."""
|
||||
|
||||
id: str
|
||||
"""The agent's unique identifier, generated using shortuuid."""
|
||||
|
||||
supported_hook_types: list[str] = [
|
||||
"pre_reply",
|
||||
"post_reply",
|
||||
"pre_print",
|
||||
"post_print",
|
||||
"pre_observe",
|
||||
"post_observe",
|
||||
]
|
||||
"""Supported hook types for the agent base class."""
|
||||
|
||||
_class_pre_reply_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called before the reply
|
||||
function, taking `self` object, the input arguments as input, and
|
||||
generating the modified arguments (if needed). Then input arguments of the
|
||||
reply function will be re-organized into a keyword arguments dictionary.
|
||||
If the one hook returns a new dictionary, the modified arguments will be
|
||||
passed to the next hook or the original reply function."""
|
||||
|
||||
_class_post_reply_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Msg, # output, the output message
|
||||
],
|
||||
Msg | None,
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called after the reply
|
||||
function, which takes the `self` object and deep copied
|
||||
positional and keyword arguments (args and kwargs), and the output message
|
||||
as input. If the hook returns a message, the new message will be passed
|
||||
to the next hook or the original reply function. Otherwise, the original
|
||||
output will be passed instead."""
|
||||
|
||||
_class_pre_print_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called before printing,
|
||||
which takes the `self` object, a deep copied arguments dictionary as input,
|
||||
and output the modified arguments (if needed). """
|
||||
|
||||
_class_post_print_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Any, # output, `None` if no output
|
||||
],
|
||||
Any,
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called after the speak
|
||||
function, which takes the `self` object as input."""
|
||||
|
||||
_class_pre_observe_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called before the observe
|
||||
function, which takes the `self` object and a deep copied input
|
||||
arguments dictionary as input. To change the input arguments, the hook
|
||||
function needs to output the modified arguments dictionary, which will be
|
||||
used as the input of the next hook function or the original observe
|
||||
function."""
|
||||
|
||||
_class_post_observe_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"AgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
None, # The output, `None` if no output
|
||||
],
|
||||
None,
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level hook functions that will be called after the observe
|
||||
function, which takes the `self` object as input."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""Initialize the agent."""
|
||||
super().__init__()
|
||||
|
||||
self.id = shortuuid.uuid()
|
||||
|
||||
# The replying task and identify of the current replying
|
||||
self._reply_task: Task | None = None
|
||||
self._reply_id: str | None = None
|
||||
|
||||
# Initialize the instance-level hooks
|
||||
self._instance_pre_print_hooks = OrderedDict()
|
||||
self._instance_post_print_hooks = OrderedDict()
|
||||
|
||||
self._instance_pre_reply_hooks = OrderedDict()
|
||||
self._instance_post_reply_hooks = OrderedDict()
|
||||
|
||||
self._instance_pre_observe_hooks = OrderedDict()
|
||||
self._instance_post_observe_hooks = OrderedDict()
|
||||
|
||||
# The prefix used in streaming printing, which will save the
|
||||
# accumulated text and audio streaming data for each message id.
|
||||
# e.g. {"text": "xxx", "audio": (stream_obj, "{base64_data}")}
|
||||
self._stream_prefix = {}
|
||||
|
||||
# The subscribers that will receive the reply message by their
|
||||
# `observe` method. The key is the MsgHub id, and the value is the
|
||||
# list of agents.
|
||||
self._subscribers: dict[str, list[AgentBase]] = {}
|
||||
|
||||
# We add this variable in case developers want to disable the console
|
||||
# output of the agent, e.g., in a production environment.
|
||||
self._disable_console_output: bool = False
|
||||
|
||||
# The streaming message queue used to export the messages as a
|
||||
# generator
|
||||
self._disable_msg_queue: bool = True
|
||||
self.msg_queue = None
|
||||
|
||||
async def observe(self, msg: Msg | list[Msg] | None) -> None:
|
||||
"""Receive the given message(s) without generating a reply.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The message(s) to be observed.
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
f"The observe function is not implemented in"
|
||||
f" {self.__class__.__name__} class.",
|
||||
)
|
||||
|
||||
async def reply(self, *args: Any, **kwargs: Any) -> Msg:
|
||||
"""The main logic of the agent, which generates a reply based on the
|
||||
current state and input arguments."""
|
||||
raise NotImplementedError(
|
||||
"The reply function is not implemented in "
|
||||
f"{self.__class__.__name__} class.",
|
||||
)
|
||||
|
||||
async def print(self, msg: Msg, last: bool = True) -> None:
|
||||
"""The function to display the message.
|
||||
|
||||
Args:
|
||||
msg (`Msg`):
|
||||
The message object to be printed.
|
||||
last (`bool`, defaults to `True`):
|
||||
Whether this is the last one in streaming messages. For
|
||||
non-streaming message, this should always be `True`.
|
||||
"""
|
||||
if not self._disable_msg_queue:
|
||||
await self.msg_queue.put((deepcopy(msg), last))
|
||||
|
||||
if self._disable_console_output:
|
||||
return
|
||||
|
||||
# The accumulated textual content to print, including the text blocks
|
||||
# and the thinking blocks
|
||||
thinking_and_text_to_print = []
|
||||
|
||||
for block in msg.get_content_blocks():
|
||||
if block["type"] == "audio":
|
||||
self._process_audio_block(msg.id, block)
|
||||
|
||||
elif block["type"] == "text":
|
||||
self._print_text_block(
|
||||
msg.id,
|
||||
name_prefix=msg.name,
|
||||
text_content=block["text"],
|
||||
thinking_and_text_to_print=thinking_and_text_to_print,
|
||||
)
|
||||
|
||||
elif block["type"] == "thinking":
|
||||
self._print_text_block(
|
||||
msg.id,
|
||||
name_prefix=f"{msg.name}(thinking)",
|
||||
text_content=block["thinking"],
|
||||
thinking_and_text_to_print=thinking_and_text_to_print,
|
||||
)
|
||||
|
||||
elif last:
|
||||
self._print_last_block(block, msg)
|
||||
|
||||
# Clean up resources if this is the last message in streaming
|
||||
if last and msg.id in self._stream_prefix:
|
||||
if "audio" in self._stream_prefix[msg.id]:
|
||||
player, _ = self._stream_prefix[msg.id]["audio"]
|
||||
# Close the miniaudio player
|
||||
player.close()
|
||||
stream_prefix = self._stream_prefix.pop(msg.id)
|
||||
if "text" in stream_prefix and not stream_prefix["text"].endswith(
|
||||
"\n",
|
||||
):
|
||||
print()
|
||||
|
||||
def _process_audio_block(
|
||||
self,
|
||||
msg_id: str,
|
||||
audio_block: AudioBlock,
|
||||
) -> None:
|
||||
"""Process audio block content.
|
||||
|
||||
Args:
|
||||
msg_id (`str`):
|
||||
The unique identifier of the message
|
||||
audio_block (`AudioBlock`):
|
||||
The audio content block
|
||||
"""
|
||||
if "source" not in audio_block:
|
||||
raise ValueError(
|
||||
"The audio block must contain the 'source' field.",
|
||||
)
|
||||
|
||||
if audio_block["source"]["type"] == "url":
|
||||
import urllib.request
|
||||
import wave
|
||||
import sounddevice as sd
|
||||
|
||||
url = audio_block["source"]["url"]
|
||||
try:
|
||||
with urllib.request.urlopen(url) as response:
|
||||
audio_data = response.read()
|
||||
|
||||
with wave.open(io.BytesIO(audio_data), "rb") as wf:
|
||||
samplerate = wf.getframerate()
|
||||
n_frames = wf.getnframes()
|
||||
audio_frames = wf.readframes(n_frames)
|
||||
|
||||
# Convert byte data to numpy array
|
||||
audio_np = np.frombuffer(audio_frames, dtype=np.int16)
|
||||
|
||||
# Play audio
|
||||
sd.play(audio_np, samplerate)
|
||||
sd.wait()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to play audio from url %s: %s",
|
||||
url,
|
||||
str(e),
|
||||
)
|
||||
|
||||
elif audio_block["source"]["type"] == "base64":
|
||||
data = audio_block["source"]["data"]
|
||||
|
||||
if msg_id not in self._stream_prefix:
|
||||
self._stream_prefix[msg_id] = {}
|
||||
|
||||
audio_prefix = self._stream_prefix[msg_id].get("audio", None)
|
||||
|
||||
import sounddevice as sd
|
||||
|
||||
# The player and the prefix data is cached for streaming audio
|
||||
if audio_prefix:
|
||||
player, audio_prefix_data = audio_prefix
|
||||
else:
|
||||
player = sd.OutputStream(
|
||||
samplerate=24000,
|
||||
channels=1,
|
||||
dtype=np.float32,
|
||||
blocksize=1024,
|
||||
latency="low",
|
||||
)
|
||||
player.start()
|
||||
audio_prefix_data = ""
|
||||
|
||||
# play the audio data
|
||||
new_audio_data = data[len(audio_prefix_data) :]
|
||||
if new_audio_data:
|
||||
audio_bytes = base64.b64decode(new_audio_data)
|
||||
audio_np = np.frombuffer(audio_bytes, dtype=np.int16)
|
||||
audio_float = audio_np.astype(np.float32) / 32768.0
|
||||
|
||||
# Write to the audio output stream
|
||||
player.write(audio_float)
|
||||
|
||||
# save the player and the prefix data
|
||||
self._stream_prefix[msg_id]["audio"] = (
|
||||
player,
|
||||
data,
|
||||
)
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
"Unsupported audio source type: "
|
||||
f"{audio_block['source']['type']}",
|
||||
)
|
||||
|
||||
def _print_text_block(
|
||||
self,
|
||||
msg_id: str,
|
||||
name_prefix: str,
|
||||
text_content: str,
|
||||
thinking_and_text_to_print: list[str],
|
||||
) -> None:
|
||||
"""Print the text block and thinking block content.
|
||||
|
||||
Args:
|
||||
msg_id (`str`):
|
||||
The unique identifier of the message
|
||||
name_prefix (`str`):
|
||||
The prefix for the message, e.g. "{name}: " for text block and
|
||||
"{name}(thinking): " for thinking block.
|
||||
text_content (`str`):
|
||||
The textual content to be printed.
|
||||
thinking_and_text_to_print (`list[str]`):
|
||||
A list of textual content to be printed together. Here we
|
||||
gather the text and thinking blocks to print them together.
|
||||
"""
|
||||
thinking_and_text_to_print.append(
|
||||
f"{name_prefix}: {text_content}",
|
||||
)
|
||||
# The accumulated text and thinking blocks to print
|
||||
to_print = "\n".join(thinking_and_text_to_print)
|
||||
|
||||
# The text prefix that has been printed
|
||||
if msg_id not in self._stream_prefix:
|
||||
self._stream_prefix[msg_id] = {}
|
||||
|
||||
text_prefix = self._stream_prefix[msg_id].get("text", "")
|
||||
|
||||
# Only print when there is new text content
|
||||
if len(to_print) > len(text_prefix):
|
||||
print(to_print[len(text_prefix) :], end="")
|
||||
|
||||
# Save the printed text prefix
|
||||
self._stream_prefix[msg_id]["text"] = to_print
|
||||
|
||||
def _print_last_block(
|
||||
self,
|
||||
block: ToolUseBlock | ToolResultBlock | ImageBlock | VideoBlock,
|
||||
msg: Msg,
|
||||
) -> None:
|
||||
"""Process and print the last content block, and the block type
|
||||
is not audio, text, or thinking.
|
||||
|
||||
Args:
|
||||
block (`ToolUseBlock | ToolResultBlock | ImageBlock | VideoBlock`):
|
||||
The content block to be printed
|
||||
msg (`Msg`):
|
||||
The message object
|
||||
"""
|
||||
text_prefix = self._stream_prefix.get(msg.id, {}).get("text", "")
|
||||
|
||||
if text_prefix:
|
||||
# Add a newline to separate from previous text content
|
||||
print_newline = "" if text_prefix.endswith("\n") else "\n"
|
||||
print(
|
||||
f"{print_newline}"
|
||||
f"{json.dumps(block, indent=4, ensure_ascii=False)}",
|
||||
)
|
||||
else:
|
||||
print(
|
||||
f"{msg.name}:"
|
||||
f" {json.dumps(block, indent=4, ensure_ascii=False)}",
|
||||
)
|
||||
|
||||
async def __call__(self, *args: Any, **kwargs: Any) -> Msg:
|
||||
"""Call the reply function with the given arguments."""
|
||||
self._reply_id = shortuuid.uuid()
|
||||
|
||||
reply_msg: Msg | None = None
|
||||
try:
|
||||
self._reply_task = asyncio.current_task()
|
||||
reply_msg = await self.reply(*args, **kwargs)
|
||||
|
||||
# The interruption is triggered by calling the interrupt method
|
||||
except asyncio.CancelledError:
|
||||
reply_msg = await self.handle_interrupt(*args, **kwargs)
|
||||
|
||||
finally:
|
||||
# Broadcast the reply message to all subscribers
|
||||
if reply_msg:
|
||||
await self._broadcast_to_subscribers(reply_msg)
|
||||
self._reply_task = None
|
||||
|
||||
return reply_msg
|
||||
|
||||
async def _broadcast_to_subscribers(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None,
|
||||
) -> None:
|
||||
"""Broadcast the message to all subscribers."""
|
||||
for subscribers in self._subscribers.values():
|
||||
for subscriber in subscribers:
|
||||
await subscriber.observe(msg)
|
||||
|
||||
async def handle_interrupt(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Msg:
|
||||
"""The post-processing logic when the reply is interrupted by the
|
||||
user or something else."""
|
||||
raise NotImplementedError(
|
||||
f"The handle_interrupt function is not implemented in "
|
||||
f"{self.__class__.__name__}",
|
||||
)
|
||||
|
||||
async def interrupt(self, msg: Msg | list[Msg] | None = None) -> None:
|
||||
"""Interrupt the current reply process."""
|
||||
if self._reply_task and not self._reply_task.done():
|
||||
self._reply_task.cancel(msg)
|
||||
|
||||
def register_instance_hook(
|
||||
self,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
hook: Callable,
|
||||
) -> None:
|
||||
"""Register a hook to the agent instance, which only takes effect
|
||||
for the current instance.
|
||||
|
||||
Args:
|
||||
hook_type (`str`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook. If the name is already registered, the
|
||||
hook will be overwritten.
|
||||
hook (`Callable`):
|
||||
The hook function.
|
||||
"""
|
||||
if not isinstance(self, AgentBase):
|
||||
raise TypeError(
|
||||
"The register_instance_hook method should be called on an "
|
||||
f"instance of AsyncAgentBase, but got {self} of "
|
||||
f"type {type(self)}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{hook_type}_hooks")
|
||||
hooks[hook_name] = hook
|
||||
|
||||
def remove_instance_hook(
|
||||
self,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
) -> None:
|
||||
"""Remove an instance-level hook from the agent instance.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook to remove.
|
||||
"""
|
||||
if not isinstance(self, AgentBase):
|
||||
raise TypeError(
|
||||
"The remove_instance_hook method should be called on an "
|
||||
f"instance of AsyncAgentBase, but got {self} of "
|
||||
f"type {type(self)}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{hook_type}_hooks")
|
||||
if hook_name in hooks:
|
||||
del hooks[hook_name]
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Hook '{hook_name}' not found in '{hook_type}' hooks of "
|
||||
f"{self.__class__.__name__} instance.",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def register_class_hook(
|
||||
cls,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
hook: Callable,
|
||||
) -> None:
|
||||
"""The universal function to register a hook to the agent class, which
|
||||
will take effect for all instances of the class.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook. If the name is already registered, the
|
||||
hook will be overwritten.
|
||||
hook (`Callable`):
|
||||
The hook function.
|
||||
"""
|
||||
|
||||
assert (
|
||||
hook_type in cls.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
|
||||
hooks = getattr(cls, f"_class_{hook_type}_hooks")
|
||||
hooks[hook_name] = hook
|
||||
|
||||
@classmethod
|
||||
def remove_class_hook(
|
||||
cls,
|
||||
hook_type: AgentHookTypes,
|
||||
hook_name: str,
|
||||
) -> None:
|
||||
"""Remove a class-level hook from the agent class.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`):
|
||||
The type of the hook, indicating where the hook is to be
|
||||
triggered.
|
||||
hook_name (`str`):
|
||||
The name of the hook to remove.
|
||||
"""
|
||||
|
||||
assert (
|
||||
hook_type in cls.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
hooks = getattr(cls, f"_class_{hook_type}_hooks")
|
||||
if hook_name in hooks:
|
||||
del hooks[hook_name]
|
||||
|
||||
else:
|
||||
raise ValueError(
|
||||
f"Hook '{hook_name}' not found in '{hook_type}' hooks of "
|
||||
f"{cls.__name__} class.",
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def clear_class_hooks(
|
||||
cls,
|
||||
hook_type: AgentHookTypes | None = None,
|
||||
) -> None:
|
||||
"""Clear all class-level hooks.
|
||||
|
||||
Args:
|
||||
hook_type (`AgentHookTypes`, optional):
|
||||
The type of the hook to clear. If not specified, all
|
||||
class-level hooks will be cleared.
|
||||
"""
|
||||
|
||||
if hook_type is None:
|
||||
for typ in cls.supported_hook_types:
|
||||
hooks = getattr(cls, f"_class_{typ}_hooks")
|
||||
hooks.clear()
|
||||
else:
|
||||
assert (
|
||||
hook_type in cls.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
hooks = getattr(cls, f"_class_{hook_type}_hooks")
|
||||
hooks.clear()
|
||||
|
||||
def clear_instance_hooks(
|
||||
self,
|
||||
hook_type: AgentHookTypes | None = None,
|
||||
) -> None:
|
||||
"""If `hook_type` is not specified, clear all instance-level hooks.
|
||||
Otherwise, clear the specified type of instance-level hooks."""
|
||||
if hook_type is None:
|
||||
for typ in self.supported_hook_types:
|
||||
if not hasattr(self, f"_instance_{typ}_hooks"):
|
||||
raise ValueError(
|
||||
f"Call super().__init__() in the constructor "
|
||||
f"to initialize the instance-level hooks for "
|
||||
f"{self.__class__.__name__}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{typ}_hooks")
|
||||
hooks.clear()
|
||||
|
||||
else:
|
||||
assert (
|
||||
hook_type in self.supported_hook_types
|
||||
), f"Invalid hook type: {hook_type}"
|
||||
if not hasattr(self, f"_instance_{hook_type}_hooks"):
|
||||
raise ValueError(
|
||||
f"Call super().__init__() in the constructor "
|
||||
f"to initialize the instance-level hooks for "
|
||||
f"{self.__class__.__name__}.",
|
||||
)
|
||||
hooks = getattr(self, f"_instance_{hook_type}_hooks")
|
||||
hooks.clear()
|
||||
|
||||
def reset_subscribers(
|
||||
self,
|
||||
msghub_name: str,
|
||||
subscribers: list["AgentBase"],
|
||||
) -> None:
|
||||
"""Reset the subscribers of the agent.
|
||||
|
||||
Args:
|
||||
msghub_name (`str`):
|
||||
The name of the MsgHub that manages the subscribers.
|
||||
subscribers (`list[AgentBase]`):
|
||||
A list of agents that will receive the reply message from
|
||||
this agent via their `observe` method.
|
||||
"""
|
||||
self._subscribers[msghub_name] = [_ for _ in subscribers if _ != self]
|
||||
|
||||
def remove_subscribers(self, msghub_name: str) -> None:
|
||||
"""Remove the msghub subscribers by the given msg hub name.
|
||||
|
||||
Args:
|
||||
msghub_name (`str`):
|
||||
The name of the MsgHub that manages the subscribers.
|
||||
"""
|
||||
if msghub_name not in self._subscribers:
|
||||
logger.warning(
|
||||
"MsgHub named '%s' not found",
|
||||
msghub_name,
|
||||
)
|
||||
else:
|
||||
self._subscribers.pop(msghub_name)
|
||||
|
||||
@deprecated("Please use set_console_output_enabled() instead.")
|
||||
def disable_console_output(self) -> None:
|
||||
"""This function will disable the console output of the agent, e.g.
|
||||
in a production environment to avoid messy logs."""
|
||||
self._disable_console_output = True
|
||||
|
||||
def set_console_output_enabled(self, enabled: bool) -> None:
|
||||
"""Enable or disable the console output of the agent. E.g. in a
|
||||
production environment, you may want to disable the console output to
|
||||
avoid messy logs.
|
||||
|
||||
Args:
|
||||
enabled (`bool`):
|
||||
If `True`, enable the console output. If `False`, disable
|
||||
the console output.
|
||||
"""
|
||||
self._disable_console_output = not enabled
|
||||
|
||||
def set_msg_queue_enabled(
|
||||
self,
|
||||
enabled: bool,
|
||||
queue: Queue | None = None,
|
||||
) -> None:
|
||||
"""Enable or disable the message queue for streaming outputs.
|
||||
|
||||
Args:
|
||||
enabled (`bool`):
|
||||
If `True`, enable the message queue to allow streaming
|
||||
outputs. If `False`, disable the message queue.
|
||||
queue (`Queue | None`, optional):
|
||||
The queue instance that will be used to initialize the
|
||||
message queue when `enable` is `True`.
|
||||
"""
|
||||
if enabled:
|
||||
if queue is None:
|
||||
if self.msg_queue is None:
|
||||
self.msg_queue = asyncio.Queue(maxsize=100)
|
||||
else:
|
||||
self.msg_queue = queue
|
||||
else:
|
||||
self.msg_queue = None
|
||||
|
||||
self._disable_msg_queue = not enabled
|
||||
@@ -1,180 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The metaclass for agents in agentscope."""
|
||||
import inspect
|
||||
from copy import deepcopy
|
||||
from functools import wraps
|
||||
from typing import (
|
||||
Any,
|
||||
Dict,
|
||||
TYPE_CHECKING,
|
||||
Callable,
|
||||
)
|
||||
|
||||
from .._utils._common import _execute_async_or_sync_func
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ._agent_base import AgentBase
|
||||
else:
|
||||
AgentBase = "AgentBase"
|
||||
|
||||
|
||||
def _normalize_to_kwargs(
|
||||
func: Callable,
|
||||
self: Any,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> dict:
|
||||
"""Normalize the provided positional and keyword arguments into a
|
||||
keyword arguments dictionary that matches the function signature."""
|
||||
sig = inspect.signature(func)
|
||||
try:
|
||||
# Bind the provided arguments to the function signature
|
||||
bound = sig.bind(self, *args, **kwargs)
|
||||
# Apply the default values for parameters
|
||||
bound.apply_defaults()
|
||||
|
||||
# Return the arguments in a dictionary format
|
||||
res = dict(bound.arguments)
|
||||
res.pop("self")
|
||||
return res
|
||||
|
||||
except TypeError as e:
|
||||
# If failed to bind, we raise a TypeError with more context
|
||||
param_names = list(sig.parameters.keys())
|
||||
provided_args = len(args)
|
||||
provided_kwargs = list(kwargs.keys())
|
||||
|
||||
raise TypeError(
|
||||
f"Failed to bind parameters for function '{func.__name__}': {e}\n"
|
||||
f"Expected parameters: {param_names}\n"
|
||||
f"Provided {provided_args} positional args and kwargs: "
|
||||
f"{provided_kwargs}",
|
||||
) from e
|
||||
|
||||
|
||||
def _wrap_with_hooks(
|
||||
original_func: Callable,
|
||||
) -> Callable:
|
||||
"""A decorator to wrap the original async function with pre- and post-hooks
|
||||
|
||||
Args:
|
||||
original_func (`Callable`):
|
||||
The original async function to be wrapped with hooks.
|
||||
"""
|
||||
func_name = original_func.__name__.replace("_", "")
|
||||
|
||||
@wraps(original_func)
|
||||
async def async_wrapper(
|
||||
self: AgentBase,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""The wrapped function, which call the pre- and post-hooks before and
|
||||
after the original function."""
|
||||
|
||||
# Unify all positional and keyword arguments into a keyword arguments
|
||||
normalized_kwargs = _normalize_to_kwargs(
|
||||
original_func,
|
||||
self,
|
||||
*args,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
current_normalized_kwargs = normalized_kwargs
|
||||
assert (
|
||||
hasattr(self, f"_instance_pre_{func_name}_hooks")
|
||||
and hasattr(self, f"_instance_post_{func_name}_hooks")
|
||||
and hasattr(self.__class__, f"_class_pre_{func_name}_hooks")
|
||||
and hasattr(self.__class__, f"_class_post_{func_name}_hooks")
|
||||
), f"Hooks for {func_name} not found in {self.__class__.__name__}"
|
||||
|
||||
# pre-hooks
|
||||
pre_hooks = list(
|
||||
getattr(self, f"_instance_pre_{func_name}_hooks").values(),
|
||||
) + list(
|
||||
getattr(self, f"_class_pre_{func_name}_hooks").values(),
|
||||
)
|
||||
for pre_hook in pre_hooks:
|
||||
modified_keywords = await _execute_async_or_sync_func(
|
||||
pre_hook,
|
||||
self,
|
||||
deepcopy(current_normalized_kwargs),
|
||||
)
|
||||
if modified_keywords is not None:
|
||||
assert isinstance(modified_keywords, dict), (
|
||||
f"Pre-hook must return a dict of keyword arguments, rather"
|
||||
f" than {type(modified_keywords)} from hook "
|
||||
f"{pre_hook.__name__}"
|
||||
)
|
||||
current_normalized_kwargs = modified_keywords
|
||||
|
||||
# original function
|
||||
# handle positional and keyword arguments specifically
|
||||
args = current_normalized_kwargs.get("args", [])
|
||||
kwargs = current_normalized_kwargs.get("kwargs", {})
|
||||
others = {
|
||||
k: v
|
||||
for k, v in current_normalized_kwargs.items()
|
||||
if k not in ["args", "kwargs"]
|
||||
}
|
||||
current_output = await original_func(
|
||||
self,
|
||||
*args,
|
||||
**others,
|
||||
**kwargs,
|
||||
)
|
||||
|
||||
# post_hooks
|
||||
post_hooks = list(
|
||||
getattr(self, f"_instance_post_{func_name}_hooks").values(),
|
||||
) + list(
|
||||
getattr(self, f"_class_post_{func_name}_hooks").values(),
|
||||
)
|
||||
for post_hook in post_hooks:
|
||||
modified_output = await _execute_async_or_sync_func(
|
||||
post_hook,
|
||||
self,
|
||||
deepcopy(current_normalized_kwargs),
|
||||
deepcopy(current_output),
|
||||
)
|
||||
if modified_output is not None:
|
||||
current_output = modified_output
|
||||
return current_output
|
||||
|
||||
return async_wrapper
|
||||
|
||||
|
||||
class _AgentMeta(type):
|
||||
"""The agent metaclass that wraps the agent's reply, observe and print
|
||||
functions with pre- and post-hooks."""
|
||||
|
||||
def __new__(mcs, name: Any, bases: Any, attrs: Dict) -> Any:
|
||||
"""Wrap the agent's functions with hooks."""
|
||||
|
||||
for func_name in [
|
||||
"reply",
|
||||
"print",
|
||||
"observe",
|
||||
]:
|
||||
if func_name in attrs:
|
||||
attrs[func_name] = _wrap_with_hooks(attrs[func_name])
|
||||
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
|
||||
|
||||
class _ReActAgentMeta(_AgentMeta):
|
||||
"""The ReAct metaclass that adds pre- and post-hooks for the _reasoning
|
||||
and _acting functions."""
|
||||
|
||||
def __new__(mcs, name: Any, bases: Any, attrs: Dict) -> Any:
|
||||
"""Wrap the ReAct agent's _reasoning and _acting functions with
|
||||
hooks."""
|
||||
|
||||
for func_name in [
|
||||
"_reasoning",
|
||||
"_acting",
|
||||
]:
|
||||
if func_name in attrs:
|
||||
attrs[func_name] = _wrap_with_hooks(attrs[func_name])
|
||||
|
||||
return super().__new__(mcs, name, bases, attrs)
|
||||
@@ -1,767 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# pylint: disable=not-an-iterable
|
||||
# mypy: disable-error-code="list-item"
|
||||
"""ReAct agent class in agentscope."""
|
||||
import asyncio
|
||||
from typing import Type, Any, AsyncGenerator, Literal
|
||||
|
||||
import shortuuid
|
||||
from pydantic import BaseModel, ValidationError, Field
|
||||
|
||||
from ._react_agent_base import ReActAgentBase
|
||||
from .._logging import logger
|
||||
from ..formatter import FormatterBase
|
||||
from ..memory import MemoryBase, LongTermMemoryBase, InMemoryMemory
|
||||
from ..message import Msg, ToolUseBlock, ToolResultBlock, TextBlock
|
||||
from ..model import ChatModelBase
|
||||
from ..rag import KnowledgeBase, Document
|
||||
from ..plan import PlanNotebook
|
||||
from ..tool import Toolkit, ToolResponse
|
||||
from ..tracing import trace_reply
|
||||
|
||||
|
||||
class _QueryRewriteModel(BaseModel):
|
||||
"""The structured model used for query rewriting."""
|
||||
|
||||
rewritten_query: str = Field(
|
||||
description=(
|
||||
"The rewritten query, which should be specific and concise. "
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def finish_function_pre_print_hook(
|
||||
self: "ReActAgent",
|
||||
kwargs: dict[str, Any],
|
||||
) -> dict[str, Any] | None:
|
||||
"""A pre-speak hook function that check if finish_function is called. If
|
||||
so, it will wrap the response argument into a message and return it to
|
||||
replace the original message. By this way, the calling of the finish
|
||||
function will be displayed as a text reply instead of a tool call."""
|
||||
|
||||
msg = kwargs["msg"]
|
||||
|
||||
if isinstance(msg.content, str):
|
||||
return None
|
||||
|
||||
if isinstance(msg.content, list):
|
||||
for i, block in enumerate(msg.content):
|
||||
if (
|
||||
block["type"] == "tool_use"
|
||||
and block["name"] == self.finish_function_name
|
||||
):
|
||||
# Convert the response argument into a text block for
|
||||
# displaying
|
||||
try:
|
||||
msg.content[i] = TextBlock(
|
||||
type="text",
|
||||
text=block["input"].get("response", ""),
|
||||
)
|
||||
return kwargs
|
||||
except Exception:
|
||||
print("Error in block input", block["input"])
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class ReActAgent(ReActAgentBase):
|
||||
"""A ReAct agent implementation in AgentScope, which supports
|
||||
|
||||
- Realtime steering
|
||||
- API-based (parallel) tool calling
|
||||
- Hooks around reasoning, acting, reply, observe and print functions
|
||||
- Structured output generation
|
||||
"""
|
||||
|
||||
finish_function_name: str = "generate_response"
|
||||
"""The function name used to finish replying and return a response to
|
||||
the user."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
sys_prompt: str,
|
||||
model: ChatModelBase,
|
||||
formatter: FormatterBase,
|
||||
toolkit: Toolkit | None = None,
|
||||
memory: MemoryBase | None = None,
|
||||
long_term_memory: LongTermMemoryBase | None = None,
|
||||
long_term_memory_mode: Literal[
|
||||
"agent_control",
|
||||
"static_control",
|
||||
"both",
|
||||
] = "both",
|
||||
enable_meta_tool: bool = False,
|
||||
parallel_tool_calls: bool = False,
|
||||
knowledge: KnowledgeBase | list[KnowledgeBase] | None = None,
|
||||
enable_rewrite_query: bool = True,
|
||||
plan_notebook: PlanNotebook | None = None,
|
||||
print_hint_msg: bool = False,
|
||||
max_iters: int = 10,
|
||||
) -> None:
|
||||
"""Initialize the ReAct agent
|
||||
|
||||
Args:
|
||||
name (`str`):
|
||||
The name of the agent.
|
||||
sys_prompt (`str`):
|
||||
The system prompt of the agent.
|
||||
model (`ChatModelBase`):
|
||||
The chat model used by the agent.
|
||||
formatter (`FormatterBase`):
|
||||
The formatter used to format the messages into the required
|
||||
format of the model API provider.
|
||||
toolkit (`Toolkit | None`, optional):
|
||||
A `Toolkit` object that contains the tool functions. If not
|
||||
provided, a default empty `Toolkit` will be created.
|
||||
memory (`MemoryBase | None`, optional):
|
||||
The memory used to store the dialogue history. If not provided,
|
||||
a default `InMemoryMemory` will be created, which stores
|
||||
messages in a list in memory.
|
||||
long_term_memory (`LongTermMemoryBase | None`, optional):
|
||||
The optional long-term memory, which will provide two tool
|
||||
functions: `retrieve_from_memory` and `record_to_memory`, and
|
||||
will attach the retrieved information to the system prompt
|
||||
before each reply.
|
||||
enable_meta_tool (`bool`, defaults to `False`):
|
||||
If `True`, a meta tool function `reset_equipped_tools` will be
|
||||
added to the toolkit, which allows the agent to manage its
|
||||
equipped tools dynamically.
|
||||
long_term_memory_mode (`Literal['agent_control', 'static_control',\
|
||||
'both']`, defaults to `both`):
|
||||
The mode of the long-term memory. If `agent_control`, two
|
||||
tool functions `retrieve_from_memory` and `record_to_memory`
|
||||
will be registered in the toolkit to allow the agent to
|
||||
manage the long-term memory. If `static_control`, retrieving
|
||||
and recording will happen in the beginning and end of
|
||||
each reply respectively.
|
||||
parallel_tool_calls (`bool`, defaults to `False`):
|
||||
When LLM generates multiple tool calls, whether to execute
|
||||
them in parallel.
|
||||
knowledge (`KnowledgeBase | list[KnowledgeBase] | None`, optional):
|
||||
The knowledge object(s) used by the agent to retrieve
|
||||
relevant documents at the beginning of each reply.
|
||||
enable_rewrite_query (`bool`, defaults to `True`):
|
||||
Whether ask the agent to rewrite the user input query before
|
||||
retrieving from the knowledge base(s), e.g. rewrite "Who am I"
|
||||
to "{user's name}" to get more relevant documents. Only works
|
||||
when the knowledge base(s) is provided.
|
||||
plan_notebook (`PlanNotebook | None`, optional):
|
||||
The plan notebook instance, allow the agent to finish the
|
||||
complex task by decomposing it into a sequence of subtasks.
|
||||
print_hint_msg (`bool`, defaults to `False`):
|
||||
Whether to print the hint messages, including the reasoning
|
||||
hint from the plan notebook, the retrieved information from
|
||||
the long-term memory and knowledge base(s).
|
||||
max_iters (`int`, defaults to `10`):
|
||||
The maximum number of iterations of the reasoning-acting loops.
|
||||
"""
|
||||
super().__init__()
|
||||
|
||||
assert long_term_memory_mode in [
|
||||
"agent_control",
|
||||
"static_control",
|
||||
"both",
|
||||
]
|
||||
|
||||
# Static variables in the agent
|
||||
self.name = name
|
||||
self._sys_prompt = sys_prompt
|
||||
self.max_iters = max_iters
|
||||
self.model = model
|
||||
self.formatter = formatter
|
||||
|
||||
# -------------- Memory management --------------
|
||||
# Record the dialogue history in the memory
|
||||
self.memory = memory or InMemoryMemory()
|
||||
# If provide the long-term memory, it will be used to retrieve info
|
||||
# in the beginning of each reply, and the result will be added to the
|
||||
# system prompt
|
||||
self.long_term_memory = long_term_memory
|
||||
|
||||
# The long-term memory mode
|
||||
self._static_control = long_term_memory and long_term_memory_mode in [
|
||||
"static_control",
|
||||
"both",
|
||||
]
|
||||
self._agent_control = long_term_memory and long_term_memory_mode in [
|
||||
"agent_control",
|
||||
"both",
|
||||
]
|
||||
|
||||
# -------------- Tool management --------------
|
||||
# If None, a default Toolkit will be created
|
||||
self.toolkit = toolkit or Toolkit()
|
||||
self.toolkit.register_tool_function(
|
||||
getattr(self, self.finish_function_name),
|
||||
)
|
||||
if self._agent_control:
|
||||
# Adding two tool functions into the toolkit to allow self-control
|
||||
self.toolkit.register_tool_function(
|
||||
long_term_memory.record_to_memory,
|
||||
)
|
||||
self.toolkit.register_tool_function(
|
||||
long_term_memory.retrieve_from_memory,
|
||||
)
|
||||
# Add a meta tool function to allow agent-controlled tool management
|
||||
if enable_meta_tool or plan_notebook:
|
||||
self.toolkit.register_tool_function(
|
||||
self.toolkit.reset_equipped_tools,
|
||||
)
|
||||
|
||||
self.parallel_tool_calls = parallel_tool_calls
|
||||
|
||||
# -------------- RAG management --------------
|
||||
# The knowledge base(s) used by the agent
|
||||
if isinstance(knowledge, KnowledgeBase):
|
||||
knowledge = [knowledge]
|
||||
self.knowledge: list[KnowledgeBase] = knowledge or []
|
||||
self.enable_rewrite_query = enable_rewrite_query
|
||||
|
||||
# -------------- Plan management --------------
|
||||
# Equipped the plan-related tools provided by the plan notebook as
|
||||
# a tool group named "plan_related". So that the agent can activate
|
||||
# the plan tools by the meta tool function
|
||||
self.plan_notebook = None
|
||||
if plan_notebook:
|
||||
self.plan_notebook = plan_notebook
|
||||
# When enable_meta_tool is True, plan tools are in plan_related
|
||||
# group and active by agent.
|
||||
# Otherwise, plan tools in bassic group and always active.
|
||||
if enable_meta_tool:
|
||||
self.toolkit.create_tool_group(
|
||||
"plan_related",
|
||||
description=self.plan_notebook.description,
|
||||
)
|
||||
for tool in plan_notebook.list_tools():
|
||||
self.toolkit.register_tool_function(
|
||||
tool,
|
||||
group_name="plan_related",
|
||||
)
|
||||
else:
|
||||
for tool in plan_notebook.list_tools():
|
||||
self.toolkit.register_tool_function(
|
||||
tool,
|
||||
)
|
||||
|
||||
# If print the reasoning hint messages
|
||||
self.print_hint_msg = print_hint_msg
|
||||
|
||||
# The maximum number of iterations of the reasoning-acting loops
|
||||
self.max_iters = max_iters
|
||||
|
||||
# The hint messages that will be attached to the prompt to guide the
|
||||
# agent's behavior before each reasoning step, and cleared after
|
||||
# each reasoning step, meaning the hint messages is one-time use only.
|
||||
# We use an InMemoryMemory instance to store the hint messages
|
||||
self._reasoning_hint_msgs = InMemoryMemory()
|
||||
|
||||
# Variables to record the intermediate state
|
||||
|
||||
# If required structured output model is provided
|
||||
self._required_structured_model: Type[BaseModel] | None = None
|
||||
|
||||
# -------------- State registration and hooks --------------
|
||||
# Register the status variables
|
||||
self.register_state("name")
|
||||
self.register_state("_sys_prompt")
|
||||
|
||||
self.register_instance_hook(
|
||||
"pre_print",
|
||||
"finish_function_pre_print_hook",
|
||||
finish_function_pre_print_hook,
|
||||
)
|
||||
|
||||
@property
|
||||
def sys_prompt(self) -> str:
|
||||
"""The dynamic system prompt of the agent."""
|
||||
return self._sys_prompt
|
||||
|
||||
@trace_reply
|
||||
async def reply(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None = None,
|
||||
structured_model: Type[BaseModel] | None = None,
|
||||
) -> Msg:
|
||||
"""Generate a reply based on the current state and input arguments.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`, optional):
|
||||
The input message(s) to the agent.
|
||||
structured_model (`Type[BaseModel] | None`, optional):
|
||||
The required structured output model. If provided, the agent
|
||||
is expected to generate structured output in the `metadata`
|
||||
field of the output message.
|
||||
|
||||
Returns:
|
||||
`Msg`:
|
||||
The output message generated by the agent.
|
||||
"""
|
||||
# Record the input message(s) in the memory
|
||||
await self.memory.add(msg)
|
||||
|
||||
# Retrieve relevant records from the long-term memory if activated
|
||||
await self._retrieve_from_long_term_memory(msg)
|
||||
# Retrieve relevant documents from the knowledge base(s) if any
|
||||
await self._retrieve_from_knowledge(msg)
|
||||
|
||||
self._required_structured_model = structured_model
|
||||
# Record structured output model if provided
|
||||
if structured_model:
|
||||
self.toolkit.set_extended_model(
|
||||
self.finish_function_name,
|
||||
structured_model,
|
||||
)
|
||||
|
||||
# The reasoning-acting loop
|
||||
reply_msg = None
|
||||
for _ in range(self.max_iters):
|
||||
msg_reasoning = await self._reasoning()
|
||||
|
||||
futures = [
|
||||
self._acting(tool_call)
|
||||
for tool_call in msg_reasoning.get_content_blocks(
|
||||
"tool_use",
|
||||
)
|
||||
]
|
||||
|
||||
# Parallel tool calls or not
|
||||
if self.parallel_tool_calls:
|
||||
acting_responses = await asyncio.gather(*futures)
|
||||
|
||||
else:
|
||||
# Sequential tool calls
|
||||
acting_responses = [await _ for _ in futures]
|
||||
|
||||
# Find the first non-None replying message from the acting
|
||||
for acting_msg in acting_responses:
|
||||
reply_msg = reply_msg or acting_msg
|
||||
|
||||
if reply_msg:
|
||||
break
|
||||
|
||||
# When the maximum iterations are reached
|
||||
if reply_msg is None:
|
||||
reply_msg = await self._summarizing()
|
||||
|
||||
# Post-process the memory, long-term memory
|
||||
if self._static_control:
|
||||
await self.long_term_memory.record(
|
||||
[
|
||||
*([*msg] if isinstance(msg, list) else [msg]),
|
||||
*await self.memory.get_memory(),
|
||||
reply_msg,
|
||||
],
|
||||
)
|
||||
|
||||
await self.memory.add(reply_msg)
|
||||
return reply_msg
|
||||
|
||||
async def _reasoning(
|
||||
self,
|
||||
) -> Msg:
|
||||
"""Perform the reasoning process."""
|
||||
if self.plan_notebook:
|
||||
# Insert the reasoning hint from the plan notebook
|
||||
hint_msg = await self.plan_notebook.get_current_hint()
|
||||
if self.print_hint_msg and hint_msg:
|
||||
await self.print(hint_msg)
|
||||
await self._reasoning_hint_msgs.add(hint_msg)
|
||||
|
||||
# Convert Msg objects into the required format of the model API
|
||||
prompt = await self.formatter.format(
|
||||
msgs=[
|
||||
Msg("system", self.sys_prompt, "system"),
|
||||
*await self.memory.get_memory(),
|
||||
# The hint messages to guide the agent's behavior, maybe empty
|
||||
*await self._reasoning_hint_msgs.get_memory(),
|
||||
],
|
||||
)
|
||||
# Clear the hint messages after use
|
||||
await self._reasoning_hint_msgs.clear()
|
||||
|
||||
res = await self.model(
|
||||
prompt,
|
||||
tools=self.toolkit.get_json_schemas(),
|
||||
)
|
||||
|
||||
# handle output from the model
|
||||
interrupted_by_user = False
|
||||
msg = None
|
||||
try:
|
||||
if self.model.stream:
|
||||
msg = Msg(self.name, [], "assistant")
|
||||
async for content_chunk in res:
|
||||
msg.content = content_chunk.content
|
||||
await self.print(msg, False)
|
||||
await self.print(msg, True)
|
||||
|
||||
# Add a tiny sleep to yield the last message object in the
|
||||
# message queue
|
||||
await asyncio.sleep(0.001)
|
||||
|
||||
else:
|
||||
msg = Msg(self.name, list(res.content), "assistant")
|
||||
await self.print(msg, True)
|
||||
|
||||
except asyncio.CancelledError as e:
|
||||
interrupted_by_user = True
|
||||
raise e from None
|
||||
|
||||
finally:
|
||||
if msg and not msg.has_content_blocks("tool_use"):
|
||||
# Turn plain text response into a tool call of the finish
|
||||
# function
|
||||
msg = Msg.from_dict(msg.to_dict())
|
||||
msg.content = [
|
||||
ToolUseBlock(
|
||||
id=shortuuid.uuid(),
|
||||
type="tool_use",
|
||||
name=self.finish_function_name,
|
||||
input={"response": msg.get_text_content()},
|
||||
),
|
||||
]
|
||||
|
||||
# None will be ignored by the memory
|
||||
await self.memory.add(msg)
|
||||
|
||||
# Post-process for user interruption
|
||||
if interrupted_by_user and msg:
|
||||
# Fake tool results
|
||||
tool_use_blocks: list = msg.get_content_blocks(
|
||||
"tool_use",
|
||||
)
|
||||
for tool_call in tool_use_blocks:
|
||||
msg_res = Msg(
|
||||
"system",
|
||||
[
|
||||
ToolResultBlock(
|
||||
type="tool_result",
|
||||
id=tool_call["id"],
|
||||
name=tool_call["name"],
|
||||
output="The tool call has been interrupted "
|
||||
"by the user.",
|
||||
),
|
||||
],
|
||||
"system",
|
||||
)
|
||||
await self.memory.add(msg_res)
|
||||
await self.print(msg_res, True)
|
||||
return msg
|
||||
|
||||
async def _acting(self, tool_call: ToolUseBlock) -> Msg | None:
|
||||
"""Perform the acting process.
|
||||
|
||||
Args:
|
||||
tool_call (`ToolUseBlock`):
|
||||
The tool use block to be executed.
|
||||
|
||||
Returns:
|
||||
`Union[Msg, None]`:
|
||||
Return a message to the user if the `finish_function` is
|
||||
called, otherwise return `None`.
|
||||
"""
|
||||
|
||||
tool_res_msg = Msg(
|
||||
"system",
|
||||
[
|
||||
ToolResultBlock(
|
||||
type="tool_result",
|
||||
id=tool_call["id"],
|
||||
name=tool_call["name"],
|
||||
output=[],
|
||||
),
|
||||
],
|
||||
"system",
|
||||
)
|
||||
try:
|
||||
# Execute the tool call
|
||||
tool_res = await self.toolkit.call_tool_function(tool_call)
|
||||
|
||||
response_msg = None
|
||||
# Async generator handling
|
||||
async for chunk in tool_res:
|
||||
# Turn into a tool result block
|
||||
tool_res_msg.content[0][ # type: ignore[index]
|
||||
"output"
|
||||
] = chunk.content
|
||||
|
||||
# Skip the printing of the finish function call
|
||||
if (
|
||||
tool_call["name"] != self.finish_function_name
|
||||
or tool_call["name"] == self.finish_function_name
|
||||
and (
|
||||
chunk.metadata is None
|
||||
or not chunk.metadata.get("success")
|
||||
)
|
||||
):
|
||||
await self.print(tool_res_msg, chunk.is_last)
|
||||
|
||||
# Raise the CancelledError to handle the interruption in the
|
||||
# handle_interrupt function
|
||||
if chunk.is_interrupted:
|
||||
raise asyncio.CancelledError()
|
||||
|
||||
# Return message if generate_response is called successfully
|
||||
if (
|
||||
tool_call["name"] == self.finish_function_name
|
||||
and chunk.metadata
|
||||
and chunk.metadata.get(
|
||||
"success",
|
||||
True,
|
||||
)
|
||||
):
|
||||
response_msg = chunk.metadata.get("response_msg")
|
||||
|
||||
return response_msg
|
||||
|
||||
finally:
|
||||
# Record the tool result message in the memory
|
||||
await self.memory.add(tool_res_msg)
|
||||
|
||||
async def observe(self, msg: Msg | list[Msg] | None) -> None:
|
||||
"""Receive observing message(s) without generating a reply.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The message or messages to be observed.
|
||||
"""
|
||||
await self.memory.add(msg)
|
||||
|
||||
async def _summarizing(self) -> Msg:
|
||||
"""Generate a response when the agent fails to solve the problem in
|
||||
the maximum iterations."""
|
||||
hint_msg = Msg(
|
||||
"user",
|
||||
"You have failed to generate response within the maximum "
|
||||
"iterations. Now respond directly by summarizing the current "
|
||||
"situation.",
|
||||
role="user",
|
||||
)
|
||||
|
||||
# Generate a reply by summarizing the current situation
|
||||
prompt = await self.formatter.format(
|
||||
[
|
||||
Msg("system", self.sys_prompt, "system"),
|
||||
*await self.memory.get_memory(),
|
||||
hint_msg,
|
||||
],
|
||||
)
|
||||
# TODO: handle the structured output here, maybe force calling the
|
||||
# finish_function here
|
||||
res = await self.model(prompt)
|
||||
|
||||
res_msg = Msg(self.name, [], "assistant")
|
||||
if isinstance(res, AsyncGenerator):
|
||||
async for chunk in res:
|
||||
res_msg.content = chunk.content
|
||||
await self.print(res_msg, False)
|
||||
await self.print(res_msg, True)
|
||||
|
||||
else:
|
||||
res_msg.content = res.content
|
||||
await self.print(res_msg, True)
|
||||
|
||||
return res_msg
|
||||
|
||||
async def handle_interrupt(
|
||||
self,
|
||||
_msg: Msg | list[Msg] | None = None,
|
||||
) -> Msg:
|
||||
"""The post-processing logic when the reply is interrupted by the
|
||||
user or something else."""
|
||||
|
||||
response_msg = Msg(
|
||||
self.name,
|
||||
"I noticed that you have interrupted me. What can I "
|
||||
"do for you?",
|
||||
"assistant",
|
||||
metadata={
|
||||
# Expose this field to indicate the interruption
|
||||
"is_interrupted": True,
|
||||
},
|
||||
)
|
||||
|
||||
await self.print(response_msg, True)
|
||||
await self.memory.add(response_msg)
|
||||
return response_msg
|
||||
|
||||
def generate_response(
|
||||
self,
|
||||
response: str,
|
||||
**kwargs: Any,
|
||||
) -> ToolResponse:
|
||||
"""Generate a response. Note only the input argument `response` is
|
||||
visible to the others, you should include all the necessary
|
||||
information in the `response` argument.
|
||||
|
||||
Args:
|
||||
response (`str`):
|
||||
Your response to the user.
|
||||
"""
|
||||
response_msg = Msg(
|
||||
self.name,
|
||||
response,
|
||||
"assistant",
|
||||
)
|
||||
|
||||
# Prepare structured output
|
||||
if self._required_structured_model:
|
||||
try:
|
||||
# Use the metadata field of the message to store the
|
||||
# structured output
|
||||
response_msg.metadata = (
|
||||
self._required_structured_model.model_validate(
|
||||
kwargs,
|
||||
).model_dump()
|
||||
)
|
||||
|
||||
except ValidationError as e:
|
||||
return ToolResponse(
|
||||
content=[
|
||||
TextBlock(
|
||||
type="text",
|
||||
text=f"Arguments Validation Error: {e}",
|
||||
),
|
||||
],
|
||||
metadata={
|
||||
"success": False,
|
||||
"response_msg": None,
|
||||
},
|
||||
)
|
||||
|
||||
return ToolResponse(
|
||||
content=[
|
||||
TextBlock(
|
||||
type="text",
|
||||
text="Successfully generated response.",
|
||||
),
|
||||
],
|
||||
metadata={
|
||||
"success": True,
|
||||
"response_msg": response_msg,
|
||||
},
|
||||
is_last=True,
|
||||
)
|
||||
|
||||
async def _retrieve_from_long_term_memory(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None,
|
||||
) -> None:
|
||||
"""Insert the retrieved information from the long-term memory into
|
||||
the short-term memory as a Msg object.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The input message to the agent.
|
||||
"""
|
||||
if self._static_control and msg:
|
||||
# Retrieve information from the long-term memory if available
|
||||
retrieved_info = await self.long_term_memory.retrieve(msg)
|
||||
if retrieved_info:
|
||||
retrieved_msg = Msg(
|
||||
name="long_term_memory",
|
||||
content="<long_term_memory>The content below are "
|
||||
"retrieved from long-term memory, which maybe "
|
||||
f"useful:\n{retrieved_info}</long_term_memory>",
|
||||
role="user",
|
||||
)
|
||||
if self.print_hint_msg:
|
||||
await self.print(retrieved_msg, True)
|
||||
await self.memory.add(retrieved_msg)
|
||||
|
||||
async def _retrieve_from_knowledge(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None,
|
||||
) -> None:
|
||||
"""Insert the retrieved documents from the RAG knowledge base(s) if
|
||||
available.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`):
|
||||
The input message to the agent.
|
||||
"""
|
||||
if self.knowledge and msg:
|
||||
# Prepare the user input query
|
||||
query = None
|
||||
if isinstance(msg, Msg):
|
||||
query = msg.get_text_content()
|
||||
elif isinstance(msg, list):
|
||||
query = "\n".join(_.get_text_content() for _ in msg)
|
||||
|
||||
# Skip if the query is empty
|
||||
if not query:
|
||||
return
|
||||
|
||||
# Rewrite the query by the LLM if enabled
|
||||
if self.enable_rewrite_query:
|
||||
try:
|
||||
rewrite_prompt = await self.formatter.format(
|
||||
msgs=[
|
||||
Msg("system", self.sys_prompt, "system"),
|
||||
*await self.memory.get_memory(),
|
||||
Msg(
|
||||
"user",
|
||||
"<system-hint>Now you need to rewrite "
|
||||
"the above user query to be more specific and "
|
||||
"concise for knowledge retrieval. For "
|
||||
"example, rewrite the query 'what happened "
|
||||
"last day' to 'what happened on 2023-10-01' "
|
||||
"(assuming today is 2023-10-02)."
|
||||
"</system-hint>",
|
||||
"user",
|
||||
),
|
||||
],
|
||||
)
|
||||
stream_tmp = self.model.stream
|
||||
self.model.stream = False
|
||||
res = await self.model(
|
||||
rewrite_prompt,
|
||||
structured_model=_QueryRewriteModel,
|
||||
)
|
||||
self.model.stream = stream_tmp
|
||||
if res.metadata and res.metadata.get("rewritten_query"):
|
||||
query = res.metadata["rewritten_query"]
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"Skipping the query rewriting due to error: %s",
|
||||
str(e),
|
||||
)
|
||||
|
||||
docs: list[Document] = []
|
||||
for kb in self.knowledge:
|
||||
# retrieve the user input query
|
||||
docs.extend(
|
||||
await kb.retrieve(query=query),
|
||||
)
|
||||
if docs:
|
||||
# Rerank by the relevance score
|
||||
docs = sorted(
|
||||
docs,
|
||||
key=lambda doc: doc.score or 0.0,
|
||||
reverse=True,
|
||||
)
|
||||
# Prepare the retrieved knowledge string
|
||||
retrieved_msg = Msg(
|
||||
name="user",
|
||||
content=[
|
||||
TextBlock(
|
||||
type="text",
|
||||
text=(
|
||||
"<retrieved_knowledge>Use the following "
|
||||
"content from the knowledge base(s) if it's "
|
||||
"helpful:\n"
|
||||
),
|
||||
),
|
||||
*[_.metadata.content for _ in docs],
|
||||
TextBlock(
|
||||
type="text",
|
||||
text="</retrieved_knowledge>",
|
||||
),
|
||||
],
|
||||
role="user",
|
||||
)
|
||||
if self.print_hint_msg:
|
||||
await self.print(retrieved_msg, True)
|
||||
await self.memory.add(retrieved_msg)
|
||||
@@ -1,116 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The base class for ReAct agent in agentscope."""
|
||||
from abc import abstractmethod
|
||||
from collections import OrderedDict
|
||||
from typing import Callable, Any
|
||||
|
||||
from ._agent_base import AgentBase
|
||||
from ._agent_meta import _ReActAgentMeta
|
||||
from ..message import Msg
|
||||
|
||||
|
||||
class ReActAgentBase(AgentBase, metaclass=_ReActAgentMeta):
|
||||
"""The ReAct agent base class.
|
||||
|
||||
To support ReAct algorithm, this class extends the AgentBase class by
|
||||
adding two abstract interfaces: reasoning and acting, while supporting
|
||||
hook functions at four positions: pre-reasoning, post-reasoning,
|
||||
pre-acting, and post-acting by the `_ReActAgentMeta` metaclass.
|
||||
"""
|
||||
|
||||
supported_hook_types: list[str] = [
|
||||
"pre_reply",
|
||||
"post_reply",
|
||||
"pre_print",
|
||||
"post_print",
|
||||
"pre_observe",
|
||||
"post_observe",
|
||||
"pre_reasoning",
|
||||
"post_reasoning",
|
||||
"pre_acting",
|
||||
"post_acting",
|
||||
]
|
||||
"""Supported hook types for the agent base class."""
|
||||
|
||||
_class_pre_reasoning_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level pre-reasoning hooks, taking `self` object, the input
|
||||
arguments as input"""
|
||||
|
||||
_class_post_reasoning_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Any, # output
|
||||
],
|
||||
Msg | None, # the modified output message or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level post-reasoning hooks, taking `self` object, the input
|
||||
arguments and the output message as input, and return the modified output
|
||||
message or None if no modification is needed."""
|
||||
|
||||
_class_pre_acting_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
],
|
||||
dict[str, Any] | None, # The modified kwargs or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level pre-acting hooks, taking `self` object, the input
|
||||
arguments as input, and return the modified input arguments or None if no
|
||||
modification is needed."""
|
||||
|
||||
_class_post_acting_hooks: dict[
|
||||
str,
|
||||
Callable[
|
||||
[
|
||||
"ReActAgentBase", # self
|
||||
dict[str, Any], # kwargs
|
||||
Any, # output
|
||||
],
|
||||
Msg | None, # the modified output message or None
|
||||
],
|
||||
] = OrderedDict()
|
||||
"""The class-level post-acting hooks, taking `self` object, the input
|
||||
arguments and the output message as input, and return the modified output
|
||||
message or None if no modification is needed."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
) -> None:
|
||||
"""Initialize the ReAct agent base class."""
|
||||
super().__init__()
|
||||
|
||||
# Init reasoning and acting hooks
|
||||
self._instance_pre_reasoning_hooks = OrderedDict()
|
||||
self._instance_post_reasoning_hooks = OrderedDict()
|
||||
self._instance_pre_acting_hooks = OrderedDict()
|
||||
self._instance_post_acting_hooks = OrderedDict()
|
||||
|
||||
@abstractmethod
|
||||
async def _reasoning(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Any:
|
||||
"""The reasoning process of the ReAct agent, which will be wrapped
|
||||
with pre- and post-hooks."""
|
||||
|
||||
@abstractmethod
|
||||
async def _acting(self, *args: Any, **kwargs: Any) -> Any:
|
||||
"""The acting process of the ReAct agent, which will be wrapped with
|
||||
pre- and post-hooks."""
|
||||
@@ -1,128 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The user agent class."""
|
||||
from typing import Type, Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
from ._agent_base import AgentBase
|
||||
from ._user_input import UserInputBase, TerminalUserInput
|
||||
from ..message import Msg
|
||||
|
||||
|
||||
class UserAgent(AgentBase):
|
||||
"""The class for user interaction, allowing developers to handle the user
|
||||
input from different sources, such as web UI, cli, and other interfaces.
|
||||
"""
|
||||
|
||||
_input_method: UserInputBase = TerminalUserInput()
|
||||
"""The user input method, can be overridden by calling the
|
||||
`register_instance/class_input_method` function."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
) -> None:
|
||||
"""Initialize the user agent with a name."""
|
||||
super().__init__()
|
||||
|
||||
self.name = name
|
||||
|
||||
async def reply(
|
||||
self,
|
||||
msg: Msg | list[Msg] | None = None,
|
||||
structured_model: Type[BaseModel] | None = None,
|
||||
) -> Msg:
|
||||
"""Receive input message(s) and generate a reply message from the user.
|
||||
|
||||
Args:
|
||||
msg (`Msg | list[Msg] | None`, defaults to `None`):
|
||||
The message(s) to be replied. If `None`, the agent will wait
|
||||
for user input.
|
||||
structured_model (`Type[BaseModel] | None`, defaults to `None`):
|
||||
A child class of `pydantic.BaseModel` that defines the
|
||||
structured output format. If provided, the user will be
|
||||
prompted to fill in the required fields.
|
||||
|
||||
Returns:
|
||||
`Msg`:
|
||||
The reply message generated by the user.
|
||||
"""
|
||||
|
||||
# Get the input from the specified input method.
|
||||
input_data = await self._input_method(
|
||||
agent_id=self.id,
|
||||
agent_name=self.name,
|
||||
structured_model=structured_model,
|
||||
)
|
||||
|
||||
blocks_input = input_data.blocks_input
|
||||
if (
|
||||
blocks_input
|
||||
and len(blocks_input) == 1
|
||||
and blocks_input[0].get("type") == "text"
|
||||
):
|
||||
# Turn blocks_input into a string if only one text block exists
|
||||
blocks_input = blocks_input[0].get("text")
|
||||
|
||||
msg = Msg(
|
||||
self.name,
|
||||
content=blocks_input,
|
||||
role="user",
|
||||
metadata=input_data.structured_input,
|
||||
)
|
||||
|
||||
await self.print(msg)
|
||||
|
||||
return msg
|
||||
|
||||
def override_instance_input_method(
|
||||
self,
|
||||
input_method: UserInputBase,
|
||||
) -> None:
|
||||
"""Override the input method of the current UserAgent instance.
|
||||
|
||||
Args:
|
||||
input_method (`UserInputBase`):
|
||||
The callable input method, which should be an object of a
|
||||
class that inherits from `UserInputBase`.
|
||||
"""
|
||||
if not isinstance(input_method, UserInputBase):
|
||||
raise ValueError(
|
||||
f"The input method should be an instance of the child class "
|
||||
f"of `UserInputBase`, but got {type(input_method)} instead.",
|
||||
)
|
||||
self._input_method = input_method
|
||||
|
||||
@classmethod
|
||||
def override_class_input_method(
|
||||
cls,
|
||||
input_method: UserInputBase,
|
||||
) -> None:
|
||||
"""Override the input method of the current UserAgent class.
|
||||
|
||||
Args:
|
||||
input_method (`UserInputBase`):
|
||||
The callable input method, which should be an object of a
|
||||
class that inherits from `UserInputBase`.
|
||||
"""
|
||||
if not isinstance(input_method, UserInputBase):
|
||||
raise ValueError(
|
||||
f"The input method should be an instance of the child class "
|
||||
f"of `UserInputBase`, but got {type(input_method)} instead.",
|
||||
)
|
||||
cls._input_method = input_method
|
||||
|
||||
async def handle_interrupt(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> Msg:
|
||||
"""The post-processing logic when the reply is interrupted by the
|
||||
user or something else."""
|
||||
raise NotImplementedError(
|
||||
f"The handle_interrupt function is not implemented in "
|
||||
f"{self.__class__.__name__}",
|
||||
)
|
||||
|
||||
async def observe(self, msg: Msg | list[Msg] | None) -> None:
|
||||
"""Observe the message(s) from the other agents or the environment."""
|
||||
@@ -1,411 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The user input related classes."""
|
||||
import json.decoder
|
||||
import time
|
||||
from abc import abstractmethod
|
||||
from dataclasses import dataclass
|
||||
from queue import Queue
|
||||
from threading import Event
|
||||
from typing import Any, Type, List
|
||||
|
||||
import jsonschema
|
||||
import requests
|
||||
import shortuuid
|
||||
import socketio
|
||||
from pydantic import BaseModel
|
||||
import json5
|
||||
|
||||
from .. import _config
|
||||
from .._logging import logger
|
||||
from ..message import (
|
||||
TextBlock,
|
||||
VideoBlock,
|
||||
AudioBlock,
|
||||
ImageBlock,
|
||||
)
|
||||
|
||||
|
||||
@dataclass
|
||||
class UserInputData:
|
||||
"""The user input data."""
|
||||
|
||||
blocks_input: List[TextBlock | ImageBlock | AudioBlock | VideoBlock] = None
|
||||
"""The text input from the user"""
|
||||
|
||||
structured_input: dict[str, Any] | None = None
|
||||
"""The structured input from the user"""
|
||||
|
||||
|
||||
class UserInputBase:
|
||||
"""The base class used to handle the user input from different sources."""
|
||||
|
||||
@abstractmethod
|
||||
async def __call__(
|
||||
self,
|
||||
agent_id: str,
|
||||
agent_name: str,
|
||||
*args: Any,
|
||||
structured_model: Type[BaseModel] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> UserInputData:
|
||||
"""The user input method, which returns the user input and the
|
||||
required structured data.
|
||||
|
||||
Args:
|
||||
agent_id (`str`):
|
||||
The agent identifier.
|
||||
agent_name (`str`):
|
||||
The agent name.
|
||||
structured_model (`Type[BaseModel] | None`, optional):
|
||||
A base model class that defines the structured input format.
|
||||
|
||||
Returns:
|
||||
`UserInputData`:
|
||||
The user input data.
|
||||
"""
|
||||
|
||||
|
||||
class TerminalUserInput(UserInputBase):
|
||||
"""The terminal user input."""
|
||||
|
||||
def __init__(self, input_hint: str = "User Input: ") -> None:
|
||||
"""Initialize the terminal user input with a hint."""
|
||||
self.input_hint = input_hint
|
||||
|
||||
async def __call__(
|
||||
self,
|
||||
agent_id: str,
|
||||
agent_name: str,
|
||||
*args: Any,
|
||||
structured_model: Type[BaseModel] | None = None,
|
||||
**kwargs: Any,
|
||||
) -> UserInputData:
|
||||
"""Handle the user input from the terminal.
|
||||
|
||||
Args:
|
||||
agent_id (`str`):
|
||||
The agent identifier.
|
||||
agent_name (`str`):
|
||||
The agent name.
|
||||
structured_model (`Type[BaseModel] | None`, optional):
|
||||
A base model class that defines the structured input format.
|
||||
|
||||
Returns:
|
||||
`UserInputData`:
|
||||
The user input data.
|
||||
"""
|
||||
|
||||
text_input = input(self.input_hint)
|
||||
|
||||
structured_input = None
|
||||
if structured_model is not None:
|
||||
structured_input = {}
|
||||
|
||||
json_schema = structured_model.model_json_schema()
|
||||
required = json_schema.get("required", [])
|
||||
print("Structured input (press Enter to skip for optional):)")
|
||||
|
||||
for key, item in json_schema.get("properties").items():
|
||||
requirements = {**item}
|
||||
requirements.pop("title")
|
||||
|
||||
while True:
|
||||
res = input(f"\t{key} ({requirements}): ")
|
||||
|
||||
if res == "":
|
||||
if key in required:
|
||||
print(f"Key {key} is required.")
|
||||
continue
|
||||
|
||||
res = item.get("default", None)
|
||||
|
||||
if item.get("type").lower() == "integer":
|
||||
try:
|
||||
res = json5.loads(res)
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
print(
|
||||
"\033[31mInvalid input with error:\n"
|
||||
"```\n"
|
||||
f"{e}\n"
|
||||
"```\033[0m",
|
||||
)
|
||||
continue
|
||||
|
||||
try:
|
||||
jsonschema.validate(res, item)
|
||||
structured_input[key] = res
|
||||
break
|
||||
except jsonschema.ValidationError as e:
|
||||
print(
|
||||
f"\033[31mValidation error:\n```\n{e}\n```\033[0m",
|
||||
)
|
||||
time.sleep(0.5)
|
||||
|
||||
return UserInputData(
|
||||
blocks_input=[TextBlock(type="text", text=text_input)],
|
||||
structured_input=structured_input,
|
||||
)
|
||||
|
||||
|
||||
class StudioUserInput(UserInputBase):
|
||||
"""The class that host the user input on the AgentScope Studio."""
|
||||
|
||||
_websocket_namespace: str = "/python"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
studio_url: str,
|
||||
run_id: str,
|
||||
max_retries: int = 3,
|
||||
reconnect_attempts: int = 3,
|
||||
reconnection_delay: int = 1,
|
||||
reconnection_delay_max: int = 5,
|
||||
) -> None:
|
||||
"""Initialize the StudioUserInput object.
|
||||
|
||||
Args:
|
||||
studio_url (`str`):
|
||||
The URL of the AgentScope Studio.
|
||||
run_id (`str`):
|
||||
The current run identity.
|
||||
max_retries (`int`, defaults to `3`):
|
||||
The maximum number of retries to get user input.
|
||||
"""
|
||||
self._is_connected = False
|
||||
self._is_reconnecting = False
|
||||
|
||||
self.studio_url = studio_url
|
||||
self.run_id = run_id
|
||||
self.max_retries = max_retries
|
||||
|
||||
# Init Websocket
|
||||
self.sio = socketio.Client(
|
||||
reconnection=True,
|
||||
reconnection_attempts=reconnect_attempts,
|
||||
reconnection_delay=reconnection_delay,
|
||||
reconnection_delay_max=reconnection_delay_max,
|
||||
)
|
||||
self.input_queues = {}
|
||||
self.input_events = {}
|
||||
|
||||
@self.sio.on("connect", namespace=self._websocket_namespace)
|
||||
def on_connect() -> None:
|
||||
self._is_connected = True
|
||||
logger.info(
|
||||
'Connected to AgentScope Studio at "%s" with '
|
||||
'run name "%s".',
|
||||
self.studio_url,
|
||||
run_id,
|
||||
)
|
||||
logger.info(
|
||||
"View the run at: %s/dashboard/projects/%s",
|
||||
self.studio_url,
|
||||
_config.project,
|
||||
)
|
||||
|
||||
@self.sio.on("disconnect", namespace=self._websocket_namespace)
|
||||
def on_disconnect() -> None:
|
||||
self._is_connected = False
|
||||
logger.info(
|
||||
"Disconnected from AgentScope Studio at %s",
|
||||
self.studio_url,
|
||||
)
|
||||
|
||||
@self.sio.on("reconnect", namespace=self._websocket_namespace)
|
||||
def on_reconnect(attempt_number: int) -> None:
|
||||
self._is_connected = True
|
||||
self._is_reconnecting = False
|
||||
logger.info(
|
||||
"Reconnected to AgentScope Studio at %s with run_id %s after "
|
||||
"%d attempts",
|
||||
self.studio_url,
|
||||
self.run_id,
|
||||
attempt_number,
|
||||
)
|
||||
|
||||
@self.sio.on("reconnect_attempt", namespace=self._websocket_namespace)
|
||||
def on_reconnect_attempt(attempt_number: int) -> None:
|
||||
self._is_reconnecting = True
|
||||
logger.info(
|
||||
"Attempting to reconnect to AgentScope Studio at %s "
|
||||
"(attempt %d)",
|
||||
self.studio_url,
|
||||
attempt_number,
|
||||
)
|
||||
|
||||
@self.sio.on("reconnect_failed", namespace=self._websocket_namespace)
|
||||
def on_reconnect_failed() -> None:
|
||||
self._is_reconnecting = False
|
||||
logger.error(
|
||||
"Failed to reconnect to AgentScope Studio at %s",
|
||||
self.studio_url,
|
||||
)
|
||||
|
||||
@self.sio.on("reconnect_error", namespace=self._websocket_namespace)
|
||||
def on_reconnect_error(error: Any) -> None:
|
||||
logger.error(
|
||||
"Error while reconnecting to AgentScope Studio at %s: %s",
|
||||
self.studio_url,
|
||||
str(error),
|
||||
)
|
||||
|
||||
# The AgentScope Studio backend send the "sendUserInput" event to
|
||||
# the current python run
|
||||
@self.sio.on("forwardUserInput", namespace=self._websocket_namespace)
|
||||
def receive_user_input(
|
||||
request_id: str,
|
||||
blocks_input: List[
|
||||
TextBlock | ImageBlock | AudioBlock | VideoBlock
|
||||
],
|
||||
structured_input: dict[str, Any],
|
||||
) -> None:
|
||||
if request_id in self.input_queues:
|
||||
self.input_queues[request_id].put(
|
||||
UserInputData(
|
||||
blocks_input=blocks_input,
|
||||
structured_input=structured_input,
|
||||
),
|
||||
)
|
||||
self.input_events[request_id].set()
|
||||
|
||||
try:
|
||||
self.sio.connect(
|
||||
f"{self.studio_url}",
|
||||
namespaces=["/python"],
|
||||
auth={"run_id": self.run_id},
|
||||
)
|
||||
except Exception as e:
|
||||
raise RuntimeError(
|
||||
f"Failed to connect to AgentScope Studio at {self.studio_url}",
|
||||
) from e
|
||||
|
||||
def _ensure_connected(
|
||||
self,
|
||||
timeout: float = 30.0,
|
||||
check_interval: float = 5.0,
|
||||
) -> None:
|
||||
"""Ensure the connection is established or wait for reconnection.
|
||||
|
||||
Args:
|
||||
timeout (`float`):
|
||||
Maximum time to wait for reconnection in seconds. Defaults
|
||||
to 30.0.
|
||||
check_interval (`float`):
|
||||
Interval between connection checks in seconds. Defaults to 1.0.
|
||||
|
||||
Raises:
|
||||
`RuntimeError`:
|
||||
If connection cannot be established within timeout.
|
||||
"""
|
||||
if self._is_connected:
|
||||
return
|
||||
|
||||
if self._is_reconnecting:
|
||||
start_time = time.time()
|
||||
while self._is_reconnecting:
|
||||
# Check timeout
|
||||
elapsed_time = time.time() - start_time
|
||||
if elapsed_time > timeout:
|
||||
raise RuntimeError(
|
||||
f"Reconnection timeout after {elapsed_time} seconds",
|
||||
)
|
||||
|
||||
# Log status
|
||||
logger.info(
|
||||
"Waiting for reconnection... (%.1fs / %.1fs)",
|
||||
elapsed_time,
|
||||
timeout,
|
||||
)
|
||||
|
||||
# Wait for next check
|
||||
time.sleep(check_interval)
|
||||
|
||||
# After reconnection attempt completed, check final status
|
||||
if self._is_connected:
|
||||
return
|
||||
|
||||
# Not connected and not reconnecting
|
||||
raise RuntimeError(
|
||||
f"Not connected to AgentScope Studio at {self.studio_url}.",
|
||||
)
|
||||
|
||||
async def __call__( # type: ignore[override]
|
||||
self,
|
||||
agent_id: str,
|
||||
agent_name: str,
|
||||
*args: Any,
|
||||
structured_model: Type[BaseModel] | None = None,
|
||||
) -> UserInputData:
|
||||
"""Get the user input from AgentScope Studio.
|
||||
|
||||
Args:
|
||||
agent_id (`str`):
|
||||
The identity of the agent.
|
||||
agent_name (`str`):
|
||||
The name of the agent.
|
||||
structured_model (`Type[BaseModel] | None`, optional):
|
||||
The base model class of the structured input.
|
||||
|
||||
Raises:
|
||||
`RuntimeError`:
|
||||
Failed to get user input from AgentScope Studio.
|
||||
|
||||
Returns:
|
||||
`UserInputData`:
|
||||
The user input.
|
||||
"""
|
||||
self._ensure_connected()
|
||||
|
||||
request_id = shortuuid.uuid()
|
||||
|
||||
self.input_queues[request_id] = Queue()
|
||||
self.input_events[request_id] = Event()
|
||||
|
||||
if structured_model is None:
|
||||
structured_input = None
|
||||
else:
|
||||
structured_input = structured_model.model_json_schema()
|
||||
|
||||
n_retry = 0
|
||||
while True:
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{self.studio_url}/trpc/requestUserInput",
|
||||
json={
|
||||
"requestId": request_id,
|
||||
"runId": self.run_id,
|
||||
"agentId": agent_id,
|
||||
"agentName": agent_name,
|
||||
"structuredInput": structured_input,
|
||||
},
|
||||
)
|
||||
response.raise_for_status()
|
||||
break
|
||||
except Exception as e:
|
||||
if n_retry < self.max_retries:
|
||||
n_retry += 1
|
||||
continue
|
||||
|
||||
raise RuntimeError(
|
||||
"Failed to get user input from AgentScope Studio",
|
||||
) from e
|
||||
|
||||
try:
|
||||
self.input_events[request_id].wait()
|
||||
response_data = self.input_queues[request_id].get()
|
||||
return response_data
|
||||
|
||||
finally:
|
||||
self.input_queues.pop(request_id, None)
|
||||
self.input_events.pop(request_id, None)
|
||||
|
||||
def __del__(self) -> None:
|
||||
"""Cleanup socket connection when object it destroyed"""
|
||||
try:
|
||||
self.sio.disconnect()
|
||||
except Exception as e:
|
||||
logger.error(
|
||||
"Failed to disconnect from AgentScope Studio at %s: %s",
|
||||
self.studio_url,
|
||||
str(e),
|
||||
)
|
||||
@@ -1,27 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""The embedding module in agentscope."""
|
||||
|
||||
from ._embedding_base import EmbeddingModelBase
|
||||
from ._embedding_usage import EmbeddingUsage
|
||||
from ._embedding_response import EmbeddingResponse
|
||||
from ._dashscope_embedding import DashScopeTextEmbedding
|
||||
from ._dashscope_multimodal_embedding import DashScopeMultiModalEmbedding
|
||||
from ._openai_embedding import OpenAITextEmbedding
|
||||
from ._gemini_embedding import GeminiTextEmbedding
|
||||
from ._ollama_embedding import OllamaTextEmbedding
|
||||
from ._cache_base import EmbeddingCacheBase
|
||||
from ._file_cache import FileEmbeddingCache
|
||||
|
||||
|
||||
__all__ = [
|
||||
"EmbeddingModelBase",
|
||||
"EmbeddingUsage",
|
||||
"EmbeddingResponse",
|
||||
"DashScopeTextEmbedding",
|
||||
"DashScopeMultiModalEmbedding",
|
||||
"OpenAITextEmbedding",
|
||||
"GeminiTextEmbedding",
|
||||
"OllamaTextEmbedding",
|
||||
"EmbeddingCacheBase",
|
||||
"FileEmbeddingCache",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user