Skip to main content

Core Concepts

This guide explains the fundamental concepts and building blocks of Dhenara Agent DSL (DAD). Understanding these concepts will help you design and build effective agent systems.

Domain Specific Language (DSL)

A Domain Specific Language is a specialized language designed for a particular domain. DAD is a DSL for AI Agent creation. Though we call it a DSL, it is not a separate programming language, but rather Python with specialized patterns and structures. We call it a DSL because DAD is an attempt to make agent definitions look like a program, as shown below:

implementation_flow = (
FlowDefinition()
.node(
"dynamic_repo_analysis",
FolderAnalyzerNode(settings=FolderAnalyzerSettings(base_directory=global_data_directory)),
)
.node(
"code_generator",
AIModelNode(
pre_events=[EventType.node_input_required],
settings=AIModelNodeSettings(
models=models,
system_instructions=["You are a professional code implementation agent."],
prompt=Prompt.with_dad_text(text=("Description: $expr{task_description}\n\n")),
model_call_config=AIModelCallConfig(
structured_output=TaskImplementation,
),
),
),
)
.for_each(
id="implementation_loop",
statement="$expr{ $hier{code_generator}.outcome.structured.implementation_tasks }",
item_var="task_spec",
index_var="task_index",
start_index=0,
max_iterations=20,
body=FlowDefinition().node(
"code_generator_file_ops",
FileOperationNode(
settings=FileOperationNodeSettings(
base_directory=global_data_directory,
operations_template="$expr{ $hier{code_generator}.outcome.structured.file_operations }",
),
stage=True,
commit=False,
),
),
)
)

Basic Elements

A DAD agent definition consists of three primary types of elements:

  • Execution Flow Node (or simply Node): The atomic unit of execution
  • Execution Flow (or simply Flow): A collection of nodes with execution logic
  • Agent: Created using AgentDefinition, which organizes and coordinates multiple flows

These elements form a hierarchical structure, with Agents at the top, containing Flows, which in turn contain Nodes.

Node Types

The framework provides several built-in node types:

  • AIModelNode: Performs an AI Model API call
  • FileOperationNode: Performs file operations like create_file, edit_file, delete_file, etc.
  • FolderAnalyzerNode: Reads a folder or file with fine-grained controls
  • CommandNode: Executes a shell command

These are the core built-in nodes in the framework, with support for additional node types including MCP (Model Context Protocol) being developed.

You can also create your custom nodes by creating a NodeDefinition along with its settings and executor.

Flow Structure

A Flow is created using a FlowDefinition, to which you can add the following elements:

  • Nodes
  • Conditional Blocks (for branching logic)
  • ForEach Blocks (for iteration)
  • Other subflows (for modular design)

Agent Structure

An Agent is created using an AgentDefinition, to which you can add the following elements:

  • Flows (top-level execution units)
  • Conditional Blocks (for high-level branching)
  • ForEach Blocks (for iterative processing)
  • Other subagents (for complex, hierarchical designs)

Element Identifiers

When you add an element to a Flow/Agent definition, you need to provide an id string that uniquely identifies that element within its parent. For example, in the code above, "dynamic_repo_analysis", "code_generator", "implementation_loop", and "code_generator_file_ops" are ids.

These ids are crucial because they allow you to reference the output of one element's execution in another element using the $hier{} template syntax, like:

statement="$expr{ $hier{code_generator}.outcome.structured.implementation_tasks }",

Element Execution

Nodes

Nodes are the atomic units of execution in DAD. Each node performs a specific task such as:

  • Making an LLM API call
  • Analyzing files or folders
  • Performing file operations
  • Executing shell commands

Nodes are the leaf components in the hierarchy and do the actual work in an agent system.

Flows

Flows are collections of nodes that define execution logic. They determine how data moves between nodes and in what order nodes are executed. Flows can include:

  • Sequential execution of nodes
  • Conditional branches based on results
  • Loops for iterative processing
  • Nested subflows for modular design

Agents

Agents are top-level components that can contain multiple flows and other agents (subagents). They represent complete functional units and orchestrate the overall behavior of the system.

Execution Model

Execution in DAD follows a clear separation between definition (what to do) and execution (how to do it):

  1. Definition Classes: NodeDefinition, FlowDefinition, AgentDefinition
  2. Executable Classes: ExecutableNode, Flow, Agent
  3. Executor Classes: NodeExecutor, FlowExecutor, AgentExecutor

This separation allows for flexible composition and customization while maintaining consistent execution behavior.

Execution Context

The execution context is a crucial concept in DAD. It:

  • Tracks the execution state (pending, running, completed, failed)
  • Stores results from executed nodes
  • Manages hierarchical variable scoping
  • Provides access to resources (e.g., LLM models)
  • Enables communication between components through events

The execution context creates a hierarchical structure that mirrors the component hierarchy, allowing child components to access resources and results from their parent contexts.

Event System

The event system provides a publish-subscribe mechanism for communication between components:

  • Events: Typed messages with a specific purpose (e.g., node_input_required)
  • Event Handlers: Functions that respond to specific event types
  • Event Bus: Central hub for routing events to handlers

Common event types include:

  • node_input_required: Request input for a node
  • node_execution_completed: Notify when a node finishes execution
  • node_execution_failed: Notify when a node encounters an error

Template Engine

The template engine is a powerful feature of DAD that allows for dynamic text generation and processing:

  • Variable Substitution: Replace $var{name} with the value of a variable
  • Expression Evaluation: Evaluate expressions like $expr{1 + 2}
  • Hierarchical References: Access results from other nodes using $hier{node_id.property}
  • Python Expressions: Evaluate Python code with $expr{py: len(items)}

The template engine makes it easy to build dynamic prompts, process responses, and coordinate between components.

Run System

The run system manages the execution environment for DAD components:

  • RunContext: Manages run directories, artifacts, and settings
  • IsolatedExecution: Provides isolation between runs
  • Run Lifecycle: Initialize, setup, execute, manage artifacts, and complete

The run system ensures reproducibility and proper resource management across different runs.

Observability

Observability is a core feature of DAD that provides visibility into execution:

  • Tracing: Track the execution path of components and nodes
  • Logging: Capture structured logs with context
  • Metrics: Collect numerical data about execution
  • Dashboards: Visualize traces and metrics for analysis

Observability helps debug issues, optimize performance, and understand complex agent behaviors.

Example: Component Relationships

Here's how these concepts work together in a simple DAD agent:

# Define a flow with nodes
my_flow = FlowDefinition()
my_flow.node("analyzer", FolderAnalyzerNode(...))
my_flow.node("processor", AIModelNode(...))

# Define an agent with flows
my_agent = AgentDefinition()
my_agent.flow("main_flow", my_flow)

# Create run context for execution
run_context = RunContext(
root_component_id="my_agent",
project_root=Path("."),
)

# Run the agent
runner = AgentRunner(my_agent, run_context)
runner.setup_run()
result = await runner.run()

In this example:

  1. The flow contains two nodes that execute in sequence
  2. The agent contains the flow and potentially other flows
  3. The run context provides the execution environment
  4. The runner handles the execution process

Next Steps

Now that you understand the core concepts of DAD, you can: