Skip to content
This repository was archived by the owner on Nov 26, 2025. It is now read-only.

Latest commit

 

History

History
455 lines (363 loc) · 9.09 KB

File metadata and controls

455 lines (363 loc) · 9.09 KB

Flows & Workflows

Flows are Rohas' way of organizing multi-step workflows with state management, parallel execution, and memory.

Table of Contents

  1. Basic Flows
  2. Flow Steps
  3. Parallel Execution
  4. Flow Composition
  5. State Management
  6. Memory in Flows
  7. Conditional Flows
  8. Flow Outputs

Basic Flows

A flow is a named block that contains one or more steps:

flow myFlow {
    step first {
        prompt "First step"
    }

    step second {
        prompt "Second step"
    }
}

Simple Example

flow greetUser {
    step welcome {
        name = "Alice"
        prompt "Welcome, " + name + "!"
    }

    step personalize {
        prompt "How can I help you today, " + name + "?"
    }
}

Flow Steps

Steps are executed sequentially by default. Each step can contain any valid Rohas code:

flow researchFlow {
    step gatherInfo {
        topic = "artificial intelligence"
        prompt1 = "Give me a brief overview of " + topic
        prompt prompt1
          model: "gpt-4"
    }

    step analyzeInfo {
        prompt2 = "Analyze the previous response and provide key insights"
        prompt prompt2
          model: "gpt-4"
    }

    step summarize {
        prompt3 = "Create a concise summary of the analysis"
        prompt prompt3
          model: "gpt-4"
    }
}

Step Variables

Variables defined in one step are available to subsequent steps:

flow dataProcessing {
    step load {
        data = call csvLoader("data.csv")
    }

    step process {
        # 'data' is available here
        processed = processData(data)
    }

    step output {
        # Both 'data' and 'processed' are available
        prompt "Processed {processed.length} records from {data.length} total"
    }
}

Parallel Execution

Use parallel step to execute steps concurrently:

flow parallelResearch {
    parallel step research1 {
        prompt "What are the causes of climate change?"
    }

    parallel step research2 {
        prompt "What are the effects of climate change?"
    }

    parallel step research3 {
        prompt "What are solutions for climate change?"
    }

    step combineResults {
        # This step waits for all parallel steps to complete
        prompt "Combine all the previous research into a comprehensive report"
    }
}

Parallel vs Sequential

flow comparison {
    # Sequential - each step waits for the previous
    step step1 {
        prompt "Step 1"
    }

    step step2 {
        prompt "Step 2"
    }

    # Parallel - execute simultaneously
    parallel step taskA {
        prompt "Task A"
    }

    parallel step taskB {
        prompt "Task B"
    }

    # Sequential - waits for parallel steps
    step final {
        prompt "Final step"
    }
}

Flow Composition

Flows can use other flows with the uses keyword:

flow fetchNews {
    step search {
        prompt "Get top 5 tech news today"
        output { headlines: string[] }
    }
}

flow summarizeNews {
    uses fetchNews
    step summarize {
        prompt "Summarize these headlines in 3 sentences"
        output { summary: string }
    }
}

Flow Dependencies

flow baseFlow {
    step initialize {
        config = loadConfig()
    }
}

flow extendedFlow {
    uses baseFlow
    step process {
        # 'config' from baseFlow is available
        result = processWithConfig(config)
    }
}

State Management

State allows passing data between flow steps explicitly:

flow orderProcessing {
    step validate {
        orderId = "12345"
        prompt "Validate order {orderId}"
          state: { orderId: orderId, status: "validating" }
    }

    step process {
        prompt "Process order"
          state: { orderId: "12345", status: "processing" }
    }

    step complete {
        prompt "Complete order"
          state: { orderId: "12345", status: "completed" }
    }
}

State Persistence

State is maintained across steps and can be accessed:

flow statefulFlow {
    step init {
        prompt "Initialize"
          state: { counter: 0, items: [] }
    }

    step add {
        prompt "Add item"
          state: { counter: 1, items: ["item1"] }
    }

    step process {
        prompt "Process items"
          state: { counter: 1, items: ["item1"], processed: true }
    }
}

