Skip to main content

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 and exposed_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:


_53
{
_53
"nodes": [
_53
{
_53
"type": "extension",
_53
"name": "audio_processor",
_53
"addon": "audio_enhancement"
_53
},
_53
{
_53
"type": "extension",
_53
"name": "audio_filter",
_53
"addon": "noise_reduction"
_53
}
_53
],
_53
"connections": [
_53
{
_53
"extension": "audio_processor",
_53
"audio_frame": [
_53
{
_53
"name": "processed_audio",
_53
"dest": [
_53
{
_53
"extension": "audio_filter"
_53
}
_53
]
_53
}
_53
]
_53
}
_53
],
_53
"exposed_messages": [
_53
{
_53
"extension": "audio_processor",
_53
"type": "audio_frame_in",
_53
"name": "raw_audio"
_53
},
_53
{
_53
"extension": "audio_filter",
_53
"type": "audio_frame_out",
_53
"name": "clean_audio"
_53
}
_53
],
_53
"exposed_properties": [
_53
{
_53
"extension": "audio_processor",
_53
"name": "sample_rate",
_53
"alias": "input_sample_rate"
_53
},
_53
{
_53
"extension": "audio_filter",
_53
"name": "noise_threshold",
_53
"alias": "filter_sensitivity"
_53
}
_53
]
_53
}

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:


_9
{
_9
"exposed_messages": [
_9
{
_9
"extension": "internal_extension_name",
_9
"type": "message_direction_and_type",
_9
"name": "message_name"
_9
}
_9
]
_9
}

Message types:

  • cmd_in / cmd_out: Command messages for control and responses
  • data_in / data_out: General data messages
  • audio_frame_in / audio_frame_out: Audio stream data
  • video_frame_in / video_frame_out: Video stream data

Example:


_19
{
_19
"exposed_messages": [
_19
{
_19
"extension": "speech_recognizer",
_19
"type": "audio_frame_in",
_19
"name": "audio_input"
_19
},
_19
{
_19
"extension": "text_processor",
_19
"type": "data_out",
_19
"name": "transcribed_text"
_19
},
_19
{
_19
"extension": "speech_recognizer",
_19
"type": "cmd_in",
_19
"name": "configure_language"
_19
}
_19
]
_19
}

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:


_9
{
_9
"exposed_properties": [
_9
{
_9
"extension": "internal_extension_name",
_9
"name": "internal_property_name",
_9
"alias": "external_property_name"
_9
}
_9
]
_9
}

  • extension: The internal extension that owns the property
  • name: The actual property name within the extension
  • alias: The external name used when referencing the subgraph (optional)

Example:


_18
{
_18
"exposed_properties": [
_18
{
_18
"extension": "video_encoder",
_18
"name": "bitrate_kbps",
_18
"alias": "output_quality"
_18
},
_18
{
_18
"extension": "frame_buffer",
_18
"name": "max_buffer_size",
_18
"alias": "buffer_limit"
_18
},
_18
{
_18
"extension": "video_encoder",
_18
"name": "codec_type"
_18
}
_18
]
_18
}

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:


_47
{
_47
"nodes": [
_47
{
_47
"type": "extension",
_47
"name": "input_source",
_47
"addon": "audio_input"
_47
},
_47
{
_47
"type": "extension",
_47
"name": "output_sink",
_47
"addon": "audio_output"
_47
},
_47
{
_47
"type": "subgraph",
_47
"name": "audio_pipeline",
_47
"source_uri": "./ten_packages/extension/audio_processing/subgraph.json"
_47
}
_47
],
_47
"connections": [
_47
{
_47
"extension": "input_source",
_47
"audio_frame": [
_47
{
_47
"name": "raw_audio",
_47
"dest": [
_47
{
_47
"subgraph": "audio_pipeline"
_47
}
_47
]
_47
}
_47
]
_47
},
_47
{
_47
"subgraph": "audio_pipeline",
_47
"audio_frame": [
_47
{
_47
"name": "processed_audio",
_47
"dest": [
_47
{
_47
"extension": "output_sink"
_47
}
_47
]
_47
}
_47
]
_47
}
_47
]
_47
}

Subgraph with properties: You can configure exposed properties when referencing a subgraph:


