Skip to main content

Project overview

The TEN Agent project is built on the TEN Framework and follows a modular architecture. This page describes the project structure, configuration system, and web server API.

TEN Agent uses a graph-based configuration system built on the TEN Framework concepts. The project organizes code into modular extensions that can be orchestrated through configuration files without modifying source code. The folder structure follows this pattern:


_13
├── agents/
_13
│ └── ten_packages/
_13
│ ├── extension/
_13
│ │ ├── openai_chatgpt_python/
_13
│ │ │ ├── extension.py
_13
│ │ │ ├── ..
_13
│ │ │ └── requirements.txt
_13
│ │ ├── elevenlabs_tts
_13
│ │ └── ..
_13
│ └── property.json
_13
├── playground
_13
├── demo
_13
└── server

It contains the following important folders and files:

  • property.json: This file contains the orchestration of extensions. It is the main runtime configuration file.
  • ten_packages/extension: This folder contains the extension modules. Each extension module is a separate Python/Golang/C++ package.
  • server: This folder contains the web server code. It is responsible for handling the incoming requests and start/stop of agent processes.
  • playground: This folder contains the UI code for the playground. It is a web-based interface to interact with the agent.

Runtime configuration

The main runtime configuration file is property.json. It contains the orchestration of extensions. The file is structured as follows:


_13
"predefined_graphs": [
_13
{
_13
"name": "va_openai_azure_fashionai",
_13
"auto_start": false,
_13
"connections": [
_13
// ...
_13
],
_13
"nodes": [
_13
// ...
_13
]
_13
},
_13
// ...
_13
]

The file contains the following orchestration info:

  • Graphs: Collections of nodes and connections that determine agent behavior
  • Nodes: Individual extension instances with specific configurations
  • Connections: Data flow paths between nodes

_10
{
_10
"predefined_graphs": [
_10
{
_10
"name": "va_openai_azure_fashionai",
_10
"auto_start": false,
_10
"connections": [...],
_10
"nodes": [...]
_10
}
_10
]
_10
}

Graphs

The predefined_graphs property contains a list of available graphs. Each graph defines how agent should behave in a specific scenario. Each graph Each graph contains:

  • name: Unique identifier for the graph
  • auto_start: Whether to start this graph automatically
  • nodes: List of extension instances
  • connections: Data routing between nodes

Nodes

The nodes section contains the list of extensions that are part of the graph. Each node includes the following:

  • name: Unique identifier of a node within the graph
  • addon: Specifies the extension module to use You can create multiple instances of the same extension within a graph. For example, you might include several chatgpt_openai_python nodes, each using the same addon property but with unique name properties. This allows you to run parallel instances of an extension with different configurations or behaviors.
  • property: Extension-specific configuration

_11
json{
_11
"name": "chatgpt_openai_python",
_11
"addon": "chatgpt_openai_python",
_11
"property": {
_11
"api_key": "${env:OPENAI_API_KEY|}",
_11
"model": "gpt-3.5-turbo",
_11
"temperature": 0.5,
_11
"max_tokens": 100,
_11
"prompt": "You are a helpful assistant"
_11
}
_11
}

Node Properties

The property section of a node configures the extension's behavior. Each extension defines its available properties in the manifest.json file within its folder. You can customize an extension by setting these runtime properties.

Read environment variables

Many extensions require API keys to function. Instead of hardcoding sensitive keys in property.json, use environment variables with the syntax ${env:<env_var_name>|<default_value>}. The following example shows how to read and use the OPENAI_API_KEY environment variable:


_7
{
_7
"name": "chatgpt_openai_python",
_7
"addon": "chatgpt_openai_python",
_7
"property": {
_7
"api_key": "${env:OPENAI_API_KEY|}"
_7
}
_7
}

Connections

The connections section defines how data flows between nodes. Each connection specifies:

  • Source node: Identified by extension_group and extension properties
  • Data protocols: Types of data that can flow: audio_frame, video_frame, data, or cmd
  • Destinations: Where each data type is routed

For each protocol, you define destinations with:

  • name: The data property key
  • dest: List of target nodes

The following example connects agora_rtc extension to deepgram_asr extension. The agora_rtc extension sends pcm_frame data to deepgram_asr extension.


