Subgraphs
The TEN framework uses a graph structure of interconnected nodes to define data flow between extensions. Subgraphs extend this architecture by providing a powerful reuse mechanism that allows you to break down complex graph structures into modular, reusable components.
Subgraphs improve code organization and maintainability by enabling you to create self-contained graph modules that can be shared across different applications or used multiple times within the same application. This modular approach simplifies the development of complex systems while maintaining the same runtime performance characteristics as regular graphs.
Understand the tech
Subgraphs preserve the fundamental principle of TEN graphs: defining how data flows between extensions. Rather than introducing new runtime complexity, subgraphs act as a development-time abstraction that gets flattened into the larger graph structure during deployment.
This design approach provides the organizational benefits of modularity while using the same graph execution mechanism that powers all TEN applications.
Design principles
Subgraphs are built on the following foundational principles that ensure they integrate seamlessly with the TEN framework while providing meaningful development benefits:
-
Independence: Every subgraph is a complete, self-contained graph that can run independently or be embedded as a component within larger graphs. This independence means you can develop, test, and validate subgraphs in isolation before integrating them into complex applications.
-
Tool-friendly design: Subgraphs provide structured metadata through
exposed_messages
andexposed_properties
that development tools can use to offer intelligent suggestions, validation, and debugging capabilities. This enhanced tooling support improves the development experience without adding runtime overhead. -
Flattening mechanism: At deployment time, subgraphs are flattened into standard graph structures, ensuring that runtime performance remains identical to regular graphs. This approach provides development-time modularity benefits while maintaining the proven performance characteristics of the core TEN graph engine.
-
Simplicity: Subgraph design prioritizes simplicity. Rather than providing patching mechanisms or complex configuration options at reference points, subgraphs use straightforward mapping and exposure patterns. If a subgraph needs modification, you modify the original definition directly, avoiding complexity cascades and maintenance overhead.
This design approach allows you to treat subgraphs as black boxes. You can use them without understanding their internal complexity, while the framework handles the technical details of integration and execution.
Key features
Subgraphs provide four essential features that enable modular graph development and seamless integration within TEN applications:
-
Message exposure: Subgraphs declare their external interfaces through the
exposed_messages
field, specifying which message types (commands, data, audio, video) can be sent to or received from the subgraph. This exposure mechanism allows development tools to provide intelligent autocomplete and validation while hiding internal implementation details from external consumers. -
Property exposure: Through the
exposed_properties
field, subgraphs can selectively expose internal extension properties to external configuration. This controlled exposure enables customization of subgraph behavior without revealing the entire internal structure, maintaining encapsulation while providing necessary flexibility. -
Namespace management: Each referenced subgraph creates its own namespace, preventing naming conflicts between elements in different subgraphs. When you reference a subgraph with name
subgraph_1
, all internal elements become accessible through the namespace syntax (e.g.,subgraph_1:ext_name
), ensuring global uniqueness across complex graph hierarchies. -
Cross-graph connections: Subgraphs enable sophisticated connection patterns that span multiple graph boundaries. You can connect directly to subgraph interfaces, connect to specific elements within subgraphs, or even establish connections between elements in different subgraphs. This flexibility supports complex data flow architectures while maintaining clear organizational boundaries.
These features work together to provide a powerful abstraction layer that simplifies complex graph development without sacrificing the flexibility and performance that TEN applications require.
Creating subgraphs
Subgraph definition
A subgraph is defined in a standard JSON file that contains the same basic structure as any TEN graph, with additional metadata for external interfaces. Here's a basic example:
Following is the structure breakdown:
-
Nodes section: Defines the extensions that make up the subgraph, just like in a regular graph. Each extension specifies its type, name, and addon identifier.
-
Connections section: Establishes data flow between extensions within the subgraph. These internal connections define how the subgraph processes data internally.
-
Exposed messages section: Declares which message interfaces are available for external connections. This acts as the subgraph's public API, allowing other graphs to send data to or receive data from the subgraph without knowing its internal structure.
-
Exposed properties section: Specifies which extension properties can be configured externally. The
alias
field provides user-friendly names for external configuration, abstracting away internal implementation details.
This sample subgraph can function as a standalone audio processing pipeline or be embedded within larger applications that need audio enhancement capabilities.
Exposed interfaces
Subgraphs use two interface types to control what external graphs can access and configure. These interfaces act as the subgraph's public API, providing controlled access while maintaining internal encapsulation.
exposed_messages
The exposed_messages
field defines which message interfaces are available for external connections. This allows other graphs to interact with your subgraph without needing to understand its internal structure.
Message exposure structure:
Message types:
cmd_in
/cmd_out
: Command messages for control and responsesdata_in
/data_out
: General data messagesaudio_frame_in
/audio_frame_out
: Audio stream datavideo_frame_in
/video_frame_out
: Video stream data
Example:
This example exposes an audio input, text output, and configuration command, allowing external graphs to send audio data and receive transcribed text while configuring the recognition language.
exposed_properties
The exposed_properties
field specifies which internal extension properties can be configured from outside the subgraph. This enables customization without exposing the entire internal configuration.
Property exposure structure:
extension
: The internal extension that owns the propertyname
: The actual property name within the extensionalias
: The external name used when referencing the subgraph (optional)
Example:
In this example, external graphs can configure video quality through the output_quality
alias, set buffer limits through buffer_limit
, and specify codec type directly. The aliases provide user-friendly names while hiding implementation details. Exposed interfaces provide the following benefits:
- Encapsulation: Hide internal complexity while providing clean external APIs
- Selective exposure: Allow control over which interfaces and properties can be accessed externally
- Interface documentation: Serve as documentation for subgraph capabilities
Using subgraphs
Referencing subgraphs
To use a subgraph in your main graph, reference it as a node with type subgraph
. The subgraph becomes part of your graph's namespace and can be connected like any other component.
Basic subgraph reference:
Subgraph with properties: You can configure exposed properties when referencing a subgraph:
The properties you specify must exist in the subgraph's exposed_properties
field, otherwise the configuration is rejected.
Connection patterns
Subgraphs support multiple connection patterns that provide flexibility in how you route data between components.
Direct connections to subgraphs
Connect directly to a subgraph using its name when the subgraph exposes the appropriate message interface:
This pattern works when data_processor
exposes a cmd_in
interface for process_data
. The connection is clean and hides the subgraph's internal structure.
Connections to elements within subgraphs
For more granular control, connect directly to specific extensions within a subgraph using namespace syntax:
The subgraph_name:extension_name
syntax allows you to bypass the subgraph's exposed interfaces and connect directly to internal elements. Use this pattern when you need fine-grained control over data flow.
Advanced connection syntax
You can mix different connection patterns within the same graph to create sophisticated data flow architectures:
Connection pattern guidelines:
- Use direct subgraph connections when working with well-defined interfaces
- Use namespace syntax when you need to access specific internal functionality
- Mix patterns when building complex data flow architectures
- Prefer exposed interfaces for maintainability and clarity
These patterns give you the flexibility to build everything from simple linear pipelines to complex multi-path processing architectures while maintaining clear organizational boundaries.
Flattening process
How flattening works
Before your application runs, the TEN framework automatically flattens all subgraph references into a single, standard graph structure. This flattening process converts the modular development structure into the standard graph format that the TEN runtime executes.
Flattening transformations:
-
Namespace resolution: Subgraph references are resolved and internal elements are prefixed with the subgraph name to ensure global uniqueness.
-
Node expansion: Subgraph nodes are replaced with their constituent extension nodes, maintaining all original properties and configurations.
-
Connection mapping: References using namespace syntax (
subgraph:extension
) are converted to direct extension names, and subgraph-level connections are mapped to specific internal extensions. -
Property inheritance: Properties specified when referencing a subgraph are applied to the appropriate internal extensions based on the
exposed_properties
mapping. -
Interface removal: The
exposed_messages
andexposed_properties
metadata is removed since it's only needed during graph composition.
Naming convention:
The colon (:
) is replaced with an underscore (_
) to create valid extension names in the flattened structure.
- Original:
subgraph_name:extension_name
- Flattened:
subgraph_name_extension_name
Flattened graph example
Following is a complete example that shows how a graph with subgraphs transforms during the flattening process:
Before flattening:
After flattening:
Key changes during flattening:
- Subgraph nodes removed:
audio_pipeline
andeffects_chain
subgraph nodes are replaced with their constituent extensions - Names prefixed: Internal extensions get prefixed names (
audio_pipeline_processor
,effects_chain_reverb
) - Properties distributed: Subgraph properties are applied to the correct internal extensions
- Connections resolved: All namespace references and subgraph connections are converted to direct extension connections
- Internal connections preserved: Connections that existed within the original subgraphs are included in the flattened result
The flattened graph contains only standard extensions and direct connections, maintaining the organizational benefits you gained during development while using the standard TEN graph execution model.
Advanced features
Message conversion with subgraphs
Subgraphs support the TEN framework's message conversion mechanism, allowing you to transform message formats when routing data between components.
Message conversion syntax: You can apply message conversion rules when connecting to subgraphs, internal subgraph elements, or when subgraphs connect to external components:
Conversion during flattening: Message conversion rules are preserved during the flattening process, ensuring that your data transformations work correctly at runtime:
Multi-graph connections
Beyond subgraphs, TEN supports connections between separate graphs running in the same application or across different applications. This enables sophisticated distributed architectures.
Connecting to predefined graphs
You can reference and connect to other predefined graphs within the same TEN application:
Remote graph connections
Connect to graphs running in different TEN applications across the network:
Graph node types
TEN supports three types of graph nodes for different connection scenarios:
Subgraph nodes:
Local graph nodes:
Remote graph nodes:
Graph node properties:
- graph_name: Identifies the target graph within its application
- singleton: Controls whether multiple instances can exist (
true
= single instance,false
= multiple instances allowed) - app: Specifies the target application URL for remote connections (omit for local graphs)
These advanced features enable you to build sophisticated distributed systems where subgraphs, local graphs, and remote services work together seamlessly while maintaining clear architectural boundaries.
Reference
Graph node types
TEN graphs support three types of node references that enable different architectural patterns and connection scopes.
Subgraph nodes
Reference external graph files as reusable components within your graph:
Basic subgraph node:
Subgraph node with properties:
Remote subgraph node:
Required fields:
type
: Must be"subgraph"
name
: Unique identifier within the current graph (serves as namespace)source_uri
: Path or URL to the subgraph definition file
Optional fields:
property
: Configuration values for exposed properties
Local graph nodes
Reference other predefined graphs within the same TEN application:
Singleton local graph:
Multi-instance local graph:
Required fields:
type
: Must be"graph"
graph_name
: Identifier of the predefined graph in the same applicationsingleton
: Boolean controlling instance multiplicity
Singleton behavior:
true
: Only one instance of the graph exists, shared across referencesfalse
: Each reference creates a separate graph instance
Remote graph nodes
Reference graphs running in different TEN applications across the network:
Singleton remote graph:
Multi-instance remote graph:
Required fields:
type
: Must be"graph"
graph_name
: Identifier of the target graph in the remote applicationsingleton
: Boolean controlling instance behaviorapp
: Network address of the target TEN application
Supported protocols:
msgpack://host:port/
: MessagePack-based communication- Additional protocols may be supported in future versions
Connection syntax reference
TEN provides flexible syntax for establishing connections between different types of graph nodes and their internal elements.
subgraph_name:element_name
Access specific elements within subgraphs using namespace syntax:
Extension within subgraph:
Connecting to subgraph element:
Syntax rules:
- Format:
subgraph_name:extension_name
- The colon (
:
) separates namespace from element name - Element name must exist within the referenced subgraph
- Bypasses subgraph's exposed interface constraints
Graph references
Connect to graphs using their identifiers:
Direct graph connection:
Graph element connection:
Local graph with namespace:
Advanced patterns
Combine multiple connection types for sophisticated data flow architectures:
Multi-destination routing:
Cross-application message flow:
Conditional routing with message conversion:
Connection target types:
extension
: Direct extension namesubgraph
: Subgraph name (uses exposed interfaces)graph
: Graph name (uses exposed interfaces)extension
with namespace:namespace:extension_name
Best practices:
- Use exposed interfaces when possible for better encapsulation
- Use namespace syntax only when you need direct access to internal elements
- Prefer subgraphs over direct graph references for reusable components
- Document complex connection patterns for maintainability