_10
{
_10
"type": "subgraph",
_10
"name": "video_processor",
_10
"source_uri": "./subgraphs/video_enhancement.json",
_10
"property": {
_10
"output_quality": "high",
_10
"buffer_limit": 1024,
_10
"codec_type": "h264"
_10
}
_10
}

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:


_17
{
_17
"connections": [
_17
{
_17
"extension": "data_source",
_17
"cmd": [
_17
{
_17
"name": "process_data",
_17
"dest": [
_17
{
_17
"subgraph": "data_processor"
_17
}
_17
]
_17
}
_17
]
_17
}
_17
]
_17
}

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:


_30
{
_30
"connections": [
_30
{
_30
"extension": "external_source",
_30
"data": [
_30
{
_30
"name": "raw_input",
_30
"dest": [
_30
{
_30
"extension": "video_pipeline:frame_buffer"
_30
}
_30
]
_30
}
_30
]
_30
},
_30
{
_30
"extension": "video_pipeline:encoder",
_30
"video_frame": [
_30
{
_30
"name": "encoded_output",
_30
"dest": [
_30
{
_30
"extension": "external_sink"
_30
}
_30
]
_30
}
_30
]
_30
}
_30
]
_30
}

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:


_39
{
_39
"connections": [
_39
{
_39
"extension": "input_hub",
_39
"data": [
_39
{
_39
"name": "sensor_data",
_39
"dest": [
_39
{
_39
"subgraph": "processing_pipeline"
_39
},
_39
{
_39
"extension": "backup_pipeline:data_logger"
_39
},
_39
{
_39
"extension": "monitoring_extension"
_39
}
_39
]
_39
}
_39
]
_39
},
_39
{
_39
"subgraph": "processing_pipeline",
_39
"cmd": [
_39
{
_39
"name": "status_update",
_39
"dest": [
_39
{
_39
"extension": "monitoring_extension"
_39
},
_39
{
_39
"subgraph": "alert_system"
_39
}
_39
]
_39
}
_39
]
_39
}
_39
]
_39
}

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:

  1. Namespace resolution: Subgraph references are resolved and internal elements are prefixed with the subgraph name to ensure global uniqueness.

  2. Node expansion: Subgraph nodes are replaced with their constituent extension nodes, maintaining all original properties and configurations.

  3. Connection mapping: References using namespace syntax (subgraph:extension) are converted to direct extension names, and subgraph-level connections are mapped to specific internal extensions.

  4. Property inheritance: Properties specified when referencing a subgraph are applied to the appropriate internal extensions based on the exposed_properties mapping.

  5. Interface removal: The exposed_messages and exposed_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:


_69
{
_69
"nodes": [
_69
{
_69
"type": "extension",
_69
"name": "input_source",
_69
"addon": "microphone_input"
_69
},
_69
{
_69
"type": "extension",
_69
"name": "output_sink",
_69
"addon": "speaker_output"
_69
},
_69
{
_69
"type": "subgraph",
_69
"name": "audio_pipeline",
_69
"source_uri": "./subgraphs/audio_processing.json",
_69
"property": {
_69
"sample_rate": 48000,
_69
"noise_threshold": 0.3
_69
}
_69
},
_69
{
_69
"type": "subgraph",
_69
"name": "effects_chain",
_69
"source_uri": "./subgraphs/audio_effects.json"
_69
}
_69
],
_69
"connections": [
_69
{
_69
"extension": "input_source",
_69
"audio_frame": [
_69
{
_69
"name": "raw_audio",
_69
"dest": [
_69
{
_69
"subgraph": "audio_pipeline"
_69
}
_69
]
_69
}
_69
]
_69
},
_69
{
_69
"extension": "audio_pipeline:processor",
_69
"audio_frame": [
_69
{
_69
"name": "clean_audio",
_69
"dest": [
_69
{
_69
"extension": "effects_chain:reverb"
_69
}
_69
]
_69
}
_69
]
_69
},
_69
{
_69
"subgraph": "effects_chain",
_69
"audio_frame": [
_69
{
_69
"name": "final_audio",
_69
"dest": [
_69
{
_69
"extension": "output_sink"
_69
}
_69
]
_69
}
_69
]
_69
}
_69
]
_69
}

After flattening:


