Luma public docs
English

Kütüphane

Standard Library

Standard library, luma/std/ altında Luma ile yazılmış ince pure fn sarmalayıcılarından oluşur. Hepsi deterministiktir; where kurallarında, @valid ifadelerinde ve agent method'larında serbestçe çağrılabilir. Tek istisna std/io'dur — o io fn'lerden oluşur ve where/@valid içinde kullanılamaz.

Kullanım ve alias kuralı

luma
import math from "std/math"         // math.abs(...)
import "std/math"                    // abs(...)  — no namespace
Aşağıdaki on ad ayrılmıştır — bir dependency onlardan birini alamaz

Agent method gövdesinde x = name.function(...) satırı belirsizdir: hem bir standard library çağrısı hem de bir uses dependency'sine yapılan çağrı olabilir. Parser bunu bir namespace adları kümesine karşı çözer; bu küme aşağıdaki on geleneksel alias artı gerçekte hangi alias ile import ettiysen o. Geri kalan her şey dependency çağrısı sayılır.

Üçü de ölçülmüş üç sonuç:

  • İstediğin alias ile import edebilirsin. import numbers from "std/numeric" ardından numbers.round(3.7) çalışır — import çözülürken senin alias'ın kaydedilir. Aşağıdaki tablo bir kısıt değil, gelenektir.
  • Bir uses dependency'si bu on addan biriyle adlandırılamaz. uses col: Helper ve ardından r = col.give() namespace çağrısı olarak ayrıştırılır, dependency'ye hiç ulaşmaz ve çalışma zamanında 'col' variable is not defined yet. ile düşer — dependency'den hiç söz etmeyen bir mesaj.
  • İkisi de olmayan bir ad — bir yazım hatası ya da unuttuğun bir import — parse zamanında adıyla düşer: 'helper' is not defined as a dependency.
ModülGeleneksel aliasTür
std/mathmathpure
std/stringstrpure
std/datedatepure
std/collectionscolpure
std/regexregexpure
std/numericnumpure
std/jsonjsonpure
std/schemaschemapure
std/agentagentpure
std/findingsfindingsio
std/ioioio
✓ Doğru
agent A {
  uses helper: Helper

  fn f() -> S {
    r = helper.give()
    return { v: r.v }
  }
}
✗ Yanlış
agent A {
  uses col: Helper

  fn f() -> S {
    r = col.give()
    // Error: 'col' variable is
    //        not defined yet.
  }
}

std/math

Bu modül tamamen Luma ile yazılmıştır — luma/std/math.luma içinde kaynağını okuyabilirsin.

math.abs(x: float) → float

Mutlak değer.

math.abs(0 - 7)   // 7
math.sum(values: float[]) → float

Listedeki sayıların toplamı. Boş liste için 0.

math.sum([1, 2, 3])   // 6
math.min(a: float, b: float) → float

İki sayıdan küçüğü.

math.max(a: float, b: float) → float

İki sayıdan büyüğü.

math.clamp(x: float, minimum: float, maximum: float) → float

Değeri verilen aralığa sıkıştırır.

math.clamp(150, 0, 100)   // 100
luma
import math from "std/math"

schema Calculation {
  values: float[1..10]
  total: float

  where math.abs(math.sum(values) - total) <= 0.01
}

std/string

str.lower(value: string) → string

Küçük harfe çevirir.

str.upper(value: string) → string

Büyük harfe çevirir.

str.trim(value: string) → string

Yalnızca baştaki ve sondaki boşlukları siler. Ortadaki boşluklar korunur.

str.trim("  Ayşe  Yılmaz  ")   // "Ayşe  Yılmaz"
str.startsWith(value: string, prefix: string) → bool

Önek kontrolü.

str.endsWith(value: string, suffix: string) → bool

Sonek kontrolü.

str.replace(value: string, search: string, replacement: string) → string

Tüm eşleşmeleri değiştirir. Düz metin araması yapar — regex değildir.

str.replace("a-b-c", "-", "/")   // "a/b/c"
str.textLength(value: string) → int

UTF-16 birimi cinsinden uzunluk — astral bir karakter 2 sayılır. (Built-in length ile aynı işi yapar.)

luma
import str from "std/string"

schema Text {
  name: string @valid(x => str.startsWith(str.trim(x), "Ayşe"))
  slug: string @valid(x => str.lower(x) == "luma-dsl")
  description: string @valid(x => str.textLength(x) > 5)
}
Ortadaki boşluğu temizlemek

str.trim içerideki tekrarlı boşluklara dokunmaz. Normalize etmek için regex kullan:

import regex from "std/regex"

normalized = regex.replace(raw, "\\s+", " ")

std/date

Kabul edilen biçimler: YYYY-MM-DD ve tam ISO 8601 date-time (Z veya ±HH:MM offset zorunlu). Takvimsel olarak geçersiz tarihler (2024-02-31) reddedilir. Tüm alan okuma işlemleri UTC üzerinden yapılır.

date.isValid(value: string) → bool

Ayrıştırılabilir ve gerçek bir tarih mi?

date.isBefore(left: string, right: string) → bool

left < right. Taraflardan biri geçersizse hata değil false döner.

date.isAfter(left: string, right: string) → bool

left > right. Geçersiz girdide false.

date.diffDays(from: string, to: string) → int

Aradaki tam gün farkı (kesirli kısım atılır). Geçersiz tarihte hata fırlatır.

date.diffDays("2024-01-01", "2024-01-06")   // 5
date.year(value: string) → int

UTC yılı. Geçersiz tarihte hata.

date.month(value: string) → int

UTC ayı, 1–12 (0 tabanlı değil). Geçersiz tarihte hata.

date.day(value: string) → int

UTC ayın günü. Geçersiz tarihte hata.

date.toDate(value: string) → string

Değerin ilk 10 karakterini döndürür — date-time'ı YYYY-MM-DD'ye indirir.

date.toDate("2024-01-02T10:20:30Z")   // "2024-01-02"
luma
import date from "std/date"

schema Period {
  start: string @fmt("date") @valid(x => date.isValid(x))
  end: string @fmt("date")
  days: int @valid(x => x > 0)

  where date.isBefore(start, end)
  where date.diffDays(start, end) == days
  where date.year(start) >= 2024
}
isValid ile diffDays'in hata davranışı farklıdır

Karşılaştırma fonksiyonları (isBefore/isAfter) geçersiz girdide sessizce false döner; hesaplama fonksiyonları (diffDays, year, month, day, toDate) hata fırlatır. Nullable tarih alanlarında önce date.isValid ile koru.

std/collections

col.all(values: bool[]) → bool

Tüm elemanlar true mu? Boş liste için true.

col.any(values: bool[]) → bool

En az biri true mu? Boş liste için false.

col.contains(values: string[], value: string) → bool

Liste elemanı içeriyor mu?

col.join(values: string[], separator: string) → string

String listesini birleştirir.

col.unique(values: string[]) → string[]

Tekrarları atar; sıra korunur.

col.flatten(values: string[][]) → string[]

İç içe listeleri tamamen düzleştirir.

col.flatten([["a"], ["b", "c"]])   // ["a", "b", "c"]
luma
import col from "std/collections"

schema Collection {
  tags: string[] @valid(x => col.contains(x, "vip"))
  groups: string[][]
  flags: bool[] @valid(x => col.any(x))

  where col.contains(tags, "vip")
  where contains(col.flatten(groups), "approved")
  where col.join(tags, ",") == "vip,active"
}
col.contains ile built-in contains farkı

Built-in contains hem string'de alt-dize hem array'de eleman araması yapar ve import gerektirmez. col.contains ise yalnızca string listeleri için tiplenmiştir. Scalar string araması yapacaksan built-in olanı kullan:

name: string @valid(x => contains(x, "Ayşe"))     // built-in
tags: string[] @valid(x => col.contains(x, "vip"))   // std/collections

Kurma ve sıralama (v0.4.0)

