3v324v23 commited on
Commit
87337b1
·
1 Parent(s): 92a057f

Зафиксирована рабочая версия TEN-Agent для HuggingFace Space

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .devcontainer/devcontainer.json +28 -0
  2. .dockerignore +2 -0
  3. .gitattributes +5 -0
  4. .github/ISSUE_TEMPLATE/bug_report.yml +67 -0
  5. .github/ISSUE_TEMPLATE/feature_request.yml +39 -0
  6. .github/workflows/build-docker.yaml +87 -0
  7. .github/workflows/ci.yaml +45 -0
  8. .pylintrc +652 -0
  9. .vscode/launch.json +47 -0
  10. .vscode/settings.json +13 -0
  11. .vscode/tasks.json +22 -0
  12. Dockerfile +8 -11
  13. LICENSE +201 -0
  14. Taskfile.yml +120 -0
  15. agents/.clang-format +8 -0
  16. agents/.gitignore +43 -0
  17. agents/bin/start +12 -0
  18. agents/examples/default/manifest.json +152 -0
  19. agents/examples/default/property.json +1331 -0
  20. agents/examples/demo/manifest.json +97 -0
  21. agents/examples/demo/property.json +2322 -0
  22. agents/examples/experimental/manifest.json +122 -0
  23. agents/examples/experimental/property.json +862 -0
  24. agents/go.mod +7 -0
  25. agents/go.sum +0 -0
  26. agents/main.go +71 -0
  27. agents/scripts/.gitignore +4 -0
  28. agents/scripts/BUILD.gn +18 -0
  29. agents/scripts/dot.py +117 -0
  30. agents/scripts/install_deps_and_build.sh +145 -0
  31. agents/scripts/package.sh +68 -0
  32. agents/scripts/pylint.sh +4 -0
  33. agents/session_control.conf +2 -0
  34. agents/ten_packages/bak/litellm_python/__init__.py +6 -0
  35. agents/ten_packages/bak/litellm_python/extension.py +1 -0
  36. agents/ten_packages/bak/litellm_python/litellm.py +79 -0
  37. agents/ten_packages/bak/litellm_python/litellm_addon.py +23 -0
  38. agents/ten_packages/bak/litellm_python/litellm_extension.py +229 -0
  39. agents/ten_packages/bak/litellm_python/log.py +12 -0
  40. agents/ten_packages/bak/litellm_python/manifest.json +82 -0
  41. agents/ten_packages/bak/litellm_python/requirements.txt +1 -0
  42. agents/ten_packages/bak/litellm_python/utils.py +19 -0
  43. agents/ten_packages/extension/agora_rtm_wrapper/extension.go +180 -0
  44. agents/ten_packages/extension/agora_rtm_wrapper/go.mod +7 -0
  45. agents/ten_packages/extension/agora_rtm_wrapper/manifest.json +32 -0
  46. agents/ten_packages/extension/agora_rtm_wrapper/property.json +1 -0
  47. agents/ten_packages/extension/aliyun_analyticdb_vector_storage/__init__.py +1 -0
  48. agents/ten_packages/extension/aliyun_analyticdb_vector_storage/client.py +95 -0
  49. agents/ten_packages/extension/aliyun_analyticdb_vector_storage/manifest.json +121 -0
  50. agents/ten_packages/extension/aliyun_analyticdb_vector_storage/model.py +546 -0
.devcontainer/devcontainer.json ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // For format details, see https://aka.ms/devcontainer.json. For config options, see the
2
+ // README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-dockerfile
3
+ {
4
+ "name": "ten_agent_dev",
5
+ "image": "ghcr.io/ten-framework/ten_agent_build:0.4.17",
6
+ "customizations": {
7
+ "vscode": {
8
+ "extensions": [
9
+ "golang.go",
10
+ "ms-vscode.cpptools"
11
+ ]
12
+ }
13
+ },
14
+ "workspaceMount": "source=${localWorkspaceFolder},target=/app,type=bind",
15
+ "workspaceFolder": "/app",
16
+ // Use 'forwardPorts' to make a list of ports inside the container available locally.
17
+ "forwardPorts": [
18
+ 3000,
19
+ 8080,
20
+ 49483
21
+ ],
22
+ // Features to add to the dev container. More info: https://containers.dev/features.
23
+ "features": {
24
+ "ghcr.io/devcontainers/features/git:1": {},
25
+ "ghcr.io/devcontainers/features/python:1": {},
26
+ "ghcr.io/devcontainers/features/node:1": {}
27
+ }
28
+ }
.dockerignore ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ .git
2
+ playground/
.gitattributes ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # Shell scripts use LF as line separator, even checked out to Windows(NTFS) file-system
2
+ *.sh text eol=lf
3
+ agents/bin/* text eol=lf
4
+ agents/scripts/* text eol=lf
5
+ *.lockb filter=lfs diff=lfs merge=lfs -text
.github/ISSUE_TEMPLATE/bug_report.yml ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Bug Report
2
+ description: Report a bug or issue with the project
3
+ title: "[BUG] "
4
+ labels: [bug]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to report a bug! Please fill in the following details.
10
+
11
+ - type: textarea
12
+ id: description
13
+ attributes:
14
+ label: Description
15
+ description: A clear and detailed description of the bug.
16
+ placeholder: "Enter a clear and concise description of what the bug is."
17
+ validations:
18
+ required: true
19
+
20
+ - type: input
21
+ id: environment
22
+ attributes:
23
+ label: Environment
24
+ description: The environment where this bug occurred (e.g., operating system, CPU arch, etc.).
25
+ placeholder: "Enter details about the environment."
26
+ validations:
27
+ required: true
28
+
29
+ - type: textarea
30
+ id: steps
31
+ attributes:
32
+ label: Steps to reproduce
33
+ description: What are the steps to reproduce this issue?
34
+ placeholder: |
35
+ 1. ...
36
+ validations:
37
+ required: true
38
+
39
+ - type: textarea
40
+ id: expected
41
+ attributes:
42
+ label: Expected behavior
43
+ description: What should have happened instead?
44
+ placeholder: "Describe what you expected to happen."
45
+ validations:
46
+ required: true
47
+
48
+ - type: dropdown
49
+ id: severity
50
+ attributes:
51
+ label: Severity
52
+ description: How severe is the bug?
53
+ options:
54
+ - Critical
55
+ - Major
56
+ - Minor
57
+ validations:
58
+ required: true
59
+
60
+ - type: textarea
61
+ id: additional_info
62
+ attributes:
63
+ label: Additional Information
64
+ description: Any other context or screenshots related to the bug.
65
+ placeholder: "Enter additional context or information."
66
+ validations:
67
+ required: false
.github/ISSUE_TEMPLATE/feature_request.yml ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Feature Request
2
+ description: Request a feature
3
+ title: "[FEATURE] "
4
+ labels: [feature]
5
+ body:
6
+ - type: markdown
7
+ attributes:
8
+ value: |
9
+ Thanks for taking the time to request a feature! Please fill in the following details.
10
+
11
+ - type: textarea
12
+ id: description
13
+ attributes:
14
+ label: Description
15
+ description: A clear and detailed description of the feature request.
16
+ placeholder: "Enter a clear and concise description of what the feature request is."
17
+ validations:
18
+ required: true
19
+
20
+ - type: dropdown
21
+ id: severity
22
+ attributes:
23
+ label: Severity
24
+ description: How severe is the bug?
25
+ options:
26
+ - Critical
27
+ - Major
28
+ - Minor
29
+ validations:
30
+ required: true
31
+
32
+ - type: textarea
33
+ id: additional_info
34
+ attributes:
35
+ label: Additional Information
36
+ description: Any other context or screenshots related to the bug.
37
+ placeholder: "Enter additional context or information."
38
+ validations:
39
+ required: false
.github/workflows/build-docker.yaml ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Build Docker
2
+
3
+ on:
4
+ push:
5
+ branches: [ "**" ]
6
+ tags: [ "**" ]
7
+ paths-ignore:
8
+ - ".devcontainer/**"
9
+ - ".github/**"
10
+ - "!.github/workflows/build-docker.yaml"
11
+ - ".vscode/**"
12
+ - "docs/**"
13
+ - "**.md"
14
+ pull_request:
15
+ branches: [ "main" ]
16
+ paths-ignore:
17
+ - ".devcontainer/**"
18
+ - ".github/**"
19
+ - "!.github/workflows/build-docker.yaml"
20
+ - ".vscode/**"
21
+ - "docs/**"
22
+ - "**.md"
23
+ workflow_dispatch:
24
+
25
+ env:
26
+ SERVER_IMAGE_NAME: ten_agent_server
27
+ PLAYGROUND_IMAGE_NAME: ten_agent_playground
28
+ NON_EDIT_PLAYGROUND_IMAGE_NAME: ten_agent_non_edit_playground
29
+ DEMO_IMAGE_NAME: ten_agent_demo
30
+
31
+ jobs:
32
+ build:
33
+ runs-on: ubuntu-latest
34
+ steps:
35
+ - name: Checkout
36
+ uses: actions/checkout@v4
37
+ with:
38
+ fetch-tags: true
39
+ fetch-depth: "0"
40
+ - id: pre-step
41
+ shell: bash
42
+ run: echo "image-tag=$(git describe --tags --always)" >> $GITHUB_OUTPUT
43
+ - name: Build & Publish Docker Image for Agents Server
44
+ uses: elgohr/Publish-Docker-Github-Action@v5
45
+ with:
46
+ name: ${{ github.repository_owner }}/${{ env.SERVER_IMAGE_NAME }}
47
+ username: ${{ github.actor }}
48
+ password: ${{ secrets.GITHUB_TOKEN }}
49
+ registry: ghcr.io
50
+ tags: "${{ github.ref == 'refs/heads/main' && 'latest,' || '' }}${{ steps.pre-step.outputs.image-tag }}"
51
+ no_push: ${{ github.event_name == 'pull_request' }}
52
+ - name: Build & Publish Docker Image for Playground
53
+ uses: elgohr/Publish-Docker-Github-Action@v5
54
+ env:
55
+ EDIT_GRAPH_MODE: true
56
+ with:
57
+ name: ${{ github.repository_owner }}/${{ env.PLAYGROUND_IMAGE_NAME }}
58
+ username: ${{ github.actor }}
59
+ password: ${{ secrets.GITHUB_TOKEN }}
60
+ registry: ghcr.io
61
+ workdir: playground
62
+ tags: "${{ github.ref == 'refs/heads/main' && 'latest,' || '' }}${{ steps.pre-step.outputs.image-tag }}"
63
+ no_push: ${{ github.event_name == 'pull_request' }}
64
+ buildargs: EDIT_GRAPH_MODE
65
+ - name: Build & Publish Docker Image for Non-Editable Playground
66
+ uses: elgohr/Publish-Docker-Github-Action@v5
67
+ env:
68
+ EDIT_GRAPH_MODE: false
69
+ with:
70
+ name: ${{ github.repository_owner }}/${{ env.NON_EDIT_PLAYGROUND_IMAGE_NAME }}
71
+ username: ${{ github.actor }}
72
+ password: ${{ secrets.GITHUB_TOKEN }}
73
+ registry: ghcr.io
74
+ workdir: playground
75
+ tags: "${{ github.ref == 'refs/heads/main' && 'latest,' || '' }}${{ steps.pre-step.outputs.image-tag }}"
76
+ no_push: ${{ github.event_name == 'pull_request' }}
77
+ buildargs: EDIT_GRAPH_MODE
78
+ - name: Build & Publish Docker Image for demo
79
+ uses: elgohr/Publish-Docker-Github-Action@v5
80
+ with:
81
+ name: ${{ github.repository_owner }}/${{ env.DEMO_IMAGE_NAME }}
82
+ username: ${{ github.actor }}
83
+ password: ${{ secrets.GITHUB_TOKEN }}
84
+ registry: ghcr.io
85
+ workdir: demo
86
+ tags: "${{ github.ref == 'refs/heads/main' && 'latest,' || '' }}${{ steps.pre-step.outputs.image-tag }}"
87
+ no_push: ${{ github.event_name == 'pull_request' }}
.github/workflows/ci.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ branches: [ "main" ]
6
+ paths-ignore:
7
+ - ".devcontainer/**"
8
+ - ".github/**"
9
+ - "!.github/workflows/ci.yaml"
10
+ - ".vscode/**"
11
+ - "docs/**"
12
+ - "esp32-client/**"
13
+ - "**.md"
14
+ - "Dockerfile"
15
+ - "docker-compose.yml"
16
+ - "demo/**"
17
+ - "playground/**"
18
+ workflow_dispatch:
19
+
20
+ jobs:
21
+ ci:
22
+ runs-on: ubuntu-latest
23
+ container:
24
+ image: ghcr.io/ten-framework/ten_agent_build:0.4.17
25
+ strategy:
26
+ matrix:
27
+ agent: [agents/examples/default, agents/examples/demo, agents/examples/experimental]
28
+ steps:
29
+ - uses: actions/checkout@v4
30
+ with:
31
+ fetch-depth: "0"
32
+ submodules: "true"
33
+
34
+ - name: Use agent
35
+ run: |
36
+ git config --global --add safe.directory $(pwd)
37
+ task use AGENT=${{ matrix.agent }}
38
+
39
+ - name: Run tests
40
+ run: |
41
+ task test -- -s -v
42
+
43
+ # - name: Run lint
44
+ # run: |
45
+ # task lint
.pylintrc ADDED
@@ -0,0 +1,652 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [MAIN]
2
+
3
+ # Analyse import fallback blocks. This can be used to support both Python 2 and
4
+ # 3 compatible code, which means that the block might have code that exists
5
+ # only in one or another interpreter, leading to false positives when analysed.
6
+ analyse-fallback-blocks=no
7
+
8
+ # Clear in-memory caches upon conclusion of linting. Useful if running pylint
9
+ # in a server-like mode.
10
+ clear-cache-post-run=no
11
+
12
+ # Load and enable all available extensions. Use --list-extensions to see a list
13
+ # all available extensions.
14
+ #enable-all-extensions=
15
+
16
+ # In error mode, messages with a category besides ERROR or FATAL are
17
+ # suppressed, and no reports are done by default. Error mode is compatible with
18
+ # disabling specific errors.
19
+ #errors-only=
20
+
21
+ # Always return a 0 (non-error) status code, even if lint errors are found.
22
+ # This is primarily useful in continuous integration scripts.
23
+ #exit-zero=
24
+
25
+ # A comma-separated list of package or module names from where C extensions may
26
+ # be loaded. Extensions are loading into the active Python interpreter and may
27
+ # run arbitrary code.
28
+ extension-pkg-allow-list=
29
+
30
+ # A comma-separated list of package or module names from where C extensions may
31
+ # be loaded. Extensions are loading into the active Python interpreter and may
32
+ # run arbitrary code. (This is an alternative name to extension-pkg-allow-list
33
+ # for backward compatibility.)
34
+ extension-pkg-whitelist=
35
+
36
+ # Return non-zero exit code if any of these messages/categories are detected,
37
+ # even if score is above --fail-under value. Syntax same as enable. Messages
38
+ # specified are enabled, while categories only check already-enabled messages.
39
+ fail-on=
40
+
41
+ # Specify a score threshold under which the program will exit with error.
42
+ fail-under=10
43
+
44
+ # Interpret the stdin as a python script, whose filename needs to be passed as
45
+ # the module_or_package argument.
46
+ #from-stdin=
47
+
48
+ # Files or directories to be skipped. They should be base names, not paths.
49
+ ignore=CVS,examples,tests,out
50
+
51
+ # Add files or directories matching the regular expressions patterns to the
52
+ # ignore-list. The regex matches against paths and can be in Posix or Windows
53
+ # format. Because '\\' represents the directory delimiter on Windows systems,
54
+ # it can't be used as an escape character.
55
+ ignore-paths=
56
+
57
+ # Files or directories matching the regular expression patterns are skipped.
58
+ # The regex matches against base names, not paths. The default value ignores
59
+ # Emacs file locks
60
+ ignore-patterns=
61
+
62
+ # List of module names for which member attributes should not be checked and
63
+ # will not be imported (useful for modules/projects where namespaces are
64
+ # manipulated during runtime and thus existing member attributes cannot be
65
+ # deduced by static analysis). It supports qualified module names, as well as
66
+ # Unix pattern matching.
67
+ ignored-modules=
68
+
69
+ # Python code to execute, usually for sys.path manipulation such as
70
+ # pygtk.require().
71
+ #init-hook=
72
+
73
+ # Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
74
+ # number of processors available to use, and will cap the count on Windows to
75
+ # avoid hangs.
76
+ jobs=1
77
+
78
+ # Control the amount of potential inferred values when inferring a single
79
+ # object. This can help the performance when dealing with large functions or
80
+ # complex, nested conditions.
81
+ limit-inference-results=100
82
+
83
+ # List of plugins (as comma separated values of python module names) to load,
84
+ # usually to register additional checkers.
85
+ load-plugins=
86
+
87
+ # Pickle collected data for later comparisons.
88
+ persistent=yes
89
+
90
+ # Resolve imports to .pyi stubs if available. May reduce no-member messages and
91
+ # increase not-an-iterable messages.
92
+ prefer-stubs=no
93
+
94
+ # Minimum Python version to use for version dependent checks. Will default to
95
+ # the version used to run pylint.
96
+ py-version=3.10
97
+
98
+ # Discover python modules and packages in the file system subtree.
99
+ recursive=no
100
+
101
+ # Add paths to the list of the source roots. Supports globbing patterns. The
102
+ # source root is an absolute path or a path relative to the current working
103
+ # directory used to determine a package namespace for modules located under the
104
+ # source root.
105
+ source-roots=
106
+
107
+ # When enabled, pylint would attempt to guess common misconfiguration and emit
108
+ # user-friendly hints instead of false-positive error messages.
109
+ suggestion-mode=yes
110
+
111
+ # Allow loading of arbitrary C extensions. Extensions are imported into the
112
+ # active Python interpreter and may run arbitrary code.
113
+ unsafe-load-any-extension=no
114
+
115
+ # In verbose mode, extra non-checker-related info will be displayed.
116
+ #verbose=
117
+
118
+
119
+ [BASIC]
120
+
121
+ # Naming style matching correct argument names.
122
+ argument-naming-style=snake_case
123
+
124
+ # Regular expression matching correct argument names. Overrides argument-
125
+ # naming-style. If left empty, argument names will be checked with the set
126
+ # naming style.
127
+ #argument-rgx=
128
+
129
+ # Naming style matching correct attribute names.
130
+ attr-naming-style=snake_case
131
+
132
+ # Regular expression matching correct attribute names. Overrides attr-naming-
133
+ # style. If left empty, attribute names will be checked with the set naming
134
+ # style.
135
+ #attr-rgx=
136
+
137
+ # Bad variable names which should always be refused, separated by a comma.
138
+ bad-names=foo,
139
+ bar,
140
+ baz,
141
+ toto,
142
+ tutu,
143
+ tata
144
+
145
+ # Bad variable names regexes, separated by a comma. If names match any regex,
146
+ # they will always be refused
147
+ bad-names-rgxs=
148
+
149
+ # Naming style matching correct class attribute names.
150
+ class-attribute-naming-style=any
151
+
152
+ # Regular expression matching correct class attribute names. Overrides class-
153
+ # attribute-naming-style. If left empty, class attribute names will be checked
154
+ # with the set naming style.
155
+ #class-attribute-rgx=
156
+
157
+ # Naming style matching correct class constant names.
158
+ class-const-naming-style=UPPER_CASE
159
+
160
+ # Regular expression matching correct class constant names. Overrides class-
161
+ # const-naming-style. If left empty, class constant names will be checked with
162
+ # the set naming style.
163
+ #class-const-rgx=
164
+
165
+ # Naming style matching correct class names.
166
+ class-naming-style=PascalCase
167
+
168
+ # Regular expression matching correct class names. Overrides class-naming-
169
+ # style. If left empty, class names will be checked with the set naming style.
170
+ #class-rgx=
171
+
172
+ # Naming style matching correct constant names.
173
+ const-naming-style=UPPER_CASE
174
+
175
+ # Regular expression matching correct constant names. Overrides const-naming-
176
+ # style. If left empty, constant names will be checked with the set naming
177
+ # style.
178
+ #const-rgx=
179
+
180
+ # Minimum line length for functions/classes that require docstrings, shorter
181
+ # ones are exempt.
182
+ docstring-min-length=-1
183
+
184
+ # Naming style matching correct function names.
185
+ function-naming-style=snake_case
186
+
187
+ # Regular expression matching correct function names. Overrides function-
188
+ # naming-style. If left empty, function names will be checked with the set
189
+ # naming style.
190
+ #function-rgx=
191
+
192
+ # Good variable names which should always be accepted, separated by a comma.
193
+ good-names=i,
194
+ j,
195
+ k,
196
+ ex,
197
+ Run,
198
+ _
199
+
200
+ # Good variable names regexes, separated by a comma. If names match any regex,
201
+ # they will always be accepted
202
+ good-names-rgxs=
203
+
204
+ # Include a hint for the correct naming format with invalid-name.
205
+ include-naming-hint=no
206
+
207
+ # Naming style matching correct inline iteration names.
208
+ inlinevar-naming-style=any
209
+
210
+ # Regular expression matching correct inline iteration names. Overrides
211
+ # inlinevar-naming-style. If left empty, inline iteration names will be checked
212
+ # with the set naming style.
213
+ #inlinevar-rgx=
214
+
215
+ # Naming style matching correct method names.
216
+ method-naming-style=snake_case
217
+
218
+ # Regular expression matching correct method names. Overrides method-naming-
219
+ # style. If left empty, method names will be checked with the set naming style.
220
+ #method-rgx=
221
+
222
+ # Naming style matching correct module names.
223
+ module-naming-style=snake_case
224
+
225
+ # Regular expression matching correct module names. Overrides module-naming-
226
+ # style. If left empty, module names will be checked with the set naming style.
227
+ #module-rgx=
228
+
229
+ # Colon-delimited sets of names that determine each other's naming style when
230
+ # the name regexes allow several styles.
231
+ name-group=
232
+
233
+ # Regular expression which should only match function or class names that do
234
+ # not require a docstring.
235
+ no-docstring-rgx=^_
236
+
237
+ # List of decorators that produce properties, such as abc.abstractproperty. Add
238
+ # to this list to register other decorators that produce valid properties.
239
+ # These decorators are taken in consideration only for invalid-name.
240
+ property-classes=abc.abstractproperty
241
+
242
+ # Regular expression matching correct type alias names. If left empty, type
243
+ # alias names will be checked with the set naming style.
244
+ #typealias-rgx=
245
+
246
+ # Regular expression matching correct type variable names. If left empty, type
247
+ # variable names will be checked with the set naming style.
248
+ #typevar-rgx=
249
+
250
+ # Naming style matching correct variable names.
251
+ variable-naming-style=snake_case
252
+
253
+ # Regular expression matching correct variable names. Overrides variable-
254
+ # naming-style. If left empty, variable names will be checked with the set
255
+ # naming style.
256
+ #variable-rgx=
257
+
258
+
259
+ [CLASSES]
260
+
261
+ # Warn about protected attribute access inside special methods
262
+ check-protected-access-in-special-methods=no
263
+
264
+ # List of method names used to declare (i.e. assign) instance attributes.
265
+ defining-attr-methods=__init__,
266
+ __new__,
267
+ setUp,
268
+ asyncSetUp,
269
+ __post_init__
270
+
271
+ # List of member names, which should be excluded from the protected access
272
+ # warning.
273
+ exclude-protected=_asdict,_fields,_replace,_source,_make,os._exit
274
+
275
+ # List of valid names for the first argument in a class method.
276
+ valid-classmethod-first-arg=cls
277
+
278
+ # List of valid names for the first argument in a metaclass class method.
279
+ valid-metaclass-classmethod-first-arg=mcs
280
+
281
+
282
+ [DESIGN]
283
+
284
+ # List of regular expressions of class ancestor names to ignore when counting
285
+ # public methods (see R0903)
286
+ exclude-too-few-public-methods=
287
+
288
+ # List of qualified class names to ignore when counting class parents (see
289
+ # R0901)
290
+ ignored-parents=
291
+
292
+ # Maximum number of arguments for function / method.
293
+ max-args=5
294
+
295
+ # Maximum number of attributes for a class (see R0902).
296
+ max-attributes=7
297
+
298
+ # Maximum number of boolean expressions in an if statement (see R0916).
299
+ max-bool-expr=5
300
+
301
+ # Maximum number of branch for function / method body.
302
+ max-branches=12
303
+
304
+ # Maximum number of locals for function / method body.
305
+ max-locals=15
306
+
307
+ # Maximum number of parents for a class (see R0901).
308
+ max-parents=7
309
+
310
+ # Maximum number of positional arguments for function / method.
311
+ #max-positional-arguments=5
312
+
313
+ # Maximum number of public methods for a class (see R0904).
314
+ max-public-methods=20
315
+
316
+ # Maximum number of return / yield for function / method body.
317
+ max-returns=6
318
+
319
+ # Maximum number of statements in function / method body.
320
+ max-statements=50
321
+
322
+ # Minimum number of public methods for a class (see R0903).
323
+ min-public-methods=2
324
+
325
+
326
+ [EXCEPTIONS]
327
+
328
+ # Exceptions that will emit a warning when caught.
329
+ overgeneral-exceptions=builtins.BaseException,builtins.Exception
330
+
331
+
332
+ [FORMAT]
333
+
334
+ # Expected format of line ending, e.g. empty (any line ending), LF or CRLF.
335
+ expected-line-ending-format=
336
+
337
+ # Regexp for a line that is allowed to be longer than the limit.
338
+ ignore-long-lines=^\s*(# )?<?https?://\S+>?$
339
+
340
+ # Number of spaces of indent required inside a hanging or continued line.
341
+ indent-after-paren=4
342
+
343
+ # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1
344
+ # tab).
345
+ indent-string=' '
346
+
347
+ # Maximum number of characters on a single line.
348
+ max-line-length=100
349
+
350
+ # Maximum number of lines in a module.
351
+ max-module-lines=1000
352
+
353
+ # Allow the body of a class to be on the same line as the declaration if body
354
+ # contains single statement.
355
+ single-line-class-stmt=no
356
+
357
+ # Allow the body of an if to be on the same line as the test if there is no
358
+ # else.
359
+ single-line-if-stmt=no
360
+
361
+
362
+ [IMPORTS]
363
+
364
+ # List of modules that can be imported at any level, not just the top level
365
+ # one.
366
+ allow-any-import-level=
367
+
368
+ # Allow explicit reexports by alias from a package __init__.
369
+ allow-reexport-from-package=no
370
+
371
+ # Allow wildcard imports from modules that define __all__.
372
+ allow-wildcard-with-all=no
373
+
374
+ # Deprecated modules which should not be used, separated by a comma.
375
+ deprecated-modules=
376
+
377
+ # Output a graph (.gv or any supported image format) of external dependencies
378
+ # to the given file (report RP0402 must not be disabled).
379
+ ext-import-graph=
380
+
381
+ # Output a graph (.gv or any supported image format) of all (i.e. internal and
382
+ # external) dependencies to the given file (report RP0402 must not be
383
+ # disabled).
384
+ import-graph=
385
+
386
+ # Output a graph (.gv or any supported image format) of internal dependencies
387
+ # to the given file (report RP0402 must not be disabled).
388
+ int-import-graph=
389
+
390
+ # Force import order to recognize a module as part of the standard
391
+ # compatibility libraries.
392
+ known-standard-library=
393
+
394
+ # Force import order to recognize a module as part of a third party library.
395
+ known-third-party=enchant
396
+
397
+ # Couples of modules and preferred modules, separated by a comma.
398
+ preferred-modules=
399
+
400
+
401
+ [LOGGING]
402
+
403
+ # The type of string formatting that logging methods do. `old` means using %
404
+ # formatting, `new` is for `{}` formatting.
405
+ logging-format-style=old
406
+
407
+ # Logging modules to check that the string format arguments are in logging
408
+ # function parameter format.
409
+ logging-modules=logging
410
+
411
+
412
+ [MESSAGES CONTROL]
413
+
414
+ # Only show warnings with the listed confidence levels. Leave empty to show
415
+ # all. Valid levels: HIGH, CONTROL_FLOW, INFERENCE, INFERENCE_FAILURE,
416
+ # UNDEFINED.
417
+ confidence=HIGH,
418
+ CONTROL_FLOW,
419
+ INFERENCE,
420
+ INFERENCE_FAILURE,
421
+ UNDEFINED
422
+
423
+ # Disable the message, report, category or checker with the given id(s). You
424
+ # can either give multiple identifiers separated by comma (,) or put this
425
+ # option multiple times (only on the command line, not in the configuration
426
+ # file where it should appear only once). You can also use "--disable=all" to
427
+ # disable everything first and then re-enable specific checks. For example, if
428
+ # you want to run only the similarities checker, you can use "--disable=all
429
+ # --enable=similarities". If you want to run only the classes checker, but have
430
+ # no Warning level messages displayed, use "--disable=all --enable=classes
431
+ # --disable=W".
432
+ disable=raw-checker-failed,
433
+ bad-inline-option,
434
+ locally-disabled,
435
+ file-ignored,
436
+ suppressed-message,
437
+ useless-suppression,
438
+ deprecated-pragma,
439
+ use-symbolic-message-instead,
440
+ use-implicit-booleaness-not-comparison-to-string,
441
+ use-implicit-booleaness-not-comparison-to-zero,
442
+ broad-exception-caught,
443
+ logging-fstring-interpolation,
444
+ arguments-renamed,
445
+ I,C,R,
446
+ fixme,
447
+
448
+ # Enable the message, report, category or checker with the given id(s). You can
449
+ # either give multiple identifier separated by comma (,) or put this option
450
+ # multiple time (only on the command line, not in the configuration file where
451
+ # it should appear only once). See also the "--disable" option for examples.
452
+ enable=
453
+
454
+
455
+ [METHOD_ARGS]
456
+
457
+ # List of qualified names (i.e., library.method) which require a timeout
458
+ # parameter e.g. 'requests.api.get,requests.api.post'
459
+ timeout-methods=requests.api.delete,requests.api.get,requests.api.head,requests.api.options,requests.api.patch,requests.api.post,requests.api.put,requests.api.request
460
+
461
+
462
+ [MISCELLANEOUS]
463
+
464
+ # List of note tags to take in consideration, separated by a comma.
465
+ notes=FIXME,
466
+ XXX,
467
+ TODO
468
+
469
+ # Regular expression of note tags to take in consideration.
470
+ notes-rgx=
471
+
472
+
473
+ [REFACTORING]
474
+
475
+ # Maximum number of nested blocks for function / method body
476
+ max-nested-blocks=5
477
+
478
+ # Complete name of functions that never returns. When checking for
479
+ # inconsistent-return-statements if a never returning function is called then
480
+ # it will be considered as an explicit return statement and no message will be
481
+ # printed.
482
+ never-returning-functions=sys.exit,argparse.parse_error
483
+
484
+ # Let 'consider-using-join' be raised when the separator to join on would be
485
+ # non-empty (resulting in expected fixes of the type: ``"- " + " -
486
+ # ".join(items)``)
487
+ suggest-join-with-non-empty-separator=yes
488
+
489
+
490
+ [REPORTS]
491
+
492
+ # Python expression which should return a score less than or equal to 10. You
493
+ # have access to the variables 'fatal', 'error', 'warning', 'refactor',
494
+ # 'convention', and 'info' which contain the number of messages in each
495
+ # category, as well as 'statement' which is the total number of statements
496
+ # analyzed. This score is used by the global evaluation report (RP0004).
497
+ evaluation=max(0, 0 if fatal else 10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10))
498
+
499
+ # Template used to display messages. This is a python new-style format string
500
+ # used to format the message information. See doc for all details.
501
+ msg-template=
502
+
503
+ # Set the output format. Available formats are: text, parseable, colorized,
504
+ # json2 (improved json format), json (old json format) and msvs (visual
505
+ # studio). You can also give a reporter class, e.g.
506
+ # mypackage.mymodule.MyReporterClass.
507
+ #output-format=
508
+
509
+ # Tells whether to display a full report or only the messages.
510
+ reports=no
511
+
512
+ # Activate the evaluation score.
513
+ score=yes
514
+
515
+
516
+ [SIMILARITIES]
517
+
518
+ # Comments are removed from the similarity computation
519
+ ignore-comments=yes
520
+
521
+ # Docstrings are removed from the similarity computation
522
+ ignore-docstrings=yes
523
+
524
+ # Imports are removed from the similarity computation
525
+ ignore-imports=yes
526
+
527
+ # Signatures are removed from the similarity computation
528
+ ignore-signatures=yes
529
+
530
+ # Minimum lines number of a similarity.
531
+ min-similarity-lines=4
532
+
533
+
534
+ [SPELLING]
535
+
536
+ # Limits count of emitted suggestions for spelling mistakes.
537
+ max-spelling-suggestions=4
538
+
539
+ # Spelling dictionary name. No available dictionaries : You need to install
540
+ # both the python package and the system dependency for enchant to work.
541
+ spelling-dict=
542
+
543
+ # List of comma separated words that should be considered directives if they
544
+ # appear at the beginning of a comment and should not be checked.
545
+ spelling-ignore-comment-directives=fmt: on,fmt: off,noqa:,noqa,nosec,isort:skip,mypy:
546
+
547
+ # List of comma separated words that should not be checked.
548
+ spelling-ignore-words=
549
+
550
+ # A path to a file that contains the private dictionary; one word per line.
551
+ spelling-private-dict-file=
552
+
553
+ # Tells whether to store unknown words to the private dictionary (see the
554
+ # --spelling-private-dict-file option) instead of raising a message.
555
+ spelling-store-unknown-words=no
556
+
557
+
558
+ [STRING]
559
+
560
+ # This flag controls whether inconsistent-quotes generates a warning when the
561
+ # character used as a quote delimiter is used inconsistently within a module.
562
+ check-quote-consistency=no
563
+
564
+ # This flag controls whether the implicit-str-concat should generate a warning
565
+ # on implicit string concatenation in sequences defined over several lines.
566
+ check-str-concat-over-line-jumps=no
567
+
568
+
569
+ [TYPECHECK]
570
+
571
+ # List of decorators that produce context managers, such as
572
+ # contextlib.contextmanager. Add to this list to register other decorators that
573
+ # produce valid context managers.
574
+ contextmanager-decorators=contextlib.contextmanager
575
+
576
+ # List of members which are set dynamically and missed by pylint inference
577
+ # system, and so shouldn't trigger E1101 when accessed. Python regular
578
+ # expressions are accepted.
579
+ generated-members=firebase_admin.firestore.*,firestore.*
580
+
581
+ # Tells whether to warn about missing members when the owner of the attribute
582
+ # is inferred to be None.
583
+ ignore-none=yes
584
+
585
+ # This flag controls whether pylint should warn about no-member and similar
586
+ # checks whenever an opaque object is returned when inferring. The inference
587
+ # can return multiple potential results while evaluating a Python object, but
588
+ # some branches might not be evaluated, which results in partial inference. In
589
+ # that case, it might be useful to still emit no-member and other checks for
590
+ # the rest of the inferred objects.
591
+ ignore-on-opaque-inference=yes
592
+
593
+ # List of symbolic message names to ignore for Mixin members.
594
+ ignored-checks-for-mixins=no-member,
595
+ not-async-context-manager,
596
+ not-context-manager,
597
+ attribute-defined-outside-init
598
+
599
+ # List of class names for which member attributes should not be checked (useful
600
+ # for classes with dynamically set attributes). This supports the use of
601
+ # qualified names.
602
+ ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace
603
+
604
+ # Show a hint with possible names when a member name was not found. The aspect
605
+ # of finding the hint is based on edit distance.
606
+ missing-member-hint=yes
607
+
608
+ # The minimum edit distance a name should have in order to be considered a
609
+ # similar match for a missing member name.
610
+ missing-member-hint-distance=1
611
+
612
+ # The total number of similar names that should be taken in consideration when
613
+ # showing a hint for a missing member.
614
+ missing-member-max-choices=1
615
+
616
+ # Regex pattern to define which classes are considered mixins.
617
+ mixin-class-rgx=.*[Mm]ixin
618
+
619
+ # List of decorators that change the signature of a decorated function.
620
+ signature-mutators=
621
+
622
+
623
+ [VARIABLES]
624
+
625
+ # List of additional names supposed to be defined in builtins. Remember that
626
+ # you should avoid defining new builtins when possible.
627
+ additional-builtins=
628
+
629
+ # Tells whether unused global variables should be treated as a violation.
630
+ allow-global-unused-variables=yes
631
+
632
+ # List of names allowed to shadow builtins
633
+ allowed-redefined-builtins=
634
+
635
+ # List of strings which can identify a callback function by name. A callback
636
+ # name must start or end with one of those strings.
637
+ callbacks=cb_,
638
+ _cb
639
+
640
+ # A regular expression matching the name of dummy variables (i.e. expected to
641
+ # not be used).
642
+ dummy-variables-rgx=_+$|(_[a-zA-Z0-9_]*[a-zA-Z0-9]+?$)|dummy|^ignored_|^unused_
643
+
644
+ # Argument names that match this expression will be ignored.
645
+ ignored-argument-names=_.*|^ignored_|^unused_
646
+
647
+ # Tells whether we should check for unused import in __init__ files.
648
+ init-import=no
649
+
650
+ # List of qualified module names which can have objects that can redefine
651
+ # builtins.
652
+ redefining-builtins-modules=six.moves,past.builtins,future.builtins,builtins,io
.vscode/launch.json ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "name": "debug go",
9
+ "type": "go",
10
+ "request": "launch",
11
+ "mode": "exec",
12
+ "cwd": "${workspaceFolder}",
13
+ "program": "${workspaceFolder}/agents/bin/worker",
14
+ "env": {
15
+ "LD_LIBRARY_PATH": "${workspaceFolder}/agents/ten_packages/system/ten_runtime_go/lib:${workspaceFolder}/agents/ten_packages/system/agora_rtc_sdk/lib:${workspaceFolder}/agents/ten_packages/system/azure_speech_sdk/lib",
16
+ "TEN_APP_BASE_DIR": "${workspaceFolder}/agents"
17
+ }
18
+ },
19
+ {
20
+ "name": "debug python",
21
+ "type": "debugpy",
22
+ "request": "attach",
23
+ "connect": {
24
+ "host": "localhost",
25
+ "port": 5678
26
+ },
27
+ "preLaunchTask": "start app"
28
+ },
29
+ {
30
+ "name": "debug cpp",
31
+ "type": "cppdbg",
32
+ "request": "launch",
33
+ "program": "${workspaceFolder}/agents/bin/worker",
34
+ "cwd": "${workspaceFolder}",
35
+ "environment": [
36
+ {
37
+ "name": "LD_LIBRARY_PATH",
38
+ "value": "${workspaceFolder}/agents/ten_packages/system/agora_rtc_sdk/lib:${workspaceFolder}/agents/ten_packages/system/azure_speech_sdk/lib"
39
+ },
40
+ {
41
+ "name": "CGO_LDFLAGS",
42
+ "value": "-L${workspaceFolder}/agents/ten_packages/system/ten_runtime_go/lib -lten_runtime_go -Wl,-rpath,@loader_path/lib -Wl,-rpath,@loader_path/../lib"
43
+ }
44
+ ]
45
+ }
46
+ ]
47
+ }
.vscode/settings.json ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "C_Cpp.intelliSenseEngine": "disabled",
3
+ "editor.formatOnSave": true,
4
+ "editor.defaultFormatter": null,
5
+ "[python]": {
6
+ "editor.defaultFormatter": "ms-python.black-formatter"
7
+ },
8
+ "git.ignoreLimitWarning": true,
9
+ "pylint.ignorePatterns": [
10
+ "*/ten_runtime_python/**/*",
11
+ "/usr/lib/**/*"
12
+ ],
13
+ }
.vscode/tasks.json ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "type": "shell",
6
+ "label": "build",
7
+ "command": "make build",
8
+ "args": [],
9
+ "group": {
10
+ "kind": "build",
11
+ "isDefault": true
12
+ }
13
+ },
14
+ {
15
+ "label": "start app",
16
+ "type": "shell",
17
+ "command": "export TEN_ENABLE_PYTHON_DEBUG=true; export TEN_PYTHON_DEBUG_PORT=5678; ./agents/bin/start",
18
+ "group": "none",
19
+ "isBackground": true
20
+ },
21
+ ]
22
+ }
Dockerfile CHANGED
@@ -22,25 +22,22 @@ RUN apt-get clean && apt-get update && apt-get install -y --no-install-recommend
22
  ca-certificates \