_107
{
_107
"nodes": [
_107
{
_107
"type": "extension",
_107
"name": "input_source",
_107
"addon": "microphone_input"
_107
},
_107
{
_107
"type": "extension",
_107
"name": "output_sink",
_107
"addon": "speaker_output"
_107
},
_107
{
_107
"type": "extension",
_107
"name": "audio_pipeline_enhancer",
_107
"addon": "audio_enhancement",
_107
"property": {
_107
"sample_rate": 48000
_107
}
_107
},
_107
{
_107
"type": "extension",
_107
"name": "audio_pipeline_processor",
_107
"addon": "noise_reduction",
_107
"property": {
_107
"noise_threshold": 0.3
_107
}
_107
},
_107
{
_107
"type": "extension",
_107
"name": "effects_chain_reverb",
_107
"addon": "reverb_effect"
_107
},
_107
{
_107
"type": "extension",
_107
"name": "effects_chain_compressor",
_107
"addon": "dynamic_compressor"
_107
}
_107
],
_107
"connections": [
_107
{
_107
"extension": "input_source",
_107
"audio_frame": [
_107
{
_107
"name": "raw_audio",
_107
"dest": [
_107
{
_107
"extension": "audio_pipeline_enhancer"
_107
}
_107
]
_107
}
_107
]
_107
},
_107
{
_107
"extension": "audio_pipeline_enhancer",
_107
"audio_frame": [
_107
{
_107
"name": "enhanced_audio",
_107
"dest": [
_107
{
_107
"extension": "audio_pipeline_processor"
_107
}
_107
]
_107
}
_107
]
_107
},
_107
{
_107
"extension": "audio_pipeline_processor",
_107
"audio_frame": [
_107
{
_107
"name": "clean_audio",
_107
"dest": [
_107
{
_107
"extension": "effects_chain_reverb"
_107
}
_107
]
_107
}
_107
]
_107
},
_107
{
_107
"extension": "effects_chain_reverb",
_107
"audio_frame": [
_107
{
_107
"name": "reverb_audio",
_107
"dest": [
_107
{
_107
"extension": "effects_chain_compressor"
_107
}
_107
]
_107
}
_107
]
_107
},
_107
{
_107
"extension": "effects_chain_compressor",
_107
"audio_frame": [
_107
{
_107
"name": "final_audio",
_107
"dest": [
_107
{
_107
"extension": "output_sink"
_107
}
_107
]
_107
}
_107
]
_107
}
_107
]
_107
}

Key changes during flattening:

  • Subgraph nodes removed: audio_pipeline and effects_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:


_47
{
_47
"connections": [
_47
{
_47
"extension": "data_source",
_47
"cmd": [
_47
{
_47
"name": "user_request",
_47
"dest": [
_47
{
_47
"subgraph": "ai_processor",
_47
"msg_conversion": {
_47
"type": "per_property",
_47
"rules": [
_47
{
_47
"path": "request_type",
_47
"conversion_mode": "fixed_value",
_47
"value": "chat_completion"
_47
},
_47
{
_47
"path": "model_config.temperature",
_47
"conversion_mode": "from_original",
_47
"original_path": "settings.creativity"
_47
}
_47
],
_47
"keep_original": true
_47
}
_47
},
_47
{
_47
"extension": "nlp_pipeline:tokenizer",
_47
"msg_conversion": {
_47
"type": "per_property",
_47
"rules": [
_47
{
_47
"path": "input_text",
_47
"conversion_mode": "from_original",
_47
"original_path": "user_message"
_47
}
_47
],
_47
"keep_original": false
_47
}
_47
}
_47
]
_47
}
_47
]
_47
}
_47
]
_47
}

Conversion during flattening: Message conversion rules are preserved during the flattening process, ensuring that your data transformations work correctly at runtime:


_42
{
_42
"connections": [
_42
{
_42
"extension": "data_source",
_42
"cmd": [
_42
{
_42
"name": "user_request",
_42
"dest": [
_42
{
_42
"extension": "ai_processor_chat_handler",
_42
"msg_conversion": {
_42
"type": "per_property",
_42
"rules": [
_42
{
_42
"path": "request_type",
_42
"conversion_mode": "fixed_value",
_42
"value": "chat_completion"
_42
}
_42
],
_42
"keep_original": true
_42
}
_42
},
_42
{
_42
"extension": "nlp_pipeline_tokenizer",
_42
"msg_conversion": {
_42
"type": "per_property",
_42
"rules": [
_42
{
_42
"path": "input_text",
_42
"conversion_mode": "from_original",
_42
"original_path": "user_message"
_42
}
_42
],
_42
"keep_original": false
_42
}
_42
}
_42
]
_42
}
_42
]
_42
}
_42
]
_42
}

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:


_50
{
_50
"nodes": [
_50
{
_50
"type": "extension",
_50
"name": "local_processor",
_50
"addon": "data_processor"
_50
},
_50
{
_50
"type": "graph",
_50
"graph_name": "analytics_pipeline",
_50
"singleton": true
_50
},
_50
{
_50
"type": "graph",
_50
"graph_name": "monitoring_system",
_50
"singleton": false
_50
}
_50
],
_50
"connections": [
_50
{
_50
"extension": "local_processor",
_50
"data": [
_50
{
_50
"name": "processed_data",
_50
"dest": [
_50
{
_50
"extension": "analytics_pipeline:data_ingester"
_50
},
_50
{
_50
"graph": "monitoring_system"
_50
}
_50
]
_50
}
_50
]
_50
},
_50
{
_50
"graph": "analytics_pipeline",
_50
"cmd": [
_50
{
_50
"name": "analysis_complete",
_50
"dest": [
_50
{
_50
"extension": "local_processor"
_50
}
_50
]
_50
}
_50
]
_50
}
_50
]
_50
}

Remote graph connections

Connect to graphs running in different TEN applications across the network:


_52
{
_52
"nodes": [
_52
{
_52
"type": "extension",
_52
"name": "local_service",
_52
"addon": "api_handler"
_52
},
_52
{
_52
"type": "graph",
_52
"graph_name": "ml_inference",
_52
"singleton": true,
_52
"app": "msgpack://ml-server.example.com:8002/"
_52
},
_52
{
_52
"type": "graph",
_52
"graph_name": "data_warehouse",
_52
"singleton": false,
_52
"app": "msgpack://data-cluster.example.com:8003/"
_52
}
_52
],
_52
"connections": [
_52
{
_52
"extension": "local_service",
_52
"cmd": [
_52
{
_52
"name": "inference_request",
_52
"dest": [
_52
{
_52
"graph": "ml_inference"
_52
}
_52
]
_52
}
_52
]
_52
},
_52
{
_52
"graph": "ml_inference",
_52
"data": [
_52
{
_52
"name": "inference_result",
_52
"dest": [
_52
{
_52
"extension": "local_service"
_52
},
_52
{
_52
"graph": "data_warehouse"
_52
}
_52
]
_52
}
_52
]
_52
}
_52
]
_52
}

Graph node types

TEN supports three types of graph nodes for different connection scenarios:

Subgraph nodes:


_8
{
_8
"type": "subgraph",
_8
"name": "processing_module",
_8
"source_uri": "./subgraphs/data_processing.json",
_8
"property": {
_8
"batch_size": 100
_8
}
_8
}

Local graph nodes:


_5
{
_5
"type": "graph",
_5
"graph_name": "background_service",
_5
"singleton": true
_5
}


_5
{
_5
"type": "graph",
_5
"graph_name": "worker_pool",
_5
"singleton": false
_5
}

Remote graph nodes:


_6
{
_6
"type": "graph",
_6
"graph_name": "external_api",
_6
"singleton": true,
_6
"app": "msgpack://api.service.com:8001/"
_6
}


_6
{
_6
"type": "graph",
_6
"graph_name": "distributed_cache",
_6
"singleton": false,
_6
"app": "msgpack://cache-cluster.internal:8004/"
_6
}

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:


_5
{
_5
"type": "subgraph",
_5
"name": "unique_subgraph_name",
_5
"source_uri": "path/to/subgraph.json"
_5
}

Subgraph node with properties:


_13
{
_13
"type": "subgraph",
_13
"name": "configurable_module",
_13
"source_uri": "./ten_packages/extension/module/subgraph.json",
_13
"property": {
_13
"param1": "value1",
_13
"param2": 42,
_13
"nested_config": {
_13
"enabled": true,
_13
"threshold": 0.85
_13
}
_13
}
_13
}

Remote subgraph node:


_5
{
_5
"type": "subgraph",
_5
"name": "shared_component",
_5
"source_uri": "https://cdn.example.com/subgraphs/v1.2/nlp_pipeline.json"
_5
}

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:


_5
{
_5
"type": "graph",
_5
"graph_name": "predefined_graph_id",
_5
"singleton": true
_5
}

