Composability

One of the most powerful features of the BRX platform is the ability to compose BRKs (BRX Knowledge Representations) together to build complex AI applications. This concept, known as composability, allows you to create reusable, modular components that can be combined in various ways.

Understanding Composability

Composability in BRX works through dependencies between BRKs. When one BRK depends on another, it can use the output of the dependent BRK as part of its own processing. This creates a directed graph of dependencies, where the output of one BRK flows into another.

Key Benefits

  • Reusability: Build once, use anywhere
  • Modularity: Break complex problems into smaller, manageable pieces
  • Maintainability: Update individual components without affecting the entire system
  • Scalability: Easily extend functionality by adding new components
  • Collaboration: Different team members can work on different components

How Composability Works

In BRX, composability is implemented through the dependantBrxIds property of a BRK. This property maps a linker name to a BRK ID, creating a dependency relationship.

When a BRK is executed, the BRX engine:

  1. Identifies all dependencies
  2. Executes each dependency in the correct order
  3. Passes the outputs of dependencies to the parent BRK
  4. Executes the parent BRK with all inputs and dependency outputs

Example

Consider a simple example with three BRKs:

  1. Data Extraction BRK: Extracts structured data from unstructured text
  2. Analysis BRK: Analyzes the extracted data to identify patterns
  3. Report Generation BRK: Generates a formatted report based on the analysis

The dependency graph would look like:

Report Generation BRK

Analysis BRK

Data Extraction BRK

When you execute the Report Generation BRK, the BRX engine automatically:

  1. Executes the Data Extraction BRK
  2. Passes its output to the Analysis BRK
  3. Executes the Analysis BRK
  4. Passes its output to the Report Generation BRK
  5. Executes the Report Generation BRK
  6. Returns the final result

Implementing Composability

Creating Dependencies

When creating a BRK, you can specify its dependencies using the dependantBrxIds property:

const myBrk = {
  brxId: 'report-generation-brk',
  brxName: 'Report Generation',
  description: 'Generates a formatted report based on analysis',
  prompt: {
    prompt: new Map([
      ['main', 'Generate a report based on the following analysis: {{analysis}}']
    ])
  },
  processParams: {
    processType: 0
  },
  dependantBrxIds: new Map([
    ['main_brx_entry_schema', 'report-generation-brk'],
    ['analysis', 'analysis-brk'] // This creates a dependency on the Analysis BRK
  ])
};

Accessing Dependency Outputs

In your prompt templates, you can access the outputs of dependencies using variables:

Generate a report based on the following analysis: {{analysis}}

Here, {{analysis}} will be replaced with the output of the Analysis BRK.

Advanced Composability Patterns

Parallel Execution

BRKs can have multiple dependencies that are executed in parallel:

      ┌─────────┐
      │ Result  │
      └────┬────┘

┌──────────┼──────────┐
↓          ↓          ↓
┌─────┐ ┌─────┐ ┌─────┐
│ BRK1│ │ BRK2│ │ BRK3│
└─────┘ └─────┘ └─────┘

Conditional Execution

You can implement conditional execution by having BRKs that decide which other BRKs to execute:

┌─────────┐
│ Router  │
└────┬────┘

┌────┼────┐
↓         ↓
┌─────┐ ┌─────┐
│ BRK1│ │ BRK2│
└─────┘ └─────┘

Recursive Patterns

BRKs can implement recursive patterns, where a BRK depends on itself or creates a cycle of dependencies:

┌─────────┐
│ Recursive│
└────┬────┘



┌─────────┐
│ Base Case│
└─────────┘

Best Practices

  • Keep BRKs focused: Each BRK should do one thing well
  • Design for reusability: Create BRKs that can be used in multiple contexts
  • Document dependencies: Clearly document what each BRK depends on and why
  • Avoid deep dependency chains: Too many levels of dependencies can make debugging difficult
  • Test thoroughly: Test each BRK individually and in combination with its dependencies
  • Monitor performance: Keep track of execution time and resource usage