Sesi Language Specification
1. Philosophy & Design Principles
Sesi is built on these core principles:
- Conciseness and Legibility: The syntax is minimal
- Buildable from Scratch: Sesi is a complete, functioning language with its own lexer, parser, and interpreter.
- Simplicity Enables Power: Because the core language is simple, complex operations (like hitting APIs or orchestrating processes) become trivial extensions of the language, rather than tangled SDK implementations.
- Transparency Over Magic: Sesi executes exactly what you write.
- Practicality: Focus on reducing boilerplate code, emphasizing what developers actually need over academic completeness.
2. Target Users
Primary: Developers who want a clean, fast, and legible language where writing code, whether purely logic-based or calling out to a Reasoning model, is completely frictionless.
Secondary:
- Engineers transitioning from traditional languages (TypeScript, Python, Go)
- Developers looking for minimal boilerplate.
- Teams requiring complex logic with a fraction of the boilerplate
Use Cases:
- Writing clean CLI tools and scripts
- Interacting with APIs without SDK boilerplate
- Quickly orchestrating shell commands
- Rapid prototyping and scripting
3. Feature Set
Core Language Features
- ✅ Variables and bindings (
let) - ✅ Functions (named, anonymous)
- ✅ Class-like object templates (
make) - ✅ Conditionals (
if/else) - ✅ Loops (
while,for) - ✅ Error Handling (
try/catchblocks) - ✅ Data types (number, string, bool, array, object)
- ✅ Process and Desktop Integration (
spawn,exec,open,open_file,time,random,convert,format) - ✅ Comments (
//,/<em> </em>/) — text is preserved in AST asleadingCommentson declarations for doc tooling - ✅ Operators (arithmetic, logical, comparison)
- ✅ Standard library (show, len, range, etc.)
- ✅ Interactive REPL shell environment (
sesi) - ✅ Diagnostic Tools (
--astand--tokenspretty visualization) - ✅ Statement execution tracing (
SESI_DEBUG=1env variable) - ✅
promptblocks (composable templates for concise formatting) - ✅
structured_output()(schema-guided structured output with JSON recovery and empty-object fallback on failure) - ✅
tool_call()(Fully functional function calling for tool use) - ✅
memory(simple multi-turn script memory and retrieval context management)
Reasoning-Native Features
- ✅
model()calls (native model with configuration) - ✅
image()calls (native image generation with configuration) - ✅
imagesconfig key (multimodal vision input formodel()andimage())
Type System
- ✅ Primitive types:
number,string,bool,null - ✅ Collection types:
array<T>,object<T> - ✅ Type inference
- ✅ Union types:
T | U - ✅ Optional types:
T?
Module System
- ✅
import/export - ✅ Lib support
- ✅ Built-in modules
- ✅ Multi-path module resolution (
SESI_PATH,~/.sesi/libglobal library)
4. Target Language (Syntax)
4.1 Lexical Elements
Keywords
let if else while for fn make show import export async
prompt model image convert memory structured_output tool_call break continue try catch true false null await
These words are reserved and cannot be used as binding, function, parameter, template, prompt, memory, or import names. In particular, make is reserved exactly like prompt.
Identifiers & Literals
identifier: [a-zA-Z_][a-zA-Z0-9_]*
number: [0-9]+ | [0-9]*\.[0-9]+
string: "..." | '...'
comment: // ... | /* ... */
String Escapes & Multiline Rules
- Supported escape sequences:
\\n,\\t,\\r,\\\\,\\",\\' - Unknown escape sequences are runtime errors during lexing with line and column context
- Strings can span multiple lines when a literal newline appears before the closing quote
- Unterminated strings report the starting line and column of the string literal
4.2 Program Structure
program := statement*
statement := declaration | expression_statement | block_statement
4.3 Declarations
Variable Declaration
let_stmt := 'let' identifier (':' type)? ('=' expression)? (';' | newline)
Example:
let x = 10
let count: number = 10
let name: string = "Ada"
let y = 20
let z // z is null initially
Function Declaration
fn_stmt := 'async'? 'fn' identifier '(' parameters ')' '->' type? block
parameters := (identifier ':' type ('=' expr)?)? (',' identifier ':' type ('=' expr)?)*
Example:
fn add(a: number, b: number) {show a + b}
fn greet(name: string = "World") {show "Hello," name}
Import/Export
import_stmt := 'import' (identifier | '{' identifiers '}') 'from' string
allow_stmt := 'allow' string 'in' with (identifier | '{' identifiers '}' | string)
export_stmt := 'export' (fn_stmt | let_stmt)
Example:
allow "math" in with {
add, subtract
}
export fn multiply(a, b) {show a * b}
4.4 Control Flow
If Statement
if_stmt := 'if' expression block ('else' block)?
Loops
while_stmt := 'while' expression block
for_stmt := 'for' identifier 'in' expression block | 'for' identifier '=' expr 'to' expr block
Error Handling
try_stmt := 'try' block 'catch' '(' identifier ')' block
Loop Control
break_stmt := 'break'
continue_stmt := 'continue'
Example:
for i = 0 to 10 {show i}
try {
let result = "Hello"
} catch (e) {
show e
}
4.5 Expressions
Literals
literal := number | string | bool | null | array | object
array := '[' (expression (',' expression)*)? ']'
object := '{' (string ':' expression (',' string ':' expression)*)? '}'
Operators (Left to Right, Lowest to Highest Precedence)
expr := assignment
assignment := logical_or ('=' assignment)?
logical_or := pipe ('||' pipe)*
pipe := logical_and ('|' logical_and)*
logical_and := equality ('&&' equality)*
equality := comparison (('==' | '!=') comparison)*
comparison := addition (('<' | '>' | '<=' | '>=' | '<>') addition)*
addition := multiplication (('+' | '-') multiplication)*
multiplication := unary (('*' | '/' | '%') unary)*
unary := ('!' | '-' | 'await') unary | postfix
postfix := primary ('['expression']' | '.'identifier | '('args?')' | primary)*
primary := identifier | literal | '('expression')' | prompt | model | image | convert | memory | call
Object Templates
make_declaration := 'make' identifier '{' make_member* '}'
make_member := let_declaration | function_declaration
make declares a callable, class-like object template. Calling its name
creates a fresh object. start(self, ...) supplies the constructor parameters
and initializes the instance. Every method declares self first; method calls
bind it automatically.
make Person {
let kind = "person"
fn start(self, name) {
self.name = name
}
fn greet(self) {
return "Hello, " + self.name
}
}
let ada = Person("Ada")
show ada.kind
show ada.greet()
Function Call
call := identifier '(' (expression (',' expression)*)? ')'
Prompt Block
prompt := 'prompt' identifier '{'content'}'
content := (string | expression | newline)
Example:
prompt codeReview {"Review this code for bugs: "code" Provide specific issues found."}
Model & Image Calls
model_call := 'model' '('STRING')' config_block? '{'prompt'}'
image_call := 'image' '('STRING')' config_block? '{'prompt'}'
convert := 'convert' '('(identifier | STRING)')' config_block? '{'file'}'
config_block := '{' config_entry (',' config_entry)* '}'
config_entry := (STRING | identifier) ':' expression
Config keys:
| Key | Applies to | Type | Description | ||
|---|---|---|---|---|---|
thinkingLevel |
model |
string \ |
object |
Recommended: Effort level ("minimal", "low", "medium", "high") |
|
temperature |
model, image |
number |
\*Will be deprecated in Gemini 3.x+\_ (Sampling temperature) | ||
max_tokens |
model |
number |
Max output token count | ||
top_k |
model |
number |
\*Will be deprecated in Gemini 3.x+\_ | ||
top_p |
model |
number |
\*Will be deprecated in Gemini 3.x+\_ | ||
ratio |
image |
string |
Aspect ratio e.g. "16:9" |
||
size |
image |
string |
"512", "1K", "2K", "4K" |
||
images |
model, image |
string \ |
array |
Local file path(s) passed as visual input | |
stream |
model |
bool \ |
fn |
Enable real-time streaming to stdout (true) or a callback function |
|
system |
model, image |
string |
Provider-native system instruction |
Example:
let result = model("gemini-3.8-flash") {images: "scan.png", thinkingLevel: "low"} {"Transcribe all visible text."}
let output = model("gemini-3.8-flash") {thinkingLevel: "medium"} {prompt}
Convert Expression
convert := 'convert' '('(identifier | STRING)')' config_block? '{'file'}'
The convert expression transforms documents or media files between different formats (e.g. images, audio, documents).
Config keys:
file_type: The input format extension (e.g."md","csv","png","wav"). If the input is a local file path, this key is optional and can be inferred from the file extension.output_type: The target format extension (e.g."html","json","jpg","mp3"). This key is required.
Native document conversion pairs include md -> html, html -> md, html -> txt, csv -> json, tsv -> json, json -> csv, json -> tsv, json -> yaml, yaml -> json, svg -> html, html -> svg, and svg -> txt.
For image conversion, convert(media) also supports rasterizing svg file inputs to png, jpg, and jpeg, and wrapping raster image files such as png, jpg, jpeg, gif, webp, bmp, tiff, and avif into SVG output.
Example:
let html = convert(doc) {file_type: "md", output_type: "html"} {"# Heading\nHello world"}
let json = convert(doc) {file_type: "csv", output_type: "json"} {"name,age\nAlice,30"}
let yaml = convert(doc) {file_type: "json", output_type: "yaml"} {"[{\"name\":\"Alice\"}]"}
let markdown = convert(doc) {file_type: "html", output_type: "md"} {"<h1>Heading</h1><p>Hello world</p>"}
let converted_file = convert(doc) {file_type: "md", output_type: "html"} {"input.md"}
let rasterized_svg = convert(media) {output_type: "png"} {"logo.svg"}
Await Expression
await_expr := 'await' expression
The await expression is used to block execution and resolve the value of a Sesi Promise returned by an asynchronous function.
Example:
async fn getGreeting(name) {
return "Hello, " + name
}
let p = getGreeting("Alice") // returns a Sesi promise
let greeting = await p // blocks and resolves to "Hello, Alice"
Structured Output
structured_output := 'structured_output' '('schema')' '('expression')'
schema := '{' (identifier ':' type (',' identifier ':' type)*)? '}'
Example:
let rawJson = "{\"projectName\": \"Sesi\", \"version\": \"1.9.0\", \"status\": \"active\"}"
let parsedRegistry = structured_output({projectName: string, version: string, status: string})(rawJson)
Tool Call
The tool_call expression allows native Sesi functions registered via define_tool to be invoked programmatically.
// 1. Define the native Sesi function
fn calculateTax(amount: number, rate: number) -> number { return amount * rate }
// 2. Register the function as a tool
define_tool("calculateTax", calculateTax, "Calculate tax based on amount and rate")
// 3. Invoke the tool programmatically
let taxAmount = tool_call(calculateTax)(100, 0.08)
The tool invocation is synchronous and executes the registered function within the current interpreter context. This mechanism can be used by AI agents to perform side-effects, but it functions independently as a core language primitive.
Registered functions can also be orchestrated automatically by a model call:
let answer = model("gemini-3.8-flash") {tools: list_tools(), max_tool_calls: 4} {"What is 8% tax on $125?"}
tools accepts registered tool names, registered function values, provider schemas, or true for every registered tool. For registered tools, Sesi derives parameter schemas from type annotations, maps model-supplied named arguments to function parameters, executes the function, and resumes the model with the result. This repeats until the model returns text. max_tool_calls defaults to 8; exceeding it raises a runtime error. Automated calls to sensitive system functions remain forbidden.
Pipe Operator
The pipe operator | passes the result of the left expression as the first argument to the function call on the right.
pipe_expr := expression '|' function_call_or_identifier
Example:
fn increment(x) { return x + 1 }
fn double(x) { return x * 2 }
let result = 5 | increment | double // evaluates to 12
Rule of Thumb:
Use | for data pipelines: arrays, strings, objects, or multi-step transformations (data | filter | map | show).
Use standard syntax () for math, boolean logic (!, &&, ||), comparisons (==, !=), and inline checks.
Memory (State Management)
memory := 'memory' identifier ('{'expressions'}')?
Example:
memory conversation {"Previous messages here..."}
let userInput = "New message added."
let response = model("gemini-3-flash-preview") {conversation "New question: "userInput}
conversation = conversation + "Assistant:" + response
Memory bindings automatically compact after an update when their estimated token count exceeds the configured budget. Older content is summarized while a recent tail remains verbatim:
memory conversation {"System: Preserve project decisions."}
memory_config("conversation", {"max_tokens": 8000, "target_tokens": 4800, "summary_model": "gemini-3.5-flash-lite"})
max_tokens defaults to 900000, target_tokens defaults to 60% of that limit, and automatic summarization is enabled by default. A failed summary leaves the original memory unchanged. memory_trim() remains available for explicit compaction.
4.6 Type Annotations
type := primitive_type | collection_type | union_type | optional_type
primitive_type := 'number' | 'num' | 'string' | 'str' | 'bool' | 'null' | 'any'
collection_type := 'array' '<' type '>' | 'object' '<' type '>'
union_type := type ('|' type)
optional_type := type '?'
Type aliases: num is an alias for number, str is an alias for string, and any accepts any value. These can be used interchangeably in function signatures, variable annotations, and return types.
Variable annotations go between the variable name and =. They are optional, so either of these declarations is valid:
let total: number = 42
let label = "draft"
5. Expression Evaluation Rules
- Short-circuit evaluation:
&&and||short-circuit - Type coercion: Automatic for numeric operations; explicit for string/number
- Null propagation: Operations on
nullreturnnull(no exceptions in v1.x) - Model responses: Always returned as strings initially; structured_output provides type safety
6. Scope and Binding
- Global scope: Module level
- Function scope: Within function definitions
- Block scope: Within blocks (if/while/for)
- Lexical scoping: Inner scopes shadow outer scopes
- Closure support: Functions capture enclosing scope
7. Runtime Semantics
Execution Order
- Tokenize (lexer)
- Parse (parser) → AST
- Evaluate (interpreter)
- Model calls are blocking (no async in v1)
Memory Model
- Stack: Local variables, function parameters
- Heap: Arrays, objects, strings
- Reasoning Context: Implicit conversation history per
memorybinding
Error Handling (V1 Simple)
- Runtime and model errors can be caught with
try/catch - Model errors throw when Gemini returns no text or a non-
STOPfinish reason read_file(),write_file(),list_dir(),open(), andopen_file()throw on filesystem or launch failurestructured_output()currently logs parsing failures and returns{}if recovery fails
Desktop Launching
open() and open_file() hand a target to an external desktop application and return true after the operating system accepts the launch request. They do not wait for the application to exit.
open("https://code-with-sesi.netlify.app")
open("reports/dashboard.html", {mode: "browser", browser: "Firefox"})
open_file("README.md", {editor: "Visual Studio Code"})
open_file("favicon.png", {viewer: "Preview"})
Both functions are disabled in safe mode and require sesi -l or sesi --local.
open(target, options?) accepts an http, https, ftp, file, or mailto URL. When its target is not a URL, it behaves like open_file() and resolves an existing local path through the filesystem safety checks. open_file(path, options?) accepts only an existing local path.
The optional settings object supports:
| Key | Type | Meaning | |
|---|---|---|---|
browser |
string |
Preferred browser application | |
editor |
string |
Preferred text editor application | |
viewer |
string |
Preferred viewer application | |
image_viewer |
string |
Alias for viewer |
|
mode |
string |
"auto", "browser", "editor", "viewer", or "image_viewer" |
In "auto" mode, Sesi uses the requested image viewer for image extensions, the requested editor for text extensions, or the requested browser for browser-friendly extensions. If no matching application is specified, the operating system default is used.
8. Built-in Functions
show(any) // Output to stdout
debug() // Pauses and opens interactive REPL debugger
len(array | string | object) // Length
range(number) -> array // [0, 1, ..., n-1]
type(any) -> string // Type name
str(any) -> string // Convert to string
num(any) -> number // Convert to number
float(any) -> number // Convert to floating-point number
bool(any) -> bool // Convert to bool
keys(object) -> array // Object keys
values(object) -> array // Object values
push(array, any) // Add element
append(array|string, any) // Append to array or concatenate to string
pop(array) -> any // Remove last
join(array, string) -> string // Join with separator
split(string, string) -> array // Split by separator
regex(string, string, string|object?) -> array|bool|string // Regular-expression operations
tokenize(string, string|object?) -> array // Local OpenAI-compatible token IDs
count_tokens(string, string|object?) -> number // Native OpenAI/Gemini request count
estimate_tokens(string, string|object?) -> number // Explicit local approximation
estimate_cost(string, number|string, number|string?, object?) -> object // Token cost estimate
model_usage() -> object|null // Latest provider-reported usage and estimated cost
gif(string|array, string, object?) -> string // FFmpeg-backed animated GIF creation
video(string) {object?} {expression} -> string // AI video generation; returns Base64 MP4
video(string|array, string, object?) -> string // FFmpeg-backed video creation/transcoding overload
ffmpeg(array, object?) -> object // Structured raw FFmpeg invocation
matrix_dot(array, array) -> array // Native rectangular matrix multiplication
matrix_transpose(array) -> array // Native matrix transpose
matrix_add(array, array) -> array // Native addition with single-row bias broadcasting
matrix_sub(array, array) -> array // Native same-shape subtraction
matrix_mul_elements(array, array) -> array // Native elementwise multiplication
matrix_scale(array, number) -> array // Native scalar multiplication
matrix_sigmoid(array) -> array // Native elementwise sigmoid
matrix_dsigmoid(array) -> array // Native sigmoid-output derivative
matrix_sum_rows(array) -> array // Native column sums as a single-row matrix
matrix_mse(array, array) -> number // Native mean squared error
to_upper(string) -> string // Convert to uppercase
to_lower(string) -> string // Convert to lowercase
trim(string) -> string // Trim whitespace
slice(collection, number, number?) -> collection // Slice string or array
swap(string, string, string) -> string // Replace all target substrings
contains(string, string) -> bool // Check if string contains substring
locate(string, string) -> number // First index of substring, or -1
map(array, fn) -> array // Transform array elements
filter(array, fn) -> array // Filter array elements
reduce(array, fn, any?) -> any // Accumulate array elements
find(array, fn) -> any // Find matching element
retry(fn, number | object) -> any // Execute function with retry and backoff
lazy(fn, ...args) -> lazy // Create a memoized delayed computation
force(any) -> any // Resolve lazy values and promises
timeout(fn, number, any?) -> any // Run function with millisecond deadline
profile(string, fn) -> any // Measure function runtime and return its result
profile_start(string) -> string // Begin manual profiling section
profile_end(string) -> object // End manual profiling section
profile_report(string?) -> array | string // Return profiler measurements
read_file(string, string?) -> string // Read file contents (text or base64)
encrypt(string, string) -> string // AES-256-CBC encrypt UTF-8 string content
decrypt(string, string) -> string // AES-256-CBC decrypt iv:ciphertext content
write_file(string, string) -> bool // Write file contents
append_file(string, string) -> bool // Append string content to file
write_image(string, string) -> bool // Write base64 image data to file
open(string, object?) -> bool // Open URL or local file in external app; local mode only
open_file(string, object?) -> bool // Open existing local file in external app; local mode only
list_dir(string) -> array<string> // List directory contents
make_dir(string) -> bool // Create directory (recursive)
spawn(string) -> number // Concurrent process creation
exec(string) -> string // Synchronous shell execution
run(string) -> string // Exact alias of exec
get_ext(string) -> string // Lowercase extension without a dot
exists(string) -> bool // Sandbox-aware path existence check
zip(source, destination?, operation?) // Create, list, or extract archives
sesi(string, bool?, bool?) -> string // Synchronous in-process Sesi execution or compile check
python(string, args) -> string // Inline Python code execution
js(strings, args) -> string // In-proccess Javascript execution
time() -> number // Current Unix timestamp
random() -> number // Random float (0.0 to 1.0)
trunc(value, number?) -> any // Truncate number (integer part) or string (char limit)
convert() -> bool // Convert between formats
memory_search(string, string, number?) -> array // Semantic similarity search over memory entries
memory_config(string, object?) -> object // Configure automatic memory summarization
memory_trim(string, number?) -> string // Context window management with auto-summarization
Built-in Global Variables
args
9. Module System
Runtime module execution and standard library modules are fully implemented and natively supported in v1.x.
Defining Modules
// math.sesi
export fn add(a, b) {show a + b}
export fn multiply(a, b) {show a * b}
export let PI = 3.14159
Importing Modules
You can import variables and functions from other modules using traditional import or the scoped library allow syntax:
// Option 1: import named bindings directly
import {
add,
multiply,
PI
} from "math"
let result = add(10, 20)
// Option 2: allow module to bind under a scoped library namespace
allow "math" in as Math
let result = Math.add(10, 20)
// Option 3: allow module to bind specific names directly
allow "math" in with {
add, multiply
}
let result = add(10, 20)
Built-in Standard Library Modules
allow "std/time" in as Time // Time/date functions
allow "std/math" in as Math // Math operations
// JSON conversion uses the built-in from_json and to_json functions.
allow "std/draw" in as Draw // SVG/Pixel creation
allow "std/audio" in as Audio // Audio synthesis
allow "std/theory" in as Music // Music Theory
allow "std/terminal" in as Term // Terminal options
allow "std/base64" in as Base64 // Base64 encode/decode
allow "std/api" in as API // FastAPI-style HTTP API framework
allow "std/game" in as Game // Babylon-powered 3D desktop games (optional package)
std/game is an imperative native-object module. Scenes use left-handed coordinates with Y up, +X right, and +Z forward. Development-time relative asset paths and build outputs resolve from the current working directory; packaged assets resolve from the staged application root. Member reads and writes on handles are dispatched through guarded native hooks in both execution engines. Handles preserve identity, enumerate only allowlisted properties, reject protected prototype names, and raise typed errors for disposed, read-only, or cross-scene access. Development execution and desktop builds require -l; the optional runtime is installed with npm install @misterscan/sesi-game. See getting-started/GAME.md.
Module Resolution Order (v1.x)
When you write allow "mymodule" in with {x} , Sesi searches for mymodule.sesi in the following order, stopping at the first match:
| Priority | Location | Description | |
|---|---|---|---|
| 1 | Script's own directory | Same folder as the currently running .sesi file |
|
| 2 | Current working directory | The directory you ran sesi from |
|
| 3 | SESI_PATH |
Semicolon-separated (Windows) or colon-separated (Unix) list of additional directories | |
| 4 | ~/.sesi/lib |
Global shared library directory — available system-wide |
This means imports always resolve correctly regardless of where you run sesi from.
Global Library: ~/.sesi/lib
The global library directory (C:\Users\<you>\.sesi\lib on Windows, ~/.sesi/lib on Unix) lets you maintain shared modules that are importable from any project on your system.
To install a module globally, copy it to the lib directory:
# Windows
copy mymodule.sesi $env:USERPROFILE\.sesi\lib\
# Unix / macOS
cp mymodule.sesi ~/.sesi/lib/
Then import it from any project without copying the file:
// Works from any folder anywhere on your system
allow "mymodule" in with {
function1,
function2,
function3
}
allow "another-module" in as Name
Custom Library Paths: SESI_PATH
For team or monorepo setups, set the SESI_PATH environment variable to point to one or more shared library directories:
# Windows — add to your shell profile for persistence
$env:SESI_PATH = "C:\MyLibs\sesi-shared;C:\Projects\common"
# Unix / macOS
export SESI_PATH="/mylibs/sesi-shared:/projects/common"
Multiple paths are separated by ; on Windows and : on Unix.
Sub-module Resolution
When a module is loaded from any search path, its own imports are resolved relative to that module's directory first. This means modules can safely import their own siblings without any path configuration.
10. Reasoning Features Details
Prompt Blocks
Prompts are composable message templates:
prompt generate {"Craft a full report on the following: "sourceText}
prompt summarize {"Summarize this in 3 sentences: "sourceText}
prompt combined {summarize" Now "generate}
Model & Image Calls
Model calls can take optional configuration parameters (written on a single line) followed by one or more prompts/strings.
// Model call with native thinking effort level
let response = model("gemini-3.8-flash") {thinkingLevel: "low"} {"Say hello"}
show response // Returns string
let logo = image("gemini-3.1-flash-image") {ratio: "1:1", size: "512"} {"A vector logo"}
write_image("logo.png", logo)
show "Image written to logo.png"
Config Block Options:
thinkingLevel:string("minimal","low","medium","high") or legacyobjectwith keys"thinking"and"level". Natively configures Gemini's reasoning budget.max_tokens:number(maximum response tokens)images:stringorarray<string>(paths to multimodal vision input files)cache:bool(set tofalseto explicitly bypass Sesi Logic Caching)stream:bool | fn(set totrueto stream tokens to standard output, or pass a Sesi function reference to handle incoming chunks)temperature: Will be deprecated in Gemini 3.x+, use thinkingLevel instead. — reasoning is pre-optimized for defaults.top_k/top_p: Will be deprecated in Gemini 3.x+, use thinkingLevel instead. — reasoning is pre-optimized for defaults.
Speech and Transcription
Sesi provides built-ins for spoken output and transcription.
speech("Analysis complete")
let transcript = from_speech("interview.wav", "en")
show transcript
speech(text, voice = null, gemini_model = null)speaks through the operating system's local voice tool, or uses the optional Gemini model.from_speech(audio_path, language = null, gemini_model = null)transcribes withnodejs-whisper, or the optional Gemini model.
Reasoning with Structured Output
let result = structured_output({title: string, category: string, confidence: number})
(model("gemini-3.5-flash-lite") {"Extract metadata from this text: "text})
show result.title // Access fields
show result.confidence // Type-safe access
Reasoning with Tool Calling
While tool_call() is a core language feature, it is the primary interface for AI agents to interact with your Sesi scripts. When an agent is given access to tools, it can decide to invoke them based on its reasoning process.
fn calculateTax(amount: number, rate: number) -> number { return amount * rate }
// Register as a tool
define_tool("calculateTax", calculateTax, "Calculate tax based on amount and rate")
// Agent-driven usage:
// The model decides to invoke 'calculateTax' with specific parameters
let taxAmount = tool_call(calculateTax)(model("gemini-3.5-flash-lite") {"Extract tax amount and rate from text"}, 0.08)
Reasoning with Memory
memory chat {"System: You are a helpful assistant."}
fn askQuestion(question: string) {
let response = model("gemini-3-flash-preview") {chat "User:" question}
chat = chat + "Assistant:" + response
return chat
}
11. Examples
Example 1: Simple Computation
let x = 10
let y = 20
show x + y // Output: 30
Example 2: Function with Reasoning
let text = "Reasoning is transforming industries!"
fn analyzeText(text: string) -> string {return model("gemini-3.8-flash") {thinkingLevel: "low"} {"Analyze this text and return key insights: "text}}
show analyzeText()
Example 3: Reasoning with Structured Output
let userInput = "I love working with Sesi!"
let sentiment = structured_output({label: string, score: number})(model("gemini-3-flash-preview") {"Analyze sentiment of: "userInput})
show sentiment.label
show sentiment.score
12. Undefined Behavior & Limitations
- No custom types: Only built-in types are supported natively.
- No pattern matching: Basic if/else only.
- No generics: Array and object collections are untyped at runtime.
- Limited introspection: Basic type() only.
- No macros: No compile-time code generation.
- Single-threaded runtime: Execution per script event loop is single-threaded. System-level concurrency is handled via multi-process
spawn(). - No garbage collection tuning: Rely on Node.js GC.
13. Compatibility Notes
- Sesi programs run on Node.js 20+, using local models relies on Node.js 22+
- Requires
@google/genaiSDK v2.0.1+ - Requires valid Gemini API key (GEMINI_API_KEY env var)