col.append(values: any[], value: any) → any[]

Değeri sona ekleyen yeni bir liste döner. Hiçbir std fonksiyonu girdisini değiştirmez.

col.concat(first: any[], second: any[]) → any[]

İki listeyi yeni bir listede birleştirir.

col.sort(values: any[]) → any[]

Artan, kararlı sıralama. Karşılaştırılabilir eleman türleri string, int ve float; bir listenin sıralanamaz olmasının iki yolu farklı mesajlarla reddedilir: başka türden bir eleman col.sort supports string, int and float values., karşılaştırılabilir ama karışık türler ise col.sort values have mixed types. verir. Liste olmayan argüman col.sort expects a list. verir.

col.sortBy(items: any[], field: string) → any[]

Kayıt listesini bir alana göre artan ve kararlı sıralar. Anahtar string alan adıdır, lambda değil — Luma'da lambda değeri yok. Alan her elemanda bulunmalı ve tek tipli olmalı.

by_amount = col.sortBy(items, "amount")
col.sortByDesc(items: any[], field: string) → any[]

col.sortBy ile aynı sözleşme, azalan.

col.keys(entries: map<any>) → string[]

Map'in anahtarları, deterministik yineleme sırasıyla.

Dilimleme ve biçimlendirme (v0.4.0)

col.slice(values: any[], start: int, end: int) → any[]

start'tan end'e kadar (hariç) elemanlar. Negatif sınırlar adıyla reddeder; start > end boş liste verir; uzunluğu aşan end kırpılır.

col.take(values: any[], count: int) → any[]

İlk count eleman. Uzunluğu aşan count tüm listeyi döner — hata değil. Negatif sayı adıyla reddeder.

col.drop(values: any[], count: int) → any[]

İlk count elemandan sonrası; uzunluğu aşınca boş liste.

col.chunk(values: any[], size: int) → any[]

size boyutlu kovalara böler; son kova kısa kalabilir. size < 1 adıyla reddeder.

col.chunk([1, 2, 3, 4, 5], 2)   // [[1, 2], [3, 4], [5]]
col.zip(first: any[], second: any[]) → any[]

Elemanları indekse göre ikili listelerde eşler; uzun liste kısaya göre kesilir.

col.reverse(values: any[]) → any[]

Ters sırada yeni bir liste.

col.indexOf(values: any[], value: any) → int

İlk eşleşmenin indeksi, yoksa -1.

col.first(values: any[]) → any

İlk eleman. Boş liste adıyla reddeder: col.first on an empty list.

col.last(values: any[]) → any

Son eleman; boş liste sözleşmesi col.first ile aynı.

Gruplama ve toplama (v0.4.0)

col.groupBy(items: any[], field: string) → map<any>

Kayıtları string değerli bir alana göre kovalar. Anahtar sırası deterministiktir (alan değerine göre sıralı); string olmayan anahtar alanı adıyla reddeder.

buckets = col.groupBy(orders, "region")   // map<Order[]>
col.distinctBy(items: any[], field: string) → any[]

Her ayrık alan değeri için ilk kayıt. Sonuç alan değerine göre sıralıdır, girdi sırasına göre değil — col.sortBy'a delege ediyor; yalnızca bir kova içinde hangi kaydın kazandığı girdi sırasını izler.

col.sum(values: float[]) → float

Sayısal listenin toplamı; boş liste için 0. Int listesi kabul eder.

col.count(items: any[], field: string, value: any) → int

field alanında value taşıyan kayıt sayısı; eşleşme yoksa 0.

Sınır hataları doğrulama katmanından gelir

Luma ile yazılmış collection fonksiyonları sınır sözleşmelerini parametre annotation'larıyla (@valid + @feedback) ifade eder; hataları bu yüzden doğrulama önekini taşır: Error: pure col.first.values: col.first on an empty list. Önekten sonraki mesaj metni testlerle byte byte sabitlenmiştir.

std/regex

