.lm File Syntax¶
Lamia .lm files use a hybrid Python syntax that lets you write LLM commands, file operations, and web actions as regular function definitions. Lamia syntax can be combined with normal Python code. So you get the power of Python combined with human-friendly syntax for LLM commands and other operations needed for daily tasks by non-technical users. You can run Lamia scripts with:
The execution flow¶
Lamia detects its own syntax and executes through its engine, the rest of the code is executed as normal Python code. Here are some function definitions that will be executed by Lamia:
# LLM command — plain text goes to the AI
def generate_story():
"Write a short story about a robot discovering emotions"
# File read — paths are read from disk
def read_config() -> JSON:
"./config.json"
# Web request — URLs trigger HTTP requests
def fetch_data() -> JSON:
"https://api.example.com/data"
Users must be careful, because unlike Python, Lamia functions must skip return statements. See the example below:
# The return statement makes this a Python function which returns the string "Write a short story about a robot discovering emotions"
def generate_story():
return "Write a short story about a robot discovering emotions"
# This function is a Lamia function which sends the string "Write a short story about a robot discovering emotions" to the AI.
def generate_story():
"Write a short story about a robot discovering emotions"
Lamia uses -> syntax to return data. In Python -> is used to define the return type of the function. In Lamia it is used to actually return a value or stream data.
Return Types¶
Without return types, Lamia feels incomplete. Return type markers are more than markers, they are extractors and validators at runtime. Here is an example of how to use return types:
def get_data() -> JSON:
"./users.json" # Must be valid JSON - otherwise the function will fail
def generate_page() -> HTML:
"Create a login form" # Must be valid HTML - otherwise the function will fail
def plain_text() -> TEXT:
"Write a summary" # No validation, just extraction
Available types: HTML, JSON, YAML, XML, Markdown, CSV, TEXT
Simplified Syntax¶
For one-line functions, defining functions seems like overkill sometimes. That is why Lamia provides a simplified syntax. The functions we wrote above can be shortened to:
But for these executions we won't be able to catch the result of the function. We need to assign the result to a variable.
data = "./users.json" -> JSON:
page = "Create a login form" -> HTML:
summary = "Write a summary" -> TEXT:
But if we are not interested in catching the values and we want to save the execution result to a file, we can use the -> File(...) syntax.
"./users.json" -> File(JSON, "users.json"):
"Create a login form" -> File(HTML, "login.html"):
"Write a summary" -> File(TEXT, "summary.txt"):
Model Selection¶
Instead of simplified syntax, we need function definitions if we want to execute the function later, execute many times in different parts of the script, etc.
There is however a very important reason to use function definitions: model selection. All LLM commands in Lamia scripts use the global model chain coming from the config.yaml file mostly. But for some LLM commands users might need to use different models and even model chains. Here are examples of how to use model selection:
def analyze(models="openai:gpt-4"):
"Analyze the data"
def with_fallback(models=["openai:gpt-4", "anthropic:sonnet-4"]):
"Generate a report with model fallback"
# Same as above but gpt-4 will be retried twice before falling back to sonnet-4
def with_fallback(models=["openai:gpt-4", 'openai:gpt-4', "anthropic:sonnet-4"]):
"Generate a report with model fallback"
Variable substitution¶
Variable substitution is a feature that allows you to use variables in your LLM prompts, web actions and file operations. Example:
def stock_data(ticker: str = "AAPL") -> File(CSV[StockQuote], "stocks.csv", append=True):
"extract the stock quote data https://finance.yahoo.com/quote/{ticker}"
for ticker in ["AAPL", "NVDA", "GOOG"]:
stock_data(ticker)
# Or with simpler syntax
for ticker in ["AAPL", "NVDA", "GOOG"]:
"extract the stock quote data https://finance.yahoo.com/quote/{ticker}" -> File(CSV[StockQuote], "stocks.csv", append=True)
File Operations¶
Reading Files¶
Use relative or absolute paths:
def read_data():
"./data/input.txt"
def load_settings() -> JSON:
"../config/settings.json"
def read_logs():
"/var/log/application.log"
In addition, Lamia's file action API can be used:
Writing to Files¶
As we have seen, the -> File(...) syntax can be used to save the execution result to a file. For complex file operations:
# With type validation
def generate_page() -> File(HTML, "output.html"):
"Generate an HTML page about cats"
# Without type validation
def generate_text() -> File("output.txt"):
"Generate some text"
# Append instead of overwrite
def add_rows() -> File(CSV, "data.csv", append=True):
"Generate additional CSV rows"
# Custom encoding
def generate_latin() -> File("output.txt", encoding="latin-1"):
"Generate text with special characters"
File Context (with files())¶
Reference local files in LLM prompts using {@filename} syntax:
with files("~/Documents/"):
def answer_question(question: str, models="openai:gpt-4"):
"""
Answer: {question}
Use information from {@resume.pdf} and {@cover_letter.txt}
"""
Files are resolved using smart search (exact match, content grep, fuzzy matching). PDF and DOCX are automatically extracted to text.
{@resume.pdf} # Search indexed directories
{@/Users/me/Documents/resume.pdf} # Absolute path
{@resum.pdf} # Fuzzy match → resume.pdf
{@config} # Finds config.yaml, config.json, etc.
Multiple directories and nested contexts:
with files("~/Documents/", "~/projects/"):
with session("job_application"):
def fill_form(models="openai:gpt-4"):
"Fill the form using {@resume.pdf}"
For full details see the File Context Reference.
Imports¶
Lamia avoids explicit imports. All Lamia types and interfaces are available without any import statements. But if you mix it with Python code, you will import Python dependencies as usual.
Because of implicit imports, IDEs will show warnings on some Lamia commands. They need to be ignored if the syntax is correct.
Session Management¶
Use with session() for multi-step workflows that persist across runs:
def login_to_site():
with session("login"):
web.navigate("https://example.com/login")
web.type_text("#username", "your_username")
web.type_text("#password", "your_password")
web.click("#login-button")
# Always runs — session block is skipped if already completed
web.navigate("https://example.com/dashboard")
First run: executes the block, saves session on success. Subsequent runs: detects valid session, skips the block.
Sessions are stored in .lamia_sessions/. Clear with rm -rf .lamia_sessions/.
Web Actions¶
Use the web object for browser automation:
web.navigate("https://example.com")
web.click("#login-button")
web.type_text("#username", "user@example.com")
text = web.get_text(".result")
web.wait_for(".loading", "hidden")
web.screenshot("page.png")
Scoped elements:
modal = web.get_element("div.modal")
modal.click("button.close")
fields = web.get_elements("div.form-field")
for field in fields:
label = field.get_text("label")
field.type_text("input", "answer")
Parameters and Models¶
Parameter Substitution¶
Advanced: Async and Parallel Execution¶
Functions can be defined as async and executed in parallel: