diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b7fef5f9..9b464b8f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,7 +2,7 @@ // README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile { "name": "ten_agent_dev", - "image": "ghcr.io/ten-framework/ten_agent_build:0.3.4", + "image": "ghcr.io/ten-framework/ten_agent_build:0.4.10", "customizations": { "vscode": { "extensions": [ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000..9e7724fd --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,40 @@ +name: CI + +on: + pull_request: + branches: [ "main" ] + paths-ignore: + - ".devcontainer/**" + - ".github/**" + - "!.github/workflows/build-docker.yaml" + - ".vscode/**" + - "docs/**" + - "**.md" + workflow_dispatch: + +jobs: + ci: + runs-on: ubuntu-latest + container: + image: ghcr.io/ten-framework/ten_agent_build:0.4.10 + strategy: + matrix: + agent: [agents/examples/default, agents/examples/demo] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: "0" + submodules: "true" + + - name: Use agent + run: | + git config --global --add safe.directory $(pwd) + task use AGENT=${{ matrix.agent }} + + - name: Run tests + run: | + task test -- -s -v + + # - name: Run lint + # run: | + # task lint diff --git a/.gitignore b/.gitignore index 69da8967..28b3b623 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,7 @@ agoradns.dat agorartmdns.dat agora_rtm_cache.db agorareport.dat -bin/ +server/bin/ /BUILD.gn .cache/ /compile_commands.json diff --git a/Dockerfile b/Dockerfile index c89fba60..76bda6be 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM ghcr.io/ten-framework/ten_agent_build:0.3.4 AS builder +FROM ghcr.io/ten-framework/ten_agent_build:0.4.10 AS builder ARG SESSION_CONTROL_CONF=session_control.conf diff --git a/Taskfile.yml b/Taskfile.yml index 28e11ffd..4e01ee1e 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -69,7 +69,11 @@ tasks: dir: ./agents internal: true cmds: - - rm -rf manifest.json property.json manifest-lock.json bin/main bin/worker out .release ten_packages/system/ten_runtime* ten_packages/system/agora_rtc_sdk ten_packages/system/azure_speech_sdk ten_packages/system/nlohmann_json ten_packages/extension/agora_rtc ten_packages/extension/agora_rtm ten_packages/extension/agora_sess_ctrl ten_packages/extension/azure_tts ten_packages/extension/py_init_extension_cpp + - rm -rf manifest.json property.json manifest-lock.json bin/main bin/worker out .release ten_packages/system ten_packages/system/agora_rtc_sdk ten_packages/system/azure_speech_sdk ten_packages/system/nlohmann_json ten_packages/extension/agora_rtc ten_packages/extension/agora_rtm ten_packages/extension/agora_sess_ctrl ten_packages/extension/azure_tts ten_packages/addon_loader + - find . -type d -name .pytest_cache -exec rm -rf {} \; || true + - find . -type d -name __pycache__ -exec rm -rf {} \; || true + - find . -type d -name .ten -exec rm -rf {} \; || true + - find . -name .coverage -exec rm -f {} \; || true clean-server: desc: clean up server @@ -77,3 +81,40 @@ tasks: internal: true cmds: - rm -rf bin + + test: + desc: run tests + cmds: + - task: test-agent-extensions + - task: test-server + + test-server: + desc: test server + dir: ./server + internal: true + cmds: + - go test -v ./... + + test-agent-extensions: + desc: run standalone testing of extensions + internal: true + env: + PYTHONPATH: "{{.USER_WORKING_DIR}}:{{.USER_WORKING_DIR}}/agents/ten_packages/system/ten_runtime_python/lib:{{.USER_WORKING_DIR}}/agents/ten_packages/system/ten_runtime_python/interface:{{.USER_WORKING_DIR}}/agents/ten_packages/system/ten_ai_base/interface" + vars: + EXTENSIONS: + sh: 'find agents/ten_packages/extension -type d -exec test -d "{}/tests" \; -print' + cmds: + - for: { var: EXTENSIONS } + task: test-extension + vars: + EXTENSION: '{{ .ITEM }}' + + test-extension: + desc: run standalone testing of one single extension + vars: + EXTENSION: '{{.EXTENSION| default "agents/ten_packages/extension/elevenlabs_tts_python"}}' + env: + PYTHONPATH: "{{.USER_WORKING_DIR}}:{{.USER_WORKING_DIR}}/agents/ten_packages/system/ten_runtime_python/lib:{{.USER_WORKING_DIR}}/agents/ten_packages/system/ten_runtime_python/interface:{{.USER_WORKING_DIR}}/agents/ten_packages/system/ten_ai_base/interface" + dotenv: ['.env'] + cmds: + - cd {{.EXTENSION}} && tman -y install --standalone && ./tests/bin/start {{ .CLI_ARGS }} diff --git a/agents/.gitignore b/agents/.gitignore index b7e793bf..b0f7ab36 100644 --- a/agents/.gitignore +++ b/agents/.gitignore @@ -9,12 +9,15 @@ ten_packages/system/agora_rtc_sdk ten_packages/system/azure_speech_sdk ten_packages/system/nlohmann_json ten_packages/system/ten_runtime* +ten_packages/system ten_packages/addon_loader .ten agoradns.dat agorareport.dat agorartmreport.dat -bin/ +agora_cache.db +bin/man +bin/worker /BUILD.gn .cache/ /compile_commands.json diff --git a/agents/examples/default/manifest.json b/agents/examples/default/manifest.json index a4684d3e..5fd85f4f 100644 --- a/agents/examples/default/manifest.json +++ b/agents/examples/default/manifest.json @@ -1,37 +1,37 @@ { "type": "app", "name": "agent_demo", - "version": "0.6.0", + "version": "0.8.0", "dependencies": [ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" - }, - { - "type": "extension", - "name": "py_init_extension_cpp", - "version": "0.6" + "version": "0.8" }, { "type": "extension", "name": "agora_rtc", - "version": "=0.10.2" + "version": "=0.11.4" }, { "type": "extension", "name": "agora_sess_ctrl", - "version": "=0.4.1" + "version": "=0.4.2" }, { "type": "system", "name": "azure_speech_sdk", "version": "1.38.0" }, + { + "type": "system", + "name": "ten_ai_base", + "version": "0.2" + }, { "type": "extension", "name": "azure_tts", - "version": "=0.7.2" + "version": "=0.8.0" }, { "type": "extension", diff --git a/agents/examples/demo/manifest.json b/agents/examples/demo/manifest.json index 8491519c..5a0c7ac5 100644 --- a/agents/examples/demo/manifest.json +++ b/agents/examples/demo/manifest.json @@ -1,37 +1,37 @@ { "type": "app", "name": "agent_demo", - "version": "0.6.0", + "version": "0.8.0", "dependencies": [ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" - }, - { - "type": "extension", - "name": "py_init_extension_cpp", - "version": "0.6" + "version": "0.8" }, { "type": "extension", "name": "agora_rtc", - "version": "=0.10.2" + "version": "=0.11.4" }, { "type": "extension", "name": "agora_sess_ctrl", - "version": "=0.4.1" + "version": "=0.4.2" }, { "type": "system", "name": "azure_speech_sdk", "version": "1.38.0" }, + { + "type": "system", + "name": "ten_ai_base", + "version": "0.2" + }, { "type": "extension", "name": "azure_tts", - "version": "=0.7.2" + "version": "=0.8.0" }, { "type": "extension", diff --git a/agents/examples/experimental/manifest.json b/agents/examples/experimental/manifest.json index 7c7506b6..805f395c 100644 --- a/agents/examples/experimental/manifest.json +++ b/agents/examples/experimental/manifest.json @@ -1,37 +1,37 @@ { "type": "app", "name": "agent_experimental", - "version": "0.6.0", + "version": "0.8.0", "dependencies": [ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" - }, - { - "type": "extension", - "name": "py_init_extension_cpp", - "version": "0.6" + "version": "0.8" }, { "type": "extension", "name": "agora_rtc", - "version": "=0.10.2" + "version": "=0.11.4" }, { "type": "extension", "name": "agora_sess_ctrl", - "version": "=0.4.1" + "version": "=0.4.2" }, { "type": "system", "name": "azure_speech_sdk", "version": "1.38.0" }, + { + "type": "system", + "name": "ten_ai_base", + "version": "0.2" + }, { "type": "extension", "name": "azure_tts", - "version": "=0.7.2" + "version": "=0.8.0" }, { "type": "extension", diff --git a/agents/ten_packages/bak/litellm_python/manifest.json b/agents/ten_packages/bak/litellm_python/manifest.json index ab382bec..19e1cda1 100644 --- a/agents/ten_packages/bak/litellm_python/manifest.json +++ b/agents/ten_packages/bak/litellm_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/agora_rtm_wrapper/manifest.json b/agents/ten_packages/extension/agora_rtm_wrapper/manifest.json index deb4ee1b..8bb8ace6 100644 --- a/agents/ten_packages/extension/agora_rtm_wrapper/manifest.json +++ b/agents/ten_packages/extension/agora_rtm_wrapper/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/aliyun_analyticdb_vector_storage/manifest.json b/agents/ten_packages/extension/aliyun_analyticdb_vector_storage/manifest.json index 3ba20fdc..0463972f 100644 --- a/agents/ten_packages/extension/aliyun_analyticdb_vector_storage/manifest.json +++ b/agents/ten_packages/extension/aliyun_analyticdb_vector_storage/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/aliyun_text_embedding/manifest.json b/agents/ten_packages/extension/aliyun_text_embedding/manifest.json index c7cba56f..2164f24d 100644 --- a/agents/ten_packages/extension/aliyun_text_embedding/manifest.json +++ b/agents/ten_packages/extension/aliyun_text_embedding/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/bedrock_llm_python/manifest.json b/agents/ten_packages/extension/bedrock_llm_python/manifest.json index 0c693989..eca39e1f 100644 --- a/agents/ten_packages/extension/bedrock_llm_python/manifest.json +++ b/agents/ten_packages/extension/bedrock_llm_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/bingsearch_tool_python/BUILD.gn b/agents/ten_packages/extension/bingsearch_tool_python/BUILD.gn deleted file mode 100644 index 68d4594a..00000000 --- a/agents/ten_packages/extension/bingsearch_tool_python/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("bingsearch_tool_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/bingsearch_tool_python/manifest.json b/agents/ten_packages/extension/bingsearch_tool_python/manifest.json index 600f0039..4caef2c1 100644 --- a/agents/ten_packages/extension/bingsearch_tool_python/manifest.json +++ b/agents/ten_packages/extension/bingsearch_tool_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/bytedance_tts/BUILD.gn b/agents/ten_packages/extension/bytedance_tts/BUILD.gn deleted file mode 100644 index 5275c1f5..00000000 --- a/agents/ten_packages/extension/bytedance_tts/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("bytedance_tts") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/bytedance_tts/manifest.json b/agents/ten_packages/extension/bytedance_tts/manifest.json index 01948223..580bf5da 100644 --- a/agents/ten_packages/extension/bytedance_tts/manifest.json +++ b/agents/ten_packages/extension/bytedance_tts/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/bytedance_tts/tests/test_basic.py b/agents/ten_packages/extension/bytedance_tts/tests/test_basic.py deleted file mode 100644 index 96bf9172..00000000 --- a/agents/ten_packages/extension/bytedance_tts/tests/test_basic.py +++ /dev/null @@ -1,53 +0,0 @@ -# -# Copyright © 2024 Agora -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0, with certain conditions. -# Refer to the "LICENSE" file in the root directory for more information. -# -from pathlib import Path -from ten import ExtensionTester, TenEnvTester, AudioFrame, Data -import os - - -class ExtensionTesterBasic(ExtensionTester): - def __init__(self): - super().__init__() - self.dump_pcm = True - - def on_audio_frame( - self, ten_env_tester: TenEnvTester, audio_frame: AudioFrame - ) -> None: - if self.dump_pcm: - buf = audio_frame.lock_buf() - with open("test.pcm", "ab") as f: - f.write(buf) - - audio_frame.unlock_buf() - - def on_start(self, ten_env: TenEnvTester) -> None: - # Text to be synthesized. - data = Data.create("text_data") - data.set_property_string( - "text", - """ - 传入1时表示启用。新版时间戳参数,可用来替换with_frontend和frontend_type, - 可返回原文本的时间戳,而非TN后文本,即保留原文中的阿拉伯数字或者特殊符号等。 - 注意:原文本中的多个标点连用或者空格依然会被处理,但不影响时间戳连贯性。 - """, - ) - data.set_property_bool("end_of_segment", True) - ten_env.send_data(data) - - print("tester on_start_done") - ten_env.on_start_done() - - -def test_basic(): - env = os.environ.copy() - env["BYTEDANCE_TTS_APPID"] = "your appid" - env["BYTEDANCE_TTS_TOKEN"] = "your token" - - tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") - tester.run() diff --git a/agents/ten_packages/extension/cartesia_tts/BUILD.gn b/agents/ten_packages/extension/cartesia_tts/BUILD.gn deleted file mode 100644 index 4e409853..00000000 --- a/agents/ten_packages/extension/cartesia_tts/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("cartesia_tts") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/cartesia_tts/manifest.json b/agents/ten_packages/extension/cartesia_tts/manifest.json index df2b50a4..43ae8ba9 100644 --- a/agents/ten_packages/extension/cartesia_tts/manifest.json +++ b/agents/ten_packages/extension/cartesia_tts/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/cartesia_tts/tests/bin/start b/agents/ten_packages/extension/cartesia_tts/tests/bin/start new file mode 100755 index 00000000..04d784ea --- /dev/null +++ b/agents/ten_packages/extension/cartesia_tts/tests/bin/start @@ -0,0 +1,21 @@ +#!/bin/bash + +set -e + +cd "$(dirname "${BASH_SOURCE[0]}")/../.." + +export PYTHONPATH=.ten/app:.ten/app/ten_packages/system/ten_runtime_python/lib:.ten/app/ten_packages/system/ten_runtime_python/interface:.ten/app/ten_packages/system/ten_ai_base/interface:$PYTHONPATH + +# If the Python app imports some modules that are compiled with a different +# version of libstdc++ (ex: PyTorch), the Python app may encounter confusing +# errors. To solve this problem, we can preload the correct version of +# libstdc++. +# +# export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6 +# +# Another solution is to make sure the module 'ten_runtime_python' is imported +# _after_ the module that requires another version of libstdc++ is imported. +# +# Refer to https://github.com/pytorch/pytorch/issues/102360?from_wecom=1#issuecomment-1708989096 + +pytest tests/ "$@" \ No newline at end of file diff --git a/agents/ten_packages/extension/cartesia_tts/tests/conftest.py b/agents/ten_packages/extension/cartesia_tts/tests/conftest.py new file mode 100644 index 00000000..9a2175e3 --- /dev/null +++ b/agents/ten_packages/extension/cartesia_tts/tests/conftest.py @@ -0,0 +1,36 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import pytest +import sys +import os +from ten import ( + unregister_all_addons_and_cleanup, +) + + +@pytest.fixture(scope="session", autouse=True) +def global_setup_and_teardown(): + # Set the environment variable. + os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] = "true" + + # Verify the environment variable is correctly set. + if ( + "TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE" not in os.environ + or os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] != "true" + ): + print( + "Failed to set TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE", + file=sys.stderr, + ) + sys.exit(1) + + # Yield control to the test; after the test execution is complete, continue + # with the teardown process. + yield + + # Teardown part. + unregister_all_addons_and_cleanup() \ No newline at end of file diff --git a/agents/ten_packages/extension/cartesia_tts/tests/test_basic.py b/agents/ten_packages/extension/cartesia_tts/tests/test_basic.py index cdd9193b..a8978b39 100644 --- a/agents/ten_packages/extension/cartesia_tts/tests/test_basic.py +++ b/agents/ten_packages/extension/cartesia_tts/tests/test_basic.py @@ -31,6 +31,5 @@ def on_start(self, ten_env: TenEnvTester) -> None: def test_basic(): tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") + tester.set_test_mode_single("cartesia_tts") tester.run() diff --git a/agents/ten_packages/extension/cosy_tts_python/BUILD.gn b/agents/ten_packages/extension/cosy_tts_python/BUILD.gn deleted file mode 100644 index 40bb6dd4..00000000 --- a/agents/ten_packages/extension/cosy_tts_python/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("cosy_tts_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/cosy_tts_python/manifest.json b/agents/ten_packages/extension/cosy_tts_python/manifest.json index 30a3da78..06da42cd 100644 --- a/agents/ten_packages/extension/cosy_tts_python/manifest.json +++ b/agents/ten_packages/extension/cosy_tts_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/cosy_tts_python/tests/bin/start b/agents/ten_packages/extension/cosy_tts_python/tests/bin/start new file mode 100755 index 00000000..04d784ea --- /dev/null +++ b/agents/ten_packages/extension/cosy_tts_python/tests/bin/start @@ -0,0 +1,21 @@ +#!/bin/bash + +set -e + +cd "$(dirname "${BASH_SOURCE[0]}")/../.." + +export PYTHONPATH=.ten/app:.ten/app/ten_packages/system/ten_runtime_python/lib:.ten/app/ten_packages/system/ten_runtime_python/interface:.ten/app/ten_packages/system/ten_ai_base/interface:$PYTHONPATH + +# If the Python app imports some modules that are compiled with a different +# version of libstdc++ (ex: PyTorch), the Python app may encounter confusing +# errors. To solve this problem, we can preload the correct version of +# libstdc++. +# +# export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6 +# +# Another solution is to make sure the module 'ten_runtime_python' is imported +# _after_ the module that requires another version of libstdc++ is imported. +# +# Refer to https://github.com/pytorch/pytorch/issues/102360?from_wecom=1#issuecomment-1708989096 + +pytest tests/ "$@" \ No newline at end of file diff --git a/agents/ten_packages/extension/cosy_tts_python/tests/conftest.py b/agents/ten_packages/extension/cosy_tts_python/tests/conftest.py new file mode 100644 index 00000000..9a2175e3 --- /dev/null +++ b/agents/ten_packages/extension/cosy_tts_python/tests/conftest.py @@ -0,0 +1,36 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import pytest +import sys +import os +from ten import ( + unregister_all_addons_and_cleanup, +) + + +@pytest.fixture(scope="session", autouse=True) +def global_setup_and_teardown(): + # Set the environment variable. + os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] = "true" + + # Verify the environment variable is correctly set. + if ( + "TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE" not in os.environ + or os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] != "true" + ): + print( + "Failed to set TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE", + file=sys.stderr, + ) + sys.exit(1) + + # Yield control to the test; after the test execution is complete, continue + # with the teardown process. + yield + + # Teardown part. + unregister_all_addons_and_cleanup() \ No newline at end of file diff --git a/agents/ten_packages/extension/cosy_tts_python/tests/test_basic.py b/agents/ten_packages/extension/cosy_tts_python/tests/test_basic.py index cdd9193b..5b080057 100644 --- a/agents/ten_packages/extension/cosy_tts_python/tests/test_basic.py +++ b/agents/ten_packages/extension/cosy_tts_python/tests/test_basic.py @@ -31,6 +31,5 @@ def on_start(self, ten_env: TenEnvTester) -> None: def test_basic(): tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") + tester.set_test_mode_single("cosy_tts_python") tester.run() diff --git a/agents/ten_packages/extension/coze_python_async/BUILD.gn b/agents/ten_packages/extension/coze_python_async/BUILD.gn deleted file mode 100644 index dafb851d..00000000 --- a/agents/ten_packages/extension/coze_python_async/BUILD.gn +++ /dev/null @@ -1,18 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("coze_python_async") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/coze_python_async/manifest.json b/agents/ten_packages/extension/coze_python_async/manifest.json index 18379f4f..47c5b3ac 100644 --- a/agents/ten_packages/extension/coze_python_async/manifest.json +++ b/agents/ten_packages/extension/coze_python_async/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/deepgram_asr_python/manifest.json b/agents/ten_packages/extension/deepgram_asr_python/manifest.json index a6b96d85..a09d0077 100644 --- a/agents/ten_packages/extension/deepgram_asr_python/manifest.json +++ b/agents/ten_packages/extension/deepgram_asr_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/dify_python/BUILD.gn b/agents/ten_packages/extension/dify_python/BUILD.gn deleted file mode 100644 index 24b67c52..00000000 --- a/agents/ten_packages/extension/dify_python/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("dify_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/dify_python/manifest.json b/agents/ten_packages/extension/dify_python/manifest.json index 89331544..ff7f1501 100644 --- a/agents/ten_packages/extension/dify_python/manifest.json +++ b/agents/ten_packages/extension/dify_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/dify_python/tests/test_basic.py b/agents/ten_packages/extension/dify_python/tests/test_basic.py deleted file mode 100644 index cdd9193b..00000000 --- a/agents/ten_packages/extension/dify_python/tests/test_basic.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright © 2024 Agora -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0, with certain conditions. -# Refer to the "LICENSE" file in the root directory for more information. -# -from pathlib import Path -from ten import ExtensionTester, TenEnvTester, Cmd, CmdResult, StatusCode - - -class ExtensionTesterBasic(ExtensionTester): - def check_hello(self, ten_env: TenEnvTester, result: CmdResult): - statusCode = result.get_status_code() - print("receive hello_world, status:" + str(statusCode)) - - if statusCode == StatusCode.OK: - ten_env.stop_test() - - def on_start(self, ten_env: TenEnvTester) -> None: - new_cmd = Cmd.create("hello_world") - - print("send hello_world") - ten_env.send_cmd( - new_cmd, - lambda ten_env, result, _: self.check_hello(ten_env, result), - ) - - print("tester on_start_done") - ten_env.on_start_done() - - -def test_basic(): - tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") - tester.run() diff --git a/agents/ten_packages/extension/elevenlabs_tts/manifest.json b/agents/ten_packages/extension/elevenlabs_tts/manifest.json index 0e0a25d9..47e868b1 100644 --- a/agents/ten_packages/extension/elevenlabs_tts/manifest.json +++ b/agents/ten_packages/extension/elevenlabs_tts/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/elevenlabs_tts_python/BUILD.gn b/agents/ten_packages/extension/elevenlabs_tts_python/BUILD.gn deleted file mode 100644 index 008eed3d..00000000 --- a/agents/ten_packages/extension/elevenlabs_tts_python/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("elevenlabs_tts_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/elevenlabs_tts_python/manifest.json b/agents/ten_packages/extension/elevenlabs_tts_python/manifest.json index b551367c..b50298b4 100644 --- a/agents/ten_packages/extension/elevenlabs_tts_python/manifest.json +++ b/agents/ten_packages/extension/elevenlabs_tts_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/elevenlabs_tts_python/tests/bin/start b/agents/ten_packages/extension/elevenlabs_tts_python/tests/bin/start new file mode 100755 index 00000000..04d784ea --- /dev/null +++ b/agents/ten_packages/extension/elevenlabs_tts_python/tests/bin/start @@ -0,0 +1,21 @@ +#!/bin/bash + +set -e + +cd "$(dirname "${BASH_SOURCE[0]}")/../.." + +export PYTHONPATH=.ten/app:.ten/app/ten_packages/system/ten_runtime_python/lib:.ten/app/ten_packages/system/ten_runtime_python/interface:.ten/app/ten_packages/system/ten_ai_base/interface:$PYTHONPATH + +# If the Python app imports some modules that are compiled with a different +# version of libstdc++ (ex: PyTorch), the Python app may encounter confusing +# errors. To solve this problem, we can preload the correct version of +# libstdc++. +# +# export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6 +# +# Another solution is to make sure the module 'ten_runtime_python' is imported +# _after_ the module that requires another version of libstdc++ is imported. +# +# Refer to https://github.com/pytorch/pytorch/issues/102360?from_wecom=1#issuecomment-1708989096 + +pytest tests/ "$@" \ No newline at end of file diff --git a/agents/ten_packages/extension/elevenlabs_tts_python/tests/conftest.py b/agents/ten_packages/extension/elevenlabs_tts_python/tests/conftest.py new file mode 100644 index 00000000..9a2175e3 --- /dev/null +++ b/agents/ten_packages/extension/elevenlabs_tts_python/tests/conftest.py @@ -0,0 +1,36 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import pytest +import sys +import os +from ten import ( + unregister_all_addons_and_cleanup, +) + + +@pytest.fixture(scope="session", autouse=True) +def global_setup_and_teardown(): + # Set the environment variable. + os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] = "true" + + # Verify the environment variable is correctly set. + if ( + "TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE" not in os.environ + or os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] != "true" + ): + print( + "Failed to set TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE", + file=sys.stderr, + ) + sys.exit(1) + + # Yield control to the test; after the test execution is complete, continue + # with the teardown process. + yield + + # Teardown part. + unregister_all_addons_and_cleanup() \ No newline at end of file diff --git a/agents/ten_packages/extension/elevenlabs_tts_python/tests/test_basic.py b/agents/ten_packages/extension/elevenlabs_tts_python/tests/test_basic.py index 61ebea9f..b3ad3d44 100644 --- a/agents/ten_packages/extension/elevenlabs_tts_python/tests/test_basic.py +++ b/agents/ten_packages/extension/elevenlabs_tts_python/tests/test_basic.py @@ -14,6 +14,7 @@ def check_hello(self, ten_env: TenEnvTester, result: CmdResult): print("receive hello_world, status:" + str(statusCode)) if statusCode == StatusCode.OK: + # TODO: move stop_test() to where the test passes ten_env.stop_test() def on_start(self, ten_env: TenEnvTester) -> None: @@ -31,6 +32,5 @@ def on_start(self, ten_env: TenEnvTester) -> None: def test_basic(): tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") + tester.set_test_mode_single("elevenlabs_tts_python") tester.run() diff --git a/agents/ten_packages/extension/fashionai/BUILD.gn b/agents/ten_packages/extension/fashionai/BUILD.gn deleted file mode 100644 index 4dd55d40..00000000 --- a/agents/ten_packages/extension/fashionai/BUILD.gn +++ /dev/null @@ -1,21 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("fashionai") { - package_kind = "extension" - - resources = [ - "__init__.py", - "manifest.json", - "property.json", - "src/__init__.py", - "src/addon.py", - "src/extension.py", - ] -} diff --git a/agents/ten_packages/extension/fashionai/manifest.json b/agents/ten_packages/extension/fashionai/manifest.json index 33f6ff95..eadb2cc2 100644 --- a/agents/ten_packages/extension/fashionai/manifest.json +++ b/agents/ten_packages/extension/fashionai/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/file_chunker/manifest.json b/agents/ten_packages/extension/file_chunker/manifest.json index 00370056..c777aae8 100644 --- a/agents/ten_packages/extension/file_chunker/manifest.json +++ b/agents/ten_packages/extension/file_chunker/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/fish_audio_tts/manifest.json b/agents/ten_packages/extension/fish_audio_tts/manifest.json index e0b76927..fb34e464 100644 --- a/agents/ten_packages/extension/fish_audio_tts/manifest.json +++ b/agents/ten_packages/extension/fish_audio_tts/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/gemini_llm_python/manifest.json b/agents/ten_packages/extension/gemini_llm_python/manifest.json index 67fa9bdf..34f9ef4e 100644 --- a/agents/ten_packages/extension/gemini_llm_python/manifest.json +++ b/agents/ten_packages/extension/gemini_llm_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/gemini_v2v_python/BUILD.gn b/agents/ten_packages/extension/gemini_v2v_python/BUILD.gn deleted file mode 100644 index f44affe0..00000000 --- a/agents/ten_packages/extension/gemini_v2v_python/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("gemini_v2v_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/gemini_v2v_python/manifest.json b/agents/ten_packages/extension/gemini_v2v_python/manifest.json index 27cfdacb..ab70a6a4 100644 --- a/agents/ten_packages/extension/gemini_v2v_python/manifest.json +++ b/agents/ten_packages/extension/gemini_v2v_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/glue_python_async/BUILD.gn b/agents/ten_packages/extension/glue_python_async/BUILD.gn deleted file mode 100644 index c0ccf4d5..00000000 --- a/agents/ten_packages/extension/glue_python_async/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("glue_python_async") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "log.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/glue_python_async/manifest.json b/agents/ten_packages/extension/glue_python_async/manifest.json index d3331ecb..c81d7eea 100644 --- a/agents/ten_packages/extension/glue_python_async/manifest.json +++ b/agents/ten_packages/extension/glue_python_async/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/glue_python_async/tests/test_basic.py b/agents/ten_packages/extension/glue_python_async/tests/test_basic.py deleted file mode 100644 index cdd9193b..00000000 --- a/agents/ten_packages/extension/glue_python_async/tests/test_basic.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright © 2024 Agora -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0, with certain conditions. -# Refer to the "LICENSE" file in the root directory for more information. -# -from pathlib import Path -from ten import ExtensionTester, TenEnvTester, Cmd, CmdResult, StatusCode - - -class ExtensionTesterBasic(ExtensionTester): - def check_hello(self, ten_env: TenEnvTester, result: CmdResult): - statusCode = result.get_status_code() - print("receive hello_world, status:" + str(statusCode)) - - if statusCode == StatusCode.OK: - ten_env.stop_test() - - def on_start(self, ten_env: TenEnvTester) -> None: - new_cmd = Cmd.create("hello_world") - - print("send hello_world") - ten_env.send_cmd( - new_cmd, - lambda ten_env, result, _: self.check_hello(ten_env, result), - ) - - print("tester on_start_done") - ten_env.on_start_done() - - -def test_basic(): - tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") - tester.run() diff --git a/agents/ten_packages/extension/http_server_python/manifest.json b/agents/ten_packages/extension/http_server_python/manifest.json index d0241346..795e0e98 100644 --- a/agents/ten_packages/extension/http_server_python/manifest.json +++ b/agents/ten_packages/extension/http_server_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/interrupt_detector/manifest.json b/agents/ten_packages/extension/interrupt_detector/manifest.json index 5c87b632..dc3412c6 100644 --- a/agents/ten_packages/extension/interrupt_detector/manifest.json +++ b/agents/ten_packages/extension/interrupt_detector/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/interrupt_detector_python/manifest.json b/agents/ten_packages/extension/interrupt_detector_python/manifest.json index 2579f8e4..262b0662 100644 --- a/agents/ten_packages/extension/interrupt_detector_python/manifest.json +++ b/agents/ten_packages/extension/interrupt_detector_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/llama_index_chat_engine/manifest.json b/agents/ten_packages/extension/llama_index_chat_engine/manifest.json index 5fe25a42..0da035e0 100644 --- a/agents/ten_packages/extension/llama_index_chat_engine/manifest.json +++ b/agents/ten_packages/extension/llama_index_chat_engine/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/message_collector/BUILD.gn b/agents/ten_packages/extension/message_collector/BUILD.gn deleted file mode 100644 index 82bdfae9..00000000 --- a/agents/ten_packages/extension/message_collector/BUILD.gn +++ /dev/null @@ -1,21 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("message_collector") { - package_kind = "extension" - - resources = [ - "__init__.py", - "manifest.json", - "property.json", - "src/__init__.py", - "src/addon.py", - "src/extension.py", - ] -} diff --git a/agents/ten_packages/extension/message_collector/manifest.json b/agents/ten_packages/extension/message_collector/manifest.json index 6fb60d50..baeddee9 100644 --- a/agents/ten_packages/extension/message_collector/manifest.json +++ b/agents/ten_packages/extension/message_collector/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/message_collector_rtm/BUILD.gn b/agents/ten_packages/extension/message_collector_rtm/BUILD.gn deleted file mode 100644 index 7a89eef0..00000000 --- a/agents/ten_packages/extension/message_collector_rtm/BUILD.gn +++ /dev/null @@ -1,22 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("message_collector_rtm") { - package_kind = "extension" - - resources = [ - "__init__.py", - "manifest.json", - "property.json", - "src/__init__.py", - "src/addon.py", - "src/extension.py", - "src/log.py", - ] -} diff --git a/agents/ten_packages/extension/message_collector_rtm/manifest.json b/agents/ten_packages/extension/message_collector_rtm/manifest.json index b130f21f..516a2923 100644 --- a/agents/ten_packages/extension/message_collector_rtm/manifest.json +++ b/agents/ten_packages/extension/message_collector_rtm/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/minimax_tts/manifest.json b/agents/ten_packages/extension/minimax_tts/manifest.json index 0d583283..8846415d 100644 --- a/agents/ten_packages/extension/minimax_tts/manifest.json +++ b/agents/ten_packages/extension/minimax_tts/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/minimax_tts_python/BUILD.gn b/agents/ten_packages/extension/minimax_tts_python/BUILD.gn deleted file mode 100644 index 02a50c6e..00000000 --- a/agents/ten_packages/extension/minimax_tts_python/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("minimax_tts_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/minimax_tts_python/manifest.json b/agents/ten_packages/extension/minimax_tts_python/manifest.json index bf9c2f02..4a4dfbcb 100644 --- a/agents/ten_packages/extension/minimax_tts_python/manifest.json +++ b/agents/ten_packages/extension/minimax_tts_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/minimax_tts_python/tests/bin/start b/agents/ten_packages/extension/minimax_tts_python/tests/bin/start new file mode 100755 index 00000000..04d784ea --- /dev/null +++ b/agents/ten_packages/extension/minimax_tts_python/tests/bin/start @@ -0,0 +1,21 @@ +#!/bin/bash + +set -e + +cd "$(dirname "${BASH_SOURCE[0]}")/../.." + +export PYTHONPATH=.ten/app:.ten/app/ten_packages/system/ten_runtime_python/lib:.ten/app/ten_packages/system/ten_runtime_python/interface:.ten/app/ten_packages/system/ten_ai_base/interface:$PYTHONPATH + +# If the Python app imports some modules that are compiled with a different +# version of libstdc++ (ex: PyTorch), the Python app may encounter confusing +# errors. To solve this problem, we can preload the correct version of +# libstdc++. +# +# export LD_PRELOAD=/lib/x86_64-linux-gnu/libstdc++.so.6 +# +# Another solution is to make sure the module 'ten_runtime_python' is imported +# _after_ the module that requires another version of libstdc++ is imported. +# +# Refer to https://github.com/pytorch/pytorch/issues/102360?from_wecom=1#issuecomment-1708989096 + +pytest tests/ "$@" \ No newline at end of file diff --git a/agents/ten_packages/extension/minimax_tts_python/tests/conftest.py b/agents/ten_packages/extension/minimax_tts_python/tests/conftest.py new file mode 100644 index 00000000..9a2175e3 --- /dev/null +++ b/agents/ten_packages/extension/minimax_tts_python/tests/conftest.py @@ -0,0 +1,36 @@ +# +# Copyright © 2025 Agora +# This file is part of TEN Framework, an open source project. +# Licensed under the Apache License, Version 2.0, with certain conditions. +# Refer to the "LICENSE" file in the root directory for more information. +# +import pytest +import sys +import os +from ten import ( + unregister_all_addons_and_cleanup, +) + + +@pytest.fixture(scope="session", autouse=True) +def global_setup_and_teardown(): + # Set the environment variable. + os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] = "true" + + # Verify the environment variable is correctly set. + if ( + "TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE" not in os.environ + or os.environ["TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE"] != "true" + ): + print( + "Failed to set TEN_DISABLE_ADDON_UNREGISTER_AFTER_APP_CLOSE", + file=sys.stderr, + ) + sys.exit(1) + + # Yield control to the test; after the test execution is complete, continue + # with the teardown process. + yield + + # Teardown part. + unregister_all_addons_and_cleanup() \ No newline at end of file diff --git a/agents/ten_packages/extension/minimax_tts_python/tests/test_basic.py b/agents/ten_packages/extension/minimax_tts_python/tests/test_basic.py index cdd9193b..fb639c32 100644 --- a/agents/ten_packages/extension/minimax_tts_python/tests/test_basic.py +++ b/agents/ten_packages/extension/minimax_tts_python/tests/test_basic.py @@ -31,6 +31,5 @@ def on_start(self, ten_env: TenEnvTester) -> None: def test_basic(): tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") + tester.set_test_mode_single("minimax_tts_python") tester.run() diff --git a/agents/ten_packages/extension/minimax_v2v_python/manifest.json b/agents/ten_packages/extension/minimax_v2v_python/manifest.json index d31df6c7..7c8f5122 100644 --- a/agents/ten_packages/extension/minimax_v2v_python/manifest.json +++ b/agents/ten_packages/extension/minimax_v2v_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/openai_chatgpt/manifest.json b/agents/ten_packages/extension/openai_chatgpt/manifest.json index 4e678221..e5b5b8d5 100644 --- a/agents/ten_packages/extension/openai_chatgpt/manifest.json +++ b/agents/ten_packages/extension/openai_chatgpt/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_go", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/openai_chatgpt_python/BUILD.gn b/agents/ten_packages/extension/openai_chatgpt_python/BUILD.gn deleted file mode 100644 index 0b03f3ef..00000000 --- a/agents/ten_packages/extension/openai_chatgpt_python/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("openai_chatgpt_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/openai_chatgpt_python/manifest.json b/agents/ten_packages/extension/openai_chatgpt_python/manifest.json index f71d0d76..eb875445 100644 --- a/agents/ten_packages/extension/openai_chatgpt_python/manifest.json +++ b/agents/ten_packages/extension/openai_chatgpt_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/openai_image_generate_tool/manifest.json b/agents/ten_packages/extension/openai_image_generate_tool/manifest.json index b240bcff..b3c4b84a 100644 --- a/agents/ten_packages/extension/openai_image_generate_tool/manifest.json +++ b/agents/ten_packages/extension/openai_image_generate_tool/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/openai_v2v_python/BUILD.gn b/agents/ten_packages/extension/openai_v2v_python/BUILD.gn deleted file mode 100644 index 10ce2da4..00000000 --- a/agents/ten_packages/extension/openai_v2v_python/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("openai_v2v_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/openai_v2v_python/manifest.json b/agents/ten_packages/extension/openai_v2v_python/manifest.json index a2a957fa..721d1aee 100644 --- a/agents/ten_packages/extension/openai_v2v_python/manifest.json +++ b/agents/ten_packages/extension/openai_v2v_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/polly_tts/BUILD.gn b/agents/ten_packages/extension/polly_tts/BUILD.gn deleted file mode 100644 index ddc17463..00000000 --- a/agents/ten_packages/extension/polly_tts/BUILD.gn +++ /dev/null @@ -1,18 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("polly_tts") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} \ No newline at end of file diff --git a/agents/ten_packages/extension/polly_tts/manifest.json b/agents/ten_packages/extension/polly_tts/manifest.json index 74181c21..5345c69c 100644 --- a/agents/ten_packages/extension/polly_tts/manifest.json +++ b/agents/ten_packages/extension/polly_tts/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/qwen_llm_python/manifest.json b/agents/ten_packages/extension/qwen_llm_python/manifest.json index 732da271..a4c9ae66 100644 --- a/agents/ten_packages/extension/qwen_llm_python/manifest.json +++ b/agents/ten_packages/extension/qwen_llm_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/transcribe_asr_python/manifest.json b/agents/ten_packages/extension/transcribe_asr_python/manifest.json index 810b2bb2..6d3ebc30 100644 --- a/agents/ten_packages/extension/transcribe_asr_python/manifest.json +++ b/agents/ten_packages/extension/transcribe_asr_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "api": { diff --git a/agents/ten_packages/extension/tsdb_firestore/BUILD.gn b/agents/ten_packages/extension/tsdb_firestore/BUILD.gn deleted file mode 100644 index a71d1642..00000000 --- a/agents/ten_packages/extension/tsdb_firestore/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("tsdb_firestore") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/tsdb_firestore/manifest.json b/agents/ten_packages/extension/tsdb_firestore/manifest.json index 5b74ee41..2a1cfc25 100644 --- a/agents/ten_packages/extension/tsdb_firestore/manifest.json +++ b/agents/ten_packages/extension/tsdb_firestore/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/vision_analyze_tool_python/BUILD.gn b/agents/ten_packages/extension/vision_analyze_tool_python/BUILD.gn deleted file mode 100644 index 4d5fcbab..00000000 --- a/agents/ten_packages/extension/vision_analyze_tool_python/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("vision_analyze_tool_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/vision_analyze_tool_python/manifest.json b/agents/ten_packages/extension/vision_analyze_tool_python/manifest.json index e087377a..84dd7f6e 100644 --- a/agents/ten_packages/extension/vision_analyze_tool_python/manifest.json +++ b/agents/ten_packages/extension/vision_analyze_tool_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/vision_analyze_tool_python/tests/test_basic.py b/agents/ten_packages/extension/vision_analyze_tool_python/tests/test_basic.py deleted file mode 100644 index cdd9193b..00000000 --- a/agents/ten_packages/extension/vision_analyze_tool_python/tests/test_basic.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright © 2024 Agora -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0, with certain conditions. -# Refer to the "LICENSE" file in the root directory for more information. -# -from pathlib import Path -from ten import ExtensionTester, TenEnvTester, Cmd, CmdResult, StatusCode - - -class ExtensionTesterBasic(ExtensionTester): - def check_hello(self, ten_env: TenEnvTester, result: CmdResult): - statusCode = result.get_status_code() - print("receive hello_world, status:" + str(statusCode)) - - if statusCode == StatusCode.OK: - ten_env.stop_test() - - def on_start(self, ten_env: TenEnvTester) -> None: - new_cmd = Cmd.create("hello_world") - - print("send hello_world") - ten_env.send_cmd( - new_cmd, - lambda ten_env, result, _: self.check_hello(ten_env, result), - ) - - print("tester on_start_done") - ten_env.on_start_done() - - -def test_basic(): - tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_async_extension_python") - tester.run() diff --git a/agents/ten_packages/extension/vision_tool_python/BUILD.gn b/agents/ten_packages/extension/vision_tool_python/BUILD.gn deleted file mode 100644 index 83e8c5d1..00000000 --- a/agents/ten_packages/extension/vision_tool_python/BUILD.gn +++ /dev/null @@ -1,19 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import("//build/feature/ten_package.gni") - -ten_package("vision_tool_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - "tests", - ] -} diff --git a/agents/ten_packages/extension/vision_tool_python/manifest.json b/agents/ten_packages/extension/vision_tool_python/manifest.json index ae483903..c6e5206a 100644 --- a/agents/ten_packages/extension/vision_tool_python/manifest.json +++ b/agents/ten_packages/extension/vision_tool_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/extension/vision_tool_python/tests/test_basic.py b/agents/ten_packages/extension/vision_tool_python/tests/test_basic.py deleted file mode 100644 index 7f413db1..00000000 --- a/agents/ten_packages/extension/vision_tool_python/tests/test_basic.py +++ /dev/null @@ -1,36 +0,0 @@ -# -# Copyright © 2024 Agora -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0, with certain conditions. -# Refer to the "LICENSE" file in the root directory for more information. -# -from pathlib import Path -from ten import ExtensionTester, TenEnvTester, Cmd, CmdResult, StatusCode - - -class ExtensionTesterBasic(ExtensionTester): - def check_hello(self, ten_env: TenEnvTester, result: CmdResult): - statusCode = result.get_status_code() - print("receive hello_world, status:" + str(statusCode)) - - if statusCode == StatusCode.OK: - ten_env.stop_test() - - def on_start(self, ten_env: TenEnvTester) -> None: - new_cmd = Cmd.create("hello_world") - - print("send hello_world") - ten_env.send_cmd( - new_cmd, - lambda ten_env, result, _: self.check_hello(ten_env, result), - ) - - print("tester on_start_done") - ten_env.on_start_done() - - -def test_basic(): - tester = ExtensionTesterBasic() - tester.add_addon_base_dir(str(Path(__file__).resolve().parent.parent)) - tester.set_test_mode_single("default_extension_python") - tester.run() diff --git a/agents/ten_packages/extension/weatherapi_tool_python/BUILD.gn b/agents/ten_packages/extension/weatherapi_tool_python/BUILD.gn deleted file mode 100644 index 2fa4be7b..00000000 --- a/agents/ten_packages/extension/weatherapi_tool_python/BUILD.gn +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2022-11. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import("//build/feature/ten_package.gni") - -ten_package("weatherapi_tool_python") { - package_kind = "extension" - - resources = [ - "__init__.py", - "addon.py", - "extension.py", - "manifest.json", - "property.json", - ] -} diff --git a/agents/ten_packages/extension/weatherapi_tool_python/manifest.json b/agents/ten_packages/extension/weatherapi_tool_python/manifest.json index c7124370..7412445f 100644 --- a/agents/ten_packages/extension/weatherapi_tool_python/manifest.json +++ b/agents/ten_packages/extension/weatherapi_tool_python/manifest.json @@ -6,7 +6,7 @@ { "type": "system", "name": "ten_runtime_python", - "version": "0.6" + "version": "0.8" } ], "package": { diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/__init__.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/__init__.py deleted file mode 100644 index f31a766d..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/__init__.py +++ /dev/null @@ -1,40 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# - -from .types import ( - LLMCallCompletionArgs, - LLMDataCompletionArgs, - LLMToolMetadata, - LLMToolResult, - LLMChatCompletionMessageParam, -) -from .usage import LLMUsage, LLMCompletionTokensDetails, LLMPromptTokensDetails -from .chat_memory import ChatMemory, EVENT_MEMORY_APPENDED, EVENT_MEMORY_EXPIRED -from .helper import AsyncQueue, AsyncEventEmitter -from .config import BaseConfig -from .llm import AsyncLLMBaseExtension -from .llm_tool import AsyncLLMToolBaseExtension - -# Specify what should be imported when a user imports * from the -# ten_ai_base package. -__all__ = [ - "LLMToolMetadata", - "LLMToolResult", - "LLMCallCompletionArgs", - "LLMDataCompletionArgs", - "AsyncLLMBaseExtension", - "AsyncLLMToolBaseExtension", - "ChatMemory", - "AsyncQueue", - "AsyncEventEmitter", - "BaseConfig", - "LLMChatCompletionMessageParam", - "LLMUsage", - "LLMCompletionTokensDetails", - "LLMPromptTokensDetails", - "EVENT_MEMORY_APPENDED", - "EVENT_MEMORY_EXPIRED", -] diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/chat_memory.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/chat_memory.py deleted file mode 100644 index 3a1c9b1e..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/chat_memory.py +++ /dev/null @@ -1,61 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -import threading -import asyncio - -from typing import Dict, List - -EVENT_MEMORY_EXPIRED = "memory_expired" -EVENT_MEMORY_APPENDED = "memory_appended" - -class ChatMemory: - def __init__(self, max_history_length): - self.max_history_length = max_history_length - self.history = [] - self.mutex = threading.Lock() # TODO: no need lock for asyncio - self.listeners: Dict[str, List] = {} - - def put(self, message): - with self.mutex: - self.history.append(message) - self.emit(EVENT_MEMORY_APPENDED, message) - - while True: - history_count = len(self.history) - if history_count > 0 and history_count > self.max_history_length: - self.emit(EVENT_MEMORY_EXPIRED, self.history.pop(0)) - continue - if history_count > 0 and (self.history[0]["role"] == "assistant" or self.history[0]["role"] == "tool"): - # we cannot have an assistant message at the start of the chat history - # if after removal of the first, we have an assistant message, - # we need to remove the assistant message too - self.emit(EVENT_MEMORY_EXPIRED, self.history.pop(0)) - continue - break - - def get(self): - with self.mutex: - return self.history - - def count(self): - with self.mutex: - return len(self.history) - - def clear(self): - with self.mutex: - self.history = [] - - def on(self, event_name, listener): - """Register an event listener.""" - if event_name not in self.listeners: - self.listeners[event_name] = [] - self.listeners[event_name].append(listener) - - def emit(self, event_name, *args, **kwargs): - """Fire the event without waiting for listeners to finish.""" - if event_name in self.listeners: - for listener in self.listeners[event_name]: - asyncio.create_task(listener(*args, **kwargs)) diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/config.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/config.py deleted file mode 100644 index 99f2d09d..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/config.py +++ /dev/null @@ -1,84 +0,0 @@ -import builtins -import json - -from typing import TypeVar, Type, List -from ten import AsyncTenEnv, TenEnv -from dataclasses import dataclass, fields - - -T = TypeVar('T', bound='BaseConfig') - - -@dataclass -class BaseConfig: - """ - Base class for implementing configuration. - Extra configuration fields can be added in inherited class. - """ - - @classmethod - def create(cls: Type[T], ten_env: TenEnv) -> T: - c = cls() - c._init(ten_env) - return c - - @classmethod - async def create_async(cls: Type[T], ten_env: AsyncTenEnv) -> T: - c = cls() - await c._init_async(ten_env) - return c - - def _init(obj, ten_env: TenEnv): - """ - Get property from ten_env to initialize the dataclass config. - """ - for field in fields(obj): - # TODO: 'is_property_exist' has a bug that can not be used in async extension currently, use it instead of try .. except once fixed - # if not ten_env.is_property_exist(field.name): - # continue - try: - match field.type: - case builtins.str: - val = ten_env.get_property_string(field.name) - if val: - setattr(obj, field.name, val) - case builtins.int: - val = ten_env.get_property_int(field.name) - setattr(obj, field.name, val) - case builtins.bool: - val = ten_env.get_property_bool(field.name) - setattr(obj, field.name, val) - case builtins.float: - val = ten_env.get_property_float(field.name) - setattr(obj, field.name, val) - case _: - val = ten_env.get_property_to_json(field.name) - setattr(obj, field.name, json.loads(val)) - except Exception as e: - pass - - async def _init_async(obj, ten_env: AsyncTenEnv): - """ - Get property from ten_env to initialize the dataclass config. - """ - for field in fields(obj): - try: - match field.type: - case builtins.str: - val = await ten_env.get_property_string(field.name) - if val: - setattr(obj, field.name, val) - case builtins.int: - val = await ten_env.get_property_int(field.name) - setattr(obj, field.name, val) - case builtins.bool: - val = await ten_env.get_property_bool(field.name) - setattr(obj, field.name, val) - case builtins.float: - val = await ten_env.get_property_float(field.name) - setattr(obj, field.name, val) - case _: - val = await ten_env.get_property_to_json(field.name) - setattr(obj, field.name, json.loads(val)) - except Exception as e: - pass \ No newline at end of file diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/const.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/const.py deleted file mode 100644 index 1eac3083..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/const.py +++ /dev/null @@ -1,22 +0,0 @@ -CMD_TOOL_REGISTER = "tool_register" -CMD_TOOL_CALL = "tool_call" -CMD_PROPERTY_TOOL = "tool" -CMD_PROPERTY_RESULT = "tool_result" -CMD_CHAT_COMPLETION_CALL = "chat_completion_call" -CMD_GENERATE_IMAGE_CALL = "generate_image_call" -CMD_IN_FLUSH = "flush" -CMD_OUT_FLUSH = "flush" - -DATA_OUT_NAME = "text_data" -CONTENT_DATA_OUT_NAME = "content_data" -DATA_OUT_PROPERTY_TEXT = "text" -DATA_OUT_PROPERTY_TEXT = "text" -DATA_OUT_PROPERTY_END_OF_SEGMENT = "end_of_segment" - -DATA_IN_PROPERTY_TEXT = "text" -DATA_IN_PROPERTY_END_OF_SEGMENT = "end_of_segment" - -DATA_INPUT_NAME = "text_data" -CONTENT_DATA_INPUT_NAME = "content_data" - -AUDIO_FRAME_OUTPUT_NAME = "pcm_frame" \ No newline at end of file diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/helper.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/helper.py deleted file mode 100644 index 4da14707..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/helper.py +++ /dev/null @@ -1,161 +0,0 @@ -# -# -# Agora Real Time Engagement -# Created by Wei Hu in 2024-08. -# Copyright (c) 2024 Agora IO. All rights reserved. -# -# -import asyncio -from collections import deque -from datetime import datetime -import functools -from typing import Callable -from ten.async_ten_env import AsyncTenEnv - - -def get_property_bool(ten_env: AsyncTenEnv, property_name: str) -> bool: - """Helper to get boolean property from ten_env with error handling.""" - try: - return ten_env.get_property_bool(property_name) - except Exception as err: - ten_env.log_warn(f"GetProperty {property_name} failed: {err}") - return False - -def get_properties_bool(ten_env: AsyncTenEnv, property_names: list[str], callback: Callable[[str, bool], None]) -> None: - """Helper to get boolean properties from ten_env with error handling.""" - for property_name in property_names: - callback(property_name, get_property_bool(ten_env, property_name)) - - -def get_property_string(ten_env: AsyncTenEnv, property_name: str) -> str: - """Helper to get string property from ten_env with error handling.""" - try: - return ten_env.get_property_string(property_name) - except Exception as err: - ten_env.log_warn(f"GetProperty {property_name} failed: {err}") - return "" - - -def get_properties_string(ten_env: AsyncTenEnv, property_names: list[str], callback: Callable[[str, str], None]) -> None: - """Helper to get string properties from ten_env with error handling.""" - for property_name in property_names: - callback(property_name, get_property_string(ten_env, property_name)) - -def get_property_int(ten_env: AsyncTenEnv, property_name: str) -> int: - """Helper to get int property from ten_env with error handling.""" - try: - return ten_env.get_property_int(property_name) - except Exception as err: - ten_env.log_warn(f"GetProperty {property_name} failed: {err}") - return 0 - -def get_properties_int(ten_env: AsyncTenEnv, property_names: list[str], callback: Callable[[str, int], None]) -> None: - """Helper to get int properties from ten_env with error handling.""" - for property_name in property_names: - callback(property_name, get_property_int(ten_env, property_name)) - -def get_property_float(ten_env: AsyncTenEnv, property_name: str) -> float: - """Helper to get float property from ten_env with error handling.""" - try: - return ten_env.get_property_float(property_name) - except Exception as err: - ten_env.log_warn(f"GetProperty {property_name} failed: {err}") - return 0.0 - -def get_properties_float(ten_env: AsyncTenEnv, property_names: list[str], callback: Callable[[str, float], None]) -> None: - """Helper to get float properties from ten_env with error handling.""" - for property_name in property_names: - callback(property_name, get_property_float(ten_env, property_name)) - -class AsyncEventEmitter: - def __init__(self): - self.listeners = {} - - def on(self, event_name, listener): - """Register an event listener.""" - if event_name not in self.listeners: - self.listeners[event_name] = [] - self.listeners[event_name].append(listener) - - def emit(self, event_name, *args, **kwargs): - """Fire the event without waiting for listeners to finish.""" - if event_name in self.listeners: - for listener in self.listeners[event_name]: - asyncio.create_task(listener(*args, **kwargs)) - - -class AsyncQueue: - def __init__(self): - self._queue = deque() # Use deque for efficient prepend and append - self._condition = asyncio.Condition() # Use Condition to manage access - - async def put(self, item, prepend=False): - """Add an item to the queue (prepend if specified).""" - async with self._condition: - if prepend: - self._queue.appendleft(item) # Prepend item to the front - else: - self._queue.append(item) # Append item to the back - self._condition.notify() - - async def get(self): - """Remove and return an item from the queue.""" - async with self._condition: - while not self._queue: - await self._condition.wait() # Wait until an item is available - return self._queue.popleft() # Pop from the front of the deque - - async def flush(self): - """Flush all items from the queue.""" - async with self._condition: - while self._queue: - self._queue.popleft() # Clear the queue - self._condition.notify_all() # Notify all consumers that the queue is empty - - def __len__(self): - """Return the current size of the queue.""" - return len(self._queue) - -def write_pcm_to_file(buffer: bytearray, file_name: str) -> None: - """Helper function to write PCM data to a file.""" - with open(file_name, "ab") as f: # append to file - f.write(buffer) - - -def generate_file_name(prefix: str) -> str: - # Create a timestamp for the file name - timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") - return f"{prefix}_{timestamp}.pcm" - -class PCMWriter: - def __init__(self, prefix: str, write_pcm: bool, buffer_size: int = 1024 * 64): - self.write_pcm = write_pcm - self.buffer = bytearray() - self.buffer_size = buffer_size - self.file_name = generate_file_name(prefix) if write_pcm else None - self.loop = asyncio.get_event_loop() - - async def write(self, data: bytes) -> None: - """Accumulate data into the buffer and write to file when necessary.""" - if not self.write_pcm: - return - - self.buffer.extend(data) - - # Write to file if buffer is full - if len(self.buffer) >= self.buffer_size: - await self._flush() - - async def flush(self) -> None: - """Write any remaining data in the buffer to the file.""" - if self.write_pcm and self.buffer: - await self._flush() - - async def _flush(self) -> None: - """Helper method to write the buffer to the file.""" - if self.file_name: - await self.loop.run_in_executor( - None, - functools.partial(write_pcm_to_file, self.buffer[:], self.file_name), - ) - self.buffer.clear() \ No newline at end of file diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/llm.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/llm.py deleted file mode 100644 index 67a4066f..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/llm.py +++ /dev/null @@ -1,170 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -from abc import ABC, abstractmethod -import asyncio -import traceback - -from ten import ( - AsyncExtension, - Data, -) -from ten.async_ten_env import AsyncTenEnv -from ten.cmd import Cmd -from ten.cmd_result import CmdResult, StatusCode -from .const import ( - CMD_PROPERTY_TOOL, - CMD_TOOL_REGISTER, - DATA_OUT_NAME, - DATA_OUT_PROPERTY_END_OF_SEGMENT, - DATA_OUT_PROPERTY_TEXT, - CMD_CHAT_COMPLETION_CALL, -) -from .types import LLMCallCompletionArgs, LLMDataCompletionArgs, LLMToolMetadata -from .helper import AsyncQueue -import json - - -class AsyncLLMBaseExtension(AsyncExtension, ABC): - """ - Base class for implementing a Language Model Extension. - This class provides a basic implementation for processing chat completions. - It automatically handles the registration of tools and the processing of chat completions. - Use queue_input_item to queue input items for processing. - Use flush_input_items to flush the queue and cancel the current task. - Override on_call_chat_completion and on_data_chat_completion to implement the chat completion logic. - """ - - # Create the queue for message processing - - def __init__(self, name: str): - super().__init__(name) - self.queue = AsyncQueue() - self.available_tools: list[LLMToolMetadata] = [] - self.available_tools_lock = asyncio.Lock() # Lock to ensure thread-safe access - self.current_task = None - self.hit_default_cmd = False - self.loop_task = None - self.loop = None - - async def on_init(self, async_ten_env: AsyncTenEnv) -> None: - await super().on_init(async_ten_env) - - async def on_start(self, async_ten_env: AsyncTenEnv) -> None: - await super().on_start(async_ten_env) - - if self.loop_task is None: - self.loop = asyncio.get_event_loop() - self.loop_task = self.loop.create_task(self._process_queue(async_ten_env)) - - async def on_stop(self, async_ten_env: AsyncTenEnv) -> None: - await super().on_stop(async_ten_env) - await self.queue.put(None) - - async def on_deinit(self, async_ten_env: AsyncTenEnv) -> None: - await super().on_deinit(async_ten_env) - - async def on_cmd(self, async_ten_env: AsyncTenEnv, cmd: Cmd) -> None: - """ - handle default commands - return True if the command is handled, False otherwise - """ - cmd_name = cmd.get_name() - async_ten_env.log_debug(f"on_cmd name {cmd_name}") - if cmd_name == CMD_TOOL_REGISTER: - try: - tool_metadata_json = cmd.get_property_to_json(CMD_PROPERTY_TOOL) - async_ten_env.log_info(f"register tool: {tool_metadata_json}") - tool_metadata = LLMToolMetadata.model_validate_json(tool_metadata_json) - async with self.available_tools_lock: - self.available_tools.append(tool_metadata) - await self.on_tools_update(async_ten_env, tool_metadata) - await async_ten_env.return_result(CmdResult.create(StatusCode.OK), cmd) - except Exception: - async_ten_env.log_warn(f"on_cmd failed: {traceback.format_exc()}") - await async_ten_env.return_result( - CmdResult.create(StatusCode.ERROR), cmd - ) - elif cmd_name == CMD_CHAT_COMPLETION_CALL: - try: - args = json.loads(cmd.get_property_to_json("arguments")) - response = await self.on_call_chat_completion(async_ten_env, **args) - cmd_result = CmdResult.create(StatusCode.OK) - cmd_result.set_property_from_json("response", response) - await async_ten_env.return_result(cmd_result, cmd) - except Exception as err: - async_ten_env.log_warn(f"on_cmd failed: {err}") - await async_ten_env.return_result( - CmdResult.create(StatusCode.ERROR), cmd - ) - - async def queue_input_item( - self, prepend: bool = False, **kargs: LLMDataCompletionArgs - ): - """Queues an input item for processing.""" - await self.queue.put(kargs, prepend) - - async def flush_input_items(self, async_ten_env: AsyncTenEnv): - """Flushes the self.queue and cancels the current task.""" - # Flush the queue using the new flush method - await self.queue.flush() - - # Cancel the current task if one is running - if self.current_task: - async_ten_env.log_info("Cancelling the current task during flush.") - self.current_task.cancel() - - def send_text_output( - self, async_ten_env: AsyncTenEnv, sentence: str, end_of_segment: bool - ): - try: - output_data = Data.create(DATA_OUT_NAME) - output_data.set_property_string(DATA_OUT_PROPERTY_TEXT, sentence) - output_data.set_property_bool( - DATA_OUT_PROPERTY_END_OF_SEGMENT, end_of_segment - ) - asyncio.create_task(async_ten_env.send_data(output_data)) - async_ten_env.log_info( - f"{'end of segment ' if end_of_segment else ''}sent sentence [{sentence}]" - ) - except Exception as err: - async_ten_env.log_warn(f"send sentence [{sentence}] failed, err: {err}") - - @abstractmethod - async def on_call_chat_completion( - self, async_ten_env: AsyncTenEnv, **kargs: LLMCallCompletionArgs - ) -> any: - """Called when a chat completion is requested by cmd call. Implement this method to process the chat completion.""" - - @abstractmethod - async def on_data_chat_completion( - self, async_ten_env: AsyncTenEnv, **kargs: LLMDataCompletionArgs - ) -> None: - """ - Called when a chat completion is requested by data input. Implement this method to process the chat completion. - Note that this method is stream-based, and it should consider supporting local context caching. - """ - - @abstractmethod - async def on_tools_update( - self, async_ten_env: AsyncTenEnv, tool: LLMToolMetadata - ) -> None: - """Called when a new tool is registered. Implement this method to process the new tool.""" - - async def _process_queue(self, async_ten_env: AsyncTenEnv): - """Asynchronously process queue items one by one.""" - while True: - # Wait for an item to be available in the queue - args = await self.queue.get() - try: - async_ten_env.log_info(f"Processing queue item: {args}") - self.current_task = asyncio.create_task( - self.on_data_chat_completion(async_ten_env, **args) - ) - await self.current_task # Wait for the current task to finish or be cancelled - except asyncio.CancelledError: - async_ten_env.log_info(f"Task cancelled: {args}") - except Exception: - async_ten_env.log_error(f"Task failed: {args}, err: {traceback.format_exc()}") diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/llm_tool.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/llm_tool.py deleted file mode 100644 index c1232660..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/llm_tool.py +++ /dev/null @@ -1,97 +0,0 @@ -from abc import ABC, abstractmethod -import asyncio -import traceback -from ten import ( - AsyncExtension, - Data, - TenEnv, -) -from ten.async_ten_env import AsyncTenEnv -from ten.audio_frame import AudioFrame -from ten.cmd import Cmd -from ten.cmd_result import CmdResult, StatusCode -from ten.video_frame import VideoFrame -from .types import LLMToolMetadata, LLMToolResult -from .const import ( - CMD_TOOL_REGISTER, - CMD_TOOL_CALL, - CMD_PROPERTY_TOOL, - CMD_PROPERTY_RESULT, -) -import json - - -class AsyncLLMToolBaseExtension(AsyncExtension, ABC): - async def on_start(self, async_ten_env: AsyncTenEnv) -> None: - await super().on_start(async_ten_env) - - tools: list[LLMToolMetadata] = self.get_tool_metadata(async_ten_env) - for tool in tools: - async_ten_env.log_info(f"tool: {tool}") - c: Cmd = Cmd.create(CMD_TOOL_REGISTER) - c.set_property_from_json(CMD_PROPERTY_TOOL, json.dumps(tool.model_dump())) - async_ten_env.log_info(f"begin tool register, {tool}") - await async_ten_env.send_cmd(c) - async_ten_env.log_info(f"tool registered, {tool}") - - async def on_stop(self, async_ten_env: AsyncTenEnv) -> None: - await super().on_stop(async_ten_env) - - async def on_cmd(self, async_ten_env: AsyncTenEnv, cmd: Cmd) -> None: - cmd_name = cmd.get_name() - async_ten_env.log_debug("on_cmd name {}".format(cmd_name)) - - if cmd_name == CMD_TOOL_CALL: - try: - tool_name = cmd.get_property_string("name") - tool_args = json.loads(cmd.get_property_to_json("arguments")) - async_ten_env.log_debug( - f"tool_name: {tool_name}, tool_args: {tool_args}" - ) - result = await asyncio.create_task( - self.run_tool(async_ten_env, tool_name, tool_args) - ) - - if result is None: - await async_ten_env.return_result( - CmdResult.create(StatusCode.OK), cmd - ) - return - - cmd_result: CmdResult = CmdResult.create(StatusCode.OK) - cmd_result.set_property_from_json( - CMD_PROPERTY_RESULT, json.dumps(result) - ) - await async_ten_env.return_result(cmd_result, cmd) - async_ten_env.log_info(f"tool result done, {result}") - except Exception: - async_ten_env.log_warn(f"on_cmd failed: {traceback.format_exc()}") - await async_ten_env.return_result( - CmdResult.create(StatusCode.ERROR), cmd - ) - - async def on_data(self, async_ten_env: AsyncTenEnv, data: Data) -> None: - data_name = data.get_name() - async_ten_env.log_debug(f"on_data name {data_name}") - - async def on_audio_frame( - self, async_ten_env: AsyncTenEnv, audio_frame: AudioFrame - ) -> None: - audio_frame_name = audio_frame.get_name() - async_ten_env.log_debug("on_audio_frame name {}".format(audio_frame_name)) - - async def on_video_frame( - self, async_ten_env: AsyncTenEnv, video_frame: VideoFrame - ) -> None: - video_frame_name = video_frame.get_name() - async_ten_env.log_debug("on_video_frame name {}".format(video_frame_name)) - - @abstractmethod - def get_tool_metadata(self, ten_env: TenEnv) -> list[LLMToolMetadata]: - pass - - @abstractmethod - async def run_tool( - self, ten_env: AsyncTenEnv, name: str, args: dict - ) -> LLMToolResult | None: - pass diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/tts.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/tts.py deleted file mode 100644 index bc8a9ac1..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/tts.py +++ /dev/null @@ -1,168 +0,0 @@ -# -# This file is part of TEN Framework, an open source project. -# Licensed under the Apache License, Version 2.0. -# See the LICENSE file for more information. -# -from abc import ABC, abstractmethod -import asyncio -import traceback - -from ten import ( - AsyncExtension, - Data, -) -from ten.async_ten_env import AsyncTenEnv -from ten.audio_frame import AudioFrame, AudioFrameDataFmt -from ten.cmd import Cmd -from ten.cmd_result import CmdResult, StatusCode -from ten_ai_base.const import ( - CMD_IN_FLUSH, - CMD_OUT_FLUSH, - DATA_IN_PROPERTY_END_OF_SEGMENT, - DATA_IN_PROPERTY_TEXT, -) -from ten_ai_base.types import TTSPcmOptions -from .helper import AsyncQueue, PCMWriter, get_property_bool, get_property_string - - -class AsyncTTSBaseExtension(AsyncExtension, ABC): - """ - Base class for implementing a Text-to-Speech Extension. - This class provides a basic implementation for converting text to speech. - It automatically handles the processing of tts requests. - Use begin_send_audio_out, send_audio_out, end_send_audio_out to send the audio data to the output. - Override on_request_tts to implement the TTS logic. - """ - - # Create the queue for message processing - - def __init__(self, name: str): - super().__init__(name) - self.queue = AsyncQueue() - self.current_task = None - self.loop_task = None - self.leftover_bytes = b"" - - async def on_init(self, ten_env: AsyncTenEnv) -> None: - await super().on_init(ten_env) - - async def on_start(self, ten_env: AsyncTenEnv) -> None: - await super().on_start(ten_env) - - if self.loop_task is None: - self.loop = asyncio.get_event_loop() - self.loop_task = self.loop.create_task(self._process_queue(ten_env)) - - async def on_stop(self, ten_env: AsyncTenEnv) -> None: - await super().on_stop(ten_env) - self.loop_task.cancel() - - async def on_deinit(self, ten_env: AsyncTenEnv) -> None: - await super().on_deinit(ten_env) - - async def on_cmd(self, async_ten_env: AsyncTenEnv, cmd: Cmd) -> None: - cmd_name = cmd.get_name() - async_ten_env.log_info(f"on_cmd name: {cmd_name}") - - if cmd_name == CMD_IN_FLUSH: - await self.on_cancel_tts(async_ten_env) - await self.flush_input_items(async_ten_env) - await async_ten_env.send_cmd(Cmd.create(CMD_OUT_FLUSH)) - async_ten_env.log_info("on_cmd sent flush") - status_code, detail = StatusCode.OK, "success" - cmd_result = CmdResult.create(status_code) - cmd_result.set_property_string("detail", detail) - await async_ten_env.return_result(cmd_result, cmd) - - async def on_data(self, async_ten_env: AsyncTenEnv, data: Data) -> None: - # Get the necessary properties - async_ten_env.log_info(f"on_data name: {data.get_name()}") - input_text = get_property_string(data, DATA_IN_PROPERTY_TEXT) - end_of_segment = get_property_bool(data, DATA_IN_PROPERTY_END_OF_SEGMENT) - - if not input_text: - async_ten_env.log_warn("ignore empty text") - return - - # Start an asynchronous task for handling tts - await self.queue.put([input_text, end_of_segment]) - - async def flush_input_items(self, ten_env: AsyncTenEnv): - """Flushes the self.queue and cancels the current task.""" - # Flush the queue using the new flush method - await self.queue.flush() - - # Cancel the current task if one is running - if self.current_task: - ten_env.log_info("Cancelling the current task during flush.") - self.current_task.cancel() - - async def send_audio_out( - self, ten_env: AsyncTenEnv, audio_data: bytes, **args: TTSPcmOptions - ) -> None: - """End sending audio out.""" - sample_rate = args.get("sample_rate", 16000) - bytes_per_sample = args.get("bytes_per_sample", 2) - number_of_channels = args.get("number_of_channels", 1) - try: - # Combine leftover bytes with new audio data - combined_data = self.leftover_bytes + audio_data - - # Check if combined_data length is odd - if len(combined_data) % (bytes_per_sample * number_of_channels) != 0: - # Save the last incomplete frame - valid_length = len(combined_data) - ( - len(combined_data) % (bytes_per_sample * number_of_channels) - ) - self.leftover_bytes = combined_data[valid_length:] - combined_data = combined_data[:valid_length] - else: - self.leftover_bytes = b"" - - if combined_data: - f = AudioFrame.create("pcm_frame") - f.set_sample_rate(sample_rate) - f.set_bytes_per_sample(bytes_per_sample) - f.set_number_of_channels(number_of_channels) - f.set_data_fmt(AudioFrameDataFmt.INTERLEAVE) - f.set_samples_per_channel( - len(combined_data) // (bytes_per_sample * number_of_channels) - ) - f.alloc_buf(len(combined_data)) - buff = f.lock_buf() - buff[:] = combined_data - f.unlock_buf(buff) - await ten_env.send_audio_frame(f) - except Exception as e: - ten_env.log_error(f"error send audio frame, {traceback.format_exc()}") - - @abstractmethod - async def on_request_tts( - self, ten_env: AsyncTenEnv, input_text: str, end_of_segment: bool - ) -> None: - """ - Called when a new input item is available in the queue. Override this method to implement the TTS request logic. - Use send_audio_out to send the audio data to the output when the audio data is ready. - """ - pass - - @abstractmethod - async def on_cancel_tts(self, ten_env: AsyncTenEnv) -> None: - """Called when the TTS request is cancelled.""" - pass - - async def _process_queue(self, ten_env: AsyncTenEnv): - """Asynchronously process queue items one by one.""" - while True: - # Wait for an item to be available in the queue - [text, end_of_segment] = await self.queue.get() - - try: - self.current_task = asyncio.create_task( - self.on_request_tts(ten_env, text, end_of_segment) - ) - await self.current_task # Wait for the current task to finish or be cancelled - except asyncio.CancelledError: - ten_env.log_info(f"Task cancelled: {text}") - except Exception as err: - ten_env.log_error(f"Task failed: {text}, err: {traceback.format_exc()}") diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/types.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/types.py deleted file mode 100644 index a32cfebc..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/types.py +++ /dev/null @@ -1,128 +0,0 @@ -from typing import Iterable, Optional, TypeAlias, Union -from pydantic import BaseModel -from typing_extensions import Literal, Required, TypedDict - - -class LLMToolMetadataParameter(BaseModel): - name: str - type: str - description: str - required: Optional[bool] = False - - -class LLMToolMetadata(BaseModel): - name: str - description: str - parameters: list[LLMToolMetadataParameter] - - -class ImageURL(TypedDict, total=False): - url: Required[str] - """Either a URL of the image or the base64 encoded image data.""" - - detail: Literal["auto", "low", "high"] - """Specifies the detail level of the image. - - Learn more in the - [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). - """ - - -class LLMChatCompletionContentPartImageParam(TypedDict, total=False): - image_url: Required[ImageURL] - - type: Required[Literal["image_url"]] - """The type of the content part.""" - - -class InputAudio(TypedDict, total=False): - data: Required[str] - """Base64 encoded audio data.""" - - format: Required[Literal["wav", "mp3"]] - """The format of the encoded audio data. Currently supports "wav" and "mp3".""" - - -class LLMChatCompletionContentPartInputAudioParam(TypedDict, total=False): - input_audio: Required[InputAudio] - - type: Required[Literal["input_audio"]] - """The type of the content part. Always `input_audio`.""" - - -class LLMChatCompletionContentPartTextParam(TypedDict, total=False): - text: Required[str] - """The text content.""" - - type: Required[Literal["text"]] - """The type of the content part.""" - - -LLMChatCompletionContentPartParam: TypeAlias = Union[ - LLMChatCompletionContentPartTextParam, - LLMChatCompletionContentPartImageParam, - LLMChatCompletionContentPartInputAudioParam, -] - - -class LLMChatCompletionToolMessageParam(TypedDict, total=False): - content: Required[Union[str, Iterable[LLMChatCompletionContentPartTextParam]]] - """The contents of the tool message.""" - - role: Required[Literal["tool"]] - """The role of the messages author, in this case `tool`.""" - - tool_call_id: Required[str] - """Tool call that this message is responding to.""" - - -class LLMChatCompletionUserMessageParam(TypedDict, total=False): - content: Required[Union[str, Iterable[LLMChatCompletionContentPartParam]]] - """The contents of the user message.""" - - role: Required[Literal["user"]] - """The role of the messages author, in this case `user`.""" - - name: str - """An optional name for the participant. - - Provides the model information to differentiate between participants of the same - role. - """ - - -LLMChatCompletionMessageParam: TypeAlias = Union[ - LLMChatCompletionUserMessageParam, LLMChatCompletionToolMessageParam -] - -class LLMToolResultRequery(TypedDict, total=False): - type: Required[Literal["requery"]] - content: Required[Union[str, Iterable[LLMChatCompletionContentPartParam]]] - -class LLMToolResultLLMResult(TypedDict, total=False): - type: Required[Literal["llmresult"]] - content: Required[Union[str, Iterable[LLMChatCompletionContentPartParam]]] - -LLMToolResult: TypeAlias = Union[ - LLMToolResultRequery, - LLMToolResultLLMResult, -] - -class LLMCallCompletionArgs(TypedDict, total=False): - messages: Iterable[LLMChatCompletionMessageParam] - - -class LLMDataCompletionArgs(TypedDict, total=False): - messages: Iterable[LLMChatCompletionMessageParam] - no_tool: bool - - -class TTSPcmOptions(TypedDict, total=False): - sample_rate: int - """The sample rate of the audio data in Hz.""" - - num_channels: int - """The number of audio channels.""" - - bytes_per_sample: int - """The number of bytes per sample.""" diff --git a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/usage.py b/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/usage.py deleted file mode 100644 index fdfe0872..00000000 --- a/agents/ten_packages/system/ten_ai_base/interface/ten_ai_base/usage.py +++ /dev/null @@ -1,23 +0,0 @@ -from pydantic import BaseModel - - -class LLMCompletionTokensDetails(BaseModel): - accepted_prediction_tokens: int = 0 - audio_tokens: int = 0 - reasoning_tokens: int = 0 - rejected_prediction_tokens: int = 0 - - -class LLMPromptTokensDetails(BaseModel): - audio_tokens: int = 0 - cached_tokens: int = 0 - text_tokens: int = 0 - - -class LLMUsage(BaseModel): - completion_tokens: int = 0 - prompt_tokens: int = 0 - total_tokens: int = 0 - - completion_tokens_details: LLMCompletionTokensDetails | None = None - prompt_tokens_details: LLMPromptTokensDetails | None = None diff --git a/agents/ten_packages/system/ten_ai_base/manifest.json b/agents/ten_packages/system/ten_ai_base/manifest.json deleted file mode 100644 index 9da9cd71..00000000 --- a/agents/ten_packages/system/ten_ai_base/manifest.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "type": "system", - "name": "ten_ai_base", - "version": "0.1.0", - "package": { - "include": [ - "manifest.json", - "interface/**", - "requirements.txt" - ] - }, - "dependencies": [ - { - "type": "system", - "name": "ten_runtime_python", - "version": "0.6" - } - ], - "api": {} -} \ No newline at end of file diff --git a/agents/ten_packages/system/ten_ai_base/requirements.txt b/agents/ten_packages/system/ten_ai_base/requirements.txt deleted file mode 100644 index e9f3515f..00000000 --- a/agents/ten_packages/system/ten_ai_base/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -pydantic>=2 -typing-extensions \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index a8ba9f08..2d2c5268 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: ten_agent_dev: - image: ghcr.io/ten-framework/ten_agent_build:0.3.4 + image: ghcr.io/ten-framework/ten_agent_build:0.4.10 container_name: ten_agent_dev platform: linux/amd64 tty: true