Desenler JavaScript regex sözdizimini kullanır. Desen uzunluğu 1000 karakterle sınırlıdır; geçersiz desen hata fırlatır.

regex.matches(value: string, pattern: string) → bool

Desen metinde bulunuyor mu? (test semantiği — tam eşleşme için ^…$ yaz.)

regex.replace(value: string, pattern: string, replacement: string) → string

Tüm eşleşmeleri değiştirir (global bayrak).

regex.replace("Ada 42 elma", "[0-9]+", "#")   // "Ada # elma"
regex.find(value: string, pattern: string) → string | null

İlk eşleşmeyi döndürür; yoksa null.

regex.count(value: string, pattern: string) → int

Eşleşme sayısı; yoksa 0.

regex.isValidPattern(pattern: string) → bool

Desen derlenebiliyor mu? Hata fırlatmaz.

luma
import regex from "std/regex"

schema RegexExample {
  code: string @valid(x => regex.matches(x, "^[A-Z]{3}-[0-9]+$"))
  text: string
  found: string | null

  where regex.count(text, "a") == 2
  where regex.find(text, "[0-9]+") == found
}
Desen içindeki | karakteri güvenlidir

@valid gövdesindeki && ve || birleşimleri string ve parantez farkındalığıyla bölünür; regex deseninin içindeki | karakteri ifadeyi bozmaz:

code: string @valid(x => regex.matches(x, "^(AA||BB)-[0-9]+$"))

std/numeric

num.round(value: float) → int

En yakın tam sayıya yuvarlar. Sonlu olmayan değerde hata.

num.floor(value: float) → int

Aşağı yuvarlar.

num.ceil(value: float) → int

Yukarı yuvarlar.

num.isFinite(value: float) → bool

Sonlu bir sayı mı? NaN/Infinity için false.

num.isInteger(value: float) → bool

Tam sayı mı?

num.approximatelyEqual(left: float, right: float, tolerance: float) → bool

|left − right| ≤ tolerance. Kayan nokta karşılaştırmaları için doğru araç budur.

num.approximatelyEqual(0.1 + 0.2, 0.3, 0.0001)   // true
num.clamp(value: float, minimum: float, maximum: float) → float

Değeri aralığa sıkıştırır.

luma
import num from "std/numeric"

schema InvoiceItem {
  quantity: float | null
  unit_price: float | null
  total: float | null

  where quantity == null || unit_price == null || total == null || num.approximatelyEqual(quantity * unit_price, total, 0.01)
    @feedback("quantity * unit_price toplamına uymuyor")
}
Para hesaplarında her zaman tolerans kullan

where total == subtotal + tax gibi doğrudan eşitlikler kayan nokta hataları yüzünden sağlam modellerde bile başarısız olur ve gereksiz retry'a yol açar. num.approximatelyEqual(…, 0.01) kuruş hassasiyeti için uygun bir seçimdir.

std/json

json.parse(raw: string) → any

JSON metnini değere çevirir. Geçersizse Invalid JSON text. hatası.

json.stringify(value: any) → string

Kompakt JSON metni.

json.pretty(value: any) → string

2 boşluk girintili JSON metni.

json.compact(value: any) → string

stringify ile aynı — okunabilirlik için ayrı isim.

json.isValid(raw: string) → bool

Ayrıştırılabilir mi? Hata fırlatmaz.

json.has(value: any, path: string) → bool

Nokta ayraçlı yolda değer var mı? undefined değilse true.

json.has(data, "seller.name")
json.getString(value: any, path: string) → string | null

Yoldaki değer string ise döndürür; yoksa veya tipi farklıysa null.

json.getNumber(value: any, path: string) → float | null

Yoldaki değer sayı ise döndürür, aksi halde null.

json.getBoolean(value: any, path: string) → bool | null

Yoldaki değer boolean ise döndürür, aksi halde null.

Şeklini kontrol etmediğin veriyi yürümenin tek yolu bu aile

json.parse'tan gelen değerin tipi any'dir ve any üzerinde doğrudan alan erişimi, alan yoksa hata fırlatır:

