Synsema docsENES

Memoria y estado

El estado persistente del agente se declara, no es implícito. Una línea al tope del programa nombra la memoria y habilita toda la familia — memoria, reglas del owner y progreso:

require memory("support-agent")

El nombre declarado es la identidad: el estado persiste en <dir-del-programa>/.synsema/state/<name>.db (gitignoreá .synsema/), keyed por ese nombre — no por el nombre del archivo. Un remember() en una corrida lo encuentra recall() en la siguiente; renombrar el .syn no cambia nada; dos entry points que declaran el mismo nombre comparten una memoria.

memory.syn
-- Doc example: DECLARED agent memory, progress, and owner rules (persist to SQLite).
-- The declared name IS the identity: state lives in .synsema/state/doc-memory.db,
-- keyed by the name below — not by this file's name. Without the declaration the
-- whole family fails with `Capability not granted: memory` and creates no files.
intent: "doc example: declared memory, namespaces, progress, rules"
require memory("doc-memory")

remember("learning", "demo note from run", ["demo"])
print("recalled → " + text((recall("learning", ["demo"])[0])["content"]))

test "remember then recall — newest first ([0] is the most recent)"
    remember("learning", "API is slow on Mondays", ["api"])
    let notes be recall("learning", ["api"])
    assert_eq((notes[0])["content"], "API is slow on Mondays")

test "recall named args: limit caps results; from filters by writer namespace"
    remember("context", "note-a", ["ns"])
    remember("context", "note-b", ["ns"])
    assert_eq(length(recall("context", ["ns"], limit = 1)), 1)
    -- top-level writes source = "main"; agents write under their own name
    assert(length(recall("context", ["ns"], from = "main")) >= 2)
    assert_eq(length(recall("context", ["ns"], from = "nobody")), 0)

test "progress: resume_point returns the step to resume from"
    create_progress("import", ["ingest", "validate", "load"])
    start_step("import", "ingest")
    complete_step("import", "ingest", "100 rows")
    assert_eq(resume_point("import"), "validate")

test "owner rules: a numeric must-rule flags a violation"
    add_rule("max_discount", "must", "discount <= 0.20", "pricing")
    assert(length(check_rules("pricing", {"discount": 0.25})) > 0)

La declaración (sabelo antes que nada)

Memoria persistente

require memory("assistant")
remember("learning", "API lenta los lunes", ["api", "performance"])
let notes be recall("learning", ["api"])        -- más nuevo primero ([0] = más reciente)
let hits  be recall(nothing, nothing, "lunes")  -- búsqueda libre (saltá args con nothing)
forget_memory(entry_id)

Una entrada de recall es un map con id, category, content, source, tags.

recall toma 6 argsrecall(category, tags, search, mode, limit, from) — todos opcionales, todos usables como args nombrados (recall("learning", limit = 10)):

ArgSignificado
categoryuna de las categorías fijas (abajo)
tagslista; OR por defecto
searchbúsqueda por substring
mode"all" = todos los tags deben matchear (AND)
limitmáximo de entradas, default 200
fromnamespace source a leer (sección siguiente)
Las categorías son un set fijo en inglés: preference, rule, learning, decision, context. Cualquier otro string (p. ej. "preferencia") da error.

Namespaces por agente (source / from)

Cada entrada registra quién la escribió en source: dentro de agent X un remember escribe source = "X"; el código top-level (y los handlers de serve) escriben "main". Las lecturas están namespaceadas por defecto, así los agentes que comparten una memoria no confunden sus notas:

require memory("newsroom")

agent Writer
    remember("context", "borrador listo")    -- source = "Writer"

agent Analyzer
    let mine   be recall()                   -- solo las entradas propias de Analyzer (default)
    let theirs be recall(from = "Writer")    -- cruce de namespace explícito
    let all    be recall(from = "*")         -- todo

spawn Writer
spawn Analyzer
let everything be recall()                   -- el top-level ve TODO por defecto

Las reglas y el progreso no están namespaceados — un solo reglamento, un solo tablero de planes por programa.

Progreso (reanudable tras crash)

require memory("import-agent")
create_progress("import", ["ingest", "validate", "load"])
start_step("import", "ingest")
complete_step("import", "ingest", "100 filas")    -- o fail_step(...)
let where be resume_point("import")               -- "validate" — dónde reanudar tras un restart

Reglas del owner

require memory("pricing-agent")
add_rule("max_discount", "must", "discount <= 0.20", "pricing")
let violations be check_rules("pricing", {"discount": 0.25})   -- no vacío → violada

Niveles: must (bloqueo duro), should (warning), avoid / prefer (preferencias). Las condiciones numéricas se evalúan contra el map de contexto. get_rules(category?) las lista; memory_summary() imprime un resumen de todo lo guardado.

Estado de serve (por proceso, en memoria)

Bajo serve, los builtins state_* (p. ej. state_incr("visits")) comparten estado en memoria entre requests — ver Servidor HTTP. (Son una feature de serve, no disponibles en run plano, y no necesitan declaración de memory — nunca tocan disco.) Para estado durable, usá los builtins de memoria/progreso declarados de arriba o una base de datos.