Syntax and dynamic strings

Agents are written in JSONC (JSON with comments), plus one extension: a string enclosed in braces is a Python expression, called a dynamic string.

Dynamic strings

A string value enclosed in { ... } is evaluated at runtime as a Python expression in the agent's execution context. The result of the expression replaces the string. The result can be of any Python type: a number, a list, a dict, an object. Any other string is a literal. A string that may be either a literal or an expression is called a dynamic string.

Dynamic strings in a var command
"var": {
  "greeting": "Hello, world!",                       // a literal
  "now": "{ datetime.now().isoformat() }",           // datetime must be in the allowlist
  "weather": "{ f'{city}: {temperature}' }",         // f-strings are common
  "squares": "{ [n * n for n in numbers] }",
  "square_map": "{ {n: n * n for n in numbers} }",
  "profile1": "{ await fetch_url_profile(user_id) }",
  "profile2": "{ fetch_user_profile(user_id) }",     // an async function is awaited automatically
  "lines": "{ [line async for line in stream_lines(url)] }"
}

What an expression can use

  • Variables set earlier in the same function, and the function's arguments.
  • Agent and conversation variables set earlier, as agent.x and conv.x. See Variables and namespaces.
  • The read-only sys and command namespaces, and the inputs, query, result and exc variables. See Variables and namespaces.
  • Functions and objects on the allowlist, and the public members of allowlisted objects.

Nothing else is available. Names that are not on the allowlist, private and dunder members, and import are all unavailable. The rules are set out in Allowlist and Compile rules.

Awaiting

When the whole expression is a call to an async function, the result is awaited automatically, so await is optional there. Inside a larger expression, an async call must be awaited explicitly. To run several calls at once, use the parallel command.

Characters

Expressions are ASCII. Non-ASCII characters are rejected inside braces; they are fine in literal strings. A string that starts with a brace is treated as an expression only when the string also ends with a closing brace. To keep a leading brace literal, make sure the string does not end with a closing brace.

Comments

Line comments (//) and block comments (/* */) are allowed anywhere. Comments are stripped when the draft is validated.