Error: Field 'd.isyeri' was not found.

Yani bariz yoldan koruyamazsın — if d.isyeri != null, karşılaştırma olmadan önce erişimin kendisinde patlar. Bu, xs[5] is out of bounds (length 2). ve m["missing"] is not present. ile aynı kural ve bilinçli: buradaki sessiz bir null akıp giderek doğrulanmış çıktının içine düşerdi, ki bu dilin var olma sebebi tam olarak bunu engellemek. Ayrıca alan adındaki yazım hatası "yok" diye okunmak yerine yakalanmış oluyor.

Şekil senin kontrolündeyse schema bildir ve işi doğrulamaya bırak. Değilse — heterojen payload'lar, bir ext.json kolonu, üçüncü taraf webhook — gezinme yüzeyi json.has artı json.get* ailesidir; get* fonksiyonları hem eksik hem yanlış tipli için null döndürdüğü için tek kontrol ikisini birden kapsar.

luma
import json from "std/json"

schema JsonExample {
  raw: string
  data: any
  payload: json<Payload>

  where json.isValid(raw)
  where json.has(data, "id")
  where json.getString(data, "id") == "p1"
  where json.getNumber(data, "count") == 2
}

agent JsonProducer {
  fn create() -> JsonExample {
    raw: string  = "{\"id\":\"p1\",\"count\":2}"
    data: any     = json.parse(raw)
    payload: Payload = json.parse(raw)
    return { raw: raw, data: data, payload: payload }
  }
}
getX null döndürünce sebebi ayırt edilemez

json.getString(v, "a.b") hem "yol yok" hem "değer string değil" durumunda null döndürür. Ayrımı önemsiyorsan önce json.has(v, "a.b") ile kontrol et.

std/schema

Schema'lar compile-time tanımlardır ve runtime'da değiştirilemez; bu modül onları yalnızca okur. Bir schema adı expression içinde geçtiğinde otomatik olarak schema referansına dönüşür.

schema.name(ref) → string

Schema adı.

schema.description(ref) → string | null

Schema seviyesi @desc metni.

schema.prompt(ref) → string | null

Schema seviyesi @prompt metni. Modele otomatik gönderilmez; prompt'a sen eklersin.

schema.describe(ref) → any

Tam descriptor: { name, description, prompt, fields, rules, components }.

schema.fields(ref) → any[]

Alan descriptor'ları listesi (aşağıdaki şekil).

schema.field(ref, field_name: string) → any

Tek alanın descriptor'ı; yoksa null.

schema.hasField(ref, field_path: string) → bool

Nokta ayraçlı yol var mı? Nested schema'lara ve array eleman tiplerine iner.

schema.hasField(InvoiceExtract, "seller.name")   // true
schema.rules(ref) → any[]

where ve koşullu kuralların listesi: { kind: "where" | "conditional", expression, feedback }.

schema.components(ref) → string[]

Composition parçaları. Tagged union üzerinde ise üye adlarını döndürür — v0.9.0'dan beri resmî ve testle sabit. İkisi de değilse []. İsim → referans köprüsü yoktur: string'ler üyeleri adlandırır, onlara çözülmez.

schema.catalog(refs: any[]) → any[]

Birden çok schema'nın descriptor listesi. Tekrar eden schema hata verir.

schema.toJsonSchema(ref) → any

Tek schema'nın JSON Schema karşılığı. $defs içermez.

schema.toJsonSchemas(refs: any[]) → any

Ad → JSON Schema eşlemesi.

Alan descriptor'ının şekli

json
{
  "name": "name",
  "type": "string",
  "optional": false,
  "description": null,
  "title": "Ad Soyad",
  "format": null,
  "aliases": [],
  "deprecated": null,
  "examples": ["Ayşe Yılmaz"],
  "constraints": { "minLength": 2, "maxLength": 40 }
}

type alanı Luma sözdiziminde yazılır: "string", "int", "LineItem[]", "map<float>", "string | null", "enum[\"a\", \"b\"]". optional, alan ? ile işaretliyse veya @default taşıyorsa true olur. constraints yalnızca tanımlı olan kısıtları içerir.

