Basic syntax
Hello and welcome! Agency is a language for building agents, or any other type of system that is complex, hard to debug, and involves non-deterministic outputs. But before you read about that, let's take two minutes to quickly cover installation and syntax.
Agency is a language that compiles down to TypeScript or JavaScript. It borrows its syntax from these languages, if you have used either JS or TS before, a lot of Agency will be familiar to you.
Note: I'll just say TypeScript everywhere, because writing "TypeScript or JavaScript" gets really boring, but you'll know that I mean both.
You've got primitives: strings, numbers, booleans:
const name: string = "Alice"
const age: number = 30
const isAgent: boolean = trueYou can define variables with let or const. You can add type annotations, just like TypeScript.
You can define arrays and objects:
const names: string[] = ["Alice", "Bob", "Charlie"]
const person: { name: string, age: number } = { name: "Alice", age: 30 }You can define functions:
def greet(name: string): string {
return `Hello, ${name}!`
}You can use if statements, while loops and for loops:
if (age > 18) {
print("You are an adult.")
} else {
print("You are a minor.")
}
while (age < 100) {
print(`You are ${age} years old.`)
age = age + 1
}
for (name in names) {
print(name)
}You can have single-line or multi-line comments.
// This is a single-line comment
/*
This is a multi-line comment
*/Or doc comments for documentation generation:
/** This is a doc comment for the Person type */
type Person = {
name: string
age: number
}You can also write a module-level doc comment using the @module tag. This documents the file itself and appears at the top of the generated documentation:
/** @module
This module provides utilities for working with dates.
*/Note: comments must be on their own line, they cannot be at the end of a line containing code.
Regexes are also supported as a primitive:
// you must use the `re` prefix:
const regex = re/(foo|bar)/
// Use the =~ operator to test if a string matches a regex:
if (name =~ re/^A/) {
print("Your name starts with A!")
}
// or !~ to test if it doesn't match:
if (str !~ regex) {
print("The string does not match the regex.")
}Array slice syntax is supported:
let arr = [1, 2, 3, 4, 5]
const sliced = arr[1:4] // sliced is [2, 3, 4]
const slicedToEnd = arr[2:] // slicedToEnd is [3, 4, 5]
const slicedFromStart = arr[:3] // slicedFromStart is [1, 2, 3]
const negativeSlice = arr[-3:-1] // negativeSlice is [3, 4]
arr[:3] = [10, 20, 30] // arr is now [10, 20, 30, 4, 5]Unit literals
Agency supports unit literals for time, cost, and size values. They compile to plain numbers at compile time:
// time
const timeout = 30s // compiles to 30000 (milliseconds)
const delay = 500ms // compiles to 500
const duration = 2h // compiles to 7200000
const week = 1w // compiles to 604800000
// cost
const budget = $5.00 // compiles to 5.00
// size
const size = 100KB // compiles to bytes
const mediumSize = 500MB // compiles to bytes
const bigSize = 2GB // compiles to bytesSupported time units: ms (milliseconds), s (seconds), m (minutes), h (hours), d (days), w (weeks). All time units normalize to milliseconds.
Supported cost units: $ (dollars).
Supported size units: kb (kilobytes), mb (megabytes), gb (gigabytes). Case insensitive. All size units normalize to bytes.
Unit math works because both sides normalize to the same base unit:
1s + 500ms // 1000 + 500 = 1500
2s * 3 // 2000 * 3 = 6000
if (elapsed > 30s) { ... }Mixing dimensions is a type error:
1s + $5.00 // ERROR: cannot add time and costReserved names
Identifiers beginning with two underscores (__name) are reserved for the compiler and runtime. The codegen uses this prefix for plumbing identifiers like __ctx, __stack, and __call, and the __internal_ prefix for context-injected stdlib builtins. Do not define functions, variables, or globals whose names start with __ — your code may compile today but collide with a future internal addition.
Destructuring and pattern matching
Array and object destructuring work in let / const declarations and in for loops:
let [a, b, ...rest] = items
let { name, age } = person
for ({ name, age } in users) { ... }The is operator, optional guards on match arms, and full pattern matching are documented in the Pattern matching guide.
JavaScript features that don't exist in Agency
- lambdas
- async/await. Everything is awaited by default, and there are specific constructs for concurrency.
- classes.