13. Funzioni built-in
Questo capitolo è il catalogo della stdlib: conversioni, math, stringhe, file, JSON, date e helper di errore. I tool degli agenti, i piani di task, le operazioni dei workflow durevoli e ui.* sono indicizzati in fondo al capitolo e documentati nei rispettivi capitoli di origine.
13.1 Conversioni di tipo
var num = int("123"); // Convert string to integer
var floatVal = float("3.14"); // Convert string to float
var str = string(42); // Convert number to string
13.1.1 Helper di conversione intera sicura
Usa questi helper quando l'input può essere vuoto, null o malformato.
var page = toIntOr(query.page, 1); // Fallback when null/empty/unparseable
var limit = toIntOr(query.limit, 50); // Always returns integer
var ownerId = toIntOrNull(query.ownerId); // Returns null when missing/unparseable
toIntOr(value, fallback)- restituisce l'intero analizzato quando possibile, altrimentifallback.toIntOrNull(value)- restituisce l'intero analizzato onullquando il valore è null/vuoto/non analizzabile.- Entrambe le funzioni accettano valori interi, float, boolean e stringhe numeriche.
13.2 Namespace della stdlib e alias piatti
La maggior parte della libreria standard è raggiungibile in due forme: una chiamata namespaced tramite un oggetto modulo, e un globale piatto con lo stesso nome. Entrambe risolvono la stessa implementazione e si comportano in modo identico a runtime.
print(math.sqrt(16)); // namespaced
print(sqrt(16)); // flat alias, same result
print(str.join(str.split("a,b", ","), "|")); // a|b
print(io.readFile("config.json"));
Gli oggetti modulo
| Modulo | Copre |
|---|---|
math | Arrotondamento, trigonometria, aggregati, helper random, math per LLM e le costanti math.PI, math.E, math.TAU, math.INF, math.NaN |
str | Maiuscole/minuscole, trimming, split e join, padding, helper regex, similarità, base64, md5 / sha256 |
io | print, input, helper per file e path, glob, grep, variabili d'ambiente, helper git |
pdf | extractText — legge il testo da un file PDF (livello di testo digitale; nessun OCR) |
doc | extractText — legge il testo da un Word .docx (Open XML; non il .doc legacy) |
result | ok, err, map, unwrapOr, isOk, isErr — vedi 13.19.1 |
option | some, none, map, unwrapOr, isSome, isNone — vedi 13.19.1 |
Math (M maiuscola) è un alias deprecato per lo stesso oggetto di math.
Quali nomi piatti sono deprecati
Solo i nomi piatti che hanno una controparte math., str. o io. sono considerati alias deprecati. Chiamarne uno produce un warning nell'IDE e nel language server dalla sorgente malda-style, nella forma Prefer 'io.print(...)' instead of 'print(...)' (deprecated flat alias). Il warning è solo un avviso: a runtime non viene rimosso nulla e i transpiler accettano entrambe le forme.
I nomi interessati, che rispecchiano MaldaLang/BuiltIns/StdLibNamespaces.cs:
- math:
abs,sum,average,max,min,pow,sqrt,floor,ceil,round,trunc,sign,exp,log,log10,log2,sin,cos,tan,asin,acos,atan,atan2,hypot,clamp,degToRad,radToDeg,rsqrt,randn,argmax,argmin,logSumExp,softmax,crossEntropyFromLogits,randomChoiceWeighted,seed,random,randomInt,randomFloat - str:
length,upper,lower,trim,text,trimText,substring,indexOf,replace,split,normalizeText,tokenize,tokenOverlap,similarity,extractNumbers,regexMatch,regexReplace,regexFind,startsWith,endsWith,padStart,padEnd,includes,join,repeat,base64Encode,base64Decode,md5,sha256 - io:
print,input,readFile,writeFile,readFileBase64,writeFileBase64,readTextFileLines,deleteFile,hasFile,hasDirectory,ensureDir,listDirectory,hasEmbeddedFolder,embeddedFolderRoot,glob,grep,replaceInFile,pathExists,pathJoin,pathNormalize,pathGetExtension,isPathUnder,getEnv,getEnvOr,hasEnv,getFileName,getDirectoryName,gitStatus,gitAdd,gitCommit,gitDiff,gitLog,gitBranch,gitCheckout,gitPull,gitPush
Ogni altro built-in in questo capitolo — sleep, runCommand, parseJson, gli helper di agenti e workflow, e così via — non ha una controparte di modulo e non ha deprecazione associata.
Examples/ usano la forma piatta (print(...), sqrt(...)) perché è più breve ed è quella del codice MALDA esistente. Leggile come equivalenti alla forma namespaced. Nel codice nuovo, preferisci la forma namespaced se vuoi che l'editor resti senza warning.
13.3 Funzioni matematiche
Le operazioni math sono disponibili come math.* (preferito), built-in piatti deprecati e Math.* (alias deprecato).
// Flat built-ins (deprecated flat alias; still supported)
var absVal = abs(-5); // Absolute value
var total = sum([1, 2, 3, 4]); // 10
var avg = average([1, 2, 3, 4]); // 2.5
var maxVal = max(10, 20); // Maximum of two values
var maxArr = max([10, 20, 5]); // Maximum in a numeric array
var minVal = min(10, 20); // Minimum of two values
var minArr = min([10, 20, 5]); // Minimum in a numeric array
var powVal = pow(2, 3); // Power: 2^3 = 8
var sqrtVal = sqrt(16); // Square root: 4
// Extended math (rounding and sign)
var f = floor(3.7); // 3
var c = ceil(3.2); // 4
var r = round(2.5); // 2 (banker’s rounding, .NET default)
var t = trunc(-3.9); // -3
var s1 = sign(-10); // -1
var s2 = sign(0); // 0
var s3 = sign(10); // 1
// Extended math (exponential and logarithm)
var e = exp(1); // ~2.718281828 (Math.E)
var ln = log(Math.E); // Natural log, ~1
var lg = log10(1000); // Base-10 log, 3
var lb = log2(8); // Base-2 log, 3
// Extended math (trigonometry, radians)
var halfPi = degToRad(90); // Convert degrees to radians
var s = sin(halfPi); // ~1.0
var c0 = cos(0); // ~1.0
var t = tan(0); // 0.0
var a = atan2(1, 1); // ~PI/4
// Inverse trigonometry (single argument, result in radians)
var as1 = asin(1); // ~PI/2
var ac1 = acos(1); // 0.0
var at1 = atan(1); // ~PI/4
var outOfDomain = asin(2); // NaN: no error is raised
// Extended math (utility)
var h = hypot(3, 4); // 5 (sqrt(3*3 + 4*4))
var cl1 = clamp(-1, 0, 10); // 0
var cl2 = clamp(5, 0, 3); // 3
var rad = degToRad(180); // PI
var deg = radToDeg(Math.PI / 2); // 90
// LLM-oriented math helpers
seed(42); // Deterministic random stream
var n = randn(0.1); // Gaussian random ~ N(0, 0.1^2)
var inv = rsqrt(16); // 0.25 (1/sqrt(x))
var idxMax = argmax([0.1, 0.7, 0.2]); // 1
var idxMin = argmin([0.1, 0.7, 0.2]); // 0
var probs = softmax([2.0, 1.0, 0.0]); // Probability array
var lse = logSumExp([2.0, 1.0, 0.0]); // Stable log(sum(exp(x)))
var ce = crossEntropyFromLogits([2.0, 1.0, 0.0], 0); // NLL for target index
var sampled = randomChoiceWeighted([0.1, 0.7, 0.2]); // Weighted sampled index
// All trigonometric functions take angles in radians, accept an integer or a
// float, and return a float. Out-of-domain input yields NaN rather than an error.
// Preferred: math.* module (Math.* is deprecated alias)
var cCirc = 2 * math.PI * r;
var cCircLegacy = 2 * Math.PI * r; // deprecated alias
var total2 = Math.sum([1, 2, 3]); // Same as sum(...)
var avg2 = Math.average([1, 2, 3]); // Same as average(...)
var powVal2 = Math.pow(2, 3); // 8
var sqrtVal2 = Math.sqrt(16); // 4
var floorVal = Math.floor(3.7); // 3
var sinVal = Math.sin(degToRad(90)); // ~1.0
var rand = Math.random(); // Random float between 0.0 and 1.0
var randInt = Math.randomInt(1, 10); // Random integer between 1 and 10 (inclusive)
var randFloat = Math.randomFloat(0.0, 100.0); // Random float between 0.0 and 100.0
var n2 = Math.randn(0.1); // Same as randn(0.1)
var probs2 = Math.softmax([2.0, 1.0, 0.0]); // Same as softmax(...)
sum(values) restituisce il totale di un array numerico. average(values) restituisce la media aritmetica di un array numerico non vuoto come float.
max e min supportano sia la forma (a, b) sia (values). Quando si passa un singolo argomento array, l'array deve essere non vuoto e contenere solo numeri.
Per gli array numerici, queste operazioni di aggregazione sono disponibili anche come metodi: values.sum(), values.average(), values.min() e values.max().
13.3.1 Helper matematici orientati agli LLM (riferimento)
Questi helper sono disponibili come math.softmax(values) (preferito), softmax(values) piatto (deprecato) e Math.softmax(values) (alias deprecato).
seed(seedValue)
Imposta il seed pseudo-casuale globale usato da random(), randomInt(), randomFloat(), randn() e randomChoiceWeighted(). L'argomento deve essere un intero. Restituisce null.
seed(42);
print(random()); // Deterministic across runs with same seed
print(Math.random());
randn(std?, mean?)
Genera un float casuale a distribuzione normale usando la trasformata di Box-Muller. Firma: randn(std = 1.0, mean = 0.0). Restituisce un float.
var z1 = randn(); // N(0, 1)
var z2 = randn(0.1); // N(0, 0.1^2)
var z3 = randn(0.1, 1.5); // N(1.5, 0.1^2)
rsqrt(x)
Restituisce la radice quadrata reciproca: 1 / sqrt(x). Utile nelle formule di attention e normalizzazione. Restituisce un float.
print(rsqrt(16)); // 0.25
print(Math.rsqrt(4)); // 0.5
argmax(values)
Restituisce l'indice del valore massimo in un array numerico non vuoto. Se più valori sono pari al massimo, restituisce il primo indice. Restituisce un intero.
print(argmax([0.1, 0.7, 0.2])); // 1
print(argmax([3, 3, 1])); // 0 (first max)
argmin(values)
Restituisce l'indice del valore minimo in un array numerico non vuoto. Se più valori sono pari al minimo, restituisce il primo indice. Restituisce un intero.
print(argmin([0.1, 0.7, 0.2])); // 0
print(argmin([3, 1, 1])); // 1 (first min)
logSumExp(values)
Calcola in modo numericamente stabile log(sum(exp(values[i]))) su un array numerico non vuoto. Restituisce un float.
var lse = logSumExp([2.0, 1.0, 0.0]);
print(lse);
softmax(values, temperature?)
Calcola le probabilità softmax da un array numerico non vuoto. temperature opzionale ha default 1.0 e deve essere > 0. Restituisce un array di float che sommano approssimativamente a 1.
var p1 = softmax([2.0, 1.0, 0.0]); // temperature = 1.0
var p2 = softmax([2.0, 1.0, 0.0], 0.5); // Sharper distribution
print(p1);
crossEntropyFromLogits(logits, targetIndex)
Calcola la negative log-likelihood direttamente dai logits per una classe target: -log(softmax(logits)[targetIndex]). targetIndex deve essere un indice intero valido nell'array dei logits. Restituisce un float.
var loss = crossEntropyFromLogits([2.0, 1.0, 0.0], 0);
print(loss);
randomChoiceWeighted(weights)
Campiona e restituisce un indice da un array di pesi numerici non vuoto. Tutti i pesi devono essere >= 0 e il loro totale deve essere > 0.
var idx = randomChoiceWeighted([0.1, 0.7, 0.2]); // Often 1
print(idx);
Comportamento sugli errori: questi helper sollevano errori a runtime per conteggi/tipi di argomenti non validi, array vuoti dove non ammessi, indici target fuori range, temperature softmax non positiva, pesi negativi o peso totale zero.
13.4 Funzioni sulle stringhe
Le operazioni sulle stringhe sono disponibili come funzioni built-in piatte (es. upper(s)) e come metodi in stile extension sui valori stringa (es. s.upper()). Entrambe le forme funzionano nell'interprete e nel codice transpile.
var len = length("Hello"); // String length
var upper = upper("hello"); // Convert to uppercase
var lower = lower("HELLO"); // Convert to lowercase
var trimmed = trim(" hello "); // Remove leading and trailing whitespace (returns "hello")
var substr = substring("Hello", 0, 3); // Extract substring: start at index 0, take 3 characters (returns "Hel")
// substring(text, startIndex, length) - third parameter is COUNT/LENGTH, not end index
var singleChar = substring("Hello", 1, 1); // Get single character at index 1 (returns "e")
var pos = indexOf("hello world", "world"); // Find position (returns 6, 0-indexed)
var notFound = indexOf("hello", "xyz"); // Returns -1 if not found
var replaced = replace("Hello world", "world", "MALDA"); // Replace all occurrences (returns "Hello MALDA")
var parts = split("a,b,c", ","); // Split string into array (returns ["a", "b", "c"])
var normalized = normalizeText(" Città, 42! "); // "citta 42"
var words = tokenize("Uno, due, tre!"); // ["uno", "due", "tre"]
var score = similarity("equazione lineare", "equazioni lineari");
var numbers = extractNumbers("x=12, y=3.5"); // [12, 3.5]
var joined = parts.join(","); // Join array into string (returns "a,b,c")
// Null-safe boundary helpers (prefer str.* spelling):
var asText = str.text(maybeNull); // null → "" (unlike string(null) → "null")
var cleaned = str.trimText(maybeNull); // null → ""; else string then trim
str.text(value) converte qualsiasi valore in stringa, mappando null su "". str.trimText(value) è str.trim(str.text(value)). Usale ai confini env / JSON / CLI invece di nidificare controlli su null prima di str.trim.
Metodi stringa in stile extension
Le funzioni length, upper, lower, trim, substring, indexOf, replace, split, startsWith, endsWith, padStart, padEnd e repeat si possono chiamare anche come metodi su qualsiasi valore stringa. Il ricevente è trattato come primo argomento. È analogo ai metodi di extension in VB.NET/C#.
var name = "pippo";
var nameUpper = string(name).upper(); // same as upper(string(name)) or upper(name)
print("hello".upper()); // HELLO
print("HELLO".lower()); // hello
var s = "Hello";
print(s.length()); // 5
print(s.substring(0, 3)); // Hel
print(s.indexOf("ll")); // 2
print(s.replace("He", "Ye")); // Yello
print("abc".repeat(2)); // abcabc
var f = "world".upper; // method as value
print(f()); // WORLD
Chiamare un membro non supportato su una stringa (es. s.foo()) causa un errore a runtime.
Funzioni per espressioni regolari
var matches = regexMatch("test123", "\\d+"); // Check if pattern matches (returns true)
var result = regexReplace("abc123", "\\d+", "456"); // Replace matches (returns "abc456")
// Use $1, $2, etc. for capture groups in replacement
var swapped = regexReplace("John Doe", "(\\w+) (\\w+)", "$2, $1"); // Returns "Doe, John"
var matches = regexFind("test123 test456", "\\d+"); // Find all matches (returns array of match objects)
Funzioni stringa aggiuntive
var starts = startsWith("Hello", "He"); // Check if string starts with prefix (returns true)
var ends = endsWith("Hello", "lo"); // Check if string ends with suffix (returns true)
var padded = padStart("5", 3, "0"); // Pad string to length from left (returns "005")
var padded2 = padEnd("5", 3, "0"); // Pad string to length from right (returns "500")
var repeated = repeat("Hi", 3); // Repeat string N times (returns "HiHiHi")
Helper di matching del testo
var normalizedText = normalizeText(" Città, 42! "); // "citta 42"
var tokens = tokenize("CPU, RAM e disco"); // ["cpu", "ram", "e", "disco"]
var overlap = tokenOverlap("cpu memoria cache", "cache cpu");
print(overlap.sharedCount); // 2
print(overlap.jaccard); // 0.66...
var sim1 = similarity("equazione lineare", "equazioni lineari");
var sim2 = similarity("processore", "processor", "char-ngram");
var nums = extractNumbers("x=12, y=3.5, z=-2"); // [12, 3.5, -2]
Funzioni sui path
var filename = getFileName("ReferenceManual/09-functions.html"); // Returns "09-functions.html"
var dir = getDirectoryName("ReferenceManual/09-functions.html"); // Returns "ReferenceManual"
var dir2 = getDirectoryName("09-functions.html"); // Returns "" (empty for files in current directory)
var joined = pathJoin("dir1", "dir2", "file.txt"); // Join path segments (returns "dir1/dir2/file.txt" or "dir1\\dir2\\file.txt" on Windows)
var normalized = pathNormalize("./dir/../file.txt"); // Normalize path (returns absolute path)
var exists = pathExists("file.txt"); // Check if path exists (file or directory)
var ext = pathGetExtension("file.txt"); // Get file extension (returns ".txt")
var under = isPathUnder("brain", "brain/notes/a.md"); // true when path resolves under root (disk or embed:)
var escape = isPathUnder("brain", "brain/../secret.txt"); // false
isPathUnder(root, path) — Restituisce true quando path si risolve nella stessa posizione di root o in un discendente. Usa il confronto sul path completo con un confine di separatore di directory (così demo non corrisponde a demo-evil). Funziona per path su disco e per root virtuali embed:<alias>/…. Restituisce false su coppie non valide o con scheme diversi.
Home e config MALDA
Queste funzioni supportano la directory di config ~/.malda dell'assistente personale e CLI.
var home = getMaldaHome(); // Returns "~/.malda" (e.g. C:\Users\You\.malda on Windows)
var config = getMaldaConfig(); // Returns config object from ./.malda/config.json or ~/.malda/config.json, or null
getMaldaHome() — Restituisce il path della directory utente MALDA (nessun argomento).
getMaldaConfig() — Legge il primo file di config esistente tra ./.malda/config.json e ~/.malda/config.json, lo analizza come JSON e restituisce il risultato come oggetto. Restituisce null se nessuno dei due file esiste o se l'analisi fallisce. Usala per leggere providers.openrouter.apiKey, agents.defaults.model, tools.web.search.apiKey, ecc.
getAssistantMemory(path?) — Restituisce un'istanza GraphMemory inizializzata con MALDA_MEMORY_EMBED (default hash) e caricata da ~/.malda/memory/assistant quando gli artefatti esistono. Il path opzionale sovrascrive il path base di storage (senza estensione).
Skill
Queste funzioni supportano il caricamento delle skill da ~/.malda/skills/.
var names = getSkillNames(); // Returns array of skill base names, e.g. ["github", "weather"]
var skill = loadSkill("github"); // Loads ~/.malda/skills/github.malda, returns object with module globals (e.g. skill.tools, skill.agent)
var skills = loadSkillsFromDir(); // Scans ~/.malda/skills/*.malda; each entry has name + exports (or error)
getSkillNames() — Restituisce un array di stringhe: i nomi base (senza .malda) di tutti i file .malda in ~/.malda/skills/. Restituisce [] se la directory non esiste o è vuota. Nessun argomento.
loadSkill(name) — Carica il file skill ~/.malda/skills/<name>.malda, lo esegue in un ambiente isolato e restituisce un oggetto le cui proprietà sono le variabili globali del modulo. Convenzione: le skill esportano un array tools (e opzionalmente agent). Restituisce null se il file non esiste o name è vuoto. Un argomento: il nome della skill (stringa).
loadSkillsFromDir(path?) — Scansiona una directory (default ~/.malda/skills) in cerca di file *.malda e restituisce un array di oggetti. Ogni oggetto include name più i globali del modulo skill (tools, agent, ecc.). In caso di fallimento del carico, l'oggetto ha name e error al loro posto. Primo argomento opzionale: path della directory (stringa).
13.5 Ambiente e host
Guida pratica e l'insidia di getEnv / str.trim: 12.5 Ambiente e host.
var apiKey = getEnv("OPENAI_API_KEY"); // string, or null when unset
var apiKeyOr = io.getEnvOr("OPENAI_API_KEY"); // "" when unset (optional 2nd arg = default)
var hasKey = hasEnv("API_KEY"); // Check if environment variable exists
io.getEnvOr(name, default?) — stessa ricerca di getEnv, ma non restituisce mai null: le variabili assenti producono default (stringa vuota se omesso). Preferiscila prima di str.trim / altre funzioni che si aspettano una stringa.
13.5.1 Informazioni sull'host
I built-in senza argomenti descrivono la macchina e l'invocazione sotto cui gira il programma. Passare un qualsiasi argomento solleva un errore.
var host = getHostPlatform();
print(host.os); // Operating system identifier
print(host.arch); // Process architecture
print(host.pathSeparator); // "\" on Windows, "/" elsewhere
print(host.description); // Full OS description string
var args = getCommandLineArgs();
// Arguments passed to the program, excluding the program name itself
if (args.length > 0) {
print("first argument: " + args[0]);
}
// Folder of the .malda script (interpreter) or of the compiled .exe (transpile)
var programDir = getProgramDirectory();
var modelPath = io.pathJoin(programDir, "bge-m3-Q4_K_M.gguf");
getHostPlatform() restituisce un oggetto con i quattro campi mostrati sopra. getCommandLineArgs() restituisce un array di stringhe ed è il modo per leggere gli argomenti CLI da un programma MALDA, sia in esecuzioni interpretate sia transpile. getProgramDirectory() restituisce la directory assoluta del file sorgente .malda in esecuzione sotto l'interprete, oppure AppContext.BaseDirectory (la cartella che contiene l'eseguibile compilato) dopo malda compile.
13.5.2 Ricerca web (Brave Search API)
webSearch(query, apiKey?) — Esegue una ricerca web usando la Brave Search API. query è la stringa di ricerca. apiKey è opzionale; se omessa, la chiave viene presa (in ordine) dall'argomento apiKey, dalla variabile d'ambiente BRAVE_SEARCH_API_KEY o da tools.web.search.apiKey in ~/.malda/config.json (vedi Assistente personale e CLI). Restituisce un oggetto: { ok: true, results: [{ title, url, description }, ...], moreResultsAvailable: bool } in caso di successo, oppure { ok: false, error: "message" } in caso di fallimento.
var r = webSearch("MALDA programming language"); // Uses BRAVE_SEARCH_API_KEY or config
var r2 = webSearch("weather London", "your-brave-api-key"); // Explicit key
if (r.ok) { for (var i = 0; i < r.results.length; i++) print(r.results[i].title); }
13.5.3 Helper per token di autenticazione HTTP
Questi helper estraggono token da oggetti simili a request usati dagli handler di HttpServer.
var bearer = httpBearerToken(req); // Reads Authorization: Bearer <token>
var cookie = httpCookieToken(req, "app_session", "cookie-secret"); // Signed cookie token
var token = httpAuthToken(req, {
"allowBearer": true,
"allowCookie": true,
"allowBody": true,
"cookieName": "app_session",
"cookieSecret": "cookie-secret",
"bodyKey": "auth"
});
httpBearerToken(request)- restituisce la stringa del token bearer o la stringa vuota.httpCookieToken(request, cookieName, cookieSecret?)- restituisce il token del cookie decodificato (o il valore del cookie sicuro verificato quando è fornito il secret), altrimenti la stringa vuota.httpAuthToken(request, options?)- prova bearer/cookie/body in ordine e restituisce il primo token non vuoto.
13.6 Funzioni di utilità sugli array
var arr = [1, 2, 3, 4, 5];
var total = sum(arr); // 15
var avg = average(arr); // 3.0
var smallest = min(arr); // 1
var largest = max(arr); // 5
var total2 = arr.sum(); // 15
var avg2 = arr.average(); // 3.0
var smallest2 = arr.min(); // 1
var largest2 = arr.max(); // 5
var joined = join(arr, ", "); // Join array elements into string (returns "1, 2, 3, 4, 5")
var reversed = reverse(arr); // Return reversed array (returns [5, 4, 3, 2, 1])
var sorted = sort([3, 1, 4, 1, 5]); // Sort array (returns [1, 1, 3, 4, 5])
var sortedDesc = sort([3, 1, 2], (a, b) => b - a); // Custom compare: descending (interpreter and transpiled)
var hasValue = includes(arr, 3); // Check if array contains value (returns true)
sort(array, compareFn?) — Con un argomento, restituisce un nuovo array ordinato con il confronto di default (numeri poi stringhe). Con un compareFn opzionale, il secondo argomento deve essere una funzione (a, b) => number: restituire negativo se a prima di b, 0 se uguali, positivo se a dopo b. Il confronto personalizzato è supportato sia nell'interprete sia in modalità transpile.
sum(array) restituisce il totale di un array numerico. average(array) restituisce la media aritmetica di un array numerico non vuoto come float. min(array) e max(array) restituiscono l'elemento numerico più piccolo e più grande in un array non vuoto.
Le stesse operazioni di aggregazione supportano anche la sintassi a metodo sull'array: array.sum(), array.average(), array.min() e array.max().
13.6.1 Helper di esportazione CSV
var rows = [
{"name": "Alice", "score": 95},
{"name": "Bob", "score": 88}
];
var csv1 = toCsv(rows, ["name", "score"]); // With explicit column order
var csv2 = toCsv(rows); // Infer columns from first row
var csv3 = toCsv(rows, ["name", "score"], {
"delimiter": ";",
"includeHeader": true,
"quoteAll": false,
"newline": "\n"
});
toCsv(rows, columns?, options?) converte un array di righe in testo CSV. Esegue l'escape delle virgolette e racchiude le celle quando serve (delimitatore/newline/virgolette). Utile per report e endpoint di esportazione dati.
13.7 Funzioni JSON
var jsonStr = toJSON(obj); // Convert object to JSON string
var obj = parseJSON('{"name":"Alice","age":30}'); // Parse JSON string to object
parseJSON analizza JSON arbitrario in valori MALDA. parseJson(jsonString, schemaName) analizza JSON e lo valida rispetto a una dichiarazione schema registrata, sollevando un'eccezione in caso di mancata corrispondenza.
schema Answer {
text: string;
sources: string[];
}
var parsed = parseJson('{"text":"ok","sources":["a.md"]}', "Answer");
print(parsed.text); // ok
print(parsed.sources[0]); // a.md
I tipi di campo array usano la sintassi type[] (es. string[], int[] o OtherSchema[]). I tipi di campo possono anche nominare un altro schema dichiarato (le forme oggetto nidificate vengono espanse per la validazione e i prompt tipizzati) o un sum type dichiarato (JSON oneOf con tag). I campi opzionali aggiungono ? dopo il tipo. Nomi di tipo di campo sconosciuti e riferimenti ciclici allo schema sollevano un errore quando lo schema viene risolto.
13.7.1 validate(schema, value)
Controlla un valore che hai già rispetto a uno schema, senza analizzare JSON. A differenza di parseJson, un fallimento di validazione non è un'eccezione: il risultato è sempre un oggetto che riporta l'esito.
- In caso di successo:
{ ok: true, data: value } - In caso di fallimento:
{ ok: false, error: "message" }
Il primo argomento è il nome di uno schema o sum type registrato, oppure un oggetto schema in linea. Un nome sconosciuto solleva Unknown schema 'Name'. In caso di successo, data è il valore originale — un dict con tag resta un dict (non viene coercizzato a variant). Usa await prompt … -> Intent quando ti serve un variant per match.
schema Answer {
text: string;
sources: string[];
}
var candidate = dict { "text": "ok", "sources": ["a.md"] };
var checked = validate("Answer", candidate);
if (checked.ok) {
print(checked.data.text); // ok
} else {
print("invalid: " + checked.error);
}
type Intent = Search(query) | Buy(sku, qty);
var tagged = dict { "tag": "Buy", "sku": "SKU-9", "qty": 2 };
var checkedIntent = validate("Intent", tagged);
if (checkedIntent.ok) {
print(checkedIntent.data.tag);
}
type Intent = Search(query: string) | Buy(sku: string, qty: int);
var tagged = dict { "tag": "Buy", "sku": "SKU-9", "qty": "x" };
var checkedTyped = validate("Intent", tagged);
print(checkedTyped.ok);
memory.validate() su un'istanza GraphMemory, che controlla l'integrità del grafo piuttosto che uno schema. Condividono il nome ma non sono correlati.
13.7.2 Funzioni per pipeline AI
Questi built-in si compongono con l'operatore pipe (|>) per la retrieval-augmented generation (RAG) e l'output LLM strutturato. Vedi anche 15. VectorDB (asRetriever) e Examples/Prompts/rag_pipeline.malda.
// Load text files matching a glob pattern (default directory: current)
var docs = loadDocuments("**/*.md", "docs/");
// Split long documents into overlapping chunks
var chunks = splitDocuments(docs, 512, 64);
// Index documents into a VectorDB (embeds content, preserves metadata)
indexInto(vdb, chunks);
// Format retrieved documents for prompt context
var context = query |> retriever.get |> formatRetrievedDocs;
// Execute a PromptInstance with the default or supplied LLM client
var response = await (promptInstance |> runPrompt(client));
// Stream tokens while the model responds
var seen = "";
function onTok(token) { seen = seen + token; }
var response = await runPrompt(promptInstance, client, { onToken: onTok });
// Stream model reasoning/thinking deltas (OpenRouter-compatible providers)
var reasoning = "";
function onReason(token) { reasoning = reasoning + token; }
var response = await runPrompt(promptInstance, client, { onReasoning: onReason });
// Attach runtime few-shot examples to a prompt instance
var p = classify("query") |> withExamples(dynamicExamples);
// Validate LLM JSON output against a schema
var parsed = response |> parseJson("Answer");
// Advanced composition: sequence + parallel branches
var pipeline = composePipe(formatRetrievedDocs, (ctx) => answerPrompt(q, ctx));
var context = question |> pipeline;
var branches = parallelRun(question, {
context: (q) => q |> retriever.get,
tags: classifyIntent
});
var merged = mergeRetrievedDocs(branches.context, branches.tags);
| Funzione | Descrizione |
|---|---|
loadDocuments(pattern, dirPath?) | Corrisponde ai file con glob sotto dirPath (default "."); restituisce { content, metadata: { source } } per file |
splitDocuments(docs, chunkSize, overlap?) | Divide il contenuto dei documenti in chunk sovrapposti; copia i metadata su ogni chunk |
indexInto(vdb, docs) | Esegue l'embed e aggiunge ogni documento a un VectorDB tramite il suo calculator; memorizza i metadata con gli hit |
formatRetrievedDocs(docs) | Formatta gli array di documenti come blocchi [source: …] uniti per il contesto del prompt |
composePipe(step1, step2, …) | Compone 2+ callable (funzioni, lambda, built-in, prompt) da sinistra a destra in una funzione riutilizzabile (input) => …. Attende gli step async. Compatibile con la pipe: input |> composePipe(f, g) |
parallelRun(input, branches) | RunnableParallel: alimenta lo stesso input a ogni branch nominato in concorrenza; restituisce un oggetto/mappa di risultati. Usa await quando i branch includono step async. |
mergeRetrievedDocs(docArrays…) | Appiattisce più array Document[] (es. da parallelRun) in un unico array; deduplica per metadata source+chunk o per contenuto |
withExamples(prompt, examples, options?) | Restituisce una copia di un PromptInstance con esempi few-shot a runtime. Passa { merge: true } per accodarli dopo eventuali examples statici dalla dichiarazione del prompt. Compatibile con la pipe. |
runPrompt(prompt, client?, options?) | Async: esegue un PromptInstance tramite un LLM; restituisce il testo della risposta. options opzionali: { onToken: (token) => ... } per i token di contenuto in streaming; { onReasoning: (token) => ... } per i token di reasoning/thinking in streaming. Entrambe funzionano in modalità interpretata e transpile con await e step di pipe. |
parseJson(json, schemaName) | Analizza e valida JSON rispetto a una dichiarazione schema; restituisce un oggetto tipizzato |
13.8 Funzioni del file system
Guida pratica, stili di fallimento, intervalli di righe, capability token e note sul backend: 12. Input/Output. Questa sezione è il catalogo delle firme.
var content = readFile("example.txt"); // Read entire file
var lines = readFile("example.txt", 10, 20); // Read lines 10-20 (1-indexed)
var fromLine = readFile("example.txt", 5); // Read from line 5 to end
writeFile("output.txt", "Hello"); // Write content to file
var exists = hasFile("example.txt"); // Check if file exists
var dirExists = hasDirectory("mydir"); // Check if directory exists
ensureDir("path/to/dir"); // Create directory and parents if missing
var files = listDirectory("."); // List directory contents
ensureDir(path) — Crea la directory e ogni directory padre mancante. Non fa nulla se la directory esiste già. Utile per creare ~/.malda/memory prima di salvare la memoria dell'assistente.
13.8.0 Cartelle embedded (embed:)
Compila con malda compile … --embed-folder <dir[=alias]> per impacchettare una directory nell'eseguibile come risorse dell'assembly. A runtime, leggi quei file con lo scheme virtuale embed:<alias>/<relative> — nulla viene estratto su disco. Le scritture (writeFile, ensureDir, …) rifiutano i path embed:.
if (io.hasEmbeddedFolder("secondbrain")) {
var root = io.embeddedFolderRoot("secondbrain"); // "embed:secondbrain"
var catalog = io.readFile(io.pathJoin(root, "brain.json"));
var entries = io.listDirectory(root);
}
hasEmbeddedFolder(alias) restituisce se quell'alias è stato embedded. embeddedFolderRoot(alias) restituisce embed:<alias>, oppure null quando l'alias manca. I tool degli agenti come createReadFileTool, createGrepTool e createListDirectoryTool accettano una working directory embed:<alias>.
replaceInFile("file.txt", "old", "new", 3); // Replace text in file (single replacement)
var edits = [{"oldText": "old1", "newText": "new1"}, {"oldText": "old2", "newText": "new2"}];
var result = editFile("file.txt", edits); // Apply multiple edits to file
13.8.1 Linee, binario, eliminazione e testo PDF
| Funzione | Restituisce | Comportamento |
|---|---|---|
pdf.extractText(path, password?) | string | Estrae il testo da un PDF usando PdfPig (ContentOrderTextExtractor). password opzionale per i file cifrati. Solleva un'eccezione quando il path manca o il PDF non può essere aperto. Solo testo digitale — i PDF scansionati/immagine richiedono OCR altrove. Preferisci la forma namespaced; il nome CallBuiltIn è extractPdfText. |
doc.extractText(path) | string | Estrae il testo dei paragrafi del corpo da un Word .docx usando l'Open XML SDK. Solleva un'eccezione quando il path manca, il file non è .docx o il package non può essere aperto. Il .doc binario legacy non è supportato. Preferisci la forma namespaced; il nome CallBuiltIn è extractDocxText. |
readTextFileLines(path) | array di stringhe, oppure null | Legge il file come UTF-8 e lo divide in righe. Restituisce null quando il file manca o non può essere letto. |
deleteFile(path) | boolean | Elimina il file. Restituisce true quando il file è stato eliminato o era già assente; false su un path vuoto o un fallimento I/O. |
insertAtLine(path, lineNumber, content, insertAfter?) | boolean | Inserisce content (che può coprire più righe) a una riga con indice a base 1. Restituisce false se il file non esiste. |
readFileBase64(path) | string, oppure null | Legge il file come byte e restituisce base64. Restituisce null quando il file manca. |
writeFileBase64(path, base64Content) | boolean | Decodifica il base64 e scrive i byte. Restituisce false quando l'input non è base64 valido o la scrittura fallisce. |
var lines = readTextFileLines("notes.txt");
if (lines != null) {
print("line count: " + lines.length);
}
insertAtLine("notes.txt", 1, "# Header"); // Insert before line 1
insertAtLine("notes.txt", 3, "appended", true); // Insert after line 3
var encoded = readFileBase64("logo.png");
writeFileBase64("logo-copy.png", encoded);
deleteFile("scratch.txt");
var pdfText = pdf.extractText("manual.pdf");
// var unlocked = pdf.extractText("secret.pdf", "password");
var docText = doc.extractText("brief.docx");
Per insertAtLine, un lineNumber di 0 o inferiore inserisce all'inizio del file, e un valore oltre l'ultima riga accoda in fondo. insertAfter ha default false, cioè il contenuto viene inserito prima della riga data.
readTextFileLines, deleteFile, insertAtLine e gli helper base64 segnalano i fallimenti ordinari tramite il valore di ritorno (false o null) anziché sollevando un'eccezione. Sollevano un errore solo se chiamati con il numero sbagliato di argomenti o con tipi di argomenti sbagliati. Controlla il risultato invece di affidarti a try/catch. pdf.extractText e doc.extractText sollevano un'eccezione su file mancanti e fallimenti di analisi.
insertAtLine è solo interprete: non è disponibile negli eseguibili transpile. Gli altri helper sui file, pdf.extractText / extractPdfText e doc.extractText / extractDocxText sono supportati dal transpiler C#.
13.8.2 Ricerca nei file: glob e grep
glob trova i path per pattern e grep cerca nel contenuto dei file. Entrambi prendono prima un argomento obbligatorio e poi una serie di argomenti opzionali posizionali.
glob(pattern, dirPath?, maxResults?, includeDirectories?, excludeDirs?, workingDirectory?)
dirPathha default".",maxResults200(limitato a 500),includeDirectoriesfalsee i due argomenti stringa rimanenti"".- In caso di successo restituisce un oggetto
{ items, count, truncated }, dove ogni item è{ name, type, path }etruncatedindica se il risultato ha raggiuntomaxResults.
var found = glob("**/*.malda", "Examples");
print(found.count);
print(found.truncated);
var first = found.items[0];
print(first.path + " (" + first.type + ")");
grep(pattern, filePath, useRegex?, caseInsensitive?, includeLineNumbers?, contextLines?, countOnly?, recursive?, workingDirectory?)
- Default:
useRegexfalse,caseInsensitivefalse,includeLineNumberstrue,contextLines3,countOnlyfalse,recursivetrue. - Di norma restituisce un array di match con forma
{ filePath, content, lineNumber, contextBefore, contextAfter }. ConcountOnlyimpostato restituisce invece{ count, filesSearched }. - I file che non possono essere letti vengono saltati in silenzio.
var matches = grep("function ", "Examples");
for (var m in matches) {
print(m.filePath + ":" + m.lineNumber + " " + m.content);
}
var summary = grep("TODO", "Examples", false, true, true, 0, true);
print(summary.count + " hits in " + summary.filesSearched + " files");
glob e grep restituiscono un messaggio di errore invece del risultato normale. Proteggi con typeOf(result) == "string" prima di trattare il valore come una collezione.
var result = grep("needle", "does-not-exist");
if (typeOf(result) == "string") {
print("search failed: " + result);
}
13.9 Funzioni Git
var status = gitStatus("."); // Get repository status
gitAdd(".", "."); // Stage files
gitCommit(".", "Fix bug"); // Create commit
var commits = gitLog(".", 10); // Get last 10 commits
var diff = gitDiff(".", null, false); // Get unstaged diff
var branches = gitBranch(".", "list"); // List all branches
gitBranch(".", "create", "feature-x"); // Create new branch
// Note: Branch deletion is disabled for safety
gitCheckout(".", "main", false); // Switch to branch
gitPush(".", "origin", "main"); // Push to remote
gitPull(".", "origin", "main"); // Pull from remote
13.10 Funzioni di esecuzione comandi
// Execute shell commands
var result = runCommand("dotnet", ["build"], ".", 30000); // Run dotnet build with 30s timeout
// Returns: {exitCode: 0, stdout: "...", stderr: ""}
var result = runCommand("npm", ["test"]); // Run npm test (no timeout)
var result = runCommand("python", ["script.py"], "./scripts"); // Run with custom working directory
// Result object structure:
// - exitCode (integer): Process exit code (0 typically indicates success)
// - stdout (string): Standard output from the command
// - stderr (string): Standard error output from the command
13.11 Funzioni di esecuzione MALDA
// Execute MALDA code from file or string
var result = runMALDA("example.malda"); // Execute from file
var result = runMALDA("print('Hello');"); // Execute from string
var result = runMALDA("example.malda", "input data"); // Execute with stdin input
// Result object structure:
// - success (boolean): true if execution completed without errors
// - output (string): Standard output from the program
// - error (string): Parse error message if any, empty string otherwise
// - runtimeError (string, optional): Runtime error message if any
// Compile a .malda program to an executable (optional embed folder = CLI --embed-folder)
var packed = compileMALDA("app.malda", "dist/app.exe", "transpile", "secondbrain");
// embedFolder may be "path" or "path=alias"; result: { success, outputPath, error, errors }
13.10.1 getSymbols(sourceOrFilePath)
Analizza codice MALDA ed estrae informazioni strutturate sui simboli (classi, funzioni, actor, prompt) con numeri di riga e firme. Accetta un argomento stringa: un path a un file .malda oppure codice sorgente MALDA. Se la stringa sembra un path di file (contiene separatori di path o termina con .malda) e il file esiste, il file viene letto e il suo contenuto analizzato; altrimenti l'argomento è trattato come codice sorgente. Il path traversal (.., ~) è rifiutato. Restituisce un oggetto con classes, functions, actors, prompts e parseErrors (tutti array). Ogni class/actor ha name, line, column, members; ogni funzione ha name, line, column, parameters, signature; ogni prompt ha name, line, column, parameters, returnType?, signature. Gli errori di parse hanno line, column, message.
var sym = getSymbols("Examples/OOP/classes_objects.malda"); // From file
var sym2 = getSymbols("function f() { } class C { }"); // From source
// sym.classes, sym.functions, sym.actors, sym.prompts, sym.parseErrors
13.10.2 getParseErrors(sourceOrFilePath)
Analizza codice MALDA e restituisce solo gli errori di parse (nessuna esecuzione). Accetta lo stesso argomento di getSymbols: path di file o stringa sorgente. La risoluzione del path e i controlli di sicurezza sono gli stessi. Restituisce { parseErrors: [{ line, column, message }, ...] }. Usala per validare la sintassi senza eseguire o compilare.
var errs = getParseErrors("var x = ;"); // Invalid: empty rhs
// errs.parseErrors is non-empty with line, column, message
var ok = getParseErrors("var x = 1;"); // Valid: parseErrors is []
runCommand include controlli di sicurezza completi:
- I comandi pericolosi sono bloccati (es.
rm,del,format,shutdown,powershell,cmd, ecc.) - La working directory è validata e normalizzata per prevenire il path traversal
- Timeout massimo di 1 ora (3.600.000 ms) per evitare attese indefinite
- I path dei comandi sono validati per i path assoluti
- I tentativi di path traversal (
..,~) sono rilevati e bloccati
13.12 Integrazione Spectre.Console
MALDA espone un oggetto globale AnsiConsole che incapsula la libreria .NET Spectre.Console e fornisce output di console ricco:
// Markup (colors, bold, links, etc.)
AnsiConsole.markupLine("[green]Hello[/] [bold red]Spectre.Console[/]!"); // Appends a newline
AnsiConsole.markup("[dim]no newline, [/]"); // Stays on the same line
AnsiConsole.markupLine("[cyan]rest of the line[/]");
// Tables
var rows = [
{"Name": "Alice", "Score": 95},
{"Name": "Bob", "Score": 88}
];
AnsiConsole.table(rows, "Scores");
// Panels (body and title accept markup)
AnsiConsole.panel("[bold]Important[/] message", "Info", "rounded");
// Trees
var treeData = {
"root": "Project",
"children": [
{"label": "src"},
{"label": "tests"}
]
};
AnsiConsole.tree("Project", treeData);
// Status
AnsiConsole.status("Processing...", () => {
// Long-running work here
});
// Prompt (configuration object)
AnsiConsole.prompt({
"type": "text",
"message": "Enter your name"
});
// Progress - New callback-based syntax (recommended)
AnsiConsole.progress((ctx) => {
ctx.addTask("Loading World Map", 100);
while (!ctx.isFinished()) {
ctx.increment("Loading World Map", 1.5);
sleep(50);
}
});
// Progress - Object-based syntax (legacy)
AnsiConsole.progress({
"tasks": [
{"name": "Task 1", "maxValue": 100}
],
"action": (progressObj) => {
var current = 0;
while (current < 100) {
current = current + 10;
// Update progress by setting the value
progressObj["Task 1"] = current;
sleep(50);
}
}
});
AnsiConsole.markupLine(text)scrive il testo e accoda un newline. È la chiamata giusta per una riga di output autonoma.AnsiConsole.markup(text)scrive il testo senza newline finale, così le chiamate consecutive restano sulla stessa riga. Usala per comporre una riga da più frammenti stilizzati, poi chiudi la riga conmarkupLine.- Entrambe analizzano i tag di markup come
[bold],[green]e[/]. Per stampare una parentesi quadra letterale, raddoppiala:[[e]]. AnsiConsole.panel(body, title?, border?)analizza il markup sia nel body sia nel title. Il contenuto che non è markup valido — JSON arbitrario, codice o testo di errore con parentesi quadre — viene reso letteralmente invece di sollevare un errore.
- Sintassi a callback: Passa una funzione che riceve un oggetto context con i metodi:
ctx.addTask(name, maxValue)- Aggiunge un task di progressoctx.increment(taskName, value)- Incrementa il progresso di un task del valore datoctx.isFinished()- Controlla se tutti i task sono finiti
- Sintassi a oggetto: Passa un oggetto con un array
taskse un callbackaction. Il callback riceve un oggetto progresso in cui puoi leggere e aggiornare i valori impostando le proprietà:progressObj["Task Name"] = value
- Interprete da riga di comando: Quando esegui
maldain un terminale reale, MALDA configura UTF-8 e abilita le sequenze di escape ANSI sulle console Windows supportate, così il markup Spectre.Console viene reso con colori e stile completi. - Eseguibili transpile: Gli eseguibili C# generati abilitano le sequenze di escape ANSI all'avvio su Windows, così le chiamate
AnsiConsole.*vengono rese correttamente nei terminali compatibili. - Desktop IDE: Il pannello di output dell'IDE è testo semplice. Al primo uso di
AnsiConsole, MALDA apre automaticamente una finestra di console separata e instrada l'output sia al pannello IDE (testo semplice) sia alla console (rendering ricco Spectre.Console).
13.13 Funzioni data e ora
var timestamp = now(); // Get current timestamp in milliseconds (Unix epoch)
var formatted = formatDate(timestamp, "yyyy-MM-dd HH:mm:ss"); // Format timestamp (default: "yyyy-MM-dd HH:mm:ss")
var parsed = parseDate("2026-01-26 10:30:00"); // Parse date string to timestamp
var tomorrow = addDays(timestamp, 1); // Add days to timestamp
var inHours = addHours(timestamp, 2); // Add hours to timestamp
- I timestamp sono in millisecondi dall'epoca Unix (1 gennaio 1970 UTC)
formatDateusa le stringhe di formato data .NET standard (es. "yyyy-MM-dd", "HH:mm:ss", "dd/MM/yyyy")parseDateaccetta formati data comuni e li converte in timestamp
13.14 Funzioni per numeri casuali
var rand = math.random(); // Random float between 0.0 and 1.0
var randInt = math.randomInt(1, 10); // Random integer, 1 and 10 both included
var randFloat = math.randomFloat(0.0, 100.0); // Random float between 0.0 and 100.0
math.seed(7); // Pin the sequence for reproducible runs
var pinned = math.randomInt(1, 100); // Always 39 after seed(7)
randomInt(min, max)include entrambi gli estremi, a differenza degli intervalli semiaperti comuni in altri linguaggi.math.seed(n)reimposta il generatore condiviso dietrorandom,randomInt,randomFloaterandn. Imposta il seed in cima a un programma per rendere un'esecuzione deterministica, che è ciò che rende testabile un programma casuale.- Le forme piatte
randomInt(1, 10)eMath.randomInt(1, 10)continuano a funzionare, ma il language server le segnala entrambe come alias deprecati. Preferiscimath., come descritto in 13.2 Namespace della stdlib e alias piatti.
13.15 Funzioni di controllo del tipo
var isNum = isNumber(42); // Check if value is a number (integer or float)
var isStr = isString("hello"); // Check if value is a string
var isArr = isArray([1, 2, 3]); // Check if value is an array
var isObj = isObject({name: "Alice"}); // Check if value is an object
var type = typeOf(42); // Canonical tag ("int", "string", "dict", "object", "variant", "task", "null", ...)
var isInt = isTag(42, "int"); // true; isTag also accepts legacy names like "integer" during deprecation
13.16 Funzioni di encoding e decoding
var encoded = base64Encode("Hello World"); // Base64 encode string
var decoded = base64Decode(encoded); // Base64 decode string
var urlEncoded = urlEncode("Hello World"); // URL encode string (returns "Hello%20World")
var urlDecoded = urlDecode(urlEncoded); // URL decode string
13.17 Funzioni hash
var md5Hash = md5("Hello World"); // Calculate MD5 hash (returns hex string)
var sha256Hash = sha256("Hello World"); // Calculate SHA-256 hash (returns hex string)
- Sia
md5siasha256restituiscono stringhe esadecimali in minuscolo - MD5 produce stringhe hex di 32 caratteri
- SHA-256 produce stringhe hex di 64 caratteri
13.16.1 Funzioni di sicurezza per password e JWT
var passwordHash = hashPassword("my-password"); // PBKDF2-SHA256 hash
var isValid = verifyPassword("my-password", passwordHash); // true/false
var claims = {"sub": "user-123", "role": "admin"};
var token = createJwt(claims, "my-jwt-secret", 3600); // expires in 3600s
var token2 = createJwt(claims, "my-jwt-secret", {
"expiresInSeconds": 3600,
"issuer": "malda-core",
"audience": "malda-apps",
"notBeforeSeconds": 0
});
var verifiedClaims = verifyJwt(token2, "my-jwt-secret", {
"issuer": "malda-core",
"audience": "malda-apps"
});
print(verifiedClaims.sub);
var csrfToken = generateCsrfToken("csrf-secret", 3600);
var csrfOk = verifyCsrfToken(csrfToken, "csrf-secret"); // true/false
var setCookieHeader = createSecureCookie("session", "user-123", "cookie-secret");
// send with res.header("Set-Cookie", setCookieHeader) or use res.cookie(...)
var cookieValue = split(split(setCookieHeader, ";")[0], "=")[1];
var session = readSecureCookie(urlDecode(cookieValue), "cookie-secret");
hashPassword(password, iterations?)usa PBKDF2 con SHA-256 e sale casualeverifyPassword(password, passwordHash)esegue un confronto in tempo costantecreateJwt(payload, secret, expiresInSeconds? | options?)firma token HS256 e aggiungeiat; le options possono impostareexpiresInSeconds,issuer(iss),audience(aud) enotBeforeSeconds(nbf)verifyJwt(token, secret, options?)valida la firma,nbf,expe gliissuer/audienceattesi opzionaliverifyJwtsolleva errori di autenticazione standardizzati per token mancanti, non validi, non ancora validi o scaduti- Negli handler HTTP/REST preferisci
req.auth.authenticateBearerJwt(secret)oreq.auth.authenticateCookieJwt(cookieName, jwtSecret, cookieSecret?)— verificano il token e popolano claim/ruoli direq.auth. Usareq.auth.requireRole/requirePermissionper l'autorizzazione.setVerifiedSubresta per i casi ingress/gateway senza un JWT locale. generateCsrfToken(secret, ttlSeconds?)crea token CSRF firmati per i flussi di mutazione di form e APIverifyCsrfToken(token, secret)valida firma + scadenza e restituisce booleancsrfField(secret, ttlSeconds?)restituisce un frammento HTML di input nascosto_csrfper i form (il token corrisponde aenableCsrf)bindForm(body, fields)associa/valida i campi del form (name,required,trim,minLength/maxLength,pattern: "email") in{ ok, values, errors }formErrors(errors)rende un elenco HTML di errori con escapepageLayout(title, bodyHtml, options?)restituisce un involucro HTML minimale a documento intero per le app stringa@PAGE(preferisciui.layoutper i layout ricchi)createSecureCookie(name, value, secret, options?)restituisce una stringa di headerSet-Cookiefirmata con default sicurireadSecureCookie(cookieValue, secret)verifica un valore di cookie firmato e restituisce il plaintext onull
13.16.1a Job in background (coda leggera)
Le unità async brevi (email, webhook) usano una coda SQLite in ./.malda/jobs.db. È distinta dai processi workflow durevoli.
var jobId = enqueueJob("mail", {"to": "user@example.com"}, {"maxAttempts": 3});
var job = claimJob("mail", "worker-1");
if (job != null) {
// ... do work with job.payload ...
completeJob(job.id, {"sent": true});
// or: failJob(job.id, "SMTP timeout", true);
}
var open = listJobs("mail", "pending", 20);
var one = getJob(jobId);
enqueueJob(queue, payload, options?)— options:runAt,maxAttempts,correlationIdclaimJob(queue, workerId?)— restituisce un job in esecuzione onullcompleteJob(jobId, result?)/failJob(jobId, error?, retry?)getJob(jobId)/listJobs(queue?, status?, limit?)
13.16.2 Contesto di autenticazione della richiesta (req.auth)
Sia HttpServer sia RestServer espongono la stessa superficie req.auth su ogni richiesta:
- Stato:
verified,sub/subject,claims,roles,permissions,token - AuthN:
authenticateBearerJwt(secret),authenticateCookieJwt(cookieName, jwtSecret, cookieSecret?),setVerifiedSub(sub),setAnonymous()/clear() - AuthZ:
claim(name, default?),hasClaim,hasRole/requireRole,hasPermission/requirePermission,requireVerified()
function requireAuth(req, res, next) {
req.auth.authenticateBearerJwt(getEnv("MALDA_JWT_SECRET"));
next();
}
server.use(requireAuth, { "except": ["/api/health", "/metrics"] });
13.18 Generazione di range
var range1 = range(5); // Generate [0, 1, 2, 3, 4]
var range2 = range(1, 10); // Generate [1, 2, 3, 4, 5, 6, 7, 8, 9]
var range3 = range(0, 10, 2); // Generate [0, 2, 4, 6, 8] (step of 2)
var range4 = range(10, 0, -1); // Generate [10, 9, 8, 7, 6, 5, 4, 3, 2, 1] (negative step)
13.19 Funzioni di gestione errori
exit(0); // Exit program with exit code 0 (success)
exit(1); // Exit program with exit code 1 (error)
error("Something went wrong"); // Throw runtime error with message
assert(x > 0, "x must be positive"); // Assert condition is true, throw error if false
assert(isValid, "Validation failed"); // Assert without custom message
exit(code)termina immediatamente il programma con il codice di uscita specificato (0 = successo, non zero = errore)error(message)solleva un errore a runtime che può essere catturato dai meccanismi di gestione erroriassert(condition, message?)è utile per debug e validazione - solleva un errore se la condizione è falsa
13.19.1 result e option
Preferisci questi moduli quando una funzione deve segnalare successo o assenza senza sollevare eccezioni. Restituiscono variant con tag Ok/Err e Some/None — la stessa forma di una dichiarazione type Result = Ok(value) | Err(message), ma non devi dichiarare il tipo. I nomi dei moduli sono in minuscolo (result, option); un type Result dichiarato dall'utente è un nome diverso.
Usa try/catch per i fallimenti inattesi (vedi 8. Strutture di controllo). Usa result/option per gli esiti attesi nel valore di ritorno.
function parseAge(raw) {
var n = toIntOrNull(raw);
if (n == null) {
return result.err("not an int");
}
return result.ok(n);
}
print(result.unwrapOr(parseAge("12"), 0));
print(result.isErr(parseAge("x")));
var present = option.some("hi");
var missing = option.none();
print(option.unwrapOr(present, "no"));
print(option.isNone(missing));
result.ok(value)/result.err(value)— costruisce un variantOkoErrresult.isOk(r)/result.isErr(r)— test sul tagresult.unwrapOr(r, fallback)— payload diOk, altrimentifallbackresult.map(r, fn)— applicafna un payloadOk; lasciaErrinvariatoresult.andThen(r, fn)— seOk, chiamafn(payload)e restituisce quel Result; seErr, non chiamafn.fndeve restituireOk/Err(usamapper trasformare un payload nudo)option.some(value)/option.none()— costruisce un variantSomeoNoneoption.isSome(o)/option.isNone(o)/option.unwrapOr(o, fallback)/option.map(o, fn)/option.andThen(o, fn)— lo stesso schema per i valori opzionali
function parseAge(raw) {
var n = toIntOrNull(raw);
if (n == null) {
return result.err("not an int");
}
return result.ok(n);
}
function doubleAge(n) {
return result.ok(n * 2);
}
print(result.unwrapOr(parseAge("12") |> result.andThen(doubleAge), 0));
print(result.isErr(parseAge("x") |> result.andThen(doubleAge)));
Non trattare i type hint (var n: int = …) come validazione a runtime. Per i payload a forma JSON usa schema e validate(). Tutorial: errori, Result/Option e validate dello schema.
13.19.2 grounded.wrap
Le citazioni di retrieval (GraphMemory, file, tool) non sono un kind di valore visibile a match. Avvolgi un payload così la provenienza è un dict che puoi leggere:
var g = grounded.wrap("the sky is blue", [
{ "source": "wiki", "id": "p1", "span": "12-40" }
]);
print(g.value);
print(g.sourced);
print(g.citations[0].source);
grounded.wrap(value, citations?)— restituisce{ value, citations, sourced }.sourcedè true quando l'elenco delle citazioni è non vuoto dopo la normalizzazione.- Ogni citazione è
{ source, id?, span? }. Una citazione stringa diventa{ source }. Non esiste un alias piattogrounded(). - ASK opt-in di GraphMemory:
memory.ask(query, maxResults?, options?)(oppurequery(..., { grounded: true })) avvolge gli hit con citazioni dafilePath/source/nodeId.query()semplice restituisce ancora un array. Vedi 19. GraphMemory §19.3.15.
13.19.3 cap.fileRead
@effects("io") è un allow-list di nomi. Passa un token non contraffabile in un tool così il modello non può inventare un path. I token sono oggetti host sigillati, non dict — JSON e object literal non possono rigenerarne uno.
var notes = cap.fileRead("notes.md");
print(notes.kind);
print(cap.is(notes, "fileRead"));
var forged = false;
try {
cap.read({ "kind": "fileRead", "path": "notes.md" });
} catch (e) {
forged = true;
}
print(forged);
cap.fileRead(path)/cap.fileWrite(path)/cap.dirList(path)— emette un token conkindepath. Non esiste un alias piattocap().cap.read(token)/cap.write(token, content)/cap.list(token)— consuma solo un token corrispondente. Stringhe e dict{ kind, path }sollevano un'eccezione.cap.is(value, kind?)— true solo per un token reale.cap.confine(token, relativePath)restituisce un token più stretto dello stesso kind; i path fuori dal padre sollevano un'eccezione.io.readFile/io.writeFile/io.listDirectoryaccettano anche un token corrispondente. I path stringa ordinari continuano a funzionare.- Marca gli handler che emettono o consumano token con
@effects("cap")(o elenca sia"io"sia"cap"). JavaScript può emettere /is/confine; il consumo dei file è solo host. - Esempio:
Examples/Tools/capability_tokens.malda.
13.20 Pianificazione strutturata dei task
decomposeTask, executePlan e createSubmitPlanTool vivono in 18. Orchestrazione di agenti (§ 18.13). runProgram esegue un valore chiuso api / program(ApiName) senza ulteriori chiamate LLM — vedi 10. Prompt (§ 10.8 API chiuse e programmi deterministici).
13.21 Funzioni di creazione tool
Le factory di tool per agenti (createReadFileTool, createWriteFileTool, createReplaceInFileTool, createEditFileTool, createInsertAtLineTool, createGrepTool, createListDirectoryTool, createAskUserTool, createWebSearchTool, createGitStatusTool, createGitAddTool, createGitCommitTool, createGitLogTool, createGitDiffTool, createGitBranchTool, createGitCheckoutTool, createGitPushTool, createGitPullTool, createRunCommandTool, createRunMALDATool, createCompileMALDATool, createGetSymbolsTool, createGetParseErrorsTool, createSubmitPlanTool, createGlobTool, createCreateMcpAgentScriptTool) vivono in 18. Orchestrazione di agenti (§ 18.6). createNativeCallback incapsula una funzione MALDA come delegate .NET — vedi 30. Interop .NET.
13.22 Operazioni dei workflow durevoli
Gli helper di runtime, query e controllo (startWorkflow, getWorkflowStatus, getWorkflow, getWorkflowSteps, getWorkflowEvents, getWorkflowMetrics, listWorkflows, listWorkflowDeadLetters, requeueDeadLetter, runWorkflowInstance) vivono in 22. Workflow durevoli.
13.23 Logging del runtime degli agenti
Gli helper diagnostici (enableAgentVerboseLogging, setAgentVerbosePhase, setAgentStatusBanner, reportRalphStatus) vivono in 18. Orchestrazione di agenti (§ 18.5 e 18.18 Ralph Wiggum). Influenzano solo la presentazione e non cambiano mai il risultato di un agente.
13.24 Funzioni Web UI
Gli helper dei componenti server (renderTemplate, componentFragment, componentLiveEmit, componentState*, onAgentProgress, clearAgentProgress) e i controlli ui.* vivono in 24. Componenti server Web UI. Parti da 23. Panoramica Web UI se stai scegliendo un modello UI.
13.25 Pacchetti opzionali (non nel core)
Il BuiltInRegistry del core elenca solo i simboli open-source del core. I built-in di dominio possono essere distribuiti in pack separati; caricali con loadNativeModule(...) e distribuisci gli assembly richiesti accanto all'app. Il core non registra automaticamente i globali dei pack.
Vedi anche
- Appendice — Pacchetti opzionali
- Input/Output — console, file, path, ambiente, I/O dell'host; preferisci
io.* - Prompt —
runProgrameapi/program(ApiName)chiusi - Componenti server Web UI — UI server-side e API dei componenti
- Orchestrazione di agenti — Tool, piani di task e logging degli agenti
- Workflow durevoli — Built-in del runtime dei workflow