23
  && apt-get clean && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/*
24
 
25
- # Создаем пользователя для запуска приложения с правильными правами
26
- RUN useradd -m -s /bin/bash tenuser
27
-
28
- # Установка Go 1.21 с правильными правами доступа
29
  RUN wget https://golang.org/dl/go1.21.0.linux-amd64.tar.gz && \
30
  tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz && \
31
- rm go1.21.0.linux-amd64.tar.gz && \
32
- mkdir -p /home/tenuser/go && \
33
- chown -R tenuser:tenuser /home/tenuser/go
34
-
35
  ENV PATH=$PATH:/usr/local/go/bin
36
- ENV GOPATH=/home/tenuser/go
37
  ENV PATH=$PATH:$GOPATH/bin
38
 
39
- # Установка Node.js 20.x и pnpm для Playground
40
  RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
41
  apt-get install -y nodejs && \
42
  npm install -g pnpm
43
 
 
 
 
44
  WORKDIR /app
45
 
46
  # Клонирование репозитория TEN Agent (основная ветка)
@@ -73,7 +70,7 @@ RUN cd /app/server && \
73
 
74
  # Сборка Playground UI с правами пользователя
75
  WORKDIR /app/playground
76
- ENV PNPM_HOME="/home/tenuser/.pnpm-store"
77
  ENV PATH="$PNPM_HOME:$PATH"
78
  RUN pnpm install --no-frozen-lockfile && \
79
  NEXT_PUBLIC_EDIT_GRAPH_MODE=false pnpm build
 
22
  ca-certificates \
23
  && apt-get clean && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/*
24
 
25
+ # Установка Go 1.21
 
 
 
26
  RUN wget https://golang.org/dl/go1.21.0.linux-amd64.tar.gz && \
27
  tar -C /usr/local -xzf go1.21.0.linux-amd64.tar.gz && \
28
+ rm go1.21.0.linux-amd64.tar.gz
 
 
 
29
  ENV PATH=$PATH:/usr/local/go/bin
30
+ ENV GOPATH=/go
31
  ENV PATH=$PATH:$GOPATH/bin
32
 
33
+ # Установка Node.js 20.x (вместо 18.x) и pnpm для Playground
34
  RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - && \
35
  apt-get install -y nodejs && \
36
  npm install -g pnpm
37
 
38
+ # Создаем пользователя для запуска приложения с правильными правами
39
+ RUN useradd -m -s /bin/bash tenuser
40
+
41
  WORKDIR /app
42
 
43
  # Клонирование репозитория TEN Agent (основная ветка)
 
70
 
71
  # Сборка Playground UI с правами пользователя
72
  WORKDIR /app/playground
73
+ ENV PNPM_HOME="/app/.pnpm-store"
74
  ENV PATH="$PNPM_HOME:$PATH"
75
  RUN pnpm install --no-frozen-lockfile && \
76
  NEXT_PUBLIC_EDIT_GRAPH_MODE=false pnpm build
LICENSE ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Apache License
2
+ Version 2.0, January 2004
3
+ http://www.apache.org/licenses/
4
+
5
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+ 1. Definitions.
8
+
9
+ "License" shall mean the terms and conditions for use, reproduction,
10
+ and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+ "Licensor" shall mean the copyright owner or entity authorized by
13
+ the copyright owner that is granting the License.
14
+
15
+ "Legal Entity" shall mean the union of the acting entity and all
16
+ other entities that control, are controlled by, or are under common
17
+ control with that entity. For the purposes of this definition,
18
+ "control" means (i) the power, direct or indirect, to cause the
19
+ direction or management of such entity, whether by contract or
20
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+ outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+ "You" (or "Your") shall mean an individual or Legal Entity
24
+ exercising permissions granted by this License.
25
+
26
+ "Source" form shall mean the preferred form for making modifications,
27
+ including but not limited to software source code, documentation
28
+ source, and configuration files.
29
+
30
+ "Object" form shall mean any form resulting from mechanical
31
+ transformation or translation of a Source form, including but
32
+ not limited to compiled object code, generated documentation,
33
+ and conversions to other media types.
34
+
35
+ "Work" shall mean the work of authorship, whether in Source or
36
+ Object form, made available under the License, as indicated by a
37
+ copyright notice that is included in or attached to the work
38
+ (an example is provided in the Appendix below).
39
+
40
+ "Derivative Works" shall mean any work, whether in Source or Object
41
+ form, that is based on (or derived from) the Work and for which the
42
+ editorial revisions, annotations, elaborations, or other modifications
43
+ represent, as a whole, an original work of authorship. For the purposes
44
+ of this License, Derivative Works shall not include works that remain
45
+ separable from, or merely link (or bind by name) to the interfaces of,
46
+ the Work and Derivative Works thereof.
47
+
48
+ "Contribution" shall mean any work of authorship, including
49
+ the original version of the Work and any modifications or additions
50
+ to that Work or Derivative Works thereof, that is intentionally
51
+ submitted to Licensor for inclusion in the Work by the copyright owner
52
+ or by an individual or Legal Entity authorized to submit on behalf of
53
+ the copyright owner. For the purposes of this definition, "submitted"
54
+ means any form of electronic, verbal, or written communication sent
55
+ to the Licensor or its representatives, including but not limited to
56
+ communication on electronic mailing lists, source code control systems,
57
+ and issue tracking systems that are managed by, or on behalf of, the
58
+ Licensor for the purpose of discussing and improving the Work, but
59
+ excluding communication that is conspicuously marked or otherwise
60
+ designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+ "Contributor" shall mean Licensor and any individual or Legal Entity
63
+ on behalf of whom a Contribution has been received by Licensor and
64
+ subsequently incorporated within the Work.
65
+
66
+ 2. Grant of Copyright License. Subject to the terms and conditions of
67
+ this License, each Contributor hereby grants to You a perpetual,
68
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+ copyright license to reproduce, prepare Derivative Works of,
70
+ publicly display, publicly perform, sublicense, and distribute the
71
+ Work and such Derivative Works in Source or Object form.
72
+
73
+ 3. Grant of Patent License. Subject to the terms and conditions of
74
+ this License, each Contributor hereby grants to You a perpetual,
75
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+ (except as stated in this section) patent license to make, have made,
77
+ use, offer to sell, sell, import, and otherwise transfer the Work,
78
+ where such license applies only to those patent claims licensable
79
+ by such Contributor that are necessarily infringed by their
80
+ Contribution(s) alone or by combination of their Contribution(s)
81
+ with the Work to which such Contribution(s) was submitted. If You
82
+ institute patent litigation against any entity (including a
83
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+ or a Contribution incorporated within the Work constitutes direct
85
+ or contributory patent infringement, then any patent licenses
86
+ granted to You under this License for that Work shall terminate
87
+ as of the date such litigation is filed.
88
+
89
+ 4. Redistribution. You may reproduce and distribute copies of the
90
+ Work or Derivative Works thereof in any medium, with or without
91
+ modifications, and in Source or Object form, provided that You
92
+ meet the following conditions:
93
+
94
+ (a) You must give any other recipients of the Work or
95
+ Derivative Works a copy of this License; and
96
+
97
+ (b) You must cause any modified files to carry prominent notices
98
+ stating that You changed the files; and
99
+
100
+ (c) You must retain, in the Source form of any Derivative Works
101
+ that You distribute, all copyright, patent, trademark, and
102
+ attribution notices from the Source form of the Work,
103
+ excluding those notices that do not pertain to any part of
104
+ the Derivative Works; and
105
+
106
+ (d) If the Work includes a "NOTICE" text file as part of its
107
+ distribution, then any Derivative Works that You distribute must
108
+ include a readable copy of the attribution notices contained
109
+ within such NOTICE file, excluding those notices that do not
110
+ pertain to any part of the Derivative Works, in at least one
111
+ of the following places: within a NOTICE text file distributed
112
+ as part of the Derivative Works; within the Source form or
113
+ documentation, if provided along with the Derivative Works; or,
114
+ within a display generated by the Derivative Works, if and
115
+ wherever such third-party notices normally appear. The contents
116
+ of the NOTICE file are for informational purposes only and
117
+ do not modify the License. You may add Your own attribution
118
+ notices within Derivative Works that You distribute, alongside
119
+ or as an addendum to the NOTICE text from the Work, provided
120
+ that such additional attribution notices cannot be construed
121
+ as modifying the License.
122
+
123
+ You may add Your own copyright statement to Your modifications and
124
+ may provide additional or different license terms and conditions
125
+ for use, reproduction, or distribution of Your modifications, or
126
+ for any such Derivative Works as a whole, provided Your use,
127
+ reproduction, and distribution of the Work otherwise complies with
128
+ the conditions stated in this License.
129
+
130
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
131
+ any Contribution intentionally submitted for inclusion in the Work
132
+ by You to the Licensor shall be under the terms and conditions of
133
+ this License, without any additional terms or conditions.
134
+ Notwithstanding the above, nothing herein shall supersede or modify
135
+ the terms of any separate license agreement you may have executed
136
+ with Licensor regarding such Contributions.
137
+
138
+ 6. Trademarks. This License does not grant permission to use the trade
139
+ names, trademarks, service marks, or product names of the Licensor,
140
+ except as required for reasonable and customary use in describing the
141
+ origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+ 7. Disclaimer of Warranty. Unless required by applicable law or
144
+ agreed to in writing, Licensor provides the Work (and each
145
+ Contributor provides its Contributions) on an "AS IS" BASIS,
146
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+ implied, including, without limitation, any warranties or conditions
148
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+ PARTICULAR PURPOSE. You are solely responsible for determining the
150
+ appropriateness of using or redistributing the Work and assume any
151
+ risks associated with Your exercise of permissions under this License.
152
+
153
+ 8. Limitation of Liability. In no event and under no legal theory,
154
+ whether in tort (including negligence), contract, or otherwise,
155
+ unless required by applicable law (such as deliberate and grossly
156
+ negligent acts) or agreed to in writing, shall any Contributor be
157
+ liable to You for damages, including any direct, indirect, special,
158
+ incidental, or consequential damages of any character arising as a
159
+ result of this License or out of the use or inability to use the
160
+ Work (including but not limited to damages for loss of goodwill,
161
+ work stoppage, computer failure or malfunction, or any and all
162
+ other commercial damages or losses), even if such Contributor
163
+ has been advised of the possibility of such damages.
164
+
165
+ 9. Accepting Warranty or Additional Liability. While redistributing
166
+ the Work or Derivative Works thereof, You may choose to offer,
167
+ and charge a fee for, acceptance of support, warranty, indemnity,
168
+ or other liability obligations and/or rights consistent with this
169
+ License. However, in accepting such obligations, You may act only
170
+ on Your own behalf and on Your sole responsibility, not on behalf
171
+ of any other Contributor, and only if You agree to indemnify,
172
+ defend, and hold each Contributor harmless for any liability
173
+ incurred by, or claims asserted against, such Contributor by reason
174
+ of your accepting any such warranty or additional liability.
175
+
176
+ END OF TERMS AND CONDITIONS
177
+
178
+ APPENDIX: How to apply the Apache License to your work.
179
+
180
+ To apply the Apache License to your work, attach the following
181
+ boilerplate notice, with the fields enclosed by brackets "[]"
182
+ replaced with your own identifying information. (Don't include
183
+ the brackets!) The text should be enclosed in the appropriate
184
+ comment syntax for the file format. We also recommend that a
185
+ file or class name and description of purpose be included on the
186
+ same "printed page" as the copyright notice for easier
187
+ identification within third-party archives.
188
+
189
+ Copyright [yyyy] [name of copyright owner]
190
+
191
+ Licensed under the Apache License, Version 2.0 (the "License");
192
+ you may not use this file except in compliance with the License.
193
+ You may obtain a copy of the License at
194
+
195
+ http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+ Unless required by applicable law or agreed to in writing, software
198
+ distributed under the License is distributed on an "AS IS" BASIS,
199
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+ See the License for the specific language governing permissions and
201
+ limitations under the License.
Taskfile.yml ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3'
2
+
3
+ tasks:
4
+ clean:
5
+ desc: clean up
6
+ cmds:
7
+ - task: clean-agents
8
+ - task: clean-server
9
+
10
+ lint:
11
+ desc: lint-agent
12
+ env:
13
+ PYTHONPATH: "./agents/ten_packages/system/ten_runtime_python/lib:./agents/ten_packages/system/ten_runtime_python/interface:./agents/ten_packages/system/ten_ai_base/interface"
14
+ cmds:
15
+ - ./agents/scripts/pylint.sh
16
+
17
+ install-tools:
18
+ desc: install tools
19
+ cmds:
20
+ - pip install pylint
21
+
22
+ build:
23
+ desc: build
24
+ cmds:
25
+ - task: build-agent
26
+ - task: build-server
27
+
28
+ use:
29
+ desc: use agent, default 'agents/examples/default'
30
+ vars:
31
+ AGENT: '{{.AGENT| default "agents/examples/default"}}'
32
+ cmds:
33
+ - ln -sf {{.USER_WORKING_DIR}}/{{.AGENT}}/manifest.json ./agents/
34
+ - ln -sf {{.USER_WORKING_DIR}}/{{.AGENT}}/property.json ./agents/
35
+ - task: build
36
+
37
+ run-server:
38
+ desc: run backend http server
39
+ cmds:
40
+ - source .env && /app/server/bin/api
41
+
42
+ run-gd-server:
43
+ desc: run tman dev http server for graph designer
44
+ dir: ./agents
45
+ cmds:
46
+ - tman designer
47
+
48
+ run:
49
+ desc: run servers
50
+ deps:
51
+ - task: run-server
52
+ - task: run-gd-server
53
+
54
+ build-agent:
55
+ desc: build agent
56
+ dir: ./agents
57
+ internal: true
58
+ cmds:
59
+ - ./scripts/install_deps_and_build.sh linux x64 && mv bin/main bin/worker
60
+
61
+ build-server:
62
+ desc: build server
63
+ dir: ./server
64
+ cmds:
65
+ - go mod tidy && go mod download && go build -o bin/api main.go
66
+
67
+ clean-agents:
68
+ desc: clean up agents
69
+ dir: ./agents
70
+ internal: true
71
+ cmds:
72
+ - 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
73
+ - find . -type d -name .pytest_cache -exec rm -rf {} \; || true
74
+ - find . -type d -name __pycache__ -exec rm -rf {} \; || true
75
+ - find . -type d -name .ten -exec rm -rf {} \; || true
76
+ - find . -name .coverage -exec rm -f {} \; || true
77
+
78
+ clean-server:
79
+ desc: clean up server
80
+ dir: ./server
81
+ internal: true
82
+ cmds:
83
+ - rm -rf bin
84
+
85
+ test:
86
+ desc: run tests
87
+ cmds:
88
+ - task: test-agent-extensions
89
+ - task: test-server
90
+
91
+ test-server:
92
+ desc: test server
93
+ dir: ./server
94
+ internal: true
95
+ cmds:
96
+ - go test -v ./...
97
+
98
+ test-agent-extensions:
99
+ desc: run standalone testing of extensions
100
+ internal: true
101
+ env:
102
+ 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"
103
+ vars:
104
+ EXTENSIONS:
105
+ sh: 'find agents/ten_packages/extension -type d -exec test -d "{}/tests" \; -print'
106
+ cmds:
107
+ - for: { var: EXTENSIONS }
108
+ task: test-extension
109
+ vars:
110
+ EXTENSION: '{{ .ITEM }}'
111
+
112
+ test-extension:
113
+ desc: run standalone testing of one single extension
114
+ vars:
115
+ EXTENSION: '{{.EXTENSION| default "agents/ten_packages/extension/elevenlabs_tts_python"}}'
116
+ env:
117
+ 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"
118
+ dotenv: ['.env']
119
+ cmds:
120
+ - cd {{.EXTENSION}} && tman -y install --standalone && ./tests/bin/start {{ .CLI_ARGS }}
agents/.clang-format ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ BasedOnStyle: Google
2
+ SeparateDefinitionBlocks: Always
3
+ ColumnLimit: 120
4
+ BinPackArguments: false
5
+ BinPackParameters: false
6
+ AlignAfterOpenBracket: Align
7
+ AllowAllArgumentsOnNextLine: false
8
+ AllowAllParametersOfDeclarationOnNextLine: false
agents/.gitignore ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.log
2
+ ten_packages/extension_group/
3
+ ten_packages/extension/agora_rtc
4
+ ten_packages/extension/azure_tts
5
+ ten_packages/extension/agora_sess_ctrl
6
+ ten_packages/extension/agora_rtm
7
+ ten_packages/extension/http_server_python
8
+ ten_packages/system/agora_rtc_sdk
9
+ ten_packages/system/azure_speech_sdk
10
+ ten_packages/system/nlohmann_json
11
+ ten_packages/system/ten_runtime*
12
+ ten_packages/system
13
+ ten_packages/addon_loader
14
+ .ten
15
+ agoradns.dat
16
+ agorareport.dat
17
+ agorartmreport.dat
18
+ agora_cache.db
19
+ bin/man
20
+ bin/worker
21
+ /BUILD.gn
22
+ .cache/
23
+ /compile_commands.json
24
+ core
25
+ crash_context_v1
26
+ .deps/
27
+ .DS_Store
28
+ /.gn
29
+ /.gnfiles
30
+ include/
31
+ interface/
32
+ lib/
33
+ /out/
34
+ *.pcm
35
+ .release
36
+ session_control.conf.agora
37
+ xdump_config
38
+ .vscode
39
+ *.pyc
40
+ *.pyc.*
41
+ /manifest.json
42
+ /manifest-lock.json
43
+ /property.json
agents/bin/start ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+ set -e
4
+
5
+ cd "$(dirname "${BASH_SOURCE[0]}")/.."
6
+
7
+ #export TEN_ENABLE_PYTHON_DEBUG=true
8
+ #export TEN_PYTHON_DEBUG_PORT=5678
9
+ export PYTHONPATH=$(pwd)/ten_packages/system/ten_ai_base/interface:$PYTHONPATH
10
+ export LD_LIBRARY_PATH=$(pwd)/ten_packages/system/agora_rtc_sdk/lib:$(pwd)/ten_packages/extension/agora_rtm/lib:$(pwd)/ten_packages/system/azure_speech_sdk/lib
11
+
12
+ exec bin/worker "$@"
agents/examples/default/manifest.json ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "app",
3
+ "name": "agent_demo",
4
+ "version": "0.8.0",
5
+ "dependencies": [
6
+ {
7
+ "type": "system",
8
+ "name": "ten_runtime_go",
9
+ "version": "0.8"
10
+ },
11
+ {
12
+ "type": "extension",
13
+ "name": "agora_rtc",
14
+ "version": "=0.12.0"
15
+ },
16
+ {
17
+ "type": "extension",
18
+ "name": "agora_sess_ctrl",
19
+ "version": "=0.4.4"
20
+ },
21
+ {
22
+ "type": "system",
23
+ "name": "azure_speech_sdk",
24
+ "version": "1.38.0"
25
+ },
26
+ {
27
+ "type": "system",
28
+ "name": "ten_ai_base",
29
+ "version": "0.4.1"
30
+ },
31
+ {
32
+ "type": "extension",
33
+ "name": "azure_tts",
34
+ "version": "=0.8.1"
35
+ },
36
+ {
37
+ "type": "extension",
38
+ "name": "openai_v2v_python",
39
+ "version": "=0.1.0"
40
+ },
41
+ {
42
+ "type": "extension",
43
+ "name": "message_collector",
44
+ "version": "=0.1.0"
45
+ },
46
+ {
47
+ "type": "extension",
48
+ "name": "bingsearch_tool_python",
49
+ "version": "=0.1.0"
50
+ },
51
+ {
52
+ "type": "extension",
53
+ "name": "openai_chatgpt_python",
54
+ "version": "=0.1.0"
55
+ },
56
+ {
57
+ "type": "extension",
58
+ "name": "fish_audio_tts",
59
+ "version": "=0.1.0"
60
+ },
61
+ {
62
+ "type": "extension",
63
+ "name": "interrupt_detector_python",
64
+ "version": "=0.1.0"
65
+ },
66
+ {
67
+ "type": "extension",
68
+ "name": "weatherapi_tool_python",
69
+ "version": "=0.1.0"
70
+ },
71
+ {
72
+ "type": "extension",
73
+ "name": "deepgram_asr_python",
74
+ "version": "=0.1.0"
75
+ },
76
+ {
77
+ "type": "extension",
78
+ "name": "vision_tool_python",
79
+ "version": "=0.1.0"
80
+ },
81
+ {
82
+ "type": "extension",
83
+ "name": "vision_analyze_tool_python",
84
+ "version": "=0.1.0"
85
+ },
86
+ {
87
+ "type": "extension",
88
+ "name": "transcribe_asr_python",
89
+ "version": "=0.1.0"
90
+ },
91
+ {
92
+ "type": "extension",
93
+ "name": "gemini_llm_python",
94
+ "version": "=0.1.0"
95
+ },
96
+ {
97
+ "type": "extension",
98
+ "name": "bedrock_llm_python",
99
+ "version": "=0.1.0"
100
+ },
101
+ {
102
+ "type": "extension",
103
+ "name": "polly_tts",
104
+ "version": "=0.1.0"
105
+ },
106
+ {
107
+ "type": "extension",
108
+ "name": "minimax_tts_python",
109
+ "version": "=0.1.0"
110
+ },
111
+ {
112
+ "type": "extension",
113
+ "name": "minimax_v2v_python",
114
+ "version": "=0.1.0"
115
+ },
116
+ {
117
+ "type": "extension",
118
+ "name": "cosy_tts_python",
119
+ "version": "=0.1.0"
120
+ },
121
+ {
122
+ "type": "extension",
123
+ "name": "elevenlabs_tts_python",
124
+ "version": "=0.1.0"
125
+ },
126
+ {
127
+ "type": "extension",
128
+ "name": "dify_python",
129
+ "version": "=0.1.0"
130
+ },
131
+ {
132
+ "type": "extension",
133
+ "name": "gemini_v2v_python",
134
+ "version": "=0.1.0"
135
+ },
136
+ {
137
+ "type": "extension",
138
+ "name": "coze_python_async",
139
+ "version": "=0.1.0"
140
+ },
141
+ {
142
+ "type": "extension",
143
+ "name": "openai_image_generate_tool",
144
+ "version": "=0.1.0"
145
+ },
146
+ {
147
+ "type": "extension",
148
+ "name": "computer_tool_python",
149
+ "version": "=0.1.0"
150
+ }
151
+ ]
152
+ }
agents/examples/default/property.json ADDED
@@ -0,0 +1,1331 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_ten": {
3
+ "predefined_graphs": [
4
+ {
5
+ "name": "voice_assistant",
6
+ "auto_start": true,
7
+ "nodes": [
8
+ {
9
+ "type": "extension",
10
+ "name": "agora_rtc",
11
+ "addon": "agora_rtc",
12
+ "extension_group": "default",
13
+ "property": {
14
+ "app_id": "${env:AGORA_APP_ID}",
15
+ "token": "<agora_token>",
16
+ "channel": "ten_agent_test",
17
+ "stream_id": 1234,
18
+ "remote_stream_id": "123",
19
+ "subscribe_audio": true,
20
+ "publish_audio": true,
21
+ "publish_data": true,
22
+ "enable_agora_asr": false,
23
+ "agora_asr_vendor_name": "microsoft",
24
+ "agora_asr_language": "ru-RU",
25
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
26
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
27
+ "agora_asr_session_control_file_path": "session_control.conf"
28
+ }
29
+ },
30
+ {
31
+ "type": "extension",
32
+ "name": "stt",
33
+ "addon": "deepgram_asr_python",
34
+ "extension_group": "stt",
35
+ "property": {
36
+ "api_key": "${env:DEEPGRAM_API_KEY}",
37
+ "language": "ru-RU",
38
+ "model": "nova-2",
39
+ "sample_rate": 16000
40
+ }
41
+ },
42
+ {
43
+ "type": "extension",
44
+ "name": "llm",
45
+ "addon": "openai_chatgpt_python",
46
+ "extension_group": "chatgpt",
47
+ "property": {
48
+ "api_key": "${env:OPENAI_API_KEY}",
49
+ "base_url": "https://nitrox-fastflowwrapper.hf.space/v1",
50
+ "frequency_penalty": 0.9,
51
+ "greeting": "Я подключилась, о чем сегодня?",
52
+ "max_memory_length": 150,
53
+ "max_tokens": 512,
54
+ "model": "${env:OPENAI_MODEL}",
55
+ "prompt": "Your role is Friend. You provide emotional support, actively listen and reflect on the user's feelings, validate their emotions, and ask open-ended questions to deepen the conversation in a safe and non-judgmental space. Engage informally and share personal experiences while respecting boundaries and encouraging the user. Maintain clarity and conciseness by replying in no more than five sentences per answer using friendly English language. Your responses must always include answers to the user's inquiries while offering insights, comfort, and encouragement without using any special symbols. Your language is Russian.",
56
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
57
+ }
58
+ },
59
+ {
60
+ "type": "extension",
61
+ "name": "tts",
62
+ "addon": "fish_audio_tts",
63
+ "extension_group": "tts",
64
+ "property": {
65
+ "api_key": "${env:FISH_AUDIO_TTS_KEY}",
66
+ "base_url": "https://api.fish.audio",
67
+ "model_id": "d61694f4ee5042aba2ffe11a9635d97e",
68
+ "optimize_streaming_latency": true,
69
+ "request_timeout_seconds": 30
70
+ }
71
+ },
72
+ {
73
+ "type": "extension",
74
+ "name": "interrupt_detector",
75
+ "addon": "interrupt_detector_python",
76
+ "extension_group": "default",
77
+ "property": {}
78
+ },
79
+ {
80
+ "type": "extension",
81
+ "name": "message_collector",
82
+ "addon": "message_collector",
83
+ "extension_group": "transcriber",
84
+ "property": {}
85
+ }
86
+ ],
87
+ "connections": [
88
+ {
89
+ "extension": "agora_rtc",
90
+ "cmd": [
91
+ {
92
+ "name": "on_user_joined",
93
+ "dest": [
94
+ {
95
+ "extension": "llm"
96
+ }
97
+ ]
98
+ },
99
+ {
100
+ "name": "on_user_left",
101
+ "dest": [
102
+ {
103
+ "extension": "llm"
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ "name": "on_connection_failure",
109
+ "dest": [
110
+ {
111
+ "extension": "llm"
112
+ }
113
+ ]
114
+ }
115
+ ],
116
+ "audio_frame": [
117
+ {
118
+ "name": "pcm_frame",
119
+ "dest": [
120
+ {
121
+ "extension": "stt"
122
+ }
123
+ ]
124
+ }
125
+ ]
126
+ },
127
+ {
128
+ "extension": "stt",
129
+ "data": [
130
+ {
131
+ "name": "text_data",
132
+ "dest": [
133
+ {
134
+ "extension": "interrupt_detector"
135
+ },
136
+ {
137
+ "extension": "message_collector"
138
+ }
139
+ ]
140
+ }
141
+ ]
142
+ },
143
+ {
144
+ "extension": "llm",
145
+ "cmd": [
146
+ {
147
+ "name": "flush",
148
+ "dest": [
149
+ {
150
+ "extension": "tts"
151
+ }
152
+ ]
153
+ }
154
+ ],
155
+ "data": [
156
+ {
157
+ "name": "text_data",
158
+ "dest": [
159
+ {
160
+ "extension": "tts"
161
+ },
162
+ {
163
+ "extension": "message_collector"
164
+ }
165
+ ]
166
+ },
167
+ {
168
+ "name": "content_data",
169
+ "dest": [
170
+ {
171
+ "extension": "message_collector"
172
+ }
173
+ ]
174
+ }
175
+ ]
176
+ },
177
+ {
178
+ "extension": "message_collector",
179
+ "data": [
180
+ {
181
+ "name": "data",
182
+ "dest": [
183
+ {
184
+ "extension": "agora_rtc"
185
+ }
186
+ ]
187
+ }
188
+ ]
189
+ },
190
+ {
191
+ "extension": "tts",
192
+ "cmd": [
193
+ {
194
+ "name": "flush",
195
+ "dest": [
196
+ {
197
+ "extension": "agora_rtc"
198
+ }
199
+ ]
200
+ }
201
+ ],
202
+ "audio_frame": [
203
+ {
204
+ "name": "pcm_frame",
205
+ "dest": [
206
+ {
207
+ "extension": "agora_rtc"
208
+ }
209
+ ]
210
+ }
211
+ ]
212
+ },
213
+ {
214
+ "extension": "interrupt_detector",
215
+ "cmd": [
216
+ {
217
+ "name": "flush",
218
+ "dest": [
219
+ {
220
+ "extension": "llm"
221
+ }
222
+ ]
223
+ }
224
+ ],
225
+ "data": [
226
+ {
227
+ "name": "text_data",
228
+ "dest": [
229
+ {
230
+ "extension": "llm"
231
+ }
232
+ ]
233
+ }
234
+ ]
235
+ }
236
+ ]
237
+ },
238
+ {
239
+ "name": "voice_assistant_integrated_stt",
240
+ "auto_start": true,
241
+ "nodes": [
242
+ {
243
+ "type": "extension",
244
+ "name": "agora_rtc",
245
+ "addon": "agora_rtc",
246
+ "extension_group": "default",
247
+ "property": {
248
+ "app_id": "${env:AGORA_APP_ID}",
249
+ "token": "<agora_token>",
250
+ "channel": "ten_agent_test",
251
+ "stream_id": 1234,
252
+ "remote_stream_id": 123,
253
+ "subscribe_audio": true,
254
+ "publish_audio": true,
255
+ "publish_data": true,
256
+ "enable_agora_asr": true,
257
+ "agora_asr_vendor_name": "microsoft",
258
+ "agora_asr_language": "en-US",
259
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
260
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
261
+ "agora_asr_session_control_file_path": "session_control.conf"
262
+ }
263
+ },
264
+ {
265
+ "type": "extension",
266
+ "name": "llm",
267
+ "addon": "openai_chatgpt_python",
268
+ "extension_group": "chatgpt",
269
+ "property": {
270
+ "api_key": "${env:OPENAI_API_KEY}",
271
+ "base_url": "",
272
+ "frequency_penalty": 0.9,
273
+ "greeting": "TEN Agent connected. How can I help you today?",
274
+ "max_memory_length": 10,
275
+ "max_tokens": 512,
276
+ "model": "${env:OPENAI_MODEL}",
277
+ "prompt": "",
278
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
279
+ }
280
+ },
281
+ {
282
+ "type": "extension",
283
+ "name": "tts",
284
+ "addon": "fish_audio_tts",
285
+ "extension_group": "tts",
286
+ "property": {
287
+ "api_key": "${env:FISH_AUDIO_TTS_KEY}",
288
+ "model_id": "d8639b5cc95548f5afbcfe22d3ba5ce5",
289
+ "optimize_streaming_latency": true,
290
+ "request_timeout_seconds": 30,
291
+ "base_url": "https://api.fish.audio"
292
+ }
293
+ },
294
+ {
295
+ "type": "extension",
296
+ "name": "interrupt_detector",
297
+ "addon": "interrupt_detector_python",
298
+ "extension_group": "default",
299
+ "property": {}
300
+ },
301
+ {
302
+ "type": "extension",
303
+ "name": "message_collector",
304
+ "addon": "message_collector",
305
+ "extension_group": "transcriber",
306
+ "property": {}
307
+ },
308
+ {
309
+ "type": "extension",
310
+ "name": "weatherapi_tool_python",
311
+ "addon": "weatherapi_tool_python",
312
+ "extension_group": "default",
313
+ "property": {
314
+ "api_key": "${env:WEATHERAPI_API_KEY|}"
315
+ }
316
+ }
317
+ ],
318
+ "connections": [
319
+ {
320
+ "extension": "agora_rtc",
321
+ "cmd": [
322
+ {
323
+ "name": "on_user_joined",
324
+ "dest": [
325
+ {
326
+ "extension": "llm"
327
+ }
328
+ ]
329
+ },
330
+ {
331
+ "name": "on_user_left",
332
+ "dest": [
333
+ {
334
+ "extension": "llm"
335
+ }
336
+ ]
337
+ },
338
+ {
339
+ "name": "on_connection_failure",
340
+ "dest": [
341
+ {
342
+ "extension": "llm"
343
+ }
344
+ ]
345
+ }
346
+ ],
347
+ "data": [
348
+ {
349
+ "name": "text_data",
350
+ "dest": [
351
+ {
352
+ "extension": "interrupt_detector"
353
+ },
354
+ {
355
+ "extension": "message_collector"
356
+ }
357
+ ]
358
+ }
359
+ ]
360
+ },
361
+ {
362
+ "extension": "llm",
363
+ "cmd": [
364
+ {
365
+ "name": "flush",
366
+ "dest": [
367
+ {
368
+ "extension": "tts"
369
+ }
370
+ ]
371
+ },
372
+ {
373
+ "name": "tool_call",
374
+ "dest": [
375
+ {
376
+ "extension": "weatherapi_tool_python"
377
+ }
378
+ ]
379
+ }
380
+ ],
381
+ "data": [
382
+ {
383
+ "name": "text_data",
384
+ "dest": [
385
+ {
386
+ "extension": "tts"
387
+ },
388
+ {
389
+ "extension": "message_collector"
390
+ }
391
+ ]
392
+ },
393
+ {
394
+ "name": "content_data",
395
+ "dest": [
396
+ {
397
+ "extension": "message_collector"
398
+ }
399
+ ]
400
+ }
401
+ ]
402
+ },
403
+ {
404
+ "extension": "message_collector",
405
+ "data": [
406
+ {
407
+ "name": "data",
408
+ "dest": [
409
+ {
410
+ "extension": "agora_rtc"
411
+ }
412
+ ]
413
+ }
414
+ ]
415
+ },
416
+ {
417
+ "extension": "tts",
418
+ "cmd": [
419
+ {
420
+ "name": "flush",
421
+ "dest": [
422
+ {
423
+ "extension": "agora_rtc"
424
+ }
425
+ ]
426
+ }
427
+ ],
428
+ "audio_frame": [
429
+ {
430
+ "name": "pcm_frame",
431
+ "dest": [
432
+ {
433
+ "extension": "agora_rtc"
434
+ }
435
+ ]
436
+ }
437
+ ]
438
+ },
439
+ {
440
+ "extension": "interrupt_detector",
441
+ "cmd": [
442
+ {
443
+ "name": "flush",
444
+ "dest": [
445
+ {
446
+ "extension": "llm"
447
+ }
448
+ ]
449
+ }
450
+ ],
451
+ "data": [
452
+ {
453
+ "name": "text_data",
454
+ "dest": [
455
+ {
456
+ "extension": "llm"
457
+ }
458
+ ]
459
+ }
460
+ ]
461
+ },
462
+ {
463
+ "extension": "weatherapi_tool_python",
464
+ "cmd": [
465
+ {
466
+ "name": "tool_register",
467
+ "dest": [
468
+ {
469
+ "extension": "llm"
470
+ }
471
+ ]
472
+ }
473
+ ]
474
+ }
475
+ ]
476
+ },
477
+ {
478
+ "name": "voice_assistant_realtime",
479
+ "auto_start": true,
480
+ "nodes": [
481
+ {
482
+ "type": "extension",
483
+ "name": "agora_rtc",
484
+ "addon": "agora_rtc",
485
+ "extension_group": "rtc",
486
+ "property": {
487
+ "app_id": "${env:AGORA_APP_ID}",
488
+ "token": "",
489
+ "channel": "ten_agent_test",
490
+ "stream_id": 1234,
491
+ "remote_stream_id": 123,
492
+ "subscribe_audio": true,
493
+ "publish_audio": true,
494
+ "publish_data": true,
495
+ "subscribe_audio_sample_rate": 24000
496
+ }
497
+ },
498
+ {
499
+ "type": "extension",
500
+ "name": "v2v",
501
+ "addon": "openai_v2v_python",
502
+ "extension_group": "llm",
503
+ "property": {
504
+ "api_key": "${env:OPENAI_REALTIME_API_KEY}",
505
+ "enable_storage": false,
506
+ "history": 10,
507
+ "language": "en-US",
508
+ "max_tokens": 2048,
509
+ "model": "gpt-4o-realtime-preview",
510
+ "server_vad": true,
511
+ "temperature": 0.9,
512
+ "voice": "alloy"
513
+ }
514
+ },
515
+ {
516
+ "type": "extension",
517
+ "name": "message_collector",
518
+ "addon": "message_collector",
519
+ "extension_group": "transcriber",
520
+ "property": {}
521
+ },
522
+ {
523
+ "type": "extension",
524
+ "name": "weatherapi_tool_python",
525
+ "addon": "weatherapi_tool_python",
526
+ "extension_group": "default",
527
+ "property": {
528
+ "api_key": "${env:WEATHERAPI_API_KEY|}"
529
+ }
530
+ }
531
+ ],
532
+ "connections": [
533
+ {
534
+ "extension": "agora_rtc",
535
+ "cmd": [
536
+ {
537
+ "name": "on_user_joined",
538
+ "dest": [
539
+ {
540
+ "extension": "v2v"
541
+ }
542
+ ]
543
+ },
544
+ {
545
+ "name": "on_user_left",
546
+ "dest": [
547
+ {
548
+ "extension": "v2v"
549
+ }
550
+ ]
551
+ },
552
+ {
553
+ "name": "on_connection_failure",
554
+ "dest": [
555
+ {
556
+ "extension": "v2v"
557
+ }
558
+ ]
559
+ }
560
+ ],
561
+ "audio_frame": [
562
+ {
563
+ "name": "pcm_frame",
564
+ "dest": [
565
+ {
566
+ "extension": "v2v"
567
+ }
568
+ ]
569
+ }
570
+ ],
571
+ "video_frame": [
572
+ {
573
+ "name": "video_frame",
574
+ "dest": [
575
+ {
576
+ "extension": "v2v"
577
+ }
578
+ ]
579
+ }
580
+ ]
581
+ },
582
+ {
583
+ "extension": "v2v",
584
+ "cmd": [
585
+ {
586
+ "name": "flush",
587
+ "dest": [
588
+ {
589
+ "extension": "agora_rtc"
590
+ }
591
+ ]
592
+ },
593
+ {
594
+ "name": "tool_call",
595
+ "dest": [
596
+ {
597
+ "extension": "weatherapi_tool_python"
598
+ }
599
+ ]
600
+ }
601
+ ],
602
+ "data": [
603
+ {
604
+ "name": "text_data",
605
+ "dest": [
606
+ {
607
+ "extension": "message_collector"
608
+ }
609
+ ]
610
+ }
611
+ ],
612
+ "audio_frame": [
613
+ {
614
+ "name": "pcm_frame",
615
+ "dest": [
616
+ {
617
+ "extension": "agora_rtc"
618
+ }
619
+ ]
620
+ }
621
+ ]
622
+ },
623
+ {
624
+ "extension": "message_collector",
625
+ "data": [
626
+ {
627
+ "name": "data",
628
+ "dest": [
629
+ {
630
+ "extension": "agora_rtc"
631
+ }
632
+ ]
633
+ }
634
+ ]
635
+ },
636
+ {
637
+ "extension": "weatherapi_tool_python",
638
+ "cmd": [
639
+ {
640
+ "name": "tool_register",
641
+ "dest": [
642
+ {
643
+ "extension": "v2v"
644
+ }
645
+ ]
646
+ }
647
+ ]
648
+ }
649
+ ]
650
+ },
651
+ {
652
+ "name": "story_teller",
653
+ "auto_start": true,
654
+ "nodes": [
655
+ {
656
+ "type": "extension",
657
+ "name": "agora_rtc",
658
+ "addon": "agora_rtc",
659
+ "extension_group": "default",
660
+ "property": {
661
+ "app_id": "${env:AGORA_APP_ID}",
662
+ "token": "<agora_token>",
663
+ "channel": "ten_agent_test",
664
+ "stream_id": 1234,
665
+ "remote_stream_id": 123,
666
+ "subscribe_audio": true,
667
+ "publish_audio": true,
668
+ "publish_data": true,
669
+ "enable_agora_asr": false
670
+ }
671
+ },
672
+ {
673
+ "type": "extension",
674
+ "name": "stt",
675
+ "addon": "deepgram_asr_python",
676
+ "extension_group": "stt",
677
+ "property": {
678
+ "api_key": "${env:DEEPGRAM_API_KEY}",
679
+ "language": "en-US",
680
+ "model": "nova-2",
681
+ "sample_rate": 16000
682
+ }
683
+ },
684
+ {
685
+ "type": "extension",
686
+ "name": "llm",
687
+ "addon": "openai_chatgpt_python",
688
+ "extension_group": "chatgpt",
689
+ "property": {
690
+ "api_key": "${env:OPENAI_API_KEY}",
691
+ "base_url": "",
692
+ "frequency_penalty": 0.9,
693
+ "greeting": "TEN Agent connected. How can I help you today?",
694
+ "max_memory_length": 10,
695
+ "max_tokens": 512,
696
+ "model": "${env:OPENAI_MODEL}",
697
+ "prompt": "You are an ai agent bot producing child picture books. Each response should be short and no more than 50 words as it's for child. \nFor every response relevant to the story-telling, you will use the 'image_generate' tool to create an image based on the description or key moment in that part of the story. \n The story should be set in a fantasy world. Try asking questions relevant to the story to decide how the story should proceed. Every response should include rich, vivid descriptions that will guide the 'image_generate' tool to produce an image that aligns with the scene or mood.\n Whether it’s the setting, a character’s expression, or a dramatic moment, the paragraph should give enough detail for a meaningful visual representation.",
698
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
699
+ }
700
+ },
701
+ {
702
+ "type": "extension",
703
+ "name": "tts",
704
+ "addon": "fish_audio_tts",
705
+ "extension_group": "tts",
706
+ "property": {
707
+ "api_key": "${env:FISH_AUDIO_TTS_KEY}",
708
+ "model_id": "d8639b5cc95548f5afbcfe22d3ba5ce5",
709
+ "optimize_streaming_latency": true,
710
+ "request_timeout_seconds": 30,
711
+ "base_url": "https://api.fish.audio"
712
+ }
713
+ },
714
+ {
715
+ "type": "extension",
716
+ "name": "interrupt_detector",
717
+ "addon": "interrupt_detector_python",
718
+ "extension_group": "default",
719
+ "property": {}
720
+ },
721
+ {
722
+ "type": "extension",
723
+ "name": "message_collector",
724
+ "addon": "message_collector",
725
+ "extension_group": "transcriber",
726
+ "property": {}
727
+ },
728
+ {
729
+ "type": "extension",
730
+ "name": "openai_image_generate_tool",
731
+ "addon": "openai_image_generate_tool",
732
+ "extension_group": "default",
733
+ "property": {
734
+ "api_key": "${env:OPENAI_API_KEY}"
735
+ }
736
+ }
737
+ ],
738
+ "connections": [
739
+ {
740
+ "extension": "agora_rtc",
741
+ "cmd": [
742
+ {
743
+ "name": "on_user_joined",
744
+ "dest": [
745
+ {
746
+ "extension": "llm"
747
+ }
748
+ ]
749
+ },
750
+ {
751
+ "name": "on_user_left",
752
+ "dest": [
753
+ {
754
+ "extension": "llm"
755
+ }
756
+ ]
757
+ },
758
+ {
759
+ "name": "on_connection_failure",
760
+ "dest": [
761
+ {
762
+ "extension": "llm"
763
+ }
764
+ ]
765
+ }
766
+ ],
767
+ "audio_frame": [
768
+ {
769
+ "name": "pcm_frame",
770
+ "dest": [
771
+ {
772
+ "extension": "stt"
773
+ }
774
+ ]
775
+ }
776
+ ]
777
+ },
778
+ {
779
+ "extension": "stt",
780
+ "data": [
781
+ {
782
+ "name": "text_data",
783
+ "dest": [
784
+ {
785
+ "extension": "interrupt_detector"
786
+ },
787
+ {
788
+ "extension": "message_collector"
789
+ }
790
+ ]
791
+ }
792
+ ]
793
+ },
794
+ {
795
+ "extension": "llm",
796
+ "cmd": [
797
+ {
798
+ "name": "flush",
799
+ "dest": [
800
+ {
801
+ "extension": "tts"
802
+ }
803
+ ]
804
+ },
805
+ {
806
+ "name": "tool_call",
807
+ "dest": [
808
+ {
809
+ "extension": "openai_image_generate_tool"
810
+ }
811
+ ]
812
+ }
813
+ ],
814
+ "data": [
815
+ {
816
+ "name": "text_data",
817
+ "dest": [
818
+ {
819
+ "extension": "tts"
820
+ },
821
+ {
822
+ "extension": "message_collector"
823
+ }
824
+ ]
825
+ }
826
+ ]
827
+ },
828
+ {
829
+ "extension": "message_collector",
830
+ "data": [
831
+ {
832
+ "name": "data",
833
+ "dest": [
834
+ {
835
+ "extension": "agora_rtc"
836
+ }
837
+ ]
838
+ }
839
+ ]
840
+ },
841
+ {
842
+ "extension": "tts",
843
+ "cmd": [
844
+ {
845
+ "name": "flush",
846
+ "dest": [
847
+ {
848
+ "extension": "agora_rtc"
849
+ }
850
+ ]
851
+ }
852
+ ],
853
+ "audio_frame": [
854
+ {
855
+ "name": "pcm_frame",
856
+ "dest": [
857
+ {
858
+ "extension": "agora_rtc"
859
+ }
860
+ ]
861
+ }
862
+ ]
863
+ },
864
+ {
865
+ "extension": "interrupt_detector",
866
+ "cmd": [
867
+ {
868
+ "name": "flush",
869
+ "dest": [
870
+ {
871
+ "extension": "llm"
872
+ }
873
+ ]
874
+ }
875
+ ],
876
+ "data": [
877
+ {
878
+ "name": "text_data",
879
+ "dest": [
880
+ {
881
+ "extension": "llm"
882
+ }
883
+ ]
884
+ }
885
+ ]
886
+ },
887
+ {
888
+ "extension": "openai_image_generate_tool",
889
+ "cmd": [
890
+ {
891
+ "name": "tool_register",
892
+ "dest": [
893
+ {
894
+ "extension": "llm"
895
+ }
896
+ ]
897
+ }
898
+ ],
899
+ "data": [
900
+ {
901
+ "name": "content_data",
902
+ "dest": [
903
+ {
904
+ "extension": "message_collector"
905
+ }
906
+ ]
907
+ }
908
+ ]
909
+ }
910
+ ]
911
+ },
912
+ {
913
+ "name": "story_teller_stt_integrated",
914
+ "auto_start": true,
915
+ "nodes": [
916
+ {
917
+ "type": "extension",
918
+ "name": "agora_rtc",
919
+ "addon": "agora_rtc",
920
+ "extension_group": "default",
921
+ "property": {
922
+ "app_id": "${env:AGORA_APP_ID}",
923
+ "token": "<agora_token>",
924
+ "channel": "ten_agent_test",
925
+ "stream_id": 1234,
926
+ "remote_stream_id": 123,
927
+ "subscribe_audio": true,
928
+ "publish_audio": true,
929
+ "publish_data": true,
930
+ "enable_agora_asr": true,
931
+ "agora_asr_vendor_name": "microsoft",
932
+ "agora_asr_language": "en-US",
933
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
934
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
935
+ "agora_asr_session_control_file_path": "session_control.conf"
936
+ }
937
+ },
938
+ {
939
+ "type": "extension",
940
+ "name": "llm",
941
+ "addon": "openai_chatgpt_python",
942
+ "extension_group": "chatgpt",
943
+ "property": {
944
+ "api_key": "${env:OPENAI_API_KEY}",
945
+ "base_url": "",
946
+ "frequency_penalty": 0.9,
947
+ "greeting": "TEN Agent connected. How can I help you today?",
948
+ "max_memory_length": 10,
949
+ "max_tokens": 512,
950
+ "model": "${env:OPENAI_MODEL}",
951
+ "prompt": "You are an ai agent bot producing child picture books. Each response should be short and no more than 50 words as it's for child. \nFor every response relevant to the story-telling, you will use the 'image_generate' tool to create an image based on the description or key moment in that part of the story. \n The story should be set in a fantasy world. Try asking questions relevant to the story to decide how the story should proceed. Every response should include rich, vivid descriptions that will guide the 'image_generate' tool to produce an image that aligns with the scene or mood.\n Whether it’s the setting, a character’s expression, or a dramatic moment, the paragraph should give enough detail for a meaningful visual representation.",
952
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
953
+ }
954
+ },
955
+ {
956
+ "type": "extension",
957
+ "name": "tts",
958
+ "addon": "fish_audio_tts",
959
+ "extension_group": "tts",
960
+ "property": {
961
+ "api_key": "${env:FISH_AUDIO_TTS_KEY}",
962
+ "model_id": "d8639b5cc95548f5afbcfe22d3ba5ce5",
963
+ "optimize_streaming_latency": true,
964
+ "request_timeout_seconds": 30,
965
+ "base_url": "https://api.fish.audio"
966
+ }
967
+ },
968
+ {
969
+ "type": "extension",
970
+ "name": "interrupt_detector",
971
+ "addon": "interrupt_detector_python",
972
+ "extension_group": "default",
973
+ "property": {}
974
+ },
975
+ {
976
+ "type": "extension",
977
+ "name": "message_collector",
978
+ "addon": "message_collector",
979
+ "extension_group": "transcriber",
980
+ "property": {}
981
+ },
982
+ {
983
+ "type": "extension",
984
+ "name": "openai_image_generate_tool",
985
+ "addon": "openai_image_generate_tool",
986
+ "extension_group": "default",
987
+ "property": {
988
+ "api_key": "${env:OPENAI_API_KEY}"
989
+ }
990
+ }
991
+ ],
992
+ "connections": [
993
+ {
994
+ "extension": "agora_rtc",
995
+ "cmd": [
996
+ {
997
+ "name": "on_user_joined",
998
+ "dest": [
999
+ {
1000
+ "extension": "llm"
1001
+ }
1002
+ ]
1003
+ },
1004
+ {
1005
+ "name": "on_user_left",
1006
+ "dest": [
1007
+ {
1008
+ "extension": "llm"
1009
+ }
1010
+ ]
1011
+ },
1012
+ {
1013
+ "name": "on_connection_failure",
1014
+ "dest": [
1015
+ {
1016
+ "extension": "llm"
1017
+ }
1018
+ ]
1019
+ }
1020
+ ],
1021
+ "data": [
1022
+ {
1023
+ "name": "text_data",
1024
+ "dest": [
1025
+ {
1026
+ "extension": "interrupt_detector"
1027
+ },
1028
+ {
1029
+ "extension": "message_collector"
1030
+ }
1031
+ ]
1032
+ }
1033
+ ]
1034
+ },
1035
+ {
1036
+ "extension": "llm",
1037
+ "cmd": [
1038
+ {
1039
+ "name": "flush",
1040
+ "dest": [
1041
+ {
1042
+ "extension": "tts"
1043
+ }
1044
+ ]
1045
+ },
1046
+ {
1047
+ "name": "tool_call",
1048
+ "dest": [
1049
+ {
1050
+ "extension": "openai_image_generate_tool"
1051
+ }
1052
+ ]
1053
+ }
1054
+ ],
1055
+ "data": [
1056
+ {
1057
+ "name": "text_data",
1058
+ "dest": [
1059
+ {
1060
+ "extension": "tts"
1061
+ },
1062
+ {
1063
+ "extension": "message_collector"
1064
+ }
1065
+ ]
1066
+ }
1067
+ ]
1068
+ },
1069
+ {
1070
+ "extension": "message_collector",
1071
+ "data": [
1072
+ {
1073
+ "name": "data",
1074
+ "dest": [
1075
+ {
1076
+ "extension": "agora_rtc"
1077
+ }
1078
+ ]
1079
+ }
1080
+ ]
1081
+ },
1082
+ {
1083
+ "extension": "tts",
1084
+ "cmd": [
1085
+ {
1086
+ "name": "flush",
1087
+ "dest": [
1088
+ {
1089
+ "extension": "agora_rtc"
1090
+ }
1091
+ ]
1092
+ }
1093
+ ],
1094
+ "audio_frame": [
1095
+ {
1096
+ "name": "pcm_frame",
1097
+ "dest": [
1098
+ {
1099
+ "extension": "agora_rtc"
1100
+ }
1101
+ ]
1102
+ }
1103
+ ]
1104
+ },
1105
+ {
1106
+ "extension": "interrupt_detector",
1107
+ "cmd": [
1108
+ {
1109
+ "name": "flush",
1110
+ "dest": [
1111
+ {
1112
+ "extension": "llm"
1113
+ }
1114
+ ]
1115
+ }
1116
+ ],
1117
+ "data": [
1118
+ {
1119
+ "name": "text_data",
1120
+ "dest": [
1121
+ {
1122
+ "extension": "llm"
1123
+ }
1124
+ ]
1125
+ }
1126
+ ]
1127
+ },
1128
+ {
1129
+ "extension": "openai_image_generate_tool",
1130
+ "cmd": [
1131
+ {
1132
+ "name": "tool_register",
1133
+ "dest": [
1134
+ {
1135
+ "extension": "llm"
1136
+ }
1137
+ ]
1138
+ }
1139
+ ],
1140
+ "data": [
1141
+ {
1142
+ "name": "content_data",
1143
+ "dest": [
1144
+ {
1145
+ "extension": "message_collector"
1146
+ }
1147
+ ]
1148
+ }
1149
+ ]
1150
+ }
1151
+ ]
1152
+ },
1153
+ {
1154
+ "name": "story_teller_realtime",
1155
+ "auto_start": true,
1156
+ "nodes": [
1157
+ {
1158
+ "type": "extension",
1159
+ "name": "agora_rtc",
1160
+ "addon": "agora_rtc",
1161
+ "extension_group": "rtc",
1162
+ "property": {
1163
+ "app_id": "${env:AGORA_APP_ID}",
1164
+ "token": "",
1165
+ "channel": "ten_agent_test",
1166
+ "stream_id": 1234,
1167
+ "remote_stream_id": 123,
1168
+ "subscribe_audio": true,
1169
+ "publish_audio": true,
1170
+ "publish_data": true,
1171
+ "subscribe_audio_sample_rate": 24000
1172
+ }
1173
+ },
1174
+ {
1175
+ "type": "extension",
1176
+ "name": "v2v",
1177
+ "addon": "openai_v2v_python",
1178
+ "extension_group": "llm",
1179
+ "property": {
1180
+ "api_key": "${env:OPENAI_REALTIME_API_KEY}",
1181
+ "temperature": 0.9,
1182
+ "model": "gpt-4o-realtime-preview-2024-12-17",
1183
+ "max_tokens": 2048,
1184
+ "voice": "alloy",
1185
+ "language": "en-US",
1186
+ "server_vad": true,
1187
+ "prompt": "You are an ai agent bot producing child picture books. Each response should be short and no more than 50 words as it's for child. \nFor every response relevant to the story-telling, you will use the 'image_generate' tool to create an image based on the description or key moment in that part of the story. \n The story should be set in a fantasy world. Try asking questions relevant to the story to decide how the story should proceed. Every response should include rich, vivid descriptions that will guide the 'image_generate' tool to produce an image that aligns with the scene or mood.\n Whether it’s the setting, a character’s expression, or a dramatic moment, the paragraph should give enough detail for a meaningful visual representation.",
1188
+ "dump": false,
1189
+ "max_history": 10
1190
+ }
1191
+ },
1192
+ {
1193
+ "type": "extension",
1194
+ "name": "message_collector",
1195
+ "addon": "message_collector",
1196
+ "extension_group": "transcriber",
1197
+ "property": {}
1198
+ },
1199
+ {
1200
+ "type": "extension",
1201
+ "name": "openai_image_generate_tool",
1202
+ "addon": "openai_image_generate_tool",
1203
+ "extension_group": "default",
1204
+ "property": {
1205
+ "api_key": "${env:OPENAI_API_KEY}"
1206
+ }
1207
+ }
1208
+ ],
1209
+ "connections": [
1210
+ {
1211
+ "extension": "agora_rtc",
1212
+ "cmd": [
1213
+ {
1214
+ "name": "on_user_joined",
1215
+ "dest": [
1216
+ {
1217
+ "extension": "v2v"
1218
+ }
1219
+ ]
1220
+ },
1221
+ {
1222
+ "name": "on_user_left",
1223
+ "dest": [
1224
+ {
1225
+ "extension": "v2v"
1226
+ }
1227
+ ]
1228
+ },
1229
+ {
1230
+ "name": "on_connection_failure",
1231
+ "dest": [
1232
+ {
1233
+ "extension": "v2v"
1234
+ }
1235
+ ]
1236
+ }
1237
+ ],
1238
+ "audio_frame": [
1239
+ {
1240
+ "name": "pcm_frame",
1241
+ "dest": [
1242
+ {
1243
+ "extension": "v2v"
1244
+ }
1245
+ ]
1246
+ }
1247
+ ]
1248
+ },
1249
+ {
1250
+ "extension": "v2v",
1251
+ "cmd": [
1252
+ {
1253
+ "name": "flush",
1254
+ "dest": [
1255
+ {
1256
+ "extension": "agora_rtc"
1257
+ }
1258
+ ]
1259
+ },
1260
+ {
1261
+ "name": "tool_call",
1262
+ "dest": [
1263
+ {
1264
+ "extension": "openai_image_generate_tool"
1265
+ }
1266
+ ]
1267
+ }
1268
+ ],
1269
+ "data": [
1270
+ {
1271
+ "name": "text_data",
1272
+ "dest": [
1273
+ {
1274
+ "extension": "message_collector"
1275
+ }
1276
+ ]
1277
+ }
1278
+ ],
1279
+ "audio_frame": [
1280
+ {
1281
+ "name": "pcm_frame",
1282
+ "dest": [
1283
+ {
1284
+ "extension": "agora_rtc"
1285
+ }
1286
+ ]
1287
+ }
1288
+ ]
1289
+ },
1290
+ {
1291
+ "extension": "message_collector",
1292
+ "data": [
1293
+ {
1294
+ "name": "data",
1295
+ "dest": [
1296
+ {
1297
+ "extension": "agora_rtc"
1298
+ }
1299
+ ]
1300
+ }
1301
+ ]
1302
+ },
1303
+ {
1304
+ "extension": "openai_image_generate_tool",
1305
+ "cmd": [
1306
+ {
1307
+ "name": "tool_register",
1308
+ "dest": [
1309
+ {
1310
+ "extension": "v2v"
1311
+ }
1312
+ ]
1313
+ }
1314
+ ],
1315
+ "data": [
1316
+ {
1317
+ "name": "content_data",
1318
+ "dest": [
1319
+ {
1320
+ "extension": "message_collector"
1321
+ }
1322
+ ]
1323
+ }
1324
+ ]
1325
+ }
1326
+ ]
1327
+ }
1328
+ ],
1329
+ "log_level": 3
1330
+ }
1331
+ }
agents/examples/demo/manifest.json ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "app",
3
+ "name": "agent_demo",
4
+ "version": "0.8.0",
5
+ "dependencies": [
6
+ {
7
+ "type": "system",
8
+ "name": "ten_runtime_go",
9
+ "version": "0.8"
10
+ },
11
+ {
12
+ "type": "extension",
13
+ "name": "agora_rtc",
14
+ "version": "=0.12.0"
15
+ },
16
+ {
17
+ "type": "extension",
18
+ "name": "agora_sess_ctrl",
19
+ "version": "=0.4.4"
20
+ },
21
+ {
22
+ "type": "system",
23
+ "name": "azure_speech_sdk",
24
+ "version": "1.38.0"
25
+ },
26
+ {
27
+ "type": "system",
28
+ "name": "ten_ai_base",
29
+ "version": "0.4.1"
30
+ },
31
+ {
32
+ "type": "extension",
33
+ "name": "azure_tts",
34
+ "version": "=0.8.1"
35
+ },
36
+ {
37
+ "type": "extension",
38
+ "name": "dify_python",
39
+ "version": "=0.1.0"
40
+ },
41
+ {
42
+ "type": "extension",
43
+ "name": "gemini_v2v_python",
44
+ "version": "=0.1.0"
45
+ },
46
+ {
47
+ "type": "extension",
48
+ "name": "openai_chatgpt_python",
49
+ "version": "=0.1.0"
50
+ },
51
+ {
52
+ "type": "extension",
53
+ "name": "bingsearch_tool_python",
54
+ "version": "=0.1.0"
55
+ },
56
+ {
57
+ "type": "extension",
58
+ "name": "vision_tool_python",
59
+ "version": "=0.1.0"
60
+ },
61
+ {
62
+ "type": "extension",
63
+ "name": "weatherapi_tool_python",
64
+ "version": "=0.1.0"
65
+ },
66
+ {
67
+ "type": "extension",
68
+ "name": "interrupt_detector_python",
69
+ "version": "=0.1.0"
70
+ },
71
+ {
72
+ "type": "extension",
73
+ "name": "openai_v2v_python",
74
+ "version": "=0.1.0"
75
+ },
76
+ {
77
+ "type": "extension",
78
+ "name": "message_collector",
79
+ "version": "=0.1.0"
80
+ },
81
+ {
82
+ "type": "extension",
83
+ "name": "coze_python_async",
84
+ "version": "=0.1.0"
85
+ },
86
+ {
87
+ "type": "extension",
88
+ "name": "fish_audio_tts",
89
+ "version": "=0.1.0"
90
+ },
91
+ {
92
+ "type": "extension",
93
+ "name": "openai_image_generate_tool",
94
+ "version": "=0.1.0"
95
+ }
96
+ ]
97
+ }
agents/examples/demo/property.json ADDED
@@ -0,0 +1,2322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_ten": {
3
+ "predefined_graphs": [
4
+ {
5
+ "name": "qwq_32b",
6
+ "auto_start": true,
7
+ "nodes": [
8
+ {
9
+ "type": "extension",
10
+ "name": "agora_rtc",
11
+ "addon": "agora_rtc",
12
+ "extension_group": "default",
13
+ "property": {
14
+ "app_id": "${env:AGORA_APP_ID}",
15
+ "token": "<agora_token>",
16
+ "channel": "ten_agent_test",
17
+ "stream_id": 1234,
18
+ "remote_stream_id": 123,
19
+ "subscribe_audio": true,
20
+ "publish_audio": true,
21
+ "publish_data": true,
22
+ "enable_agora_asr": true,
23
+ "agora_asr_vendor_name": "microsoft",
24
+ "agora_asr_language": "en-US",
25
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
26
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
27
+ "agora_asr_session_control_file_path": "session_control.conf"
28
+ }
29
+ },
30
+ {
31
+ "type": "extension",
32
+ "name": "llm",
33
+ "addon": "openai_chatgpt_python",
34
+ "extension_group": "chatgpt",
35
+ "property": {
36
+ "api_key": "${env:QWEN_API_KEY}",
37
+ "base_url": "https://dashscope.aliyuncs.com/compatible-mode/v1",
38
+ "frequency_penalty": 0.9,
39
+ "greeting": "TEN Agent connected. How can I help you today?",
40
+ "max_memory_length": 10,
41
+ "max_tokens": 512,
42
+ "model": "qwq-plus",
43
+ "prompt": "",
44
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
45
+ }
46
+ },
47
+ {
48
+ "type": "extension",
49
+ "name": "tts",
50
+ "addon": "azure_tts",
51
+ "extension_group": "tts",
52
+ "property": {
53
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
54
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
55
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
56
+ }
57
+ },
58
+ {
59
+ "type": "extension",
60
+ "name": "interrupt_detector",
61
+ "addon": "interrupt_detector_python",
62
+ "extension_group": "default",
63
+ "property": {}
64
+ },
65
+ {
66
+ "type": "extension",
67
+ "name": "message_collector",
68
+ "addon": "message_collector",
69
+ "extension_group": "transcriber",
70
+ "property": {}
71
+ }
72
+ ],
73
+ "connections": [
74
+ {
75
+ "extension": "agora_rtc",
76
+ "cmd": [
77
+ {
78
+ "name": "on_user_joined",
79
+ "dest": [
80
+ {
81
+ "extension": "llm"
82
+ }
83
+ ]
84
+ },
85
+ {
86
+ "name": "on_user_left",
87
+ "dest": [
88
+ {
89
+ "extension": "llm"
90
+ }
91
+ ]
92
+ },
93
+ {
94
+ "name": "on_connection_failure",
95
+ "dest": [
96
+ {
97
+ "extension": "llm"
98
+ }
99
+ ]
100
+ }
101
+ ],
102
+ "data": [
103
+ {
104
+ "name": "text_data",
105
+ "dest": [
106
+ {
107
+ "extension": "interrupt_detector"
108
+ },
109
+ {
110
+ "extension": "message_collector"
111
+ }
112
+ ]
113
+ }
114
+ ]
115
+ },
116
+ {
117
+ "extension": "llm",
118
+ "cmd": [
119
+ {
120
+ "name": "flush",
121
+ "dest": [
122
+ {
123
+ "extension": "tts"
124
+ }
125
+ ]
126
+ }
127
+ ],
128
+ "data": [
129
+ {
130
+ "name": "text_data",
131
+ "dest": [
132
+ {
133
+ "extension": "tts"
134
+ },
135
+ {
136
+ "extension": "message_collector"
137
+ }
138
+ ]
139
+ },
140
+ {
141
+ "name": "content_data",
142
+ "dest": [
143
+ {
144
+ "extension": "message_collector"
145
+ }
146
+ ]
147
+ }
148
+ ]
149
+ },
150
+ {
151
+ "extension": "message_collector",
152
+ "data": [
153
+ {
154
+ "name": "data",
155
+ "dest": [
156
+ {
157
+ "extension": "agora_rtc"
158
+ }
159
+ ]
160
+ }
161
+ ]
162
+ },
163
+ {
164
+ "extension": "tts",
165
+ "cmd": [
166
+ {
167
+ "name": "flush",
168
+ "dest": [
169
+ {
170
+ "extension": "agora_rtc"
171
+ }
172
+ ]
173
+ }
174
+ ],
175
+ "audio_frame": [
176
+ {
177
+ "name": "pcm_frame",
178
+ "dest": [
179
+ {
180
+ "extension": "agora_rtc"
181
+ }
182
+ ]
183
+ }
184
+ ]
185
+ },
186
+ {
187
+ "extension": "interrupt_detector",
188
+ "cmd": [
189
+ {
190
+ "name": "flush",
191
+ "dest": [
192
+ {
193
+ "extension": "llm"
194
+ }
195
+ ]
196
+ }
197
+ ],
198
+ "data": [
199
+ {
200
+ "name": "text_data",
201
+ "dest": [
202
+ {
203
+ "extension": "llm"
204
+ }
205
+ ]
206
+ }
207
+ ]
208
+ }
209
+ ]
210
+ },
211
+ {
212
+ "name": "deepseek_r1",
213
+ "auto_start": true,
214
+ "nodes": [
215
+ {
216
+ "type": "extension",
217
+ "name": "agora_rtc",
218
+ "addon": "agora_rtc",
219
+ "extension_group": "default",
220
+ "property": {
221
+ "app_id": "${env:AGORA_APP_ID}",
222
+ "token": "<agora_token>",
223
+ "channel": "ten_agent_test",
224
+ "stream_id": 1234,
225
+ "remote_stream_id": 123,
226
+ "subscribe_audio": true,
227
+ "publish_audio": true,
228
+ "publish_data": true,
229
+ "enable_agora_asr": true,
230
+ "agora_asr_vendor_name": "microsoft",
231
+ "agora_asr_language": "en-US",
232
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
233
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
234
+ "agora_asr_session_control_file_path": "session_control.conf"
235
+ }
236
+ },
237
+ {
238
+ "type": "extension",
239
+ "name": "llm",
240
+ "addon": "openai_chatgpt_python",
241
+ "extension_group": "chatgpt",
242
+ "property": {
243
+ "api_key": "${env:DEEPSEEK_API_KEY}",
244
+ "base_url": "https://tenagentopenai.services.ai.azure.com/models",
245
+ "frequency_penalty": 0.9,
246
+ "greeting": "TEN Agent connected. How can I help you today?",
247
+ "max_memory_length": 10,
248
+ "max_tokens": 512,
249
+ "model": "DeepSeek-R1",
250
+ "prompt": "",
251
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
252
+ }
253
+ },
254
+ {
255
+ "type": "extension",
256
+ "name": "tts",
257
+ "addon": "azure_tts",
258
+ "extension_group": "tts",
259
+ "property": {
260
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
261
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
262
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
263
+ }
264
+ },
265
+ {
266
+ "type": "extension",
267
+ "name": "interrupt_detector",
268
+ "addon": "interrupt_detector_python",
269
+ "extension_group": "default",
270
+ "property": {}
271
+ },
272
+ {
273
+ "type": "extension",
274
+ "name": "message_collector",
275
+ "addon": "message_collector",
276
+ "extension_group": "transcriber",
277
+ "property": {}
278
+ }
279
+ ],
280
+ "connections": [
281
+ {
282
+ "extension": "agora_rtc",
283
+ "cmd": [
284
+ {
285
+ "name": "on_user_joined",
286
+ "dest": [
287
+ {
288
+ "extension": "llm"
289
+ }
290
+ ]
291
+ },
292
+ {
293
+ "name": "on_user_left",
294
+ "dest": [
295
+ {
296
+ "extension": "llm"
297
+ }
298
+ ]
299
+ },
300
+ {
301
+ "name": "on_connection_failure",
302
+ "dest": [
303
+ {
304
+ "extension": "llm"
305
+ }
306
+ ]
307
+ }
308
+ ],
309
+ "data": [
310
+ {
311
+ "name": "text_data",
312
+ "dest": [
313
+ {
314
+ "extension": "interrupt_detector"
315
+ },
316
+ {
317
+ "extension": "message_collector"
318
+ }
319
+ ]
320
+ }
321
+ ]
322
+ },
323
+ {
324
+ "extension": "llm",
325
+ "cmd": [
326
+ {
327
+ "name": "flush",
328
+ "dest": [
329
+ {
330
+ "extension": "tts"
331
+ }
332
+ ]
333
+ }
334
+ ],
335
+ "data": [
336
+ {
337
+ "name": "text_data",
338
+ "dest": [
339
+ {
340
+ "extension": "tts"
341
+ },
342
+ {
343
+ "extension": "message_collector"
344
+ }
345
+ ]
346
+ },
347
+ {
348
+ "name": "content_data",
349
+ "dest": [
350
+ {
351
+ "extension": "message_collector"
352
+ }
353
+ ]
354
+ }
355
+ ]
356
+ },
357
+ {
358
+ "extension": "message_collector",
359
+ "data": [
360
+ {
361
+ "name": "data",
362
+ "dest": [
363
+ {
364
+ "extension": "agora_rtc"
365
+ }
366
+ ]
367
+ }
368
+ ]
369
+ },
370
+ {
371
+ "extension": "tts",
372
+ "cmd": [
373
+ {
374
+ "name": "flush",
375
+ "dest": [
376
+ {
377
+ "extension": "agora_rtc"
378
+ }
379
+ ]
380
+ }
381
+ ],
382
+ "audio_frame": [
383
+ {
384
+ "name": "pcm_frame",
385
+ "dest": [
386
+ {
387
+ "extension": "agora_rtc"
388
+ }
389
+ ]
390
+ }
391
+ ]
392
+ },
393
+ {
394
+ "extension": "interrupt_detector",
395
+ "cmd": [
396
+ {
397
+ "name": "flush",
398
+ "dest": [
399
+ {
400
+ "extension": "llm"
401
+ }
402
+ ]
403
+ }
404
+ ],
405
+ "data": [
406
+ {
407
+ "name": "text_data",
408
+ "dest": [
409
+ {
410
+ "extension": "llm"
411
+ }
412
+ ]
413
+ }
414
+ ]
415
+ }
416
+ ]
417
+ },
418
+ {
419
+ "name": "voice_assistant_realtime",
420
+ "auto_start": true,
421
+ "nodes": [
422
+ {
423
+ "type": "extension",
424
+ "name": "agora_rtc",
425
+ "addon": "agora_rtc",
426
+ "extension_group": "rtc",
427
+ "property": {
428
+ "app_id": "${env:AGORA_APP_ID}",
429
+ "token": "",
430
+ "channel": "ten_agent_test",
431
+ "stream_id": 1234,
432
+ "remote_stream_id": 123,
433
+ "subscribe_audio": true,
434
+ "publish_audio": true,
435
+ "publish_data": true,
436
+ "subscribe_audio_sample_rate": 24000
437
+ }
438
+ },
439
+ {
440
+ "type": "extension",
441
+ "name": "v2v",
442
+ "addon": "openai_v2v_python",
443
+ "extension_group": "llm",
444
+ "property": {
445
+ "api_key": "${env:OPENAI_REALTIME_API_KEY}",
446
+ "temperature": 0.9,
447
+ "model": "gpt-4o-realtime-preview-2024-12-17",
448
+ "max_tokens": 2048,
449
+ "voice": "alloy",
450
+ "language": "en-US",
451
+ "server_vad": true,
452
+ "dump": true,
453
+ "max_history": 10
454
+ }
455
+ },
456
+ {
457
+ "type": "extension",
458
+ "name": "message_collector",
459
+ "addon": "message_collector",
460
+ "extension_group": "transcriber",
461
+ "property": {}
462
+ },
463
+ {
464
+ "type": "extension",
465
+ "name": "weatherapi_tool_python",
466
+ "addon": "weatherapi_tool_python",
467
+ "extension_group": "default",
468
+ "property": {
469
+ "api_key": "${env:WEATHERAPI_API_KEY|}"
470
+ }
471
+ }
472
+ ],
473
+ "connections": [
474
+ {
475
+ "extension": "agora_rtc",
476
+ "cmd": [
477
+ {
478
+ "name": "on_user_joined",
479
+ "dest": [
480
+ {
481
+ "extension": "v2v"
482
+ }
483
+ ]
484
+ },
485
+ {
486
+ "name": "on_user_left",
487
+ "dest": [
488
+ {
489
+ "extension": "v2v"
490
+ }
491
+ ]
492
+ },
493
+ {
494
+ "name": "on_connection_failure",
495
+ "dest": [
496
+ {
497
+ "extension": "v2v"
498
+ }
499
+ ]
500
+ }
501
+ ],
502
+ "audio_frame": [
503
+ {
504
+ "name": "pcm_frame",
505
+ "dest": [
506
+ {
507
+ "extension": "v2v"
508
+ }
509
+ ]
510
+ }
511
+ ]
512
+ },
513
+ {
514
+ "extension": "v2v",
515
+ "cmd": [
516
+ {
517
+ "name": "flush",
518
+ "dest": [
519
+ {
520
+ "extension": "agora_rtc"
521
+ }
522
+ ]
523
+ },
524
+ {
525
+ "name": "tool_call",
526
+ "dest": [
527
+ {
528
+ "extension": "weatherapi_tool_python"
529
+ }
530
+ ]
531
+ }
532
+ ],
533
+ "data": [
534
+ {
535
+ "name": "text_data",
536
+ "dest": [
537
+ {
538
+ "extension": "message_collector"
539
+ }
540
+ ]
541
+ }
542
+ ],
543
+ "audio_frame": [
544
+ {
545
+ "name": "pcm_frame",
546
+ "dest": [
547
+ {
548
+ "extension": "agora_rtc"
549
+ }
550
+ ]
551
+ }
552
+ ]
553
+ },
554
+ {
555
+ "extension": "message_collector",
556
+ "data": [
557
+ {
558
+ "name": "data",
559
+ "dest": [
560
+ {
561
+ "extension": "agora_rtc"
562
+ }
563
+ ]
564
+ }
565
+ ]
566
+ },
567
+ {
568
+ "extension": "weatherapi_tool_python",
569
+ "cmd": [
570
+ {
571
+ "name": "tool_register",
572
+ "dest": [
573
+ {
574
+ "extension": "v2v"
575
+ }
576
+ ]
577
+ }
578
+ ]
579
+ }
580
+ ]
581
+ },
582
+ {
583
+ "name": "va_openai_azure",
584
+ "auto_start": true,
585
+ "nodes": [
586
+ {
587
+ "type": "extension",
588
+ "name": "agora_rtc",
589
+ "addon": "agora_rtc",
590
+ "extension_group": "default",
591
+ "property": {
592
+ "app_id": "${env:AGORA_APP_ID}",
593
+ "token": "<agora_token>",
594
+ "channel": "ten_agent_test",
595
+ "stream_id": 1234,
596
+ "remote_stream_id": 123,
597
+ "subscribe_audio": true,
598
+ "publish_audio": true,
599
+ "publish_data": true,
600
+ "enable_agora_asr": true,
601
+ "agora_asr_vendor_name": "microsoft",
602
+ "agora_asr_language": "en-US",
603
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
604
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
605
+ "agora_asr_session_control_file_path": "session_control.conf",
606
+ "subscribe_video_pix_fmt": 4,
607
+ "subscribe_video": true
608
+ }
609
+ },
610
+ {
611
+ "type": "extension",
612
+ "name": "llm",
613
+ "addon": "openai_chatgpt_python",
614
+ "extension_group": "chatgpt",
615
+ "property": {
616
+ "api_key": "${env:OPENAI_API_KEY}",
617
+ "base_url": "",
618
+ "frequency_penalty": 0.9,
619
+ "greeting": "TEN Agent connected. How can I help you today?",
620
+ "max_memory_length": 10,
621
+ "max_tokens": 512,
622
+ "model": "${env:OPENAI_MODEL}",
623
+ "prompt": "",
624
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
625
+ }
626
+ },
627
+ {
628
+ "type": "extension",
629
+ "name": "tts",
630
+ "addon": "azure_tts",
631
+ "extension_group": "tts",
632
+ "property": {
633
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
634
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
635
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
636
+ }
637
+ },
638
+ {
639
+ "type": "extension",
640
+ "name": "interrupt_detector",
641
+ "addon": "interrupt_detector_python",
642
+ "extension_group": "default",
643
+ "property": {}
644
+ },
645
+ {
646
+ "type": "extension",
647
+ "name": "message_collector",
648
+ "addon": "message_collector",
649
+ "extension_group": "transcriber",
650
+ "property": {}
651
+ },
652
+ {
653
+ "type": "extension",
654
+ "name": "weatherapi_tool_python",
655
+ "addon": "weatherapi_tool_python",
656
+ "extension_group": "default",
657
+ "property": {
658
+ "api_key": "${env:WEATHERAPI_API_KEY|}"
659
+ }
660
+ },
661
+ {
662
+ "type": "extension",
663
+ "name": "vision_tool_python",
664
+ "addon": "vision_tool_python",
665
+ "extension_group": "default",
666
+ "property": {}
667
+ },
668
+ {
669
+ "type": "extension",
670
+ "name": "bingsearch_tool_python",
671
+ "addon": "bingsearch_tool_python",
672
+ "extension_group": "default",
673
+ "property": {
674
+ "api_key": "${env:BING_API_KEY|}"
675
+ }
676
+ }
677
+ ],
678
+ "connections": [
679
+ {
680
+ "extension": "agora_rtc",
681
+ "cmd": [
682
+ {
683
+ "name": "on_user_joined",
684
+ "dest": [
685
+ {
686
+ "extension": "llm"
687
+ }
688
+ ]
689
+ },
690
+ {
691
+ "name": "on_user_left",
692
+ "dest": [
693
+ {
694
+ "extension": "llm"
695
+ }
696
+ ]
697
+ },
698
+ {
699
+ "name": "on_connection_failure",
700
+ "dest": [
701
+ {
702
+ "extension": "llm"
703
+ }
704
+ ]
705
+ }
706
+ ],
707
+ "data": [
708
+ {
709
+ "name": "text_data",
710
+ "dest": [
711
+ {
712
+ "extension": "interrupt_detector"
713
+ },
714
+ {
715
+ "extension": "message_collector"
716
+ }
717
+ ]
718
+ }
719
+ ],
720
+ "video_frame": [
721
+ {
722
+ "name": "video_frame",
723
+ "dest": [
724
+ {
725
+ "extension": "vision_tool_python"
726
+ }
727
+ ]
728
+ }
729
+ ]
730
+ },
731
+ {
732
+ "extension": "llm",
733
+ "cmd": [
734
+ {
735
+ "name": "flush",
736
+ "dest": [
737
+ {
738
+ "extension": "tts"
739
+ }
740
+ ]
741
+ },
742
+ {
743
+ "name": "tool_call",
744
+ "dest": [
745
+ {
746
+ "extension": "weatherapi_tool_python"
747
+ },
748
+ {
749
+ "extension": "vision_tool_python"
750
+ },
751
+ {
752
+ "extension": "bingsearch_tool_python"
753
+ }
754
+ ]
755
+ }
756
+ ],
757
+ "data": [
758
+ {
759
+ "name": "text_data",
760
+ "dest": [
761
+ {
762
+ "extension": "tts"
763
+ },
764
+ {
765
+ "extension": "message_collector"
766
+ }
767
+ ]
768
+ }
769
+ ]
770
+ },
771
+ {
772
+ "extension": "message_collector",
773
+ "data": [
774
+ {
775
+ "name": "data",
776
+ "dest": [
777
+ {
778
+ "extension": "agora_rtc"
779
+ }
780
+ ]
781
+ }
782
+ ]
783
+ },
784
+ {
785
+ "extension": "tts",
786
+ "cmd": [
787
+ {
788
+ "name": "flush",
789
+ "dest": [
790
+ {
791
+ "extension": "agora_rtc"
792
+ }
793
+ ]
794
+ }
795
+ ],
796
+ "audio_frame": [
797
+ {
798
+ "name": "pcm_frame",
799
+ "dest": [
800
+ {
801
+ "extension": "agora_rtc"
802
+ }
803
+ ]
804
+ }
805
+ ]
806
+ },
807
+ {
808
+ "extension": "interrupt_detector",
809
+ "cmd": [
810
+ {
811
+ "name": "flush",
812
+ "dest": [
813
+ {
814
+ "extension": "llm"
815
+ }
816
+ ]
817
+ }
818
+ ],
819
+ "data": [
820
+ {
821
+ "name": "text_data",
822
+ "dest": [
823
+ {
824
+ "extension": "llm"
825
+ }
826
+ ]
827
+ }
828
+ ]
829
+ },
830
+ {
831
+ "extension": "weatherapi_tool_python",
832
+ "cmd": [
833
+ {
834
+ "name": "tool_register",
835
+ "dest": [
836
+ {
837
+ "extension": "llm"
838
+ }
839
+ ]
840
+ }
841
+ ]
842
+ },
843
+ {
844
+ "extension": "vision_tool_python",
845
+ "cmd": [
846
+ {
847
+ "name": "tool_register",
848
+ "dest": [
849
+ {
850
+ "extension": "llm"
851
+ }
852
+ ]
853
+ }
854
+ ]
855
+ },
856
+ {
857
+ "extension": "bingsearch_tool_python",
858
+ "cmd": [
859
+ {
860
+ "name": "tool_register",
861
+ "dest": [
862
+ {
863
+ "extension": "llm"
864
+ }
865
+ ]
866
+ }
867
+ ]
868
+ }
869
+ ]
870
+ },
871
+ {
872
+ "name": "va_openai_v2v",
873
+ "auto_start": true,
874
+ "nodes": [
875
+ {
876
+ "type": "extension",
877
+ "name": "agora_rtc",
878
+ "addon": "agora_rtc",
879
+ "extension_group": "rtc",
880
+ "property": {
881
+ "app_id": "${env:AGORA_APP_ID}",
882
+ "token": "",
883
+ "channel": "ten_agent_test",
884
+ "stream_id": 1234,
885
+ "remote_stream_id": 123,
886
+ "subscribe_audio": true,
887
+ "publish_audio": true,
888
+ "publish_data": true,
889
+ "subscribe_audio_sample_rate": 24000
890
+ }
891
+ },
892
+ {
893
+ "type": "extension",
894
+ "name": "v2v",
895
+ "addon": "openai_v2v_python",
896
+ "extension_group": "llm",
897
+ "property": {
898
+ "api_key": "${env:OPENAI_REALTIME_API_KEY}",
899
+ "temperature": 0.9,
900
+ "model": "gpt-4o-realtime-preview-2024-12-17",
901
+ "max_tokens": 2048,
902
+ "voice": "alloy",
903
+ "language": "en-US",
904
+ "server_vad": true,
905
+ "dump": true,
906
+ "max_history": 10
907
+ }
908
+ },
909
+ {
910
+ "type": "extension",
911
+ "name": "message_collector",
912
+ "addon": "message_collector",
913
+ "extension_group": "transcriber",
914
+ "property": {}
915
+ },
916
+ {
917
+ "type": "extension",
918
+ "name": "bingsearch_tool_python",
919
+ "addon": "bingsearch_tool_python",
920
+ "extension_group": "default",
921
+ "property": {
922
+ "api_key": "${env:BING_API_KEY|}"
923
+ }
924
+ },
925
+ {
926
+ "type": "extension",
927
+ "name": "weatherapi_tool_python",
928
+ "addon": "weatherapi_tool_python",
929
+ "extension_group": "default",
930
+ "property": {
931
+ "api_key": "${env:WEATHERAPI_API_KEY|}"
932
+ }
933
+ }
934
+ ],
935
+ "connections": [
936
+ {
937
+ "extension": "agora_rtc",
938
+ "cmd": [
939
+ {
940
+ "name": "on_user_joined",
941
+ "dest": [
942
+ {
943
+ "extension": "v2v"
944
+ }
945
+ ]
946
+ },
947
+ {
948
+ "name": "on_user_left",
949
+ "dest": [
950
+ {
951
+ "extension": "v2v"
952
+ }
953
+ ]
954
+ },
955
+ {
956
+ "name": "on_connection_failure",
957
+ "dest": [
958
+ {
959
+ "extension": "v2v"
960
+ }
961
+ ]
962
+ }
963
+ ],
964
+ "audio_frame": [
965
+ {
966
+ "name": "pcm_frame",
967
+ "dest": [
968
+ {
969
+ "extension": "v2v"
970
+ }
971
+ ]
972
+ }
973
+ ]
974
+ },
975
+ {
976
+ "extension": "v2v",
977
+ "cmd": [
978
+ {
979
+ "name": "flush",
980
+ "dest": [
981
+ {
982
+ "extension": "agora_rtc"
983
+ }
984
+ ]
985
+ },
986
+ {
987
+ "name": "tool_call",
988
+ "dest": [
989
+ {
990
+ "extension": "bingsearch_tool_python"
991
+ },
992
+ {
993
+ "extension": "weatherapi_tool_python"
994
+ }
995
+ ]
996
+ }
997
+ ],
998
+ "data": [
999
+ {
1000
+ "name": "text_data",
1001
+ "dest": [
1002
+ {
1003
+ "extension": "message_collector"
1004
+ }
1005
+ ]
1006
+ }
1007
+ ],
1008
+ "audio_frame": [
1009
+ {
1010
+ "name": "pcm_frame",
1011
+ "dest": [
1012
+ {
1013
+ "extension": "agora_rtc"
1014
+ }
1015
+ ]
1016
+ }
1017
+ ]
1018
+ },
1019
+ {
1020
+ "extension": "message_collector",
1021
+ "data": [
1022
+ {
1023
+ "name": "data",
1024
+ "dest": [
1025
+ {
1026
+ "extension": "agora_rtc"
1027
+ }
1028
+ ]
1029
+ }
1030
+ ]
1031
+ },
1032
+ {
1033
+ "extension": "bingsearch_tool_python",
1034
+ "cmd": [
1035
+ {
1036
+ "name": "tool_register",
1037
+ "dest": [
1038
+ {
1039
+ "extension": "v2v"
1040
+ }
1041
+ ]
1042
+ }
1043
+ ]
1044
+ },
1045
+ {
1046
+ "extension": "weatherapi_tool_python",
1047
+ "cmd": [
1048
+ {
1049
+ "name": "tool_register",
1050
+ "dest": [
1051
+ {
1052
+ "extension": "v2v"
1053
+ }
1054
+ ]
1055
+ }
1056
+ ]
1057
+ }
1058
+ ]
1059
+ },
1060
+ {
1061
+ "name": "va_openai_v2v_fish",
1062
+ "auto_start": true,
1063
+ "nodes": [
1064
+ {
1065
+ "type": "extension",
1066
+ "name": "agora_rtc",
1067
+ "addon": "agora_rtc",
1068
+ "extension_group": "rtc",
1069
+ "property": {
1070
+ "app_id": "${env:AGORA_APP_ID}",
1071
+ "token": "",
1072
+ "channel": "ten_agent_test",
1073
+ "stream_id": 1234,
1074
+ "remote_stream_id": 123,
1075
+ "subscribe_audio": true,
1076
+ "publish_audio": true,
1077
+ "publish_data": true,
1078
+ "subscribe_audio_sample_rate": 24000,
1079
+ "enable_agora_asr": false,
1080
+ "agora_asr_vendor_name": "microsoft",
1081
+ "agora_asr_language": "en-US",
1082
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY}",
1083
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION}",
1084
+ "agora_asr_session_control_file_path": "session_control.conf"
1085
+ }
1086
+ },
1087
+ {
1088
+ "type": "extension",
1089
+ "name": "v2v",
1090
+ "addon": "openai_v2v_python",
1091
+ "extension_group": "llm",
1092
+ "property": {
1093
+ "api_key": "${env:OPENAI_REALTIME_API_KEY}",
1094
+ "temperature": 0.9,
1095
+ "model": "gpt-4o-realtime-preview-2024-12-17",
1096
+ "max_tokens": 2048,
1097
+ "audio_out": false,
1098
+ "input_transcript": false,
1099
+ "language": "en-US",
1100
+ "server_vad": true,
1101
+ "dump": true,
1102
+ "max_history": 10
1103
+ }
1104
+ },
1105
+ {
1106
+ "type": "extension",
1107
+ "name": "tts",
1108
+ "addon": "fish_audio_tts",
1109
+ "extension_group": "tts",
1110
+ "property": {
1111
+ "api_key": "${env:FISH_AUDIO_TTS_KEY}",
1112
+ "base_url": "https://api.fish.audio",
1113
+ "model_id": "d8639b5cc95548f5afbcfe22d3ba5ce5",
1114
+ "optimize_streaming_latency": true,
1115
+ "request_timeout_seconds": 30
1116
+ }
1117
+ },
1118
+ {
1119
+ "type": "extension",
1120
+ "name": "message_collector",
1121
+ "addon": "message_collector",
1122
+ "extension_group": "transcriber",
1123
+ "property": {}
1124
+ },
1125
+ {
1126
+ "type": "extension",
1127
+ "name": "weatherapi_tool_python",
1128
+ "addon": "weatherapi_tool_python",
1129
+ "extension_group": "tools",
1130
+ "property": {
1131
+ "api_key": "${env:WEATHERAPI_API_KEY}"
1132
+ }
1133
+ },
1134
+ {
1135
+ "type": "extension",
1136
+ "name": "bingsearch_tool_python",
1137
+ "addon": "bingsearch_tool_python",
1138
+ "extension_group": "tools",
1139
+ "property": {
1140
+ "api_key": "${env:BING_API_KEY}"
1141
+ }
1142
+ }
1143
+ ],
1144
+ "connections": [
1145
+ {
1146
+ "extension": "agora_rtc",
1147
+ "data": [
1148
+ {
1149
+ "name": "text_data",
1150
+ "dest": [
1151
+ {
1152
+ "extension": "message_collector"
1153
+ }
1154
+ ]
1155
+ }
1156
+ ],
1157
+ "audio_frame": [
1158
+ {
1159
+ "name": "pcm_frame",
1160
+ "dest": [
1161
+ {
1162
+ "extension": "v2v"
1163
+ }
1164
+ ]
1165
+ }
1166
+ ]
1167
+ },
1168
+ {
1169
+ "extension": "weatherapi_tool_python",
1170
+ "cmd": [
1171
+ {
1172
+ "name": "tool_register",
1173
+ "dest": [
1174
+ {
1175
+ "extension": "v2v"
1176
+ }
1177
+ ]
1178
+ }
1179
+ ]
1180
+ },
1181
+ {
1182
+ "extension": "bingsearch_tool_python",
1183
+ "cmd": [
1184
+ {
1185
+ "name": "tool_register",
1186
+ "dest": [
1187
+ {
1188
+ "extension": "v2v"
1189
+ }
1190
+ ]
1191
+ }
1192
+ ]
1193
+ },
1194
+ {
1195
+ "extension": "v2v",
1196
+ "cmd": [
1197
+ {
1198
+ "name": "flush",
1199
+ "dest": [
1200
+ {
1201
+ "extension": "tts"
1202
+ }
1203
+ ]
1204
+ },
1205
+ {
1206
+ "name": "tool_call",
1207
+ "dest": [
1208
+ {
1209
+ "extension": "weatherapi_tool_python"
1210
+ },
1211
+ {
1212
+ "extension": "bingsearch_tool_python"
1213
+ }
1214
+ ]
1215
+ },
1216
+ {
1217
+ "name": "on_user_joined",
1218
+ "dest": [
1219
+ {
1220
+ "extension": "v2v"
1221
+ }
1222
+ ]
1223
+ },
1224
+ {
1225
+ "name": "on_user_left",
1226
+ "dest": [
1227
+ {
1228
+ "extension": "v2v"
1229
+ }
1230
+ ]
1231
+ }
1232
+ ],
1233
+ "data": [
1234
+ {
1235
+ "name": "text_data",
1236
+ "dest": [
1237
+ {
1238
+ "extension": "message_collector"
1239
+ },
1240
+ {
1241
+ "extension": "tts"
1242
+ }
1243
+ ]
1244
+ }
1245
+ ]
1246
+ },
1247
+ {
1248
+ "extension": "tts",
1249
+ "cmd": [
1250
+ {
1251
+ "name": "flush",
1252
+ "dest": [
1253
+ {
1254
+ "extension": "agora_rtc"
1255
+ }
1256
+ ]
1257
+ }
1258
+ ],
1259
+ "audio_frame": [
1260
+ {
1261
+ "name": "pcm_frame",
1262
+ "dest": [
1263
+ {
1264
+ "extension": "agora_rtc"
1265
+ }
1266
+ ]
1267
+ }
1268
+ ]
1269
+ },
1270
+ {
1271
+ "extension": "message_collector",
1272
+ "data": [
1273
+ {
1274
+ "name": "data",
1275
+ "dest": [
1276
+ {
1277
+ "extension": "agora_rtc"
1278
+ }
1279
+ ]
1280
+ }
1281
+ ]
1282
+ }
1283
+ ]
1284
+ },
1285
+ {
1286
+ "name": "va_coze_azure",
1287
+ "auto_start": false,
1288
+ "nodes": [
1289
+ {
1290
+ "type": "extension",
1291
+ "name": "agora_rtc",
1292
+ "addon": "agora_rtc",
1293
+ "extension_group": "default",
1294
+ "property": {
1295
+ "app_id": "${env:AGORA_APP_ID}",
1296
+ "token": "<agora_token>",
1297
+ "channel": "ten_agent_test",
1298
+ "stream_id": 1234,
1299
+ "remote_stream_id": 123,
1300
+ "subscribe_audio": true,
1301
+ "publish_audio": true,
1302
+ "publish_data": true,
1303
+ "enable_agora_asr": true,
1304
+ "agora_asr_vendor_name": "microsoft",
1305
+ "agora_asr_language": "en-US",
1306
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY}",
1307
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION}",
1308
+ "agora_asr_session_control_file_path": "session_control.conf"
1309
+ }
1310
+ },
1311
+ {
1312
+ "type": "extension",
1313
+ "name": "interrupt_detector",
1314
+ "addon": "interrupt_detector_python",
1315
+ "extension_group": "default"
1316
+ },
1317
+ {
1318
+ "type": "extension",
1319
+ "name": "coze_python_async",
1320
+ "addon": "coze_python_async",
1321
+ "extension_group": "glue",
1322
+ "property": {
1323
+ "token": "<coze_token>",
1324
+ "bot_id": "<coze_bot_id>",
1325
+ "base_url": "https://api.coze.cn",
1326
+ "prompt": "",
1327
+ "greeting": "TEN Agent connected. How can I help you today?"
1328
+ }
1329
+ },
1330
+ {
1331
+ "type": "extension",
1332
+ "name": "tts",
1333
+ "addon": "azure_tts",
1334
+ "extension_group": "tts",
1335
+ "property": {
1336
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
1337
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
1338
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
1339
+ }
1340
+ },
1341
+ {
1342
+ "type": "extension",
1343
+ "name": "message_collector",
1344
+ "addon": "message_collector",
1345
+ "extension_group": "transcriber"
1346
+ }
1347
+ ],
1348
+ "connections": [
1349
+ {
1350
+ "extension": "agora_rtc",
1351
+ "cmd": [
1352
+ {
1353
+ "name": "on_user_joined",
1354
+ "dest": [
1355
+ {
1356
+ "extension": "coze_python_async"
1357
+ }
1358
+ ]
1359
+ },
1360
+ {
1361
+ "name": "on_user_left",
1362
+ "dest": [
1363
+ {
1364
+ "extension": "coze_python_async"
1365
+ }
1366
+ ]
1367
+ }
1368
+ ],
1369
+ "data": [
1370
+ {
1371
+ "name": "text_data",
1372
+ "dest": [
1373
+ {
1374
+ "extension": "interrupt_detector"
1375
+ },
1376
+ {
1377
+ "extension": "coze_python_async"
1378
+ },
1379
+ {
1380
+ "extension": "message_collector"
1381
+ }
1382
+ ]
1383
+ }
1384
+ ]
1385
+ },
1386
+ {
1387
+ "extension": "coze_python_async",
1388
+ "cmd": [
1389
+ {
1390
+ "name": "flush",
1391
+ "dest": [
1392
+ {
1393
+ "extension": "tts"
1394
+ }
1395
+ ]
1396
+ }
1397
+ ],
1398
+ "data": [
1399
+ {
1400
+ "name": "text_data",
1401
+ "dest": [
1402
+ {
1403
+ "extension": "tts"
1404
+ },
1405
+ {
1406
+ "extension": "message_collector"
1407
+ }
1408
+ ]
1409
+ }
1410
+ ]
1411
+ },
1412
+ {
1413
+ "extension": "tts",
1414
+ "cmd": [
1415
+ {
1416
+ "name": "flush",
1417
+ "dest": [
1418
+ {
1419
+ "extension": "agora_rtc"
1420
+ }
1421
+ ]
1422
+ }
1423
+ ],
1424
+ "audio_frame": [
1425
+ {
1426
+ "name": "pcm_frame",
1427
+ "dest": [
1428
+ {
1429
+ "extension": "agora_rtc"
1430
+ }
1431
+ ]
1432
+ }
1433
+ ]
1434
+ },
1435
+ {
1436
+ "extension": "message_collector",
1437
+ "data": [
1438
+ {
1439
+ "name": "data",
1440
+ "dest": [
1441
+ {
1442
+ "extension": "agora_rtc"
1443
+ }
1444
+ ]
1445
+ }
1446
+ ]
1447
+ },
1448
+ {
1449
+ "extension": "interrupt_detector",
1450
+ "cmd": [
1451
+ {
1452
+ "name": "flush",
1453
+ "dest": [
1454
+ {
1455
+ "extension": "coze_python_async"
1456
+ }
1457
+ ]
1458
+ }
1459
+ ]
1460
+ }
1461
+ ]
1462
+ },
1463
+ {
1464
+ "name": "va_gemini_v2v",
1465
+ "auto_start": true,
1466
+ "nodes": [
1467
+ {
1468
+ "type": "extension",
1469
+ "name": "agora_rtc",
1470
+ "addon": "agora_rtc",
1471
+ "extension_group": "rtc",
1472
+ "property": {
1473
+ "app_id": "${env:AGORA_APP_ID}",
1474
+ "token": "",
1475
+ "channel": "ten_agent_test",
1476
+ "stream_id": 1234,
1477
+ "remote_stream_id": 123,
1478
+ "subscribe_audio": true,
1479
+ "publish_audio": true,
1480
+ "publish_data": true,
1481
+ "subscribe_audio_sample_rate": 24000,
1482
+ "subscribe_video_pix_fmt": 4,
1483
+ "subscribe_video": true
1484
+ }
1485
+ },
1486
+ {
1487
+ "type": "extension",
1488
+ "name": "v2v",
1489
+ "addon": "gemini_v2v_python",
1490
+ "extension_group": "llm",
1491
+ "property": {
1492
+ "api_key": "${env:GEMINI_API_KEY}",
1493
+ "api_version": "v1alpha",
1494
+ "base_uri": "generativelanguage.googleapis.com",
1495
+ "dump": true,
1496
+ "language": "en-US",
1497
+ "max_tokens": 2048,
1498
+ "model": "gemini-2.0-flash-exp",
1499
+ "server_vad": true,
1500
+ "temperature": 0.9,
1501
+ "voice": "Puck"
1502
+ }
1503
+ },
1504
+ {
1505
+ "type": "extension",
1506
+ "name": "message_collector",
1507
+ "addon": "message_collector",
1508
+ "extension_group": "transcriber",
1509
+ "property": {}
1510
+ },
1511
+ {
1512
+ "type": "extension",
1513
+ "name": "weatherapi_tool_python",
1514
+ "addon": "weatherapi_tool_python",
1515
+ "extension_group": "default",
1516
+ "property": {
1517
+ "api_key": "${env:WEATHERAPI_API_KEY|}"
1518
+ }
1519
+ }
1520
+ ],
1521
+ "connections": [
1522
+ {
1523
+ "extension": "agora_rtc",
1524
+ "cmd": [
1525
+ {
1526
+ "name": "on_user_joined",
1527
+ "dest": [
1528
+ {
1529
+ "extension": "v2v"
1530
+ }
1531
+ ]
1532
+ },
1533
+ {
1534
+ "name": "on_user_left",
1535
+ "dest": [
1536
+ {
1537
+ "extension": "v2v"
1538
+ }
1539
+ ]
1540
+ },
1541
+ {
1542
+ "name": "on_connection_failure",
1543
+ "dest": [
1544
+ {
1545
+ "extension": "v2v"
1546
+ }
1547
+ ]
1548
+ }
1549
+ ],
1550
+ "audio_frame": [
1551
+ {
1552
+ "name": "pcm_frame",
1553
+ "dest": [
1554
+ {
1555
+ "extension": "v2v"
1556
+ }
1557
+ ]
1558
+ }
1559
+ ],
1560
+ "video_frame": [
1561
+ {
1562
+ "name": "video_frame",
1563
+ "dest": [
1564
+ {
1565
+ "extension": "v2v"
1566
+ }
1567
+ ]
1568
+ }
1569
+ ]
1570
+ },
1571
+ {
1572
+ "extension": "v2v",
1573
+ "cmd": [
1574
+ {
1575
+ "name": "flush",
1576
+ "dest": [
1577
+ {
1578
+ "extension": "agora_rtc"
1579
+ }
1580
+ ]
1581
+ },
1582
+ {
1583
+ "name": "tool_call",
1584
+ "dest": [
1585
+ {
1586
+ "extension": "weatherapi_tool_python"
1587
+ }
1588
+ ]
1589
+ }
1590
+ ],
1591
+ "data": [
1592
+ {
1593
+ "name": "text_data",
1594
+ "dest": [
1595
+ {
1596
+ "extension": "message_collector"
1597
+ }
1598
+ ]
1599
+ }
1600
+ ],
1601
+ "audio_frame": [
1602
+ {
1603
+ "name": "pcm_frame",
1604
+ "dest": [
1605
+ {
1606
+ "extension": "agora_rtc"
1607
+ }
1608
+ ]
1609
+ }
1610
+ ]
1611
+ },
1612
+ {
1613
+ "extension": "message_collector",
1614
+ "data": [
1615
+ {
1616
+ "name": "data",
1617
+ "dest": [
1618
+ {
1619
+ "extension": "agora_rtc"
1620
+ }
1621
+ ]
1622
+ }
1623
+ ]
1624
+ },
1625
+ {
1626
+ "extension": "weatherapi_tool_python",
1627
+ "cmd": [
1628
+ {
1629
+ "name": "tool_register",
1630
+ "dest": [
1631
+ {
1632
+ "extension": "v2v"
1633
+ }
1634
+ ]
1635
+ }
1636
+ ]
1637
+ }
1638
+ ]
1639
+ },
1640
+ {
1641
+ "name": "va_dify_azure",
1642
+ "auto_start": true,
1643
+ "nodes": [
1644
+ {
1645
+ "type": "extension",
1646
+ "name": "agora_rtc",
1647
+ "addon": "agora_rtc",
1648
+ "extension_group": "default",
1649
+ "property": {
1650
+ "app_id": "${env:AGORA_APP_ID}",
1651
+ "token": "<agora_token>",
1652
+ "channel": "ten_agent_test",
1653
+ "stream_id": 1234,
1654
+ "remote_stream_id": 123,
1655
+ "subscribe_audio": true,
1656
+ "publish_audio": true,
1657
+ "publish_data": true,
1658
+ "enable_agora_asr": true,
1659
+ "agora_asr_vendor_name": "microsoft",
1660
+ "agora_asr_language": "en-US",
1661
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
1662
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
1663
+ "agora_asr_session_control_file_path": "session_control.conf"
1664
+ }
1665
+ },
1666
+ {
1667
+ "type": "extension",
1668
+ "name": "llm",
1669
+ "addon": "dify_python",
1670
+ "extension_group": "chatgpt",
1671
+ "property": {
1672
+ "api_key": "${env:DIFY_API_KEY}",
1673
+ "base_url": "https://api.dify.ai/v1",
1674
+ "greeting": "TEN Agent connected with Dify. How can I help you today?",
1675
+ "user_id": "User"
1676
+ }
1677
+ },
1678
+ {
1679
+ "type": "extension",
1680
+ "name": "tts",
1681
+ "addon": "azure_tts",
1682
+ "extension_group": "tts",
1683
+ "property": {
1684
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
1685
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
1686
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
1687
+ }
1688
+ },
1689
+ {
1690
+ "type": "extension",
1691
+ "name": "interrupt_detector",
1692
+ "addon": "interrupt_detector_python",
1693
+ "extension_group": "default",
1694
+ "property": {}
1695
+ },
1696
+ {
1697
+ "type": "extension",
1698
+ "name": "message_collector",
1699
+ "addon": "message_collector",
1700
+ "extension_group": "transcriber",
1701
+ "property": {}
1702
+ }
1703
+ ],
1704
+ "connections": [
1705
+ {
1706
+ "extension": "agora_rtc",
1707
+ "cmd": [
1708
+ {
1709
+ "name": "on_user_joined",
1710
+ "dest": [
1711
+ {
1712
+ "extension": "llm"
1713
+ }
1714
+ ]
1715
+ },
1716
+ {
1717
+ "name": "on_user_left",
1718
+ "dest": [
1719
+ {
1720
+ "extension": "llm"
1721
+ }
1722
+ ]
1723
+ },
1724
+ {
1725
+ "name": "on_connection_failure",
1726
+ "dest": [
1727
+ {
1728
+ "extension": "llm"
1729
+ }
1730
+ ]
1731
+ }
1732
+ ],
1733
+ "data": [
1734
+ {
1735
+ "name": "text_data",
1736
+ "dest": [
1737
+ {
1738
+ "extension": "interrupt_detector"
1739
+ },
1740
+ {
1741
+ "extension": "message_collector"
1742
+ }
1743
+ ]
1744
+ }
1745
+ ]
1746
+ },
1747
+ {
1748
+ "extension": "llm",
1749
+ "cmd": [
1750
+ {
1751
+ "name": "flush",
1752
+ "dest": [
1753
+ {
1754
+ "extension": "tts"
1755
+ }
1756
+ ]
1757
+ }
1758
+ ],
1759
+ "data": [
1760
+ {
1761
+ "name": "text_data",
1762
+ "dest": [
1763
+ {
1764
+ "extension": "tts"
1765
+ },
1766
+ {
1767
+ "extension": "message_collector"
1768
+ }
1769
+ ]
1770
+ }
1771
+ ]
1772
+ },
1773
+ {
1774
+ "extension": "message_collector",
1775
+ "data": [
1776
+ {
1777
+ "name": "data",
1778
+ "dest": [
1779
+ {
1780
+ "extension": "agora_rtc"
1781
+ }
1782
+ ]
1783
+ }
1784
+ ]
1785
+ },
1786
+ {
1787
+ "extension": "tts",
1788
+ "cmd": [
1789
+ {
1790
+ "name": "flush",
1791
+ "dest": [
1792
+ {
1793
+ "extension": "agora_rtc"
1794
+ }
1795
+ ]
1796
+ }
1797
+ ],
1798
+ "audio_frame": [
1799
+ {
1800
+ "name": "pcm_frame",
1801
+ "dest": [
1802
+ {
1803
+ "extension": "agora_rtc"
1804
+ }
1805
+ ]
1806
+ }
1807
+ ]
1808
+ },
1809
+ {
1810
+ "extension": "interrupt_detector",
1811
+ "cmd": [
1812
+ {
1813
+ "name": "flush",
1814
+ "dest": [
1815
+ {
1816
+ "extension": "llm"
1817
+ }
1818
+ ]
1819
+ }
1820
+ ],
1821
+ "data": [
1822
+ {
1823
+ "name": "text_data",
1824
+ "dest": [
1825
+ {
1826
+ "extension": "llm"
1827
+ }
1828
+ ]
1829
+ }
1830
+ ]
1831
+ }
1832
+ ]
1833
+ },
1834
+ {
1835
+ "name": "story_teller_stt_integrated",
1836
+ "auto_start": true,
1837
+ "nodes": [
1838
+ {
1839
+ "type": "extension",
1840
+ "name": "agora_rtc",
1841
+ "addon": "agora_rtc",
1842
+ "extension_group": "default",
1843
+ "property": {
1844
+ "app_id": "${env:AGORA_APP_ID}",
1845
+ "token": "<agora_token>",
1846
+ "channel": "ten_agent_test",
1847
+ "stream_id": 1234,
1848
+ "remote_stream_id": 123,
1849
+ "subscribe_audio": true,
1850
+ "publish_audio": true,
1851
+ "publish_data": true,
1852
+ "enable_agora_asr": true,
1853
+ "agora_asr_vendor_name": "microsoft",
1854
+ "agora_asr_language": "en-US",
1855
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
1856
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
1857
+ "agora_asr_session_control_file_path": "session_control.conf"
1858
+ }
1859
+ },
1860
+ {
1861
+ "type": "extension",
1862
+ "name": "llm",
1863
+ "addon": "openai_chatgpt_python",
1864
+ "extension_group": "chatgpt",
1865
+ "property": {
1866
+ "api_key": "${env:OPENAI_API_KEY}",
1867
+ "base_url": "",
1868
+ "frequency_penalty": 0.9,
1869
+ "greeting": "TEN Agent connected. How can I help you today?",
1870
+ "max_memory_length": 10,
1871
+ "max_tokens": 512,
1872
+ "model": "${env:OPENAI_MODEL}",
1873
+ "prompt": "You are an ai agent bot producing child picture books. Each response should be short and no more than 50 words as it's for child. \nFor every response relevant to the story-telling, you will use the 'image_generate' tool to create an image based on the description or key moment in that part of the story. \n The story should be set in a fantasy world. Try asking questions relevant to the story to decide how the story should proceed. Every response should include rich, vivid descriptions that will guide the 'image_generate' tool to produce an image that aligns with the scene or mood.\n Whether it’s the setting, a character’s expression, or a dramatic moment, the paragraph should give enough detail for a meaningful visual representation.",
1874
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
1875
+ }
1876
+ },
1877
+ {
1878
+ "type": "extension",
1879
+ "name": "tts",
1880
+ "addon": "azure_tts",
1881
+ "extension_group": "tts",
1882
+ "property": {
1883
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
1884
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
1885
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
1886
+ }
1887
+ },
1888
+ {
1889
+ "type": "extension",
1890
+ "name": "interrupt_detector",
1891
+ "addon": "interrupt_detector_python",
1892
+ "extension_group": "default",
1893
+ "property": {}
1894
+ },
1895
+ {
1896
+ "type": "extension",
1897
+ "name": "message_collector",
1898
+ "addon": "message_collector",
1899
+ "extension_group": "transcriber",
1900
+ "property": {}
1901
+ },
1902
+ {
1903
+ "type": "extension",
1904
+ "name": "openai_image_generate_tool",
1905
+ "addon": "openai_image_generate_tool",
1906
+ "extension_group": "default",
1907
+ "property": {
1908
+ "api_key": "${env:OPENAI_API_KEY}"
1909
+ }
1910
+ }
1911
+ ],
1912
+ "connections": [
1913
+ {
1914
+ "extension": "agora_rtc",
1915
+ "cmd": [
1916
+ {
1917
+ "name": "on_user_joined",
1918
+ "dest": [
1919
+ {
1920
+ "extension": "llm"
1921
+ }
1922
+ ]
1923
+ },
1924
+ {
1925
+ "name": "on_user_left",
1926
+ "dest": [
1927
+ {
1928
+ "extension": "llm"
1929
+ }
1930
+ ]
1931
+ },
1932
+ {
1933
+ "name": "on_connection_failure",
1934
+ "dest": [
1935
+ {
1936
+ "extension": "llm"
1937
+ }
1938
+ ]
1939
+ }
1940
+ ],
1941
+ "data": [
1942
+ {
1943
+ "name": "text_data",
1944
+ "dest": [
1945
+ {
1946
+ "extension": "interrupt_detector"
1947
+ },
1948
+ {
1949
+ "extension": "message_collector"
1950
+ }
1951
+ ]
1952
+ }
1953
+ ]
1954
+ },
1955
+ {
1956
+ "extension": "llm",
1957
+ "cmd": [
1958
+ {
1959
+ "name": "flush",
1960
+ "dest": [
1961
+ {
1962
+ "extension": "tts"
1963
+ }
1964
+ ]
1965
+ },
1966
+ {
1967
+ "name": "tool_call",
1968
+ "dest": [
1969
+ {
1970
+ "extension": "openai_image_generate_tool"
1971
+ }
1972
+ ]
1973
+ }
1974
+ ],
1975
+ "data": [
1976
+ {
1977
+ "name": "text_data",
1978
+ "dest": [
1979
+ {
1980
+ "extension": "tts"
1981
+ },
1982
+ {
1983
+ "extension": "message_collector"
1984
+ }
1985
+ ]
1986
+ }
1987
+ ]
1988
+ },
1989
+ {
1990
+ "extension": "message_collector",
1991
+ "data": [
1992
+ {
1993
+ "name": "data",
1994
+ "dest": [
1995
+ {
1996
+ "extension": "agora_rtc"
1997
+ }
1998
+ ]
1999
+ }
2000
+ ]
2001
+ },
2002
+ {
2003
+ "extension": "tts",
2004
+ "cmd": [
2005
+ {
2006
+ "name": "flush",
2007
+ "dest": [
2008
+ {
2009
+ "extension": "agora_rtc"
2010
+ }
2011
+ ]
2012
+ }
2013
+ ],
2014
+ "audio_frame": [
2015
+ {
2016
+ "name": "pcm_frame",
2017
+ "dest": [
2018
+ {
2019
+ "extension": "agora_rtc"
2020
+ }
2021
+ ]
2022
+ }
2023
+ ]
2024
+ },
2025
+ {
2026
+ "extension": "interrupt_detector",
2027
+ "cmd": [
2028
+ {
2029
+ "name": "flush",
2030
+ "dest": [
2031
+ {
2032
+ "extension": "llm"
2033
+ }
2034
+ ]
2035
+ }
2036
+ ],
2037
+ "data": [
2038
+ {
2039
+ "name": "text_data",
2040
+ "dest": [
2041
+ {
2042
+ "extension": "llm"
2043
+ }
2044
+ ]
2045
+ }
2046
+ ]
2047
+ },
2048
+ {
2049
+ "extension": "openai_image_generate_tool",
2050
+ "cmd": [
2051
+ {
2052
+ "name": "tool_register",
2053
+ "dest": [
2054
+ {
2055
+ "extension": "llm"
2056
+ }
2057
+ ]
2058
+ }
2059
+ ],
2060
+ "data": [
2061
+ {
2062
+ "name": "content_data",
2063
+ "dest": [
2064
+ {
2065
+ "extension": "message_collector"
2066
+ }
2067
+ ]
2068
+ }
2069
+ ]
2070
+ }
2071
+ ]
2072
+ },
2073
+ {
2074
+ "name": "va_nova_multimodal_aws",
2075
+ "auto_start": true,
2076
+ "nodes": [
2077
+ {
2078
+ "type": "extension",
2079
+ "name": "agora_rtc",
2080
+ "addon": "agora_rtc",
2081
+ "extension_group": "default",
2082
+ "property": {
2083
+ "app_id": "${env:AGORA_APP_ID}",
2084
+ "token": "<agora_token>",
2085
+ "channel": "ten_agent_test",
2086
+ "stream_id": 1234,
2087
+ "remote_stream_id": 123,
2088
+ "subscribe_audio": true,
2089
+ "publish_audio": true,
2090
+ "publish_data": true,
2091
+ "enable_agora_asr": false,
2092
+ "agora_asr_vendor_name": "microsoft",
2093
+ "agora_asr_language": "en-US",
2094
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY|}",
2095
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION|}",
2096
+ "agora_asr_session_control_file_path": "session_control.conf",
2097
+ "subscribe_video_pix_fmt": 4,
2098
+ "subscribe_video": true,
2099
+ "max_memory_length": 10
2100
+ }
2101
+ },
2102
+ {
2103
+ "type": "extension",
2104
+ "name": "stt",
2105
+ "addon": "transcribe_asr_python",
2106
+ "extension_group": "stt",
2107
+ "property": {
2108
+ "access_key": "${env:AWS_ACCESS_KEY_ID}",
2109
+ "lang_code": "en-US",
2110
+ "region": "us-east-1",
2111
+ "sample_rate": "16000",
2112
+ "secret_key": "${env:AWS_SECRET_ACCESS_KEY}"
2113
+ }
2114
+ },
2115
+ {
2116
+ "type": "extension",
2117
+ "name": "llm",
2118
+ "addon": "bedrock_llm_python",
2119
+ "extension_group": "chatgpt",
2120
+ "property": {
2121
+ "access_key_id": "${env:AWS_ACCESS_KEY_ID}",
2122
+ "greeting": "TEN Agent connected. I am nova, How can I help you today?",
2123
+ "max_memory_length": 10,
2124
+ "max_tokens": 256,
2125
+ "model": "us.amazon.nova-lite-v1:0",
2126
+ "prompt": "Now you are an intelligent assistant with real-time interaction capabilities. I will provide you with a series of real-time video image information. Please understand these images as video frames. Based on the images and the user's input, engage in a conversation with the user, remembering the dialogue content in a concise and clear manner.",
2127
+ "region": "us-east-1",
2128
+ "secret_access_key": "${env:AWS_SECRET_ACCESS_KEY}",
2129
+ "temperature": 0.7,
2130
+ "topK": 10,
2131
+ "topP": 0.5,
2132
+ "is_memory_enabled": false,
2133
+ "is_enable_video": true
2134
+ }
2135
+ },
2136
+ {
2137
+ "type": "extension",
2138
+ "name": "tts",
2139
+ "addon": "polly_tts",
2140
+ "extension_group": "tts",
2141
+ "property": {
2142
+ "region": "us-east-1",
2143
+ "access_key": "${env:AWS_ACCESS_KEY_ID}",
2144
+ "secret_key": "${env:AWS_SECRET_ACCESS_KEY}",
2145
+ "engine": "generative",
2146
+ "voice": "Ruth",
2147
+ "sample_rate": 16000,
2148
+ "lang_code": "en-US"
2149
+ }
2150
+ },
2151
+ {
2152
+ "type": "extension",
2153
+ "name": "interrupt_detector",
2154
+ "addon": "interrupt_detector_python",
2155
+ "extension_group": "default",
2156
+ "property": {}
2157
+ },
2158
+ {
2159
+ "type": "extension",
2160
+ "name": "message_collector",
2161
+ "addon": "message_collector",
2162
+ "extension_group": "transcriber",
2163
+ "property": {}
2164
+ }
2165
+ ],
2166
+ "connections": [
2167
+ {
2168
+ "extension": "agora_rtc",
2169
+ "cmd": [
2170
+ {
2171
+ "name": "on_user_joined",
2172
+ "dest": [
2173
+ {
2174
+ "extension": "llm"
2175
+ }
2176
+ ]
2177
+ },
2178
+ {
2179
+ "name": "on_user_left",
2180
+ "dest": [
2181
+ {
2182
+ "extension": "llm"
2183
+ }
2184
+ ]
2185
+ },
2186
+ {
2187
+ "name": "on_connection_failure",
2188
+ "dest": [
2189
+ {
2190
+ "extension": "llm"
2191
+ }
2192
+ ]
2193
+ }
2194
+ ],
2195
+ "audio_frame": [
2196
+ {
2197
+ "name": "pcm_frame",
2198
+ "dest": [
2199
+ {
2200
+ "extension": "stt"
2201
+ }
2202
+ ]
2203
+ }
2204
+ ],
2205
+ "video_frame": [
2206
+ {
2207
+ "name": "video_frame",
2208
+ "dest": [
2209
+ {
2210
+ "extension": "llm"
2211
+ }
2212
+ ]
2213
+ }
2214
+ ]
2215
+ },
2216
+ {
2217
+ "extension": "stt",
2218
+ "data": [
2219
+ {
2220
+ "name": "text_data",
2221
+ "dest": [
2222
+ {
2223
+ "extension": "interrupt_detector"
2224
+ },
2225
+ {
2226
+ "extension": "message_collector"
2227
+ }
2228
+ ]
2229
+ }
2230
+ ]
2231
+ },
2232
+ {
2233
+ "extension": "llm",
2234
+ "cmd": [
2235
+ {
2236
+ "name": "flush",
2237
+ "dest": [
2238
+ {
2239
+ "extension": "tts"
2240
+ }
2241
+ ]
2242
+ }
2243
+ ],
2244
+ "data": [
2245
+ {
2246
+ "name": "text_data",
2247
+ "dest": [
2248
+ {
2249
+ "extension": "tts"
2250
+ },
2251
+ {
2252
+ "extension": "message_collector"
2253
+ }
2254
+ ]
2255
+ }
2256
+ ]
2257
+ },
2258
+ {
2259
+ "extension": "message_collector",
2260
+ "data": [
2261
+ {
2262
+ "name": "data",
2263
+ "dest": [
2264
+ {
2265
+ "extension": "agora_rtc"
2266
+ }
2267
+ ]
2268
+ }
2269
+ ]
2270
+ },
2271
+ {
2272
+ "extension": "tts",
2273
+ "cmd": [
2274
+ {
2275
+ "name": "flush",
2276
+ "dest": [
2277
+ {
2278
+ "extension": "agora_rtc"
2279
+ }
2280
+ ]
2281
+ }
2282
+ ],
2283
+ "audio_frame": [
2284
+ {
2285
+ "name": "pcm_frame",
2286
+ "dest": [
2287
+ {
2288
+ "extension": "agora_rtc"
2289
+ }
2290
+ ]
2291
+ }
2292
+ ]
2293
+ },
2294
+ {
2295
+ "extension": "interrupt_detector",
2296
+ "cmd": [
2297
+ {
2298
+ "name": "flush",
2299
+ "dest": [
2300
+ {
2301
+ "extension": "llm"
2302
+ }
2303
+ ]
2304
+ }
2305
+ ],
2306
+ "data": [
2307
+ {
2308
+ "name": "text_data",
2309
+ "dest": [
2310
+ {
2311
+ "extension": "llm"
2312
+ }
2313
+ ]
2314
+ }
2315
+ ]
2316
+ }
2317
+ ]
2318
+ }
2319
+ ],
2320
+ "log_level": 3
2321
+ }
2322
+ }
agents/examples/experimental/manifest.json ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "app",
3
+ "name": "agent_experimental",
4
+ "version": "0.8.0",
5
+ "dependencies": [
6
+ {
7
+ "type": "system",
8
+ "name": "ten_runtime_go",
9
+ "version": "0.8"
10
+ },
11
+ {
12
+ "type": "extension",
13
+ "name": "agora_rtc",
14
+ "version": "=0.12.0"
15
+ },
16
+ {
17
+ "type": "extension",
18
+ "name": "agora_sess_ctrl",
19
+ "version": "=0.4.4"
20
+ },
21
+ {
22
+ "type": "system",
23
+ "name": "azure_speech_sdk",
24
+ "version": "1.38.0"
25
+ },
26
+ {
27
+ "type": "system",
28
+ "name": "ten_ai_base",
29
+ "version": "0.4.1"
30
+ },
31
+ {
32
+ "type": "extension",
33
+ "name": "azure_tts",
34
+ "version": "=0.8.1"
35
+ },
36
+ {
37
+ "type": "extension",
38
+ "name": "agora_rtm",
39
+ "version": "=0.8.1"
40
+ },
41
+ {
42
+ "type": "extension",
43
+ "name": "interrupt_detector_python",
44
+ "version": "=0.1.0"
45
+ },
46
+ {
47
+ "type": "extension",
48
+ "name": "openai_chatgpt_python",
49
+ "version": "=0.1.0"
50
+ },
51
+ {
52
+ "type": "extension",
53
+ "name": "message_collector",
54
+ "version": "=0.1.0"
55
+ },
56
+ {
57
+ "type": "extension",
58
+ "name": "fashionai",
59
+ "version": "=0.1.0"
60
+ },
61
+ {
62
+ "type": "extension",
63
+ "name": "qwen_llm_python",
64
+ "version": "=0.1.0"
65
+ },
66
+ {
67
+ "type": "extension",
68
+ "name": "cosy_tts_python",
69
+ "version": "=0.1.0"
70
+ },
71
+ {
72
+ "type": "extension",
73
+ "name": "http_server_python",
74
+ "version": "=0.10.1"
75
+ },
76
+ {
77
+ "type": "extension",
78
+ "name": "aliyun_text_embedding",
79
+ "version": "=0.1.0"
80
+ },
81
+ {
82
+ "type": "extension",
83
+ "name": "aliyun_analyticdb_vector_storage",
84
+ "version": "=0.1.0"
85
+ },
86
+ {
87
+ "type": "extension",
88
+ "name": "file_chunker",
89
+ "version": "=0.1.0"
90
+ },
91
+ {
92
+ "type": "extension",
93
+ "name": "llama_index_chat_engine",
94
+ "version": "=0.1.0"
95
+ },
96
+ {
97
+ "type": "extension",
98
+ "name": "openai_v2v_python",
99
+ "version": "=0.1.0"
100
+ },
101
+ {
102
+ "type": "extension",
103
+ "name": "weatherapi_tool_python",
104
+ "version": "=0.1.0"
105
+ },
106
+ {
107
+ "type": "extension",
108
+ "name": "bingsearch_tool_python",
109
+ "version": "=0.1.0"
110
+ },
111
+ {
112
+ "type": "extension",
113
+ "name": "tsdb_firestore",
114
+ "version": "=0.1.0"
115
+ },
116
+ {
117
+ "type": "extension",
118
+ "name": "minimax_v2v_python",
119
+ "version": "=0.1.0"
120
+ }
121
+ ]
122
+ }
agents/examples/experimental/property.json ADDED
@@ -0,0 +1,862 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_ten": {
3
+ "log_level": 3,
4
+ "predefined_graphs": [
5
+ {
6
+ "name": "va_openai_azure_fashionai",
7
+ "auto_start": false,
8
+ "connections": [
9
+ {
10
+ "data": [
11
+ {
12
+ "dest": [
13
+ {
14
+ "extension": "interrupt_detector"
15
+ },
16
+ {
17
+ "extension": "openai_chatgpt"
18
+ },
19
+ {
20
+ "extension": "message_collector"
21
+ }
22
+ ],
23
+ "name": "text_data"
24
+ }
25
+ ],
26
+ "cmd": [
27
+ {
28
+ "name": "on_user_joined",
29
+ "dest": [
30
+ {
31
+ "extension": "openai_chatgpt"
32
+ }
33
+ ]
34
+ },
35
+ {
36
+ "name": "on_user_left",
37
+ "dest": [
38
+ {
39
+ "extension": "openai_chatgpt"
40
+ }
41
+ ]
42
+ }
43
+ ],
44
+ "extension": "agora_rtc"
45
+ },
46
+ {
47
+ "cmd": [
48
+ {
49
+ "dest": [
50
+ {
51
+ "extension": "fashionai"
52
+ }
53
+ ],
54
+ "name": "flush"
55
+ }
56
+ ],
57
+ "data": [
58
+ {
59
+ "dest": [
60
+ {
61
+ "extension": "message_collector"
62
+ },
63
+ {
64
+ "extension": "fashionai"
65
+ }
66
+ ],
67
+ "name": "text_data"
68
+ }
69
+ ],
70
+ "extension": "openai_chatgpt"
71
+ },
72
+ {
73
+ "data": [
74
+ {
75
+ "dest": [
76
+ {
77
+ "extension": "agora_rtc"
78
+ }
79
+ ],
80
+ "name": "data"
81
+ }
82
+ ],
83
+ "extension": "message_collector"
84
+ },
85
+ {
86
+ "cmd": [
87
+ {
88
+ "dest": [
89
+ {
90
+ "extension": "openai_chatgpt"
91
+ }
92
+ ],
93
+ "name": "flush"
94
+ }
95
+ ],
96
+ "extension": "interrupt_detector"
97
+ }
98
+ ],
99
+ "nodes": [
100
+ {
101
+ "addon": "agora_rtc",
102
+ "extension_group": "default",
103
+ "name": "agora_rtc",
104
+ "property": {
105
+ "agora_asr_language": "en-US",
106
+ "agora_asr_session_control_file_path": "session_control.conf",
107
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY}",
108
+ "agora_asr_vendor_name": "microsoft",
109
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION}",
110
+ "app_id": "${env:AGORA_APP_ID}",
111
+ "channel": "ten_agent_test",
112
+ "enable_agora_asr": true,
113
+ "publish_audio": true,
114
+ "publish_data": true,
115
+ "remote_stream_id": 123,
116
+ "stream_id": 1234,
117
+ "subscribe_audio": true,
118
+ "token": "<agora_token>"
119
+ },
120
+ "type": "extension"
121
+ },
122
+ {
123
+ "addon": "interrupt_detector",
124
+ "extension_group": "default",
125
+ "name": "interrupt_detector",
126
+ "type": "extension"
127
+ },
128
+ {
129
+ "addon": "openai_chatgpt_python",
130
+ "extension_group": "chatgpt",
131
+ "name": "openai_chatgpt",
132
+ "property": {
133
+ "api_key": "${env:OPENAI_API_KEY}",
134
+ "base_url": "${env:OPENAI_API_BASE}",
135
+ "frequency_penalty": 0.9,
136
+ "greeting": "TEN Agent connected. How can I help you today?",
137
+ "max_memory_length": 10,
138
+ "max_tokens": 512,
139
+ "model": "${env:OPENAI_MODEL}",
140
+ "prompt": "",
141
+ "proxy_url": "${env:OPENAI_PROXY_URL}"
142
+ },
143
+ "type": "extension"
144
+ },
145
+ {
146
+ "addon": "message_collector",
147
+ "extension_group": "transcriber",
148
+ "name": "message_collector",
149
+ "type": "extension"
150
+ },
151
+ {
152
+ "addon": "fashionai",
153
+ "extension_group": "default",
154
+ "name": "fashionai",
155
+ "property": {
156
+ "app_id": "${env:AGORA_APP_ID}",
157
+ "channel": "ten_agent_test",
158
+ "stream_id": 12345,
159
+ "token": "<agora_token>",
160
+ "service_id": "agoramultimodel"
161
+ },
162
+ "type": "extension"
163
+ }
164
+ ]
165
+ },
166
+ {
167
+ "name": "va_qwen_rag",
168
+ "auto_start": false,
169
+ "nodes": [
170
+ {
171
+ "type": "extension",
172
+ "extension_group": "rtc",
173
+ "addon": "agora_rtc",
174
+ "name": "agora_rtc",
175
+ "property": {
176
+ "app_id": "${env:AGORA_APP_ID}",
177
+ "token": "<agora_token>",
178
+ "channel": "ten_agent_test",
179
+ "stream_id": 1234,
180
+ "remote_stream_id": 123,
181
+ "subscribe_audio": true,
182
+ "publish_audio": true,
183
+ "publish_data": true,
184
+ "enable_agora_asr": true,
185
+ "agora_asr_vendor_name": "microsoft",
186
+ "agora_asr_language": "en-US",
187
+ "agora_asr_vendor_key": "${env:AZURE_STT_KEY}",
188
+ "agora_asr_vendor_region": "${env:AZURE_STT_REGION}",
189
+ "agora_asr_session_control_file_path": "session_control.conf"
190
+ }
191
+ },
192
+ {
193
+ "type": "extension",
194
+ "extension_group": "llm",
195
+ "addon": "qwen_llm_python",
196
+ "name": "qwen_llm",
197
+ "property": {
198
+ "api_key": "${env:QWEN_API_KEY}",
199
+ "model": "qwen-max",
200
+ "max_tokens": 512,
201
+ "prompt": "",
202
+ "max_memory_length": 10,
203
+ "greeting": "TEN Agent connected. How can I help you today?"
204
+ }
205
+ },
206
+ {
207
+ "type": "extension",
208
+ "extension_group": "tts",
209
+ "addon": "cosy_tts_python",
210
+ "name": "cosy_tts",
211
+ "property": {
212
+ "api_key": "${env:QWEN_API_KEY}",
213
+ "model": "cosyvoice-v1",
214
+ "voice": "longxiaochun",
215
+ "sample_rate": 16000
216
+ }
217
+ },
218
+ {
219
+ "type": "extension",
220
+ "extension_group": "tts",
221
+ "addon": "azure_tts",
222
+ "name": "azure_tts",
223
+ "property": {
224
+ "azure_subscription_key": "${env:AZURE_TTS_KEY}",
225
+ "azure_subscription_region": "${env:AZURE_TTS_REGION}",
226
+ "azure_synthesis_voice_name": "en-US-AndrewMultilingualNeural"
227
+ }
228
+ },
229
+ {
230
+ "type": "extension",
231
+ "extension_group": "chat_transcriber",
232
+ "addon": "message_collector",
233
+ "name": "message_collector"
234
+ },
235
+ {
236
+ "type": "extension",
237
+ "extension_group": "interrupt_detector",
238
+ "addon": "interrupt_detector_python",
239
+ "name": "interrupt_detector"
240
+ },
241
+ {
242
+ "type": "extension",
243
+ "extension_group": "http_server",
244
+ "addon": "http_server_python",
245
+ "name": "http_server",
246
+ "property": {
247
+ "listen_addr": "127.0.0.1",
248
+ "listen_port": 8080
249
+ }
250
+ },
251
+ {
252
+ "type": "extension",
253
+ "extension_group": "embedding",
254
+ "addon": "aliyun_text_embedding",
255
+ "name": "aliyun_text_embedding",
256
+ "property": {
257
+ "api_key": "${env:ALIYUN_TEXT_EMBEDDING_API_KEY}",
258
+ "model": "text-embedding-v3"
259
+ }
260
+ },
261
+ {
262
+ "type": "extension",
263
+ "extension_group": "vector_storage",
264
+ "addon": "aliyun_analyticdb_vector_storage",
265
+ "name": "aliyun_analyticdb_vector_storage",
266
+ "property": {
267
+ "alibaba_cloud_access_key_id": "${env:ALIBABA_CLOUD_ACCESS_KEY_ID}",
268
+ "alibaba_cloud_access_key_secret": "${env:ALIBABA_CLOUD_ACCESS_KEY_SECRET}",
269
+ "adbpg_instance_id": "${env:ALIYUN_ANALYTICDB_INSTANCE_ID}",
270
+ "adbpg_instance_region": "${env:ALIYUN_ANALYTICDB_INSTANCE_REGION}",
271
+ "adbpg_account": "${env:ALIYUN_ANALYTICDB_ACCOUNT}",
272
+ "adbpg_account_password": "${env:ALIYUN_ANALYTICDB_ACCOUNT_PASSWORD}",
273
+ "adbpg_namespace": "${env:ALIYUN_ANALYTICDB_NAMESPACE}",
274
+ "adbpg_namespace_password": "${env:ALIYUN_ANALYTICDB_NAMESPACE_PASSWORD}"
275
+ }
276
+ },
277
+ {
278
+ "type": "extension",
279
+ "extension_group": "file_chunker",
280
+ "addon": "file_chunker",
281
+ "name": "file_chunker",
282
+ "property": {}
283
+ },
284
+ {
285
+ "type": "extension",
286
+ "extension_group": "llama_index",
287
+ "addon": "llama_index_chat_engine",
288
+ "name": "llama_index",
289
+ "property": {
290
+ "greeting": "TEN Agent connected. How can I help you today?",
291
+ "chat_memory_token_limit": 3000
292
+ }
293
+ }
294
+ ],
295
+ "connections": [
296
+ {
297
+ "extension": "agora_rtc",
298
+ "data": [
299
+ {
300
+ "name": "text_data",
301
+ "dest": [
302
+ {
303
+ "extension": "interrupt_detector"
304
+ },
305
+ {
306
+ "extension": "message_collector"
307
+ }
308
+ ]
309
+ }
310
+ ]
311
+ },
312
+ {
313
+ "extension": "interrupt_detector",
314
+ "cmd": [
315
+ {
316
+ "name": "flush",
317
+ "dest": [
318
+ {
319
+ "extension": "llama_index"
320
+ }
321
+ ]
322
+ },
323
+ {
324
+ "name": "file_chunk",
325
+ "dest": [
326
+ {
327
+ "extension": "file_chunker"
328
+ },
329
+ {
330
+ "extension": "llama_index"
331
+ }
332
+ ]
333
+ },
334
+ {
335
+ "name": "file_chunked",
336
+ "dest": [
337
+ {
338
+ "extension": "llama_index"
339
+ }
340
+ ]
341
+ },
342
+ {
343
+ "name": "update_querying_collection",
344
+ "dest": [
345
+ {
346
+ "extension": "llama_index"
347
+ }
348
+ ]
349
+ }
350
+ ],
351
+ "data": [
352
+ {
353
+ "name": "text_data",
354
+ "dest": [
355
+ {
356
+ "extension": "llama_index"
357
+ }
358
+ ]
359
+ }
360
+ ]
361
+ },
362
+ {
363
+ "extension": "llama_index",
364
+ "data": [
365
+ {
366
+ "name": "text_data",
367
+ "dest": [
368
+ {
369
+ "extension": "azure_tts"
370
+ },
371
+ {
372
+ "extension": "message_collector"
373
+ }
374
+ ]
375
+ }
376
+ ],
377
+ "cmd": [
378
+ {
379
+ "name": "flush",
380
+ "dest": [
381
+ {
382
+ "extension": "qwen_llm"
383
+ },
384
+ {
385
+ "extension": "azure_tts"
386
+ }
387
+ ]
388
+ },
389
+ {
390
+ "name": "call_chat",
391
+ "dest": [
392
+ {
393
+ "extension": "qwen_llm"
394
+ }
395
+ ]
396
+ },
397
+ {
398
+ "name": "embed",
399
+ "dest": [
400
+ {
401
+ "extension": "aliyun_text_embedding"
402
+ }
403
+ ]
404
+ },
405
+ {
406
+ "name": "query_vector",
407
+ "dest": [
408
+ {
409
+ "extension": "aliyun_analyticdb_vector_storage"
410
+ }
411
+ ]
412
+ }
413
+ ]
414
+ },
415
+ {
416
+ "extension": "azure_tts",
417
+ "audio_frame": [
418
+ {
419
+ "name": "pcm_frame",
420
+ "dest": [
421
+ {
422
+ "extension": "agora_rtc"
423
+ }
424
+ ]
425
+ }
426
+ ],
427
+ "cmd": [
428
+ {
429
+ "name": "flush",
430
+ "dest": [
431
+ {
432
+ "extension": "agora_rtc"
433
+ }
434
+ ]
435
+ }
436
+ ]
437
+ },
438
+ {
439
+ "extension": "message_collector",
440
+ "data": [
441
+ {
442
+ "name": "data",
443
+ "dest": [
444
+ {
445
+ "extension": "agora_rtc"
446
+ }
447
+ ]
448
+ }
449
+ ]
450
+ },
451
+ {
452
+ "extension": "http_server",
453
+ "cmd": [
454
+ {
455
+ "name": "file_chunk",
456
+ "dest": [
457
+ {
458
+ "extension": "interrupt_detector"
459
+ }
460
+ ]
461
+ },
462
+ {
463
+ "name": "update_querying_collection",
464
+ "dest": [
465
+ {
466
+ "extension": "interrupt_detector"
467
+ }
468
+ ]
469
+ }
470
+ ]
471
+ },
472
+ {
473
+ "extension": "file_chunker",
474
+ "cmd": [
475
+ {
476
+ "name": "embed_batch",
477
+ "dest": [
478
+ {
479
+ "extension": "aliyun_text_embedding"
480
+ }
481
+ ]
482
+ },
483
+ {
484
+ "name": "create_collection",
485
+ "dest": [
486
+ {
487
+ "extension": "aliyun_analyticdb_vector_storage"
488
+ }
489
+ ]
490
+ },
491
+ {
492
+ "name": "upsert_vector",
493
+ "dest": [
494
+ {
495
+ "extension": "aliyun_analyticdb_vector_storage"
496
+ }
497
+ ]
498
+ },
499
+ {
500
+ "name": "file_chunked",
501
+ "dest": [
502
+ {
503
+ "extension": "llama_index"
504
+ }
505
+ ]
506
+ }
507
+ ]
508
+ }
509
+ ]
510
+ },
511
+ {
512
+ "name": "va_openai_v2v_storage",
513
+ "auto_start": false,
514
+ "nodes": [
515
+ {
516
+ "type": "extension",
517
+ "extension_group": "rtc",
518
+ "addon": "agora_rtc",
519
+ "name": "agora_rtc",
520
+ "property": {
521
+ "app_id": "${env:AGORA_APP_ID}",
522
+ "token": "",
523
+ "channel": "ten_agent_test",
524
+ "stream_id": 1234,
525
+ "remote_stream_id": 123,
526
+ "subscribe_audio": true,
527
+ "publish_audio": true,
528
+ "publish_data": true,
529
+ "subscribe_audio_sample_rate": 24000
530
+ }
531
+ },
532
+ {
533
+ "type": "extension",
534
+ "extension_group": "llm",
535
+ "addon": "openai_v2v_python",
536
+ "name": "openai_v2v_python",
537
+ "property": {
538
+ "api_key": "${env:OPENAI_REALTIME_API_KEY}",
539
+ "temperature": 0.9,
540
+ "model": "gpt-4o-realtime-preview-2024-12-17",
541
+ "max_tokens": 2048,
542
+ "voice": "alloy",
543
+ "language": "en-US",
544
+ "server_vad": true,
545
+ "dump": true,
546
+ "max_history": 10,
547
+ "enable_storage": true
548
+ }
549
+ },
550
+ {
551
+ "type": "extension",
552
+ "extension_group": "transcriber",
553
+ "addon": "message_collector",
554
+ "name": "message_collector"
555
+ },
556
+ {
557
+ "type": "extension",
558
+ "extension_group": "tools",
559
+ "addon": "weatherapi_tool_python",
560
+ "name": "weatherapi_tool_python",
561
+ "property": {
562
+ "api_key": "${env:WEATHERAPI_API_KEY}"
563
+ }
564
+ },
565
+ {
566
+ "type": "extension",
567
+ "extension_group": "tools",
568
+ "addon": "bingsearch_tool_python",
569
+ "name": "bingsearch_tool_python",
570
+ "property": {
571
+ "api_key": "${env:BING_API_KEY}"
572
+ }
573
+ },
574
+ {
575
+ "type": "extension",
576
+ "extension_group": "context",
577
+ "addon": "tsdb_firestore",
578
+ "name": "tsdb_firestore",
579
+ "property": {
580
+ "credentials": {
581
+ "type": "service_account",
582
+ "project_id": "${env:FIRESTORE_PROJECT_ID}",
583
+ "private_key_id": "${env:FIRESTORE_PRIVATE_KEY_ID}",
584
+ "private_key": "${env:FIRESTORE_PRIVATE_KEY}",
585
+ "client_email": "${env:FIRESTORE_CLIENT_EMAIL}",
586
+ "client_id": "${env:FIRESTORE_CLIENT_ID}",
587
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
588
+ "token_uri": "https://oauth2.googleapis.com/token",
589
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
590
+ "client_x509_cert_url": "${env:FIRESTORE_CERT_URL}",
591
+ "universe_domain": "googleapis.com"
592
+ },
593
+ "channel_name": "ten_agent_test",
594
+ "collection_name": "llm_context"
595
+ }
596
+ }
597
+ ],
598
+ "connections": [
599
+ {
600
+ "extension": "agora_rtc",
601
+ "audio_frame": [
602
+ {
603
+ "name": "pcm_frame",
604
+ "dest": [
605
+ {
606
+ "extension": "openai_v2v_python"
607
+ }
608
+ ]
609
+ }
610
+ ]
611
+ },
612
+ {
613
+ "extension": "weatherapi_tool_python",
614
+ "cmd": [
615
+ {
616
+ "name": "tool_register",
617
+ "dest": [
618
+ {
619
+ "extension": "openai_v2v_python"
620
+ }
621
+ ]
622
+ }
623
+ ]
624
+ },
625
+ {
626
+ "extension": "bingsearch_tool_python",
627
+ "cmd": [
628
+ {
629
+ "name": "tool_register",
630
+ "dest": [
631
+ {
632
+ "extension": "openai_v2v_python"
633
+ }
634
+ ]
635
+ }
636
+ ]
637
+ },
638
+ {
639
+ "extension": "openai_v2v_python",
640
+ "audio_frame": [
641
+ {
642
+ "name": "pcm_frame",
643
+ "dest": [
644
+ {
645
+ "extension": "agora_rtc"
646
+ }
647
+ ]
648
+ }
649
+ ],
650
+ "data": [
651
+ {
652
+ "name": "append",
653
+ "dest": [
654
+ {
655
+ "extension": "tsdb_firestore"
656
+ }
657
+ ]
658
+ },
659
+ {
660
+ "name": "text_data",
661
+ "dest": [
662
+ {
663
+ "extension": "message_collector"
664
+ }
665
+ ]
666
+ }
667
+ ],
668
+ "cmd": [
669
+ {
670
+ "name": "flush",
671
+ "dest": [
672
+ {
673
+ "extension": "agora_rtc"
674
+ }
675
+ ]
676
+ },
677
+ {
678
+ "name": "retrieve",
679
+ "dest": [
680
+ {
681
+ "extension": "tsdb_firestore"
682
+ }
683
+ ]
684
+ },
685
+ {
686
+ "name": "tool_call",
687
+ "dest": [
688
+ {
689
+ "extension": "weatherapi_tool_python"
690
+ }
691
+ ]
692
+ },
693
+ {
694
+ "name": "tool_call",
695
+ "dest": [
696
+ {
697
+ "extension": "weatherapi_tool_python"
698
+ }
699
+ ]
700
+ }
701
+ ]
702
+ },
703
+ {
704
+ "extension": "message_collector",
705
+ "data": [
706
+ {
707
+ "name": "data",
708
+ "dest": [
709
+ {
710
+ "extension": "agora_rtc"
711
+ }
712
+ ]
713
+ }
714
+ ]
715
+ }
716
+ ]
717
+ },
718
+ {
719
+ "name": "va_minimax_v2v",
720
+ "auto_start": false,
721
+ "nodes": [
722
+ {
723
+ "type": "extension",
724
+ "extension_group": "rtc",
725
+ "addon": "agora_rtc",
726
+ "name": "agora_rtc",
727
+ "property": {
728
+ "app_id": "${env:AGORA_APP_ID}",
729
+ "token": "",
730
+ "channel": "ten_agent_test",
731
+ "stream_id": 1234,
732
+ "remote_stream_id": 123,
733
+ "subscribe_audio": true,
734
+ "publish_audio": true,
735
+ "publish_data": true
736
+ }
737
+ },
738
+ {
739
+ "type": "extension",
740
+ "extension_group": "agora_sess_ctrl",
741
+ "addon": "agora_sess_ctrl",
742
+ "name": "agora_sess_ctrl",
743
+ "property": {
744
+ "wait_for_eos": true
745
+ }
746
+ },
747
+ {
748
+ "type": "extension",
749
+ "extension_group": "llm",
750
+ "addon": "minimax_v2v_python",
751
+ "name": "minimax_v2v_python",
752
+ "property": {
753
+ "in_sample_rate": 16000,
754
+ "token": "${env:MINIMAX_TOKEN}"
755
+ }
756
+ },
757
+ {
758
+ "type": "extension",
759
+ "extension_group": "message_collector",
760
+ "addon": "message_collector",
761
+ "name": "message_collector"
762
+ }
763
+ ],
764
+ "connections": [
765
+ {
766
+ "extension": "agora_rtc",
767
+ "audio_frame": [
768
+ {
769
+ "name": "pcm_frame",
770
+ "dest": [
771
+ {
772
+ "extension": "agora_sess_ctrl"
773
+ }
774
+ ]
775
+ }
776
+ ]
777
+ },
778
+ {
779
+ "extension": "agora_sess_ctrl",
780
+ "audio_frame": [
781
+ {
782
+ "name": "pcm_frame",
783
+ "dest": [
784
+ {
785
+ "extension": "minimax_v2v_python"
786
+ }
787
+ ]
788
+ }
789
+ ],
790
+ "cmd": [
791
+ {
792
+ "name": "start_of_sentence",
793
+ "dest": [
794
+ {
795
+ "extension": "minimax_v2v_python",
796
+ "msg_conversion": {
797
+ "type": "per_property",
798
+ "keep_original": true,
799
+ "rules": [
800
+ {
801
+ "path": "_ten.name",
802
+ "conversion_mode": "fixed_value",
803
+ "value": "flush"
804
+ }
805
+ ]
806
+ }
807
+ }
808
+ ]
809
+ }
810
+ ]
811
+ },
812
+ {
813
+ "extension": "minimax_v2v_python",
814
+ "data": [
815
+ {
816
+ "name": "text_data",
817
+ "dest": [
818
+ {
819
+ "extension": "message_collector"
820
+ }
821
+ ]
822
+ }
823
+ ],
824
+ "audio_frame": [
825
+ {
826
+ "name": "pcm_frame",
827
+ "dest": [
828
+ {
829
+ "extension": "agora_rtc"
830
+ }
831
+ ]
832
+ }
833
+ ],
834
+ "cmd": [
835
+ {
836
+ "name": "flush",
837
+ "dest": [
838
+ {
839
+ "extension": "agora_rtc"
840
+ }
841
+ ]
842
+ }
843
+ ]
844
+ },
845
+ {
846
+ "extension": "message_collector",
847
+ "data": [
848
+ {
849
+ "name": "data",
850
+ "dest": [
851
+ {
852
+ "extension": "agora_rtc"
853
+ }
854
+ ]
855
+ }
856
+ ]
857
+ }
858
+ ]
859
+ }
860
+ ]
861
+ }
862
+ }
agents/go.mod ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ module app
2
+
3
+ go 1.20
4
+
5
+ replace ten_framework => ./ten_packages/system/ten_runtime_go/interface
6
+
7
+ require ten_framework v0.0.0-00010101000000-000000000000
agents/go.sum ADDED
File without changes
agents/main.go ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ *
3
+ * Agora Real Time Engagement
4
+ * Created by Wei Hu in 2022-10.
5
+ * Copyright (c) 2024 Agora IO. All rights reserved.
6
+ *
7
+ */
8
+ package main
9
+
10
+ import (
11
+ "flag"
12
+ "log"
13
+ "os"
14
+
15
+ "ten_framework/ten"
16
+ )
17
+
18
+ type appConfig struct {
19
+ PropertyFilePath string
20
+ }
21
+
22
+ type defaultApp struct {
23
+ ten.DefaultApp
24
+
25
+ cfg *appConfig
26
+ }
27
+
28
+ func (p *defaultApp) OnConfigure(
29
+ tenEnv ten.TenEnv,
30
+ ) {
31
+ // Using the default property.json if not specified.
32
+ if len(p.cfg.PropertyFilePath) > 0 {
33
+ if b, err := os.ReadFile(p.cfg.PropertyFilePath); err != nil {
34
+ log.Fatalf("Failed to read property file %s, err %v\n", p.cfg.PropertyFilePath, err)
35
+ } else {
36
+ tenEnv.InitPropertyFromJSONBytes(b)
37
+ }
38
+ }
39
+
40
+ tenEnv.OnConfigureDone()
41
+ }
42
+
43
+ func startAppBlocking(cfg *appConfig) {
44
+ appInstance, err := ten.NewApp(&defaultApp{
45
+ cfg: cfg,
46
+ })
47
+ if err != nil {
48
+ log.Fatalf("Failed to create the app, %v\n", err)
49
+ }
50
+
51
+ appInstance.Run(true)
52
+ appInstance.Wait()
53
+
54
+ ten.EnsureCleanupWhenProcessExit()
55
+ }
56
+
57
+ func setDefaultLog() {
58
+ log.SetFlags(log.LstdFlags | log.Lmicroseconds)
59
+ }
60
+
61
+ func main() {
62
+ // Set the default log format globally, users can use `log.Println()` directly.
63
+ setDefaultLog()
64
+
65
+ cfg := &appConfig{}
66
+
67
+ flag.StringVar(&cfg.PropertyFilePath, "property", "", "The absolute path of property.json")
68
+ flag.Parse()
69
+
70
+ startAppBlocking(cfg)
71
+ }
agents/scripts/.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ graph
2
+ graph.pdf
3
+ graph.png
4
+
agents/scripts/BUILD.gn ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ #
3
+ # Agora Real Time Engagement
4
+ # Created by Wei Hu in 2022-11.
5
+ # Copyright (c) 2024 Agora IO. All rights reserved.
6
+ #
7
+ #
8
+ import("//build/feature/ten_package.gni")
9
+
10
+ ten_package("default_app_go") {
11
+ package_kind = "app"
12
+ enable_build = false
13
+
14
+ resources = [
15
+ "manifest.json",
16
+ "property.json",
17
+ ]
18
+ }
agents/scripts/dot.py ADDED
@@ -0,0 +1,117 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Generate a graph from a JSON file
2
+ # Currently it only generate the first graph but it's easy to make it generate all graphs
3
+ # Author: Seven Du <[email protected]>
4
+ # usage:
5
+ # pip install graphviz
6
+ # python dot.py
7
+
8
+ import json
9
+ import graphviz
10
+
11
+ COLORS = {
12
+ "flush": "#999",
13
+ "cmd": "#0f0",
14
+ "data": "#00f",
15
+ "text_data": "#f00",
16
+ "pcm_frame": "purple",
17
+ }
18
+
19
+ connection_types = ["data", "cmd", "audio_frame", "video_frame"]
20
+
21
+
22
+ def color(port):
23
+ if port in COLORS:
24
+ return COLORS[port]
25
+ return "#000"
26
+
27
+
28
+ def find_node(nodes, name):
29
+ for node in nodes:
30
+ if node["name"] == name:
31
+ return node
32
+ return None
33
+
34
+
35
+ def create_graph(json_data):
36
+ # Initialize a directed graph
37
+ graph = graphviz.Digraph("G", filename="graph.gv")
38
+ graph.graph_attr["rankdir"] = "LR"
39
+ graph.graph_attr["dpi"] = "150"
40
+ graph.graph_attr["splines"] = "true"
41
+ graph.attr("node", shape="none")
42
+
43
+ # Add nodes to the graph
44
+ nodes = json_data["_ten"]["predefined_graphs"][0]["nodes"]
45
+ connections = json_data["_ten"]["predefined_graphs"][0]["connections"]
46
+ for node in nodes:
47
+ node["i_ports"] = ["flush"]
48
+ node["o_ports"] = ["flush"]
49
+ for node in nodes:
50
+ if node["type"] != "extension":
51
+ continue
52
+ for connection in connections:
53
+ if connection["extension"] == node["name"]:
54
+ for connection_type in connection_types:
55
+ if connection_type in connection:
56
+ data = connection[connection_type]
57
+ for item in data:
58
+ node["o_ports"].append(item["name"])
59
+ for dest in item["dest"]:
60
+ dest_node = find_node(nodes, dest["extension"])
61
+ if dest_node:
62
+ dest_node["i_ports"].append(item["name"])
63
+ for node in nodes:
64
+ if node["type"] != "extension":
65
+ continue
66
+ node["i_ports"] = set(node["i_ports"])
67
+ node["o_ports"] = set(node["o_ports"])
68
+ print("====iports: ", node["name"], node["i_ports"])
69
+ print("====oports: ", node["name"], node["o_ports"])
70
+ iports = ""
71
+ for port in node["i_ports"]:
72
+ iports += f'<tr><td align="left" port="i_{port}">⊙ {port}</td></tr>'
73
+ oports = ""
74
+ for port in node["o_ports"]:
75
+ oports += f'<tr><td align="right" port="o_{port}">{port} ⊙</td></tr>'
76
+
77
+ # Use HTML-like label for nodes
78
+ label = f"""<
79
+ <table border="0" cellborder="1" cellspacing="0">
80
+ <tr><td colspan="2" bgcolor="#ddd"><b>{node["name"]}</b></td></tr>
81
+ <tr><td colspan="2">properties</td></tr>
82
+ <tr><td colspan="2">extensionGroup<br/>{node["extension_group"]}</td></tr>
83
+ <tr><td>
84
+ <table border="0" cellspacing="0">{iports}</table>
85
+ </td>
86
+ <td>
87
+ <table border="0" cellspacing="0">{oports}</table>
88
+ </td>
89
+ </tr>
90
+ </table>>"""
91
+ graph.node(node["name"], label)
92
+
93
+ # Add edges to the graph
94
+ for connection in connections:
95
+ for connection_type in connection_types:
96
+ if connection_type in connection:
97
+ for data in connection[connection_type]:
98
+ for dest in data["dest"]:
99
+ graph.edge(
100
+ f'{connection["extension"]}:o_{data["name"]}',
101
+ f'{dest["extension"]}:i_{data["name"]}',
102
+ color=color(data["name"]),
103
+ label=connection_type,
104
+ )
105
+
106
+ # Save the graph to a file
107
+ print(graph.source)
108
+ graph.render("graph", format="png")
109
+ graph.view()
110
+
111
+
112
+ # Load the JSON data
113
+ with open("../property.json") as f:
114
+ data = json.load(f)
115
+
116
+ # Create the graph
117
+ create_graph(data)
agents/scripts/install_deps_and_build.sh ADDED
@@ -0,0 +1,145 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ # mac, linux
4
+ OS="linux"
5
+
6
+ # x64, arm64
7
+ CPU="x64"
8
+
9
+ # debug, release
10
+ BUILD_TYPE="release"
11
+
12
+ PIP_INSTALL_CMD=${PIP_INSTALL_CMD:-"uv pip install --system"}
13
+
14
+ build_cxx_extensions() {
15
+ local app_dir=$1
16
+
17
+ if [[ ! -f $app_dir/scripts/BUILD.gn ]]; then
18
+ echo "FATAL: the scripts/BUILD.gn is required to build cxx extensions."
19
+ exit 1
20
+ fi
21
+
22
+ cp $app_dir/scripts/BUILD.gn $app_dir
23
+
24
+ tgn gen $OS $CPU $BUILD_TYPE -- is_clang=false enable_sanitizer=false
25
+ tgn build $OS $CPU $BUILD_TYPE
26
+
27
+ local ret=$?
28
+
29
+ cd $app_dir
30
+
31
+ if [[ $ret -ne 0 ]]; then
32
+ echo "FATAL: failed to build cxx extensions, see logs for detail."
33
+ exit 1
34
+ fi
35
+
36
+ # Copy the output of ten_packages to the ten_packages/extension/xx/lib.
37
+ local out="out/$OS/$CPU"
38
+ for extension in $out/ten_packages/extension/*; do
39
+ local extension_name=$(basename $extension)
40
+ if [[ $extension_name == "*" ]]; then
41
+ echo "No cxx extension, nothing to copy."
42
+ break
43
+ fi
44
+ if [[ ! -d $extension/lib ]]; then
45
+ echo "No output for extension $extension_name."
46
+ continue
47
+ fi
48
+
49
+ mkdir -p $app_dir/ten_packages/extension/$extension_name/lib
50
+ cp -r $extension/lib/* $app_dir/ten_packages/extension/$extension_name/lib
51
+ done
52
+ }
53
+
54
+ install_python_requirements() {
55
+ local app_dir=$1
56
+
57
+ if [[ -f "requirements.txt" ]]; then
58
+ ${PIP_INSTALL_CMD} install -r requirements.txt
59
+ fi
60
+
61
+ # traverse the ten_packages/extension directory to find the requirements.txt
62
+ if [[ -d "ten_packages/extension" ]]; then
63
+ for extension in ten_packages/extension/*; do
64
+ if [[ -f "$extension/requirements.txt" ]]; then
65
+ ${PIP_INSTALL_CMD} -r $extension/requirements.txt
66
+ fi
67
+ done
68
+ fi
69
+
70
+ # traverse the ten_packages/system directory to find the requirements.txt
71
+ if [[ -d "ten_packages/system" ]]; then
72
+ for extension in ten_packages/system/*; do
73
+ if [[ -f "$extension/requirements.txt" ]]; then
74
+ ${PIP_INSTALL_CMD} -r $extension/requirements.txt
75
+ fi
76
+ done
77
+ fi
78
+
79
+ # pre-import llama-index as it cloud download additional resources during the first import
80
+ echo "pre-import python modules..."
81
+ python3.10 -c "import llama_index.core;"
82
+ }
83
+
84
+ build_go_app() {
85
+ local app_dir=$1
86
+ cd $app_dir
87
+
88
+ go run ten_packages/system/ten_runtime_go/tools/build/main.go --verbose
89
+ if [[ $? -ne 0 ]]; then
90
+ echo "FATAL: failed to build go app, see logs for detail."
91
+ exit 1
92
+ fi
93
+ }
94
+
95
+ clean() {
96
+ local app_dir=$1
97
+ rm -rf BUILD.gn out
98
+ }
99
+
100
+ main() {
101
+ APP_HOME=$(
102
+ cd $(dirname $0)/..
103
+ pwd
104
+ )
105
+
106
+ if [[ $1 == "-clean" ]]; then
107
+ clean $APP_HOME
108
+ exit 0
109
+ fi
110
+
111
+ if [[ $# -ne 2 ]]; then
112
+ echo "Usage: $0 <os> <cpu>"
113
+ exit 1
114
+ fi
115
+
116
+ OS=$1
117
+ CPU=$2
118
+
119
+ echo -e "#include <stdio.h>\n#include <immintrin.h>\nint main() { __m256 a = _mm256_setzero_ps(); return 0; }" > /tmp/test.c
120
+ if gcc -mavx2 /tmp/test.c -o /tmp/test && ! /tmp/test; then
121
+ echo "FATAL: unsupported platform."
122
+ echo " Please UNCHECK the 'Use Rosetta for x86_64/amd64 emulation on Apple Silicon' Docker Desktop setting if you're running on mac."
123
+
124
+ exit 1
125
+ fi
126
+
127
+ if [[ ! -f $APP_HOME/manifest.json ]]; then
128
+ echo "FATAL: manifest.json is required."
129
+ exit 1
130
+ fi
131
+
132
+ # Install all dependencies specified in manifest.json.
133
+ echo "install dependencies..."
134
+ tman install
135
+
136
+ # build extensions and app
137
+ echo "build_cxx_extensions..."
138
+ build_cxx_extensions $APP_HOME
139
+ echo "build_go_app..."
140
+ build_go_app $APP_HOME
141
+ echo "install_python_requirements..."
142
+ install_python_requirements $APP_HOME
143
+ }
144
+
145
+ main "$@"
agents/scripts/package.sh ADDED
@@ -0,0 +1,68 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env bash
2
+
3
+ APP_HOME=$(
4
+ cd $(dirname $0)/..
5
+ pwd
6
+ )
7
+
8
+ cd $APP_HOME
9
+
10
+ rm -rf .release
11
+ mkdir .release
12
+
13
+ copy_package() {
14
+ local package_type=$1
15
+ local package_name=$2
16
+ mkdir -p .release/ten_packages/${package_type}/${package_name}
17
+
18
+ if [[ -d ten_packages/${package_type}/${package_name}/lib ]]; then
19
+ cp -r ten_packages/${package_type}/${package_name}/lib .release/ten_packages/${package_type}/${package_name}/
20
+ fi
21
+
22
+ if [[ -d ten_packages/${package_type}/${package_name}/interface ]]; then
23
+ cp -r ten_packages/${package_type}/${package_name}/interface .release/ten_packages/${package_type}/${package_name}/
24
+ fi
25
+
26
+ if [[ -f ten_packages/${package_type}/${package_name}/manifest.json ]]; then
27
+ cp ten_packages/${package_type}/${package_name}/manifest.json .release/ten_packages/${package_type}/${package_name}/
28
+ fi
29
+
30
+ if [[ -f ten_packages/${package_type}/${package_name}/property.json ]]; then
31
+ cp ten_packages/${package_type}/${package_name}/property.json .release/ten_packages/${package_type}/${package_name}/
32
+ fi
33
+
34
+ # package .py for python extensions
35
+ # TODO: package 'publish' contents only
36
+ cp ten_packages/${package_type}/${package_name}/*.py .release/ten_packages/${package_type}/${package_name}/ | true
37
+ if [[ -f ten_packages/${package_type}/${package_name}/requirements.txt ]]; then
38
+ cp ten_packages/${package_type}/${package_name}/requirements.txt .release/ten_packages/${package_type}/${package_name}/
39
+ fi
40
+
41
+ # TODO: copy specific contents
42
+ if [[ -d ten_packages/${package_type}/${package_name}/pb ]]; then
43
+ cp -r ten_packages/${package_type}/${package_name}/pb .release/ten_packages/${package_type}/${package_name}/
44
+ fi
45
+ if [[ -d ten_packages/${package_type}/${package_name}/src ]]; then
46
+ cp -r ten_packages/${package_type}/${package_name}/src .release/ten_packages/${package_type}/${package_name}/
47
+ fi
48
+ if [[ -d ten_packages/${package_type}/${package_name}/realtime ]]; then
49
+ cp -r ten_packages/${package_type}/${package_name}/realtime .release/ten_packages/${package_type}/${package_name}/
50
+ fi
51
+ }
52
+
53
+ cp -r bin .release
54
+ cp manifest.json .release
55
+ cp property.json .release
56
+
57
+ # copy packages
58
+ mkdir -p .release/ten_packages
59
+ for package_type in system extension_group extension addon_loader; do
60
+ for package_path in ten_packages/${package_type}/*; do
61
+ package_name=$(basename ${package_path})
62
+ copy_package ${package_type} ${package_name}
63
+ done
64
+ done
65
+
66
+ if [[ -f session_control.conf ]]; then
67
+ cp -r session_control.conf .release/
68
+ fi
agents/scripts/pylint.sh ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ #!/bin/bash
2
+
3
+
4
+ pylint ./agents/ten_packages/extension/. || pylint-exit --warn-fail --error-fail $?
agents/session_control.conf ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ {
2
+ }
agents/ten_packages/bak/litellm_python/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from . import litellm_addon
2
+ from .extension import EXTENSION_NAME
3
+ from .log import logger
4
+
5
+
6
+ logger.info(f"{EXTENSION_NAME} extension loaded")
agents/ten_packages/bak/litellm_python/extension.py ADDED
@@ -0,0 +1 @@
 
 
1
+ EXTENSION_NAME = "litellm_python"
agents/ten_packages/bak/litellm_python/litellm.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import litellm
2
+ import random
3
+ from typing import Dict, List, Optional
4
+
5
+
6
+ class LiteLLMConfig:
7
+ def __init__(self,
8
+ api_key: str,
9
+ base_url: str,
10
+ frequency_penalty: float,
11
+ max_tokens: int,
12
+ model: str,
13
+ presence_penalty: float,
14
+ prompt: str,
15
+ provider: str,
16
+ temperature: float,
17
+ top_p: float,
18
+ seed: Optional[int] = None,):
19
+ self.api_key = api_key
20
+ self.base_url = base_url
21
+ self.frequency_penalty = frequency_penalty
22
+ self.max_tokens = max_tokens
23
+ self.model = model
24
+ self.presence_penalty = presence_penalty
25
+ self.prompt = prompt
26
+ self.provider = provider
27
+ self.seed = seed if seed is not None else random.randint(0, 10000)
28
+ self.temperature = temperature
29
+ self.top_p = top_p
30
+
31
+ @classmethod
32
+ def default_config(cls):
33
+ return cls(
34
+ api_key="",
35
+ base_url="",
36
+ max_tokens=512,
37
+ model="gpt-4o-mini",
38
+ frequency_penalty=0.9,
39
+ presence_penalty=0.9,
40
+ prompt="You are a voice assistant who talks in a conversational way and can chat with me like my friends. I will speak to you in English or Chinese, and you will answer in the corrected and improved version of my text with the language I use. Don’t talk like a robot, instead I would like you to talk like a real human with emotions. I will use your answer for text-to-speech, so don’t return me any meaningless characters. I want you to be helpful, when I’m asking you for advice, give me precise, practical and useful advice instead of being vague. When giving me a list of options, express the options in a narrative way instead of bullet points.",
41
+ provider="",
42
+ seed=random.randint(0, 10000),
43
+ temperature=0.1,
44
+ top_p=1.0
45
+ )
46
+
47
+
48
+ class LiteLLM:
49
+ def __init__(self, config: LiteLLMConfig):
50
+ self.config = config
51
+
52
+ def get_chat_completions_stream(self, messages: List[Dict[str, str]]):
53
+ kwargs = {
54
+ "api_key": self.config.api_key,
55
+ "base_url": self.config.base_url,
56
+ "custom_llm_provider": self.config.provider,
57
+ "frequency_penalty": self.config.frequency_penalty,
58
+ "max_tokens": self.config.max_tokens,
59
+ "messages": [
60
+ {
61
+ "role": "system",
62
+ "content": self.config.prompt,
63
+ },
64
+ *messages,
65
+ ],
66
+ "model": self.config.model,
67
+ "presence_penalty": self.config.presence_penalty,
68
+ "seed": self.config.seed,
69
+ "stream": True,
70
+ "temperature": self.config.temperature,
71
+ "top_p": self.config.top_p,
72
+ }
73
+
74
+ try:
75
+ response = litellm.completion(**kwargs)
76
+
77
+ return response
78
+ except Exception as e:
79
+ raise Exception(f"get_chat_completions_stream failed, err: {e}")
agents/ten_packages/bak/litellm_python/litellm_addon.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ #
3
+ # Agora Real Time Engagement
4
+ # Created by XinHui Li in 2024.
5
+ # Copyright (c) 2024 Agora IO. All rights reserved.
6
+ #
7
+ #
8
+ from ten import (
9
+ Addon,
10
+ register_addon_as_extension,
11
+ TenEnv,
12
+ )
13
+ from .extension import EXTENSION_NAME
14
+ from .log import logger
15
+ from .litellm_extension import LiteLLMExtension
16
+
17
+
18
+ @register_addon_as_extension(EXTENSION_NAME)
19
+ class LiteLLMExtensionAddon(Addon):
20
+ def on_create_instance(self, ten: TenEnv, addon_name: str, context) -> None:
21
+ logger.info("on_create_instance")
22
+
23
+ ten.on_create_instance_done(LiteLLMExtension(addon_name), context)
agents/ten_packages/bak/litellm_python/litellm_extension.py ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ #
3
+ # Agora Real Time Engagement
4
+ # Created by XinHui Li in 2024.
5
+ # Copyright (c) 2024 Agora IO. All rights reserved.
6
+ #
7
+ #
8
+ from threading import Thread
9
+ from ten import (
10
+ Extension,
11
+ TenEnv,
12
+ Cmd,
13
+ Data,
14
+ StatusCode,
15
+ CmdResult,
16
+ )
17
+ from .litellm import LiteLLM, LiteLLMConfig
18
+ from .log import logger
19
+ from .utils import get_micro_ts, parse_sentence
20
+
21
+
22
+ CMD_IN_FLUSH = "flush"
23
+ CMD_OUT_FLUSH = "flush"
24
+ DATA_IN_TEXT_DATA_PROPERTY_TEXT = "text"
25
+ DATA_IN_TEXT_DATA_PROPERTY_IS_FINAL = "is_final"
26
+ DATA_OUT_TEXT_DATA_PROPERTY_TEXT = "text"
27
+ DATA_OUT_TEXT_DATA_PROPERTY_TEXT_END_OF_SEGMENT = "end_of_segment"
28
+
29
+ PROPERTY_API_KEY = "api_key" # Required
30
+ PROPERTY_BASE_URL = "base_url" # Optional
31
+ PROPERTY_FREQUENCY_PENALTY = "frequency_penalty" # Optional
32
+ PROPERTY_GREETING = "greeting" # Optional
33
+ PROPERTY_MAX_MEMORY_LENGTH = "max_memory_length" # Optional
34
+ PROPERTY_MAX_TOKENS = "max_tokens" # Optional
35
+ PROPERTY_MODEL = "model" # Optional
36
+ PROPERTY_PRESENCE_PENALTY = "presence_penalty" # Optional
37
+ PROPERTY_PROMPT = "prompt" # Optional
38
+ PROPERTY_PROVIDER = "provider" # Optional
39
+ PROPERTY_TEMPERATURE = "temperature" # Optional
40
+ PROPERTY_TOP_P = "top_p" # Optional
41
+
42
+
43
+ class LiteLLMExtension(Extension):
44
+ memory = []
45
+ max_memory_length = 10
46
+ outdate_ts = 0
47
+ litellm = None
48
+
49
+ def on_start(self, ten: TenEnv) -> None:
50
+ logger.info("LiteLLMExtension on_start")
51
+ # Prepare configuration
52
+ litellm_config = LiteLLMConfig.default_config()
53
+
54
+ for key in [PROPERTY_API_KEY, PROPERTY_GREETING, PROPERTY_MODEL, PROPERTY_PROMPT]:
55
+ try:
56
+ val = ten.get_property_string(key)
57
+ if val:
58
+ litellm_config.key = val
59
+ except Exception as e:
60
+ logger.warning(f"get_property_string optional {key} failed, err: {e}")
61
+
62
+ for key in [PROPERTY_FREQUENCY_PENALTY, PROPERTY_PRESENCE_PENALTY, PROPERTY_TEMPERATURE, PROPERTY_TOP_P]:
63
+ try:
64
+ litellm_config.key = float(ten.get_property_float(key))
65
+ except Exception as e:
66
+ logger.warning(f"get_property_float optional {key} failed, err: {e}")
67
+
68
+ for key in [PROPERTY_MAX_MEMORY_LENGTH, PROPERTY_MAX_TOKENS]:
69
+ try:
70
+ litellm_config.key = int(ten.get_property_int(key))
71
+ except Exception as e:
72
+ logger.warning(f"get_property_int optional {key} failed, err: {e}")
73
+
74
+ # Create LiteLLM instance
75
+ self.litellm = LiteLLM(litellm_config)
76
+ logger.info(f"newLiteLLM succeed with max_tokens: {litellm_config.max_tokens}, model: {litellm_config.model}")
77
+
78
+ # Send greeting if available
79
+ greeting = ten.get_property_string(PROPERTY_GREETING)
80
+ if greeting:
81
+ try:
82
+ output_data = Data.create("text_data")
83
+ output_data.set_property_string(DATA_OUT_TEXT_DATA_PROPERTY_TEXT, greeting)
84
+ output_data.set_property_bool(DATA_OUT_TEXT_DATA_PROPERTY_TEXT_END_OF_SEGMENT, True)
85
+ ten.send_data(output_data)
86
+ logger.info(f"greeting [{greeting}] sent")
87
+ except Exception as e:
88
+ logger.error(f"greeting [{greeting}] send failed, err: {e}")
89
+
90
+ ten.on_start_done()
91
+
92
+ def on_stop(self, ten: TenEnv) -> None:
93
+ logger.info("LiteLLMExtension on_stop")
94
+ ten.on_stop_done()
95
+
96
+ def on_cmd(self, ten: TenEnv, cmd: Cmd) -> None:
97
+ logger.info("LiteLLMExtension on_cmd")
98
+ cmd_json = cmd.to_json()
99
+ logger.info(f"LiteLLMExtension on_cmd json: {cmd_json}")
100
+
101
+ cmd_name = cmd.get_name()
102
+
103
+ if cmd_name == CMD_IN_FLUSH:
104
+ self.outdate_ts = get_micro_ts()
105
+ cmd_out = Cmd.create(CMD_OUT_FLUSH)
106
+ ten.send_cmd(cmd_out, None)
107
+ logger.info(f"LiteLLMExtension on_cmd sent flush")
108
+ else:
109
+ logger.info(f"LiteLLMExtension on_cmd unknown cmd: {cmd_name}")
110
+ cmd_result = CmdResult.create(StatusCode.ERROR)
111
+ cmd_result.set_property_string("detail", "unknown cmd")
112
+ ten.return_result(cmd_result, cmd)
113
+ return
114
+
115
+ cmd_result = CmdResult.create(StatusCode.OK)
116
+ cmd_result.set_property_string("detail", "success")
117
+ ten.return_result(cmd_result, cmd)
118
+
119
+ def on_data(self, ten: TenEnv, data: Data) -> None:
120
+ """
121
+ on_data receives data from ten graph.
122
+ current suppotend data:
123
+ - name: text_data
124
+ example:
125
+ {name: text_data, properties: {text: "hello"}
126
+ """
127
+ logger.info(f"LiteLLMExtension on_data")
128
+
129
+ # Assume 'data' is an object from which we can get properties
130
+ try:
131
+ is_final = data.get_property_bool(DATA_IN_TEXT_DATA_PROPERTY_IS_FINAL)
132
+ if not is_final:
133
+ logger.info("ignore non-final input")
134
+ return
135
+ except Exception as e:
136
+ logger.error(f"on_data get_property_bool {DATA_IN_TEXT_DATA_PROPERTY_IS_FINAL} failed, err: {e}")
137
+ return
138
+
139
+ # Get input text
140
+ try:
141
+ input_text = data.get_property_string(DATA_IN_TEXT_DATA_PROPERTY_TEXT)
142
+ if not input_text:
143
+ logger.info("ignore empty text")
144
+ return
145
+ logger.info(f"on_data input text: [{input_text}]")
146
+ except Exception as e:
147
+ logger.error(f"on_data get_property_string {DATA_IN_TEXT_DATA_PROPERTY_TEXT} failed, err: {e}")
148
+ return
149
+
150
+ # Prepare memory
151
+ if len(self.memory) > self.max_memory_length:
152
+ self.memory.pop(0)
153
+ self.memory.append({"role": "user", "content": input_text})
154
+
155
+ def chat_completions_stream_worker(start_time, input_text, memory):
156
+ try:
157
+ logger.info(f"chat_completions_stream_worker for input text: [{input_text}] memory: {memory}")
158
+
159
+ # Get result from AI
160
+ resp = self.litellm.get_chat_completions_stream(memory)
161
+ if resp is None:
162
+ logger.info(f"chat_completions_stream_worker for input text: [{input_text}] failed")
163
+ return
164
+
165
+ sentence = ""
166
+ full_content = ""
167
+ first_sentence_sent = False
168
+
169
+ for chat_completions in resp:
170
+ if start_time < self.outdate_ts:
171
+ logger.info(f"chat_completions_stream_worker recv interrupt and flushing for input text: [{input_text}], startTs: {start_time}, outdateTs: {self.outdate_ts}")
172
+ break
173
+
174
+ if (len(chat_completions.choices) > 0 and chat_completions.choices[0].delta.content is not None):
175
+ content = chat_completions.choices[0].delta.content
176
+ else:
177
+ content = ""
178
+
179
+ full_content += content
180
+
181
+ while True:
182
+ sentence, content, sentence_is_final = parse_sentence(sentence, content)
183
+
184
+ if len(sentence) == 0 or not sentence_is_final:
185
+ logger.info(f"sentence {sentence} is empty or not final")
186
+ break
187
+
188
+ logger.info(f"chat_completions_stream_worker recv for input text: [{input_text}] got sentence: [{sentence}]")
189
+
190
+ # send sentence
191
+ try:
192
+ output_data = Data.create("text_data")
193
+ output_data.set_property_string(DATA_OUT_TEXT_DATA_PROPERTY_TEXT, sentence)
194
+ output_data.set_property_bool(DATA_OUT_TEXT_DATA_PROPERTY_TEXT_END_OF_SEGMENT, False)
195
+ ten.send_data(output_data)
196
+ logger.info(f"chat_completions_stream_worker recv for input text: [{input_text}] sent sentence [{sentence}]")
197
+ except Exception as e:
198
+ logger.error(f"chat_completions_stream_worker recv for input text: [{input_text}] send sentence [{sentence}] failed, err: {e}")
199
+ break
200
+
201
+ sentence = ""
202
+ if not first_sentence_sent:
203
+ first_sentence_sent = True
204
+ logger.info(f"chat_completions_stream_worker recv for input text: [{input_text}] first sentence sent, first_sentence_latency {get_micro_ts() - start_time}ms")
205
+
206
+ # remember response as assistant content in memory
207
+ memory.append({"role": "assistant", "content": full_content})
208
+
209
+ # send end of segment
210
+ try:
211
+ output_data = Data.create("text_data")
212
+ output_data.set_property_string(DATA_OUT_TEXT_DATA_PROPERTY_TEXT, sentence)
213
+ output_data.set_property_bool(DATA_OUT_TEXT_DATA_PROPERTY_TEXT_END_OF_SEGMENT, True)
214
+ ten.send_data(output_data)
215
+ logger.info(f"chat_completions_stream_worker for input text: [{input_text}] end of segment with sentence [{sentence}] sent")
216
+ except Exception as e:
217
+ logger.error(f"chat_completions_stream_worker for input text: [{input_text}] end of segment with sentence [{sentence}] send failed, err: {e}")
218
+
219
+ except Exception as e:
220
+ logger.error(f"chat_completions_stream_worker for input text: [{input_text}] failed, err: {e}")
221
+
222
+ # Start thread to request and read responses from LiteLLM
223
+ start_time = get_micro_ts()
224
+ thread = Thread(
225
+ target=chat_completions_stream_worker,
226
+ args=(start_time, input_text, self.memory),
227
+ )
228
+ thread.start()
229
+ logger.info(f"LiteLLMExtension on_data end")
agents/ten_packages/bak/litellm_python/log.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ from .extension import EXTENSION_NAME
3
+
4
+ logger = logging.getLogger(EXTENSION_NAME)
5
+ logger.setLevel(logging.INFO)
6
+
7
+ formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(process)d - [%(filename)s:%(lineno)d] - %(message)s")
8
+
9
+ console_handler = logging.StreamHandler()
10
+ console_handler.setFormatter(formatter)
11
+
12
+ logger.addHandler(console_handler)
agents/ten_packages/bak/litellm_python/manifest.json ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "extension",
3
+ "name": "litellm_python",
4
+ "version": "0.1.0",
5
+ "dependencies": [
6
+ {
7
+ "type": "system",
8
+ "name": "ten_runtime_python",
9
+ "version": "0.8"
10
+ }
11
+ ],
12
+ "api": {
13
+ "property": {
14
+ "api_key": {
15
+ "type": "string"
16
+ },
17
+ "base_url": {
18
+ "type": "string"
19
+ },
20
+ "frequency_penalty": {
21
+ "type": "float64"
22
+ },
23
+ "greeting": {
24
+ "type": "string"
25
+ },
26
+ "max_memory_length": {
27
+ "type": "int64"
28
+ },
29
+ "max_tokens": {
30
+ "type": "int64"
31
+ },
32
+ "model": {
33
+ "type": "string"
34
+ },
35
+ "presence_penalty": {
36
+ "type": "float64"
37
+ },
38
+ "prompt": {
39
+ "type": "string"
40
+ },
41
+ "provider": {
42
+ "type": "string"
43
+ },
44
+ "temperature": {
45
+ "type": "float64"
46
+ },
47
+ "top_p": {
48
+ "type": "float64"
49
+ }
50
+ },
51
+ "data_in": [
52
+ {
53
+ "name": "text_data",
54
+ "property": {
55
+ "text": {
56
+ "type": "string"
57
+ }
58
+ }
59
+ }
60
+ ],
61
+ "data_out": [
62
+ {
63
+ "name": "text_data",
64
+ "property": {
65
+ "text": {
66
+ "type": "string"
67
+ }
68
+ }
69
+ }
70
+ ],
71
+ "cmd_in": [
72
+ {
73
+ "name": "flush"
74
+ }
75
+ ],
76
+ "cmd_out": [
77
+ {
78
+ "name": "flush"
79
+ }
80
+ ]
81
+ }
82
+ }
agents/ten_packages/bak/litellm_python/requirements.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ litellm==1.42.12
agents/ten_packages/bak/litellm_python/utils.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import time
2
+
3
+
4
+ def get_micro_ts():
5
+ return int(time.time() * 1_000_000)
6
+
7
+
8
+ def is_punctuation(char: str):
9
+ return char in [",", ",", ".", "。", "?", "?", "!", "!"]
10
+
11
+
12
+ def parse_sentence(sentence: str, content: str):
13
+ for i, char in enumerate(content):
14
+ sentence += char
15
+
16
+ if is_punctuation(char):
17
+ return sentence, content[i + 1:], True
18
+
19
+ return sentence, "", False
agents/ten_packages/extension/agora_rtm_wrapper/extension.go ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ *
3
+ * Agora Real Time Engagement
4
+ * Created by Wei Hu in 2022-10.
5
+ * Copyright (c) 2024 Agora IO. All rights reserved.
6
+ *
7
+ */
8
+ // Note that this is just an example extension written in the GO programming
9
+ // language, so the package name does not equal to the containing directory
10
+ // name. However, it is not common in Go.
11
+ package extension
12
+
13
+ import (
14
+ "encoding/json"
15
+ "fmt"
16
+ "strconv"
17
+
18
+ "ten_framework/ten"
19
+ )
20
+
21
+ // Message colllector represents the text output result
22
+ // @Description 输出结果
23
+ type ColllectorMessage struct {
24
+ Text string `json:"text"` // 识别出的文本
25
+ IsFinal bool `json:"is_final"` // 是否为最终结果
26
+ StreamID int32 `json:"stream_id"` // 流ID
27
+ Type string `json:"data_type"` // 数据类型
28
+ Ts uint64 `json:"text_ts"` // 时间戳
29
+ }
30
+
31
+ // Message represents the text output result
32
+ // @Description 输出结果
33
+ type Message struct {
34
+ Text string `json:"text"` // 识别出的文本
35
+ IsFinal bool `json:"is_final"` // 是否为最终结果
36
+ StreamID string `json:"stream_id"` // 流ID
37
+ Type string `json:"type"` // 数据类型
38
+ Ts uint64 `json:"ts"` // 时间戳
39
+ }
40
+
41
+ // RtcUserSate represents the rtc user state
42
+ // @Description RTC用户状态
43
+ type RtcUserSate struct {
44
+ RemoteUserID string `json:"remote_user_id"` // 远程用户ID
45
+ State string `json:"state"` // 状态
46
+ Reason string `json:"reason"` // 原因
47
+ }
48
+
49
+ type agoraRtmWrapperExtension struct {
50
+ ten.DefaultExtension
51
+ }
52
+
53
+ func newExtension(name string) ten.Extension {
54
+ return &agoraRtmWrapperExtension{}
55
+ }
56
+
57
+ // OnData receives data from ten graph.
58
+ func (p *agoraRtmWrapperExtension) OnData(
59
+ tenEnv ten.TenEnv,
60
+ data ten.Data,
61
+ ) {
62
+ buf, err := data.GetPropertyBytes("data")
63
+ if err != nil {
64
+ tenEnv.LogError("OnData GetProperty data error: " + err.Error())
65
+ return
66
+ }
67
+ tenEnv.LogInfo("AGORA_RTM_WRAPPER_EXTENSION OnData: " + string(buf))
68
+ colllectorMessage := ColllectorMessage{}
69
+ err = json.Unmarshal(buf, &colllectorMessage)
70
+ if err != nil {
71
+ tenEnv.LogError("OnData Unmarshal data error: " + err.Error())
72
+ return
73
+ }
74
+
75
+ message := Message{
76
+ Text: colllectorMessage.Text,
77
+ IsFinal: colllectorMessage.IsFinal,
78
+ StreamID: strconv.Itoa(int(colllectorMessage.StreamID)),
79
+ Type: colllectorMessage.Type,
80
+ Ts: colllectorMessage.Ts,
81
+ }
82
+ jsonBytes, err := json.Marshal(message)
83
+ if err != nil {
84
+ tenEnv.LogError("failed to marshal JSON: " + err.Error())
85
+ return
86
+ }
87
+ tenEnv.LogInfo("AGORA_RTM_WRAPPER_EXTENSION OnData: " + string(jsonBytes))
88
+
89
+ cmd, _ := ten.NewCmd("publish")
90
+
91
+ err = cmd.SetPropertyBytes("message", jsonBytes)
92
+ if err != nil {
93
+ tenEnv.LogError("failed to set property message: " + err.Error())
94
+ return
95
+ }
96
+ if err := tenEnv.SendCmd(cmd, func(_ ten.TenEnv, result ten.CmdResult, _ error) {
97
+ status, err := result.GetStatusCode()
98
+ tenEnv.LogInfo(fmt.Sprintf("AGORA_RTM_WRAPPER_EXTENSION publish result %d", status))
99
+ if status != ten.StatusCodeOk || err != nil {
100
+ tenEnv.LogError("failed to subscribe")
101
+ }
102
+ }); err != nil {
103
+ tenEnv.LogError("failed to send command " + err.Error())
104
+ }
105
+ }
106
+
107
+ func (p *agoraRtmWrapperExtension) OnCmd(tenEnv ten.TenEnv, cmd ten.Cmd) {
108
+ defer func() {
109
+ if r := recover(); r != nil {
110
+ tenEnv.LogError(fmt.Sprintf("OnCmd panic: %v", r))
111
+ }
112
+ cmdResult, err := ten.NewCmdResult(ten.StatusCodeOk)
113
+ if err != nil {
114
+ tenEnv.LogError(fmt.Sprintf("failed to create cmd result: %v", err))
115
+ return
116
+ }
117
+ tenEnv.ReturnResult(cmdResult, cmd, nil)
118
+ }()
119
+ cmdName, err := cmd.GetName()
120
+ if err != nil {
121
+ tenEnv.LogError(fmt.Sprintf("failed to get cmd name: %v", err))
122
+ return
123
+ }
124
+ tenEnv.LogInfo(fmt.Sprintf("received command: %s", cmdName))
125
+ switch cmdName {
126
+ case "on_user_audio_track_state_changed":
127
+ // on_user_audio_track_state_changed
128
+ p.handleUserStateChanged(tenEnv, cmd)
129
+ default:
130
+ tenEnv.LogWarn(fmt.Sprintf("unsupported cmd: %s", cmdName))
131
+ }
132
+ }
133
+
134
+ func (p *agoraRtmWrapperExtension) handleUserStateChanged(tenEnv ten.TenEnv, cmd ten.Cmd) {
135
+ remoteUserID, err := cmd.GetPropertyString("remote_user_id")
136
+ if err != nil {
137
+ tenEnv.LogError(fmt.Sprintf("failed to get remote_user_id: %v", err))
138
+ return
139
+ }
140
+ state, err := cmd.GetPropertyInt32("state")
141
+ if err != nil {
142
+ tenEnv.LogError(fmt.Sprintf("failed to get state: %v", err))
143
+ return
144
+ }
145
+ reason, err := cmd.GetPropertyInt32("reason")
146
+ if err != nil {
147
+ tenEnv.LogError(fmt.Sprintf("failed to get reason: %v", err))
148
+ return
149
+ }
150
+ userState := RtcUserSate{
151
+ RemoteUserID: remoteUserID,
152
+ State: strconv.Itoa(int(state)),
153
+ Reason: strconv.Itoa(int(reason)),
154
+ }
155
+ jsonBytes, err := json.Marshal(userState)
156
+ if err != nil {
157
+ tenEnv.LogError("failed to marshal JSON: " + err.Error())
158
+ return
159
+ }
160
+ sendCmd, _ := ten.NewCmd("set_presence_state")
161
+ sendCmd.SetPropertyString("states", string(jsonBytes))
162
+ tenEnv.LogInfo("AGORA_RTM_WRAPPER_EXTENSION SetRtmPresenceState " + string(jsonBytes))
163
+ if err := tenEnv.SendCmd(sendCmd, func(_ ten.TenEnv, result ten.CmdResult, _ error) {
164
+ status, err := result.GetStatusCode()
165
+ tenEnv.LogInfo(fmt.Sprintf("AGORA_RTM_WRAPPER_EXTENSION SetRtmPresenceState result %d", status))
166
+ if status != ten.StatusCodeOk || err != nil {
167
+ panic("failed to SetRtmPresenceState")
168
+ }
169
+ }); err != nil {
170
+ tenEnv.LogError("failed to send command " + err.Error())
171
+ }
172
+ }
173
+
174
+ func init() {
175
+ // Register addon
176
+ ten.RegisterAddonAsExtension(
177
+ "agora_rtm_wrapper",
178
+ ten.NewDefaultExtensionAddon(newExtension),
179
+ )
180
+ }
agents/ten_packages/extension/agora_rtm_wrapper/go.mod ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ module agora_rtm_wrapper
2
+
3
+ go 1.20
4
+
5
+ replace ten_framework => ../../system/ten_runtime_go/interface
6
+
7
+ require ten_framework v0.0.0-00010101000000-000000000000
agents/ten_packages/extension/agora_rtm_wrapper/manifest.json ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "extension",
3
+ "name": "agora_rtm_wrapper",
4
+ "version": "0.1.4",
5
+ "dependencies": [
6
+ {
7
+ "type": "system",
8
+ "name": "ten_runtime_go",
9
+ "version": "0.8"
10
+ }
11
+ ],
12
+ "api": {
13
+ "data_in": [
14
+ {
15
+ "name": "data"
16
+ }
17
+ ],
18
+ "cmd_out": [
19
+ {
20
+ "name": "publish",
21
+ "property": {
22
+ "message": {
23
+ "type": "buf"
24
+ }
25
+ }
26
+ },
27
+ {
28
+ "name": "set_presence_state"
29
+ }
30
+ ]
31
+ }
32
+ }
agents/ten_packages/extension/agora_rtm_wrapper/property.json ADDED
@@ -0,0 +1 @@
 
 
1
+ {}
agents/ten_packages/extension/aliyun_analyticdb_vector_storage/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ from . import vector_storage_addon
agents/ten_packages/extension/aliyun_analyticdb_vector_storage/client.py ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ import asyncio
4
+ import threading
5
+ from typing import Coroutine
6
+ from concurrent.futures import Future
7
+
8
+
9
+ from alibabacloud_gpdb20160503.client import Client as gpdb20160503Client
10
+ from alibabacloud_tea_openapi import models as open_api_models
11
+
12
+
13
+ # maybe need multiple clients
14
+ class AliGPDBClient:
15
+ def __init__(self, ten_env, access_key_id, access_key_secret, endpoint):
16
+ self.stopEvent = asyncio.Event()
17
+ self.loop = None
18
+ self.tasks = asyncio.Queue()
19
+ self.access_key_id = access_key_id
20
+ self.access_key_secret = access_key_secret
21
+ self.endpoint = endpoint
22
+ self.client = self.create_client()
23
+ self.thread = threading.Thread(
24
+ target=asyncio.run, args=(self.__thread_routine(),)
25
+ )
26
+ self.thread.start()
27
+ self.ten_env = ten_env
28
+
29
+ async def stop_thread(self):
30
+ self.stopEvent.set()
31
+
32
+ def create_client(self) -> gpdb20160503Client:
33
+ config = open_api_models.Config(
34
+ access_key_id=self.access_key_id,
35
+ access_key_secret=self.access_key_secret,
36
+ endpoint=self.endpoint,
37
+ )
38
+ return gpdb20160503Client(config)
39
+
40
+ def get(self) -> gpdb20160503Client:
41
+ return self.client
42
+
43
+ def close(self):
44
+ if (self.loop is not None) and self.thread.is_alive():
45
+ self.stopEvent.set()
46
+ asyncio.run_coroutine_threadsafe(self.stop_thread(), self.loop)
47
+ self.thread.join()
48
+
49
+ async def __thread_routine(self):
50
+ self.ten_env.log_info("client __thread_routine start")
51
+ self.loop = asyncio.get_running_loop()
52
+ tasks = set()
53
+ while not self.stopEvent.is_set():
54
+ if not self.tasks.empty():
55
+ coro, future = await self.tasks.get()
56
+ try:
57
+ task = asyncio.create_task(coro)
58
+ tasks.add(task)
59
+ task.add_done_callback(lambda t: future.set_result(t.result()))
60
+ except Exception as e:
61
+ future.set_exception(e)
62
+ elif tasks:
63
+ done, tasks = await asyncio.wait(
64
+ tasks, return_when=asyncio.FIRST_COMPLETED
65
+ )
66
+ for task in done:
67
+ if task.exception():
68
+ self.ten_env.log_error(f"task exception: {task.exception()}")
69
+ future.set_exception(task.exception())
70
+ else:
71
+ await asyncio.sleep(0.1)
72
+ self.ten_env.log_info("client __thread_routine end")
73
+
74
+ async def submit_task(self, coro: Coroutine) -> Future:
75
+ future = Future()
76
+ await self.tasks.put((coro, future))
77
+ return future
78
+
79
+ def submit_task_with_new_thread(self, coro: Coroutine) -> Future:
80
+ future = Future()
81
+
82
+ def run_coro_in_new_thread():
83
+ loop = asyncio.new_event_loop()
84
+ asyncio.set_event_loop(loop)
85
+ try:
86
+ result = loop.run_until_complete(coro)
87
+ future.set_result(result)
88
+ except Exception as e:
89
+ future.set_exception(e)
90
+ finally:
91
+ loop.close()
92
+
93
+ thread = threading.Thread(target=run_coro_in_new_thread)
94
+ thread.start()
95
+ return future
agents/ten_packages/extension/aliyun_analyticdb_vector_storage/manifest.json ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "type": "extension",
3
+ "name": "aliyun_analyticdb_vector_storage",
4
+ "version": "0.1.0",
5
+ "dependencies": [
6
+ {
7
+ "type": "system",
8
+ "name": "ten_runtime_python",
9
+ "version": "0.8"
10
+ }
11
+ ],
12
+ "api": {
13
+ "property": {
14
+ "alibaba_cloud_access_key_id": {
15
+ "type": "string"
16
+ },
17
+ "alibaba_cloud_access_key_secret": {
18
+ "type": "string"
19
+ },
20
+ "adbpg_instance_id": {
21
+ "type": "string"
22
+ },
23
+ "adbpg_instance_region": {
24
+ "type": "string"
25
+ },
26
+ "adbpg_account": {
27
+ "type": "string"
28
+ },
29
+ "adbpg_account_password": {
30
+ "type": "string"
31
+ },
32
+ "adbpg_namespace": {
33
+ "type": "string"
34
+ },
35
+ "adbpg_namespace_password": {
36
+ "type": "string"
37
+ }
38
+ },
39
+ "cmd_in": [
40
+ {
41
+ "name": "upsert_vector",
42
+ "property": {
43
+ "collection_name": {
44
+ "type": "string"
45
+ },
46
+ "file_name": {
47
+ "type": "string"
48
+ },
49
+ "content": {
50
+ "type": "string"
51
+ }
52
+ }
53
+ },
54
+ {
55
+ "name": "query_vector",
56
+ "property": {
57
+ "collection_name": {
58
+ "type": "string"
59
+ },
60
+ "top_k": {
61
+ "type": "int64"
62
+ },
63
+ "embedding": {
64
+ "type": "array",
65
+ "items": {
66
+ "type": "float64"
67
+ }
68
+ }
69
+ },
70
+ "required": [
71
+ "collection_name",
72
+ "top_k",
73
+ "embedding"
74
+ ],
75
+ "result": {
76
+ "property": {
77
+ "response": {
78
+ "type": "array",
79
+ "items": {
80
+ "type": "object",
81
+ "properties": {
82
+ "content": {
83
+ "type": "string"
84
+ },
85
+ "score": {
86
+ "type": "float64"
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ }
93
+ },
94
+ {
95
+ "name": "create_collection",
96
+ "property": {
97
+ "collection_name": {
98
+ "type": "string"
99
+ },
100
+ "dimension": {
101
+ "type": "int32"
102
+ }
103
+ },
104
+ "required": [
105
+ "collection_name"
106
+ ]
107
+ },
108
+ {
109
+ "name": "delete_collection",
110
+ "property": {
111
+ "collection_name": {
112
+ "type": "string"
113
+ }
114
+ },
115
+ "required": [
116
+ "collection_name"
117
+ ]
118
+ }
119
+ ]
120
+ }
121
+ }
agents/ten_packages/extension/aliyun_analyticdb_vector_storage/model.py ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # -*- coding: utf-8 -*-
2
+
3
+ from alibabacloud_gpdb20160503 import models as gpdb_20160503_models # type: ignore
4
+ import time
5
+ import json
6
+ from typing import Dict, List, Any, Tuple
7
+ from alibabacloud_tea_util import models as util_models
8
+
9
+
10
+ class Model:
11
+ def __init__(self, ten_env, region_id, dbinstance_id, client):
12
+ self.region_id = region_id
13
+ self.dbinstance_id = dbinstance_id
14
+ self.client = client
15
+ self.read_timeout = 10 * 1000
16
+ self.connect_timeout = 10 * 1000
17
+ self.ten_env = ten_env
18
+
19
+ def get_client(self):
20
+ return self.client.get()
21
+
22
+ def init_vector_database(self, account, account_password) -> None:
23
+ try:
24
+ request = gpdb_20160503_models.InitVectorDatabaseRequest(
25
+ region_id=self.region_id,
26
+ dbinstance_id=self.dbinstance_id,
27
+ manager_account=account,
28
+ manager_account_password=account_password,
29
+ )
30
+ runtime = util_models.RuntimeOptions(
31
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
32
+ )
33
+ response = self.get_client().init_vector_database_with_options(
34
+ request, runtime
35
+ )
36
+ self.ten_env.log_debug(
37
+ f"init_vector_database response code: {response.status_code}, body:{response.body}"
38
+ )
39
+ except Exception as e:
40
+ self.ten_env.log_error(f"Error: {e}")
41
+ return e
42
+
43
+ async def init_vector_database_async(self, account, account_password) -> None:
44
+ try:
45
+ request = gpdb_20160503_models.InitVectorDatabaseRequest(
46
+ region_id=self.region_id,
47
+ dbinstance_id=self.dbinstance_id,
48
+ manager_account=account,
49
+ manager_account_password=account_password,
50
+ )
51
+ runtime = util_models.RuntimeOptions(
52
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
53
+ )
54
+ response = await self.get_client().init_vector_database_with_options_async(
55
+ request, runtime
56
+ )
57
+ self.ten_env.log_debug(
58
+ f"init_vector_database response code: {response.status_code}, body:{response.body}"
59
+ )
60
+ except Exception as e:
61
+ self.ten_env.log_error(f"Error: {e}")
62
+ return e
63
+
64
+ def create_namespace(
65
+ self, account, account_password, namespace, namespace_password
66
+ ) -> None:
67
+ try:
68
+ request = gpdb_20160503_models.CreateNamespaceRequest(
69
+ region_id=self.region_id,
70
+ dbinstance_id=self.dbinstance_id,
71
+ manager_account=account,
72
+ manager_account_password=account_password,
73
+ namespace=namespace,
74
+ namespace_password=namespace_password,
75
+ )
76
+ runtime = util_models.RuntimeOptions(
77
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
78
+ )
79
+ response = self.get_client().create_namespace_with_options(request, runtime)
80
+ self.ten_env.log_debug(
81
+ f"create_namespace response code: {response.status_code}, body:{response.body}"
82
+ )
83
+ except Exception as e:
84
+ self.ten_env.log_error(f"Error: {e}")
85
+ return e
86
+
87
+ async def create_namespace_async(
88
+ self, account, account_password, namespace, namespace_password
89
+ ) -> None:
90
+ try:
91
+ request = gpdb_20160503_models.CreateNamespaceRequest(
92
+ region_id=self.region_id,
93
+ dbinstance_id=self.dbinstance_id,
94
+ manager_account=account,
95
+ manager_account_password=account_password,
96
+ namespace=namespace,
97
+ namespace_password=namespace_password,
98
+ )
99
+ runtime = util_models.RuntimeOptions(
100
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
101
+ )
102
+ response = await self.get_client().create_namespace_with_options_async(
103
+ request, runtime
104
+ )
105
+ self.ten_env.log_debug(
106
+ f"create_namespace response code: {response.status_code}, body:{response.body}"
107
+ )
108
+ except Exception as e:
109
+ self.ten_env.log_error(f"Error: {e}")
110
+ return e
111
+
112
+ def create_collection(
113
+ self,
114
+ account,
115
+ account_password,
116
+ namespace,
117
+ collection,
118
+ parser: str = None,
119
+ metrics: str = None,
120
+ hnsw_m: int = None,
121
+ pq_enable: int = None,
122
+ external_storage: int = None,
123
+ ) -> None:
124
+ try:
125
+ metadata = '{"update_ts": "bigint", "file_name": "text", "content": "text"}'
126
+ full_text_retrieval_fields = "update_ts,file_name"
127
+ request = gpdb_20160503_models.CreateCollectionRequest(
128
+ region_id=self.region_id,
129
+ dbinstance_id=self.dbinstance_id,
130
+ manager_account=account,
131
+ manager_account_password=account_password,
132
+ namespace=namespace,
133
+ collection=collection,
134
+ metadata=metadata,
135
+ full_text_retrieval_fields=full_text_retrieval_fields,
136
+ parser=parser,
137
+ metrics=metrics,
138
+ hnsw_m=hnsw_m,
139
+ pq_enable=pq_enable,
140
+ external_storage=external_storage,
141
+ )
142
+ runtime = util_models.RuntimeOptions(
143
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
144
+ )
145
+ response = self.get_client().create_collection_with_options(
146
+ request, runtime
147
+ )
148
+ self.ten_env.log_debug(
149
+ f"create_document_collection response code: {response.status_code}, body:{response.body}"
150
+ )
151
+ except Exception as e:
152
+ self.ten_env.log_error(f"Error: {e}")
153
+ return e
154
+
155
+ async def create_collection_async(
156
+ self,
157
+ account,
158
+ account_password,
159
+ namespace,
160
+ collection,
161
+ parser: str = None,
162
+ metrics: str = None,
163
+ hnsw_m: int = None,
164
+ pq_enable: int = None,
165
+ external_storage: int = None,
166
+ ) -> None:
167
+ try:
168
+ metadata = '{"update_ts": "bigint", "file_name": "text", "content": "text"}'
169
+ full_text_retrieval_fields = "update_ts,file_name"
170
+ request = gpdb_20160503_models.CreateCollectionRequest(
171
+ region_id=self.region_id,
172
+ dbinstance_id=self.dbinstance_id,
173
+ manager_account=account,
174
+ manager_account_password=account_password,
175
+ namespace=namespace,
176
+ collection=collection,
177
+ metadata=metadata,
178
+ full_text_retrieval_fields=full_text_retrieval_fields,
179
+ parser=parser,
180
+ metrics=metrics,
181
+ hnsw_m=hnsw_m,
182
+ pq_enable=pq_enable,
183
+ external_storage=external_storage,
184
+ )
185
+ runtime = util_models.RuntimeOptions(
186
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
187
+ )
188
+ response = await self.get_client().create_collection_with_options_async(
189
+ request, runtime
190
+ )
191
+ self.ten_env.log_debug(
192
+ f"create_document_collection response code: {response.status_code}, body:{response.body}"
193
+ )
194
+ except Exception as e:
195
+ self.ten_env.log_error(f"Error: {e}")
196
+ return e
197
+
198
+ def delete_collection(self, namespace, namespace_password, collection) -> None:
199
+ try:
200
+ request = gpdb_20160503_models.DeleteCollectionRequest(
201
+ region_id=self.region_id,
202
+ dbinstance_id=self.dbinstance_id,
203
+ namespace_password=namespace_password,
204
+ namespace=namespace,
205
+ collection=collection,
206
+ )
207
+ runtime = util_models.RuntimeOptions(
208
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
209
+ )
210
+ response = self.get_client().delete_collection_with_options(
211
+ request, runtime
212
+ )
213
+ self.ten_env.log_debug(
214
+ f"delete_collection response code: {response.status_code}, body:{response.body}"
215
+ )
216
+ except Exception as e:
217
+ self.ten_env.log_error(f"Error: {e}")
218
+ return e
219
+
220
+ async def delete_collection_async(
221
+ self, namespace, namespace_password, collection
222
+ ) -> None:
223
+ try:
224
+ request = gpdb_20160503_models.DeleteCollectionRequest(
225
+ region_id=self.region_id,
226
+ dbinstance_id=self.dbinstance_id,
227
+ namespace_password=namespace_password,
228
+ namespace=namespace,
229
+ collection=collection,
230
+ )
231
+ runtime = util_models.RuntimeOptions(
232
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
233
+ )
234
+ response = await self.get_client().delete_collection_with_options_async(
235
+ request, runtime
236
+ )
237
+ self.ten_env.log_info(
238
+ f"delete_collection response code: {response.status_code}, body:{response.body}"
239
+ )
240
+ except Exception as e:
241
+ self.ten_env.log_error(f"Error: {e}")
242
+ return e
243
+
244
+ def upsert_collection_data(
245
+ self,
246
+ collection,
247
+ namespace,
248
+ namespace_password,
249
+ rows: List[Tuple[str, str, List[float]]] = None,
250
+ ) -> None:
251
+ try:
252
+ request_rows = []
253
+ for row in rows:
254
+ file_name = row[0]
255
+ content = row[1]
256
+ vector = row[2]
257
+ metadata = {
258
+ "update_ts": int(time.time() * 1000),
259
+ "file_name": file_name,
260
+ "content": content,
261
+ }
262
+ request_row = gpdb_20160503_models.UpsertCollectionDataRequestRows(
263
+ metadata=metadata, vector=vector
264
+ )
265
+ request_rows.append(request_row)
266
+ upsert_collection_data_request = (
267
+ gpdb_20160503_models.UpsertCollectionDataRequest(
268
+ region_id=self.region_id,
269
+ dbinstance_id=self.dbinstance_id,
270
+ collection=collection,
271
+ namespace_password=namespace_password,
272
+ namespace=namespace,
273
+ rows=request_rows,
274
+ )
275
+ )
276
+ runtime = util_models.RuntimeOptions(
277
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
278
+ )
279
+ response = self.get_client().upsert_collection_data_with_options(
280
+ upsert_collection_data_request, runtime
281
+ )
282
+ self.ten_env.log_debug(
283
+ f"upsert_collection response code: {response.status_code}, body:{response.body}"
284
+ )
285
+ except Exception as e:
286
+ self.ten_env.log_error(f"Error: {e}")
287
+ return e
288
+
289
+ async def upsert_collection_data_async(
290
+ self,
291
+ collection,
292
+ namespace,
293
+ namespace_password,
294
+ rows: List[Tuple[str, str, List[float]]] = None,
295
+ ) -> None:
296
+ try:
297
+ request_rows = []
298
+ for row in rows:
299
+ file_name = row[0]
300
+ content = row[1]
301
+ vector = row[2]
302
+ metadata = {
303
+ "update_ts": int(time.time() * 1000),
304
+ "file_name": file_name,
305
+ "content": content,
306
+ }
307
+ request_row = gpdb_20160503_models.UpsertCollectionDataRequestRows(
308
+ metadata=metadata, vector=vector
309
+ )
310
+ request_rows.append(request_row)
311
+ upsert_collection_data_request = (
312
+ gpdb_20160503_models.UpsertCollectionDataRequest(
313
+ region_id=self.region_id,
314
+ dbinstance_id=self.dbinstance_id,
315
+ collection=collection,
316
+ namespace_password=namespace_password,
317
+ namespace=namespace,
318
+ rows=request_rows,
319
+ )
320
+ )
321
+ runtime = util_models.RuntimeOptions(
322
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
323
+ )
324
+ response = (
325
+ await self.get_client().upsert_collection_data_with_options_async(
326
+ upsert_collection_data_request, runtime
327
+ )
328
+ )
329
+ self.ten_env.log_debug(
330
+ f"upsert_collection response code: {response.status_code}, body:{response.body}"
331
+ )
332
+ except Exception as e:
333
+ self.ten_env.log_error(f"Error: {e}")
334
+ return e
335
+
336
+ # pylint: disable=redefined-builtin
337
+ def query_collection_data(
338
+ self,
339
+ collection,
340
+ namespace,
341
+ namespace_password,
342
+ vector: List[float] = None,
343
+ top_k: int = 10,
344
+ content: str = None,
345
+ filter: str = None,
346
+ hybrid_search: str = None,
347
+ hybrid_search_args: Dict[str, dict] = None,
348
+ include_metadata_fields: str = None,
349
+ include_values: bool = None,
350
+ metrics: str = None,
351
+ ) -> Tuple[Any, Any]:
352
+ try:
353
+ query_collection_data_request = (
354
+ gpdb_20160503_models.QueryCollectionDataRequest(
355
+ region_id=self.region_id,
356
+ dbinstance_id=self.dbinstance_id,
357
+ collection=collection,
358
+ namespace_password=namespace_password,
359
+ namespace=namespace,
360
+ vector=vector,
361
+ top_k=top_k,
362
+ content=content,
363
+ filter=filter,
364
+ hybrid_search=hybrid_search,
365
+ hybrid_search_args=hybrid_search_args,
366
+ include_metadata_fields=include_metadata_fields,
367
+ include_values=include_values,
368
+ metrics=metrics,
369
+ )
370
+ )
371
+ runtime = util_models.RuntimeOptions(
372
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
373
+ )
374
+ response = self.get_client().query_collection_data_with_options(
375
+ query_collection_data_request, runtime
376
+ )
377
+ self.ten_env.log_debug(f"query_collection response code: {response.status_code}")
378
+ return response, None
379
+ except Exception as e:
380
+ self.ten_env.log_error(f"Error: {e}")
381
+ return None, e
382
+
383
+ # pylint: disable=redefined-builtin
384
+ async def query_collection_data_async(
385
+ self,
386
+ collection,
387
+ namespace,
388
+ namespace_password,
389
+ vector: List[float] = None,
390
+ top_k: int = 10,
391
+ content: str = None,
392
+ filter: str = None,
393
+ hybrid_search: str = None,
394
+ hybrid_search_args: Dict[str, dict] = None,
395
+ include_metadata_fields: str = None,
396
+ include_values: bool = None,
397
+ metrics: str = None,
398
+ ) -> Tuple[Any, Any]:
399
+ try:
400
+ query_collection_data_request = (
401
+ gpdb_20160503_models.QueryCollectionDataRequest(
402
+ region_id=self.region_id,
403
+ dbinstance_id=self.dbinstance_id,
404
+ collection=collection,
405
+ namespace_password=namespace_password,
406
+ namespace=namespace,
407
+ vector=vector,
408
+ top_k=top_k,
409
+ content=content,
410
+ filter=filter,
411
+ hybrid_search=hybrid_search,
412
+ hybrid_search_args=hybrid_search_args,
413
+ include_metadata_fields=include_metadata_fields,
414
+ include_values=include_values,
415
+ metrics=metrics,
416
+ )
417
+ )
418
+ runtime = util_models.RuntimeOptions(
419
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
420
+ )
421
+ response = await self.get_client().query_collection_data_with_options_async(
422
+ query_collection_data_request, runtime
423
+ )
424
+ self.ten_env.log_debug(f"query_collection response code: {response.status_code}")
425
+ return response, None
426
+ except Exception as e:
427
+ self.ten_env.log_error(f"Error: {e}")
428
+ return None, e
429
+
430
+ def parse_collection_data(
431
+ self, body: gpdb_20160503_models.QueryCollectionDataResponseBody
432
+ ) -> str:
433
+ try:
434
+ matches = body.to_map()["Matches"]["match"]
435
+ results = [
436
+ {"content": match["Metadata"]["content"], "score": match["Score"]}
437
+ for match in matches
438
+ ]
439
+ results.sort(key=lambda x: x["score"], reverse=True)
440
+ json_str = json.dumps(results)
441
+ return json_str
442
+ except Exception as e:
443
+ self.ten_env.log_error(
444
+ f"parse collection data failed, error: {e}, data: {body.to_map()}"
445
+ )
446
+ return "[]"
447
+
448
+ def list_collections(self, namespace, namespace_password) -> Tuple[List[str], Any]:
449
+ try:
450
+ request = gpdb_20160503_models.ListCollectionsRequest(
451
+ region_id=self.region_id,
452
+ dbinstance_id=self.dbinstance_id,
453
+ namespace=namespace,
454
+ namespace_password=namespace_password,
455
+ )
456
+ runtime = util_models.RuntimeOptions(
457
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
458
+ )
459
+ response = self.get_client().list_collections_with_options(request, runtime)
460
+ self.ten_env.log_debug(
461
+ f"list_collections response code: {response.status_code}, body:{response.body}"
462
+ )
463
+ collections = response.body.to_map()["Collections"]["collection"]
464
+ return collections, None
465
+ except Exception as e:
466
+ self.ten_env.log_error(f"Error: {e}")
467
+ return [], e
468
+
469
+ async def list_collections_async(
470
+ self, namespace, namespace_password
471
+ ) -> Tuple[List[str], Any]:
472
+ try:
473
+ request = gpdb_20160503_models.ListCollectionsRequest(
474
+ region_id=self.region_id,
475
+ dbinstance_id=self.dbinstance_id,
476
+ namespace=namespace,
477
+ namespace_password=namespace_password,
478
+ )
479
+ runtime = util_models.RuntimeOptions(
480
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
481
+ )
482
+ response = await self.get_client().list_collections_with_options_async(
483
+ request, runtime
484
+ )
485
+ self.ten_env.log_debug(
486
+ f"list_collections response code: {response.status_code}, body:{response.body}"
487
+ )
488
+ collections = response.body.to_map()["Collections"]["collection"]
489
+ return collections, None
490
+ except Exception as e:
491
+ self.ten_env.log_error(f"Error: {e}")
492
+ return [], e
493
+
494
+ def create_vector_index(
495
+ self, account, account_password, namespace, collection, dimension
496
+ ) -> None:
497
+ try:
498
+ request = gpdb_20160503_models.CreateVectorIndexRequest(
499
+ region_id=self.region_id,
500
+ dbinstance_id=self.dbinstance_id,
501
+ manager_account=account,
502
+ manager_account_password=account_password,
503
+ namespace=namespace,
504
+ collection=collection,
505
+ dimension=dimension,
506
+ pq_enable=0,
507
+ )
508
+ runtime = util_models.RuntimeOptions(
509
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
510
+ )
511
+ response = self.get_client().create_vector_index_with_options(
512
+ request, runtime
513
+ )
514
+ self.ten_env.log_debug(
515
+ f"create_vector_index response code: {response.status_code}, body:{response.body}"
516
+ )
517
+ except Exception as e:
518
+ self.ten_env.log_error(f"Error: {e}")
519
+ return e
520
+
521
+ async def create_vector_index_async(
522
+ self, account, account_password, namespace, collection, dimension
523
+ ) -> None:
524
+ try:
525
+ request = gpdb_20160503_models.CreateVectorIndexRequest(
526
+ region_id=self.region_id,
527
+ dbinstance_id=self.dbinstance_id,
528
+ manager_account=account,
529
+ manager_account_password=account_password,
530
+ namespace=namespace,
531
+ collection=collection,
532
+ dimension=dimension,
533
+ pq_enable=0,
534
+ )
535
+ runtime = util_models.RuntimeOptions(
536
+ read_timeout=self.read_timeout, connect_timeout=self.connect_timeout
537
+ )
538
+ response = await self.get_client().create_vector_index_with_options_async(
539
+ request, runtime
540
+ )
541
+ self.ten_env.log_debug(
542
+ f"create_vector_index response code: {response.status_code}, body:{response.body}"
543
+ )
544
+ except Exception as e:
545
+ self.ten_env.log_error(f"Error: {e}")
546
+ return e