luma
import schema from "std/schema"
import json from "std/json"

agent SchemaInspector {
  fn inspect() -> ReflectionResult {
    catalog     = schema.catalog([Invoice, Receipt])
    field       = schema.field(Invoice, "invoice_number")
    json_schema = schema.toJsonSchema(Invoice)

    return { name: schema.name(Invoice)
      , description: schema.description(Invoice)
      , field_name: field.name
      , has_field: schema.hasField(Invoice, "invoice_number")
      , catalog_count: length(catalog)
      , rule_count: length(schema.rules(Invoice))
      , json_description: json.getString(json_schema, "description") }
  }
}
@prompt ile schema'yı kendi kendini belgeleyen hale getir

Extraction talimatını @prompt içine yazıp schema.prompt(...) ile okumak, talimatın schema ile birlikte versiyonlanmasını sağlar — alan eklediğinde talimatı da aynı yerde güncellersin.

instruction = schema.prompt(InvoiceExtract)
result = ask "{instruction}\n\nMARKDOWN:\n{markdown}" -> InvoiceExtract

std/agent

Hata nesnelerini okumak ve prompt parçaları kurmak için deterministik yardımcılar. Bu modül ask, tool, retry veya memory'yi sarmalamaz — bunlar dilin kendi özellikleridir.

agent.errorCode(error: any) → string | null

Hata kodunu okur (TOOL_TIMEOUT, MODEL_RATE_LIMIT…). Kod yoksa null.

agent.errorMessage(error: any) → string | null

Hata mesajını okur.

agent.isRetryable(error: any) → bool

retryable bayrağı; yoksa false.

agent.errorDetails(error: any) → any

Yapılandırılmış detay nesnesi; yoksa null.

agent.toolError(code: string, message: string, retryable: bool, details?: any) → any

Typed tool-error nesnesi üretir.

agent.toolError("VALIDATION_FAILED", "Fatura doğrulanamadı", true, { field: "total" })
agent.section(title: string, body: string) → string

"Başlık:\nmetin" biçiminde bölüm üretir.

agent.compose(parts: string[]) → string

Bölümleri çift satır sonu ile birleştirir.

luma
import agent from "std/agent"

agent Helper {
  tools: [db_write]

  fn run(data: string) -> Result {
    try {
      written = tool db_write({ request_id: "r-1", value: data })
      return { status: "ok", message: "" }
    } catch error {
      if agent.isRetryable(error) {
        return { status: "temporary_error", message: agent.errorMessage(error) }
      }
      return { status: agent.errorCode(error), message: agent.errorMessage(error) }
    }
  }
}

Prompt kurma

luma
prompt = agent.compose([
  agent.section("Talimat", "Yalnızca geçerli JSON döndür."),
  agent.section("Kurallar", "Bulunmayan alanları null yap."),
  agent.section("Veri", json.pretty(record))
])

result = ask "{prompt}" -> Output
Talimat:
Yalnızca geçerli JSON döndür.

Kurallar:
Bulunmayan alanları null yap.

Veri:
{ … }

std/findings (v0.8.0)

Bir @severity("warn") kuralının değer üzerinde bıraktığı şerhleri okur. Soft kural koşuyu durdurmaz; bulduğu şey değeri üreten operasyona kaydedilir ve programın ona ulaşma yolu bu modüldür.

findings.of(value: any) → Finding[]

Bu değer için kaydedilmiş finding'ler; yoksa boş liste. Okumak onları okundu işaretler — koşu sonu uyarısını susturan şey budur.

findings.count(value: any) → int

Listeyi oluşturmadan sayısını verir. O da okuma sayılır.

Finding alanıTipNe tutar
rulestringDüşen kural; valid:<ifade> ya da where:<ifade>. Tavanın işaret kaydı findings.capped kullanır.
pathstringNerede düştüğü, ör. Maker.make.return.score.
messagestringKuralın düşerken vereceği metin.
severitystringBugün "warn".
attemptintDeğerin kabul edildiği deneme; retry olmadıysa 1.
luma
import findings from "std/findings"