Memory in Flows

Memory can be used within flows to maintain context:

flow supportFlow {
    step capture {
        message = "Capture issue details for customer support"
        prompt message
          memory: "short_term"
          state: { topic: "customer_support" }
    }

    step respond {
        response = "Provide helpful guidance for customer support"
        prompt response
          memory: "short_term"
          state: { topic: "customer_support", priority: "high" }
    }
}

Memory Types

  • short_term - Memory for the current flow execution
  • long_term - Persistent memory across flow executions
flow memoryExample {
    step remember {
        prompt "My favorite programming language is Rust"
          memory: "long_term"
    }

    step recall {
        prompt "What's my favorite programming language?"
          memory: "long_term"
    }
}

Conditional Flows

Flows can contain conditional logic:

flow conditionalFlow {
    step check {
        userInput = "translate"
        sourceText = "Hello, how are you?"
        targetLanguage = "Khmer"

        isValid = sourceText != ""

        if isValid {
            message = "Translate the following text to " + targetLanguage + ": " + sourceText
            prompt message
        } else {
            error = "Invalid input provided"
            prompt "Error: " + error
        }
    }
}

Complex Conditionals

flow complexFlow {
    step decision {
        score = 85

        if score >= 90 {
            grade = "A"
            feedback = "Excellent work!"
        } else if score >= 80 {
            grade = "B"
            feedback = "Good job!"
        } else if score >= 70 {
            grade = "C"
            feedback = "Keep improving!"
        } else {
            grade = "F"
            feedback = "Needs improvement"
        }

        prompt "Your grade is {grade}. {feedback}"
    }
}

Flow Outputs

Flows can define outputs using the output keyword:

flow dataFlow {
    step process {
        data = call csvLoader("data.csv")
        summary = analyzeData(data)
        prompt "Analysis complete"
        output {
            recordCount: data.length,
            summary: summary,
            timestamp: getCurrentTime()
        }
    }
}

Using Flow Outputs

flow parentFlow {
    step callChild {
        result = executeFlow(dataFlow)
        # Access outputs
        count = result.recordCount
        summary = result.summary
        prompt "Processed {count} records. Summary: {summary}"
    }
}

Advanced Patterns

Retry Logic

flow retryFlow {
    step attempt {
        maxRetries = 3
        retryCount = 0
        success = false

        while retryCount < maxRetries && !success {
            try {
                result = call externalAPI()
                success = true
            } catch {
                retryCount = retryCount + 1
            }
        }

        if success {
            prompt "Success: " + result
        } else {
            prompt "Failed after {maxRetries} attempts"
        }
    }
}

Pipeline Pattern

flow dataPipeline {
    step extract {
        rawData = call extractData()
    }

    step transform {
        cleanedData = transformData(rawData)
    }

    step load {
        result = loadData(cleanedData)
        prompt "Pipeline complete. Loaded {result.count} records"
    }
}

Fan-out/Fan-in Pattern

flow fanOutIn {
    step fanOut {
        items = [1, 2, 3, 4, 5]
    }

    parallel step process1 {
        result1 = processItem(items[0])
    }

    parallel step process2 {
        result2 = processItem(items[1])
    }

    parallel step process3 {
        result3 = processItem(items[2])
    }

    step fanIn {
        allResults = [result1, result2, result3]
        prompt "Processed {allResults.length} items"
    }
}

Best Practices

  1. Keep flows focused - Each flow should have a single, clear purpose
  2. Use parallel steps - For independent operations that can run concurrently
  3. Manage state explicitly - Use state to pass data between steps
  4. Use memory for context - When you need to maintain context across prompts
  5. Compose flows - Break complex workflows into smaller, reusable flows
  6. Handle errors - Use conditional logic to handle error cases
  7. Define outputs - Make flow outputs explicit for better composability

Examples

See the examples/ directory for more flow examples:

  • flow-news.ro - Flow composition
  • multi-step-flow.ro - Multi-step workflows
  • parallel-steps.ro - Parallel execution
  • conditional-flow.ro - Conditional logic
  • flow-retry.ro - Retry patterns
  • memory-and-state.ro - Memory and state management