Concurrency
Agency offers a few concurrency primitives.
fork
fork allows you to run multiple branches in parallel and collect all their results. It's like map, but each thread runs concurrently:
node main() {
const countries = ["India", "USA", "Germany"]
const capitals = fork(countries) as country {
return llm(`What is the capital of ${country}?`)
}
}race
race is similar to fork, but instead of waiting for all the branches to finish, it returns as soon as one thread finishes and cancels the other branches.
node main() {
const prompt = "Write me a 100 word story about a talking dog."
const models = ["gpt-4o-mini", "gpt-3.5-turbo", "gemini-3.1-pro-preview"]
const story = race(models) as model {
const _story = llm(prompt, { model: model })
return { model: model, story: _story }
}
printJSON(story)
}parallel and seq
To run multiple functions concurrently, call them all inside a parallel block.
parallel {
functionA()
functionB()
functionC()
}parallel is just syntactic sugar for fork. It's for the common use case of running multiple functions concurrently.
Note that parallel blocks are mostly limited to function calls. You can't run arbitrary code in there.
Inside of a parallel block, if there's some code you want to run sequentially, use a seq block.
parallel {
functionA()
seq {
functionB()
functionC()
}
}In this example:
functionAruns concurrently with theseqblock.functionBruns beforefunctionC.
You can write normal Agency code in seq. Unlike the parallel block, it doesn't have any restrictions.
State isolation across branches
Each branch in Agency gets isolated state. We will cover this more in the state isolation section. For now, you just need to know that if you have a global variable, each thread in fork, race, or parallel will get their copy of that global variable:
const globalVar = 0
fork([1, 2, 3]) as i {
globalVar = globalVar + 1
// Always prints 1
print(globalVar)
}
// prints 0, not 3
print(globalVar)Note that not only did the branches not share globalVar with each other, they didn't even share it with their parent. So all the different changes to that variable were lost after the fork.
Opting into shared state
If you do want the branches to share state, set shared: true:
const globalVar = 0
fork([1, 2, 3], shared: true) as i {
globalVar = globalVar + 1
// Prints 1, 2, or 3 depending on which branch runs first
print(globalVar)
}
// prints 3
print(globalVar)The same option works on race and parallel too.