Multi-instance local graph:


_5
{
_5
"type": "graph",
_5
"graph_name": "worker_template",
_5
"singleton": false
_5
}

Required fields:

  • type: Must be "graph"
  • graph_name: Identifier of the predefined graph in the same application
  • singleton: Boolean controlling instance multiplicity

Singleton behavior:

  • true: Only one instance of the graph exists, shared across references
  • false: Each reference creates a separate graph instance

Remote graph nodes

Reference graphs running in different TEN applications across the network:

Singleton remote graph:


_6
{
_6
"type": "graph",
_6
"graph_name": "ml_service",
_6
"singleton": true,
_6
"app": "msgpack://ml-cluster.internal:8002/"
_6
}

Multi-instance remote graph:


_6
{
_6
"type": "graph",
_6
"graph_name": "data_processor",
_6
"singleton": false,
_6
"app": "msgpack://processing-farm.example.com:8003/"
_6
}

Required fields:

  • type: Must be "graph"
  • graph_name: Identifier of the target graph in the remote application
  • singleton: Boolean controlling instance behavior
  • app: 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:


_13
{
_13
"extension": "audio_pipeline:noise_filter",
_13
"audio_frame": [
_13
{
_13
"name": "filtered_audio",
_13
"dest": [
_13
{
_13
"extension": "output_device"
_13
}
_13
]
_13
}
_13
]
_13
}

Connecting to subgraph element:


_13
{
_13
"extension": "microphone",
_13
"audio_frame": [
_13
{
_13
"name": "raw_audio",
_13
"dest": [
_13
{
_13
"extension": "processing_chain:input_buffer"
_13
}
_13
]
_13
}
_13
]
_13
}

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:


_13
{
_13
"subgraph": "local_processor",
_13
"cmd": [
_13
{
_13
"name": "process_complete",
_13
"dest": [
_13
{
_13
"graph": "analytics_engine"
_13
}
_13
]
_13
}
_13
]
_13
}

Graph element connection:


_13
{
_13
"graph": "background_service",
_13
"data": [
_13
{
_13
"name": "status_update",
_13
"dest": [
_13
{
_13
"extension": "monitor:logger"
_13
}
_13
]
_13
}
_13
]
_13
}

Local graph with namespace:


_13
{
_13
"extension": "coordinator",
_13
"cmd": [
_13
{
_13
"name": "task_assignment",
_13
"dest": [
_13
{
_13
"extension": "worker_pool:task_manager"
_13
}
_13
]
_13
}
_13
]
_13
}

Advanced patterns

Combine multiple connection types for sophisticated data flow architectures:

Multi-destination routing:


_22
{
_22
"extension": "data_ingester",
_22
"data": [
_22
{
_22
"name": "incoming_data",
_22
"dest": [
_22
{
_22
"subgraph": "validation_pipeline"
_22
},
_22
{
_22
"extension": "processing_farm:load_balancer"
_22
},
_22
{
_22
"graph": "audit_logger"
_22
},
_22
{
_22
"extension": "backup_storage"
_22
}
_22
]
_22
}
_22
]
_22
}

Cross-application message flow:


_13
{
_13
"graph": "local_analytics",
_13
"cmd": [
_13
{
_13
"name": "analysis_request",
_13
"dest": [
_13
{
_13
"extension": "ml_cluster:inference_engine"
_13
}
_13
]
_13
}
_13
]
_13
}

Conditional routing with message conversion:


_36
{
_36
"extension": "request_router",
_36
"cmd": [
_36
{
_36
"name": "user_request",
_36
"dest": [
_36
{
_36
"subgraph": "fast_processing",
_36
"msg_conversion": {
_36
"type": "per_property",
_36
"rules": [
_36
{
_36
"path": "priority",
_36
"conversion_mode": "fixed_value",
_36
"value": "high"
_36
}
_36
]
_36
}
_36
},
_36
{
_36
"extension": "slow_processing:queue_manager",
_36
"msg_conversion": {
_36
"type": "per_property",
_36
"rules": [
_36
{
_36
"path": "priority",
_36
"conversion_mode": "fixed_value",
_36
"value": "normal"
_36
}
_36
]
_36
}
_36
}
_36
]
_36
}
_36
]
_36
}

Connection target types:

  • extension: Direct extension name
  • subgraph: 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