_15
{
_15
"extension_group": "default",
_15
"extension": "agora_rtc",
_15
"audio_frame": [
_15
{
_15
"name": "pcm_frame",
_15
"dest": [
_15
{
_15
"extension_group": "default",
_15
"extension": "deepgram_asr"
_15
}
_15
]
_15
}
_15
]
_15
}

Extension folder

The ten_packages/extension folder contains extension modules written in Python, Go, or C++. Each extension is a self-contained package with its own structure. Extension folder names typically match the module name, though the definitive module name is specified in the extension's manifest.json file. Use this module name as the addon property value in your configuration.

The extension folder is structured as follows:


_23
<project_root>/
_23
├── ten_packages/
_23
│ └── extension/
_23
│ ├── sample_python_extension/
_23
│ │ ├── ...
_23
│ │ ├── extension.py
_23
│ │ ├── manifest.json
_23
│ │ └── property.json
_23
│ ├── sample_go_extension/
_23
│ │ ├── ...
_23
│ │ ├── <xxx>_extension.go
_23
│ │ ├── manifest.json
_23
│ │ └── property.json
_23
│ └── sample_cpp_extension/
_23
│ ├── ...
_23
│ ├── src/
_23
│ │ ├── main.cc
_23
│ │ └── ...
_23
│ ├── BUILD.gn
_23
│ ├── manifest.json
_23
│ └── property.json
_23
├── manifest.json
_23
└── property.json

Extension common files

  • manifest.json: Defines the extension's metadata including name, version, available properties, and supported APIs such as data, audio_frame, and video_frame
  • property.json: Specifies default configuration values for the extension

Extension-specific files

Each language has its own set of required files for extension development:

LanguageMain logic fileDependencies/Build file
Pythonextension.pyrequirements.txt: Python dependencies required by the extension. Dependencies are installed automatically when you run task use.
Go<name>_extension.gogo.mod: Go module definition that specifies the module name and dependencies.
C++src/main.ccBUILD.gn: Build configuration that specifies the target name and dependencies.

The main logic file contains the core implementation of the extension for each language.

Web server

The Go-based web server manages agent processes and handles HTTP requests from clients. Both the playground and demo interfaces communicate with this server, though you can also interact directly using curl or any HTTP client.

API endpoints

The server exposes three endpoints for agent management:

POST /start

Starts an agent with a specified graph and property overrides. The agent joins the specified RTC channel and subscribes to the user's audio stream.

ParameterDescription
request_idUUID for request tracking
channel_nameRTC channel name (must match the channel your client joins)
user_uidUser's RTC identifier for audio subscription
bot_uidOptional agent RTC identifier
graph_nameGraph configuration name from property.json
propertiesProperty overrides (temporary, doesn't modify property.json)
timeoutInactivity timeout in seconds (-1 disables timeout, default: 60s, configurable using WORKER_QUIT_TIMEOUT_SECONDS)

Example:


_13
curl 'http://localhost:8080/start' \
_13
-H 'Content-Type: application/json' \
_13
--data-raw '{
_13
"request_id": "c1912182-924c-4d15-a8bb-85063343077c",
_13
"channel_name": "test",
_13
"user_uid": 176573,
_13
"graph_name": "camera_va_openai_azure",
_13
"properties": {
_13
"openai_chatgpt": {
_13
"model": "gpt-4o"
_13
}
_13
}
_13
}'

POST /stop

Stops a running agent instance.

ParameterDescription
request_idUUID for request tracking
channel_nameChannel name used when starting the agent

Example:


_6
curl 'http://localhost:8080/stop' \
_6
-H 'Content-Type: application/json' \
_6
--data-raw '{
_6
"request_id": "c1912182-924c-4d15-a8bb-85063343077c",
_6
"channel_name": "test"
_6
}'

POST /ping

Maintains the agent connection by sending a keepalive signal. Not required if the agent was started with timeout: -1. Without pings, agents terminate after the configured timeout period.

ParamDescription
request_idUUID for request tracking
channel_nameChannel name of the active agent

Example:


_6
curl 'http://localhost:8080/ping' \
_6
-H 'Content-Type: application/json' \
_6
--data-raw '{
_6
"request_id": "c1912182-924c-4d15-a8bb-85063343077c",
_6
"channel_name": "test"
_6
}'