Flows are Rohas' way of organizing multi-step workflows with state management, parallel execution, and memory.
- Basic Flows
- Flow Steps
- Parallel Execution
- Flow Composition
- State Management
- Memory in Flows
- Conditional Flows
- Flow Outputs
A flow is a named block that contains one or more steps:
flow myFlow {
step first {
prompt "First step"
}
step second {
prompt "Second step"
}
}
flow greetUser {
step welcome {
name = "Alice"
prompt "Welcome, " + name + "!"
}
step personalize {
prompt "How can I help you today, " + name + "?"
}
}
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"
}
}
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"
}
}
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"
}
}
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"
}
}
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 baseFlow {
step initialize {
config = loadConfig()
}
}
flow extendedFlow {
uses baseFlow
step process {
# 'config' from baseFlow is available
result = processWithConfig(config)
}
}
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 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 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" }
}
}
short_term- Memory for the current flow executionlong_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"
}
}
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
}
}
}
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}"
}
}
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()
}
}
}
flow parentFlow {
step callChild {
result = executeFlow(dataFlow)
# Access outputs
count = result.recordCount
summary = result.summary
prompt "Processed {count} records. Summary: {summary}"
}
}
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"
}
}
}
flow dataPipeline {
step extract {
rawData = call extractData()
}
step transform {
cleanedData = transformData(rawData)
}
step load {
result = loadData(cleanedData)
prompt "Pipeline complete. Loaded {result.count} records"
}
}
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"
}
}
- Keep flows focused - Each flow should have a single, clear purpose
- Use parallel steps - For independent operations that can run concurrently
- Manage state explicitly - Use state to pass data between steps
- Use memory for context - When you need to maintain context across prompts
- Compose flows - Break complex workflows into smaller, reusable flows
- Handle errors - Use conditional logic to handle error cases
- Define outputs - Make flow outputs explicit for better composability
See the examples/ directory for more flow examples:
flow-news.ro- Flow compositionmulti-step-flow.ro- Multi-step workflowsparallel-steps.ro- Parallel executionconditional-flow.ro- Conditional logicflow-retry.ro- Retry patternsmemory-and-state.ro- Memory and state management