Validate graphs
Updated
Validate predefined graphs and start_graph commands for correctness using the tman check graph command.
Graph validation is essential for preventing runtime errors in TEN applications. Invalid graph configurations can cause extension connection failures, message routing errors, schema compatibility issues, and missing dependency problems.
Use the tman check graph command to validate TEN app graphs and catch these issues before deployment. This command verifies that:
- All required nodes are defined
- Extension connections are valid
- Message schemas are compatible
- Required packages are installed
Validation helps ensure your TEN app graphs function correctly when deployed.
Command syntax
The basic syntax for the check graph command is:
tman check graph --app APP_PATH [OPTIONS]The command uses the following key parameters:
-
--app APP_PATH: The absolute path to the app directory containing graph definitions -
--predefined-graph-name GRAPH_NAME: Validate a specific predefined graph by name. If omitted, all predefined graphs in the app are validated. (Optional) -
--graph JSON_STRING: Validate a JSON string representing astart_graphcommand instead of predefined graphs from files. (Optional)
Follow these guidelines when using the command:
- Run the command from any directory—you don't need to be in the app's root directory
- Use the command to validate connections that span multiple apps in multi-app graphs
Usage examples
The following examples illustrate the use of the tman check graph command:
-
Check all predefined graphs in
property.json:tman check graph --app /home/TEN-Agent/agents -
Check a specific predefined graph:
tman check graph --predefined-graph-name va.openai.azure --app /home/TEN-Agent/agents -
Check a
start_graphcommand:tman check graph --graph '{ "type": "start_graph", "seq_id": "55", "nodes": [ { "type": "extension", "name": "test_extension", "addon": "basic_hello_world_2__test_extension", "extension_group": "test_extension_group", "app": "msgpack://127.0.0.1:8001/" }, { "type": "extension", "name": "test_extension", "addon": "basic_hello_world_1__test_extension", "extension_group": "test_extension_group", "app": "msgpack://127.0.0.1:8001/" } ] }' --app /home/TEN-Agent/agents
Requirements and setup
Before using check graph, ensure the following requirements are met:
-
Package installation: All extensions that the app depends on must be installed using
tman install. The validation process requires information about each extension in the graph, such as APIs defined in theirmanifest.jsonfiles. -
Predefined graph definition: If you specify a predefined graph name, the definition must exist in the
property.jsonfile of the app specified by the--appparameter. -
Unique app URI: In multi-app graphs, each app's
property.jsonmust define a uniqueten::uri. Theurivalue cannot be set to"localhost".
Validation rules
The tman check graph command validates the following rules:
Nodes must be present
The nodes array is required in any graph definition. If absent, an error is thrown.
-
Example: No nodes defined
tman check graph --graph '{ "type": "start_graph", "seq_id": "55", "nodes": [] }' --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: No extension node is defined in graph. All is done. ❌ Error: 1/1 graphs failed.
Node names must be unique
Each node in the nodes array represents an extension instance within a group of an app, created by a specified addon. Each extension instance must be uniquely represented by a single node. A node is uniquely identified by the combination of app, extension_group, and name. Multiple entries for the same extension instance are not allowed.
-
Example: Duplicate nodes
tman check graph --graph '{ "type": "start_graph", "seq_id": "55", "nodes": [ { "type": "extension", "name": "test_extension", "addon": "basic_hello_world_2__test_extension", "extension_group": "test_extension_group", "app": "msgpack://127.0.0.1:8001/" }, { "type": "extension", "name": "test_extension", "addon": "basic_hello_world_1__test_extension", "extension_group": "test_extension_group", "app": "msgpack://127.0.0.1:8001/" } ] }' --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: Duplicated extension was found in nodes[1], addon: basic_hello_world_1__test_extension, name: test_extension. All is done. ❌ Error: 1/1 graphs failed.
Connection extensions must be defined in nodes
All extension instances referenced in the connections field, whether as a source or destination, must be explicitly defined in the nodes field. Any instance not defined in the nodes array causes validation errors.
-
Example: Source extension not defined
Suppose that the
property.jsonfile of a TEN app is as follows.{ "ten": { "predefined_graphs": [ { "name": "default", "auto_start": false, "nodes": [ { "type": "extension", "name": "some_extension", "addon": "default_extension_go", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "hello", "dest": [ { "extension": "some_extension" } ] } ] } ] } ] } }tman check graph --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: The extension declared in connections[0] is not defined in nodes, extension_group: producer, extension: some_extension. All is done. ❌ Error: 1/1 graphs failed. -
Example: Destination extension not defined
Suppose that the
property.jsonfile of a TEN app is as follows.{ "ten": { "predefined_graphs": [ { "name": "default", "auto_start": false, "nodes": [ { "type": "extension", "name": "some_extension", "addon": "default_extension_go", "extension_group": "some_group" }, { "type": "extension", "name": "some_extension_1", "addon": "default_extension_go", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "hello", "dest": [ { "extension": "some_extension_1" } ] }, { "name": "world", "dest": [ { "extension": "some_extension_1" }, { "extension": "consumer" } ] } ] } ] } ] } }tman check graph --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: The extension declared in connections[0].cmd[1] is not defined in nodes extension_group: some_group, extension: consumer. All is done. ❌ Error: 1/1 graphs failed.
Node addons must be installed
All node addons must be installed using tman install and have matching app URIs for successful validation.
-
Example: The
ten::uriinproperty.jsonis not equal to theappfield in nodes:Suppose that the
property.jsonfile of a TEN app is as follows.{ "ten": { "predefined_graphs": [ { "name": "default", "auto_start": false, "nodes": [ { "type": "extension", "name": "some_extension", "addon": "default_extension_go", "extension_group": "some_group" } ] } ], "uri": "http://localhost:8001" } }tman check graph --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: The following packages are declared in nodes but not installed: [("localhost", Extension, "default_extension_go")]. All is done. ❌ Error: 1/1 graphs failed.The problem is that all packages in the app are stored in a map for which the key is the
uriof the app, and each node in the graph is retrieved by theappfield (localhostby default). Theappin node (localhost) is a mismatch with theuriof the app (http://localhost:8001). -
Example: The
ten_packagesdoes not exist astman installhas not been executedSuppose that the
property.jsonfile of a TEN app is as follows and theten_packagesdirectory does NOT exist.{ "ten": { "predefined_graphs": [ { "name": "default", "auto_start": false, "nodes": [ { "type": "extension", "name": "some_extension", "addon": "default_extension_go", "extension_group": "some_group" } ] } ] } }tman check graph --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: The following packages are declared in nodes but not installed: [("localhost", Extension, "default_extension_go")]. All is done. ❌ Error: 1/1 graphs failed.
Extension connections must be in one section
All messages sent from an extension must be defined within a single connection section. Multiple connection sections for the same extension are not allowed.
-
Example:
Suppose that all the packages have been installed.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "default_extension_go", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "default_extension_go", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "hello", "dest": [ { "extension": "another_ext" } ] } ] }, { "extension": "some_extension", "cmd": [ { "name": "hello_2", "dest": [ { "extension": "another_ext" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: extension 'some_extension' is defined in connection[0] and connection[1], merge them into one section. All is done. ❌ Error: 1/1 graphs failed.
Message names must be unique within each type
Each message sent from an extension must have a unique name within its message type (cmd, data, etc.). Duplicate message names within the same type are not allowed.
-
Example:
Suppose that all the packages have been installed.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "hello", "dest": [ { "extension": "another_ext" } ] }, { "name": "hello", "dest": [ { "extension": "some_extension" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: - connection[0]: - Merge the following cmd into one section: 'hello' is defined in flow[0] and flow[1]. All is done. ❌ Error: 1/1 graphs failed.
Message schemas must be compatible
Messages are validated for schema compatibility based on the schema definitions in the manifest.json files of extensions. Validation follows these compatibility rules:
-
If the message schema is not found in either the source or target extension, the message is compatible
-
If the message schema is only found in one extension, the message is incompatible
-
If schemas exist in both extensions, the message is compatible only when:
- Property types are compatible
- For object properties, all fields in both source and target schemas must have compatible types
- If the target schema defines
requiredfields, the source schema must also definerequiredfields that include all target requirements
-
Example:
Suppose that all the packages have been installed.
The
manifest.jsonfile foraddon_ais as follows.{ "type": "extension", "name": "addon_a", "version": "0.1.0", "dependencies": [ { "type": "system", "name": "ten_runtime_go", "version": "0.1.0" } ], "package": { "include": ["**"] }, "api": { "cmd_out": [ { "name": "cmd_1", "property": { "foo": { "type": "string" } } } ] } }And, the
manifest.jsonfile foraddon_bis as follows.{ "type": "extension", "name": "addon_b", "version": "0.1.0", "dependencies": [ { "type": "system", "name": "ten_runtime_go", "version": "0.1.0" } ], "package": { "include": ["**"] }, "api": { "cmd_in": [ { "name": "cmd_1", "property": { "foo": { "type": "int8" } } } ] } }Check the graph with the following command.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "cmd_1", "dest": [ { "extension": "another_ext" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
Checking graph[0]... ❌. Details: - connections[0]: - cmd[0]: Schema incompatible to [extension_group: some_group, extension: another_ext], { .foo: type is incompatible, source is [string], but target is [int8] } All is done. ❌ Error: 1/1 graphs failed.
App fields must be unambiguous
The app field in each node must follow specific rules to ensure proper app identification and routing.
App field requirements:
-
Must equal the
ten::uriof the corresponding TEN app -
Either all nodes must have
appdeclared, or none should -
Cannot be set to
localhost -
Cannot be an empty string
-
Example: Some nodes specify the
appfieldCheck the graph with the following command.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group", "app": "http://localhost:8000" } ] }' --app /home/TEN-Agent/agentsOutput:
❌ Error: The graph json string is invalid Caused by: Either all nodes should have 'app' declared, or none should, but not a mix of both. -
Example: Source extension specifies
appin connections when nodes don'tCheck the graph using the following command.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "app": "http://localhost:8000", "cmd": [ { "name": "cmd_1", "dest": [ { "extension": "another_ext" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
❌ Error: The graph json string is invalid Caused by: connections[0].the 'app' should not be declared, as not any node has declared it -
Example: Target extension specifies
appin connections when nodes don'tCheck the graph using the following command.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "cmd_1", "dest": [ { "extension": "another_ext", "app": "http://localhost:8000" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
❌ Error: The graph json string is invalid Caused by: connections[0].cmd[0].dest[0]: the 'app' should not be declared, as not any node has declared it -
Example: App field doesn't match ten::uri
Same as the example for Node addons must be installed.
-
Example: App field is
localhostin a single-app graphCheck the graph using the following command.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group", "app": "localhost" } ], "connections": [ { "extension": "some_extension", "cmd": [ { "name": "cmd_1", "dest": [ { "extension": "another_ext" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
❌ Error: Failed to parse graph string, nodes[1]: 'localhost' is not allowed in graph definition, and the graph seems to be a single-app graph, just remove the 'app' field -
Example: App field is
localhostin a multi-app graphCheck the graph using the following command.
tman check graph --graph '{ "nodes": [ { "type": "extension", "name": "some_extension", "addon": "addon_a", "extension_group": "some_group", "app": "http://localhost:8000" }, { "type": "extension", "name": "another_ext", "addon": "addon_b", "extension_group": "some_group", "app": "localhost" } ], "connections": [ { "extension": "some_extension", "app": "http://localhost:8000", "cmd": [ { "name": "cmd_1", "dest": [ { "extension": "another_ext" } ] } ] } ] }' --app /home/TEN-Agent/agentsOutput:
❌ Error: Failed to parse graph string, nodes[1]: 'localhost' is not allowed in graph definition, change the content of 'app' field to be consistent with 'ten::uri'