schema Scored {
  score: int @valid(x => x >= 0) @severity("warn")
}

agent Auditor {
  uses maker: Maker

  fn audit() -> Audit {
    shaded = maker.make(-7)
    flaws = findings.of(shaded)
    return { score: shaded.score, flaws: length(flaws), first_rule: flaws[0].rule }
  }
}
Kuraldan çağıramayacağın tek io modülü bu

İki fonksiyon da koşu durumunu okur, yani io'durlar — @valid, where ve pure fn gövdeleri onları adıyla reddeder:

Error: findings is io and cannot be used inside @valid or where rules: findings.count

Asıl mesele bu red: olmasaydı bir kural kendi ihlallerini okuyabilir ve sonucu kuralların koşma sırasına bağlı hâle gelirdi.

Finding'ler operasyon başına, parallel over altında eleman başına yaşar. Hiç şerhlenmemiş bir değer boş liste döner — çağırmadan önce korunman gereken bir durum yok. Tavan ve okunmamış uyarısı dahil tam semantik Schema & Validation sayfasında.

std/http (v0.4.0)

std/http HTTP servisleriyle sıfır bağımlılıkla konuşur — runtime'ın yerleşik fetch'i üzerinde çalışır. Bunun bedeli çağrı başına bir alt süreç, kabaca 30–80 ms: expression evaluator senkron ve senkron bir fetch yok, o yüzden istek bir alt süreçte koşuyor. Kaba taneli çağrılar için sorun değil — sayfalanmış çekme, birkaç yüz istek — ama büyük bir kümenin her satırını zenginleştirmek için yanlış araç; orada süreç maliyeti baskın çıkar. ROADMAP.md § U5'te izleniyor. Her fonksiyon standart kütüphanenin dışa açtığı ilk şemayı döner:

luma
schema HttpResponse {
  status: int
  body: string
  headers: map<string>
}
http.get(url: string, headers: map<string>, timeout: int) → HttpResponse

GET. timeout milisaniyedir ve zorunludur — varsayılan yok; sessiz sonsuz bekleme sessiz bir başarısızlıktır.

http.postJson(url: string, body: any, headers: map<string>, timeout: int) → HttpResponse

JSON gövdeli POST; content-type varsayılanı application/json.

http.put(url: string, body: any, headers: map<string>, timeout: int) → HttpResponse

JSON gövdeli PUT.

http.patch(url: string, body: any, headers: map<string>, timeout: int) → HttpResponse

JSON gövdeli PATCH.

http.delete(url: string, headers: map<string>, timeout: int) → HttpResponse

DELETE.

Statü kodları hata değildir

404 de 500 de normal döner — statünün ne anlama geldiğine karar vermek programın işidir. Fırlatan tek başarısızlık host'a hiç ulaşamamaktır: http.get could not reach '<url>': <sebep>.

luma
import http from "std/http"

response = http.get("https://api.example/v1/orders", { "authorization": token }, 5000)
if response.status == 200 {
  data = json.parse(response.body)
}
Credential ve hacim

Redaksiyon header'ın adına göre işler, değerinin ne kadar hassas olduğuna göre değil; bu yüzden onu genel bir sır filtresi saymayın. Adı api_key · apikey · api-key · password · secret · credential · authorization ile eşleşen (büyük/küçük harf duyarsız, alt dize) bir header'ın değerinin tamamı [REDACTED] ile değiştirilir — x-api-key bu kuralın kapsamındadır, authorization ise yalnızca bearer token'ını değil değerinin tamamını kaybeder. Ayrıca runtime'ın zaten bildiği her sır değeri (ortamdan ve model profillerinden çözülen api key'ler) geçtiği her yerde değiştirilir. Diğer her header trace'e düz metin gider — cookie, x-auth-token, x-session, bir imza header'ı. URL ve gövde hiç loglanmaz.

std/state (v0.4.0)

std/state artımlı çalışmanın temel taşıdır: tek bir JSON dosyasının desteklediği düz key→string deposu. Watermark zaten saklanmış bir string'dir — ayrı bir soyutlama yok.

state.read(key: string) → string | null

Saklanan değer; anahtar hiç yazılmamışsa null — ilk koşu kendini ayırt edebilir.

state.write(key: string, value: string) → string

Kalıcılaştırır ve değeri döner. Yazma atomiktir (geçici dosya + rename): yarıda kesilen koşu depoyu bozamaz.

state.keys() → string[]

Saklı tüm anahtarlar.

luma
import state from "std/state"

cursor = state.read("orders_watermark")     // ilk koşu: null
state.write("orders_watermark", latest)
Varsayılan konum yok

Deponun yolu --state-file <path> ile verilir ve varsayılan yoktur: bayrak verilmezse state.read/state.write adıyla reddeder (state.read needs a state file; pass --state-file <path>.). Sessiz bir varsayılan konum sessiz veri kaybı olurdu. State gerçek bir dosyadır ve --record/--replay'in parçası değildir.

Değerler her zaman string'dir; sayı ya da tarih saklayan program json/date ile açıkça dönüştürür. --state-file, state.keys() dahil herhangi bir state.* fonksiyonu çağrıldığında zorunludur — varsayılan konum yoktur, çünkü sessiz bir varsayılan, iki iş aynı makineyi paylaştığı ilk anda sessiz veri kaybıdır.

std/io

Bu modül io fn'lerden oluşur

std/io fonksiyonları where, @valid ve pure fn içinde kullanılamaz. Yalnızca agent method'larında ve io fn'ler içinde çağrılabilir. Tüm yollar proje köküyle sınırlıdır. Derinlemesine kullanım için → IO & Multimodal.

io.readFiles, --max-rows ile sınırlıdır (varsayılan 200000); bu bir io tuhaflığı değil, satır üreten yollara global bir tavandır — aynı sınır ve aynı mesaj bir query sonucunu da yönetir. Aşım adıyla reddeder ve col.chunk'ı işaret eder: Result set exceeded the row limit (200000). Process in batches with col.chunk, or raise --max-rows. Bayraklar ve tavanlar'a bak.

io.readText(path: string) → string

Metin dosyasını UTF-8 olarak okur.

io.writeText(path: string, content: string) → string

Metin dosyası yazar; ara klasörleri oluşturur. Yazılan dosyanın kök-göreli yolunu döndürür.

io.readFile(path: string) → any

İkili dosyayı okur: { path, mime_type, base64, size }.

io.readFiles(paths: string[]) → any[]

Birden çok dosyayı aynı yapıda okur. --max-rows ile tavanlıdır — aşağıdaki nota bak.

io.listFiles(directory: string, pattern: string, recursive: bool) → string[]

Doğal sıralı, @ ön ekli yol listesi. Desen yalnızca dosya adı glob'udur (*, ?); / içeremez.

pages = io.listFiles("@0213", "*.png", false)
io.exists(path: string) → bool

Dosya/klasör var mı?

io.mimeType(path: string) → string

Uzantıdan MIME tipi; bilinmiyorsa application/octet-stream.

io.toDataUrl(file: any) → string

io.readFile sonucunu data:<mime>;base64,… URL'ine çevirir.

io.toMultimodalMarkers(files: any[]) → string

Dosya listesini satır satır {{image_url:…}} / {{file_url:…}} marker'larına çevirir.

luma
import io from "std/io"

agent InvoiceReader {
  model: Vision

  fn transcribe(folder: string) -> Transcript {
    pages   = io.listFiles("@" + folder, "*.png", false)
    files   = io.readFiles(pages)
    markers = io.toMultimodalMarkers(files)
    text    = ask "Tüm sayfaları Markdown'a çevir: {markers}" -> Transcript
    written = io.writeText("@" + folder + "/pre.md", text.markdown)
    return text
  }
}