Rename: nlg → elp (Engram Language Protocol)

This commit is contained in:
Will Anderson
2026-05-02 22:15:25 -05:00
parent cbb27b8d87
commit 34725a3988
125 changed files with 129214 additions and 780 deletions
+80 -56
View File
@@ -7,15 +7,19 @@
// "subject" - subject referent (pronoun or noun phrase)
// "object" - object referent (optional, "" if absent)
// "modifiers" - semicolon-separated modifier strings (e.g. "in the park;quickly")
// "lang" - ISO 639-1 language code (optional, defaults to "en")
//
// sem_to_spec converts a SemFrame into a realizer slot map ready for realize().
// sem_realize is the end-to-end shortcut: frame -> realized English text.
// sem_realize is the end-to-end shortcut: frame -> realized text.
//
// Depends on: grammar (slots_*), realizer (realize)
// All existing function signatures are preserved; new *_lang variants add an
// explicit lang_code parameter.
//
// Depends on: grammar (slots_*, realize), language-profile (lang_from_code)
// SemFrame constructors
// Build a SemFrame slot map with all four fields.
// Build a SemFrame with all four core fields. Language defaults to "en".
fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) -> [String] {
let r: [String] = native_list_empty()
let r = native_list_append(r, "intent")
@@ -26,15 +30,33 @@ fn sem_frame(intent: String, subject: String, obj: String, modifiers: String) ->
let r = native_list_append(r, obj)
let r = native_list_append(r, "modifiers")
let r = native_list_append(r, modifiers)
let r = native_list_append(r, "lang")
let r = native_list_append(r, "en")
return r
}
// Convenience: frame with no object and no modifiers.
// Build a SemFrame with an explicit language code.
fn sem_frame_lang(intent: String, subject: String, obj: String, modifiers: String, lang_code: String) -> [String] {
let r: [String] = native_list_empty()
let r = native_list_append(r, "intent")
let r = native_list_append(r, intent)
let r = native_list_append(r, "subject")
let r = native_list_append(r, subject)
let r = native_list_append(r, "object")
let r = native_list_append(r, obj)
let r = native_list_append(r, "modifiers")
let r = native_list_append(r, modifiers)
let r = native_list_append(r, "lang")
let r = native_list_append(r, lang_code)
return r
}
// Convenience: no object, no modifiers, English.
fn sem_frame_simple(intent: String, subject: String) -> [String] {
return sem_frame(intent, subject, "", "")
}
// Convenience: frame with object but no modifiers.
// Convenience: with object, no modifiers, English.
fn sem_frame_obj(intent: String, subject: String, obj: String) -> [String] {
return sem_frame(intent, subject, obj, "")
}
@@ -57,18 +79,21 @@ fn sem_modifiers(frame: [String]) -> String {
return slots_get(frame, "modifiers")
}
fn sem_lang(frame: [String]) -> String {
let code: String = slots_get(frame, "lang")
if str_eq(code, "") {
return "en"
}
return code
}
// Modifier helpers
//
// Modifiers are stored as a semicolon-delimited string.
// e.g. "in the park;quickly"
// sem_first_modifier extracts the first modifier (typically a location phrase).
fn sem_first_modifier(mods: String) -> String {
let n: Int = str_len(mods)
if n == 0 {
return ""
}
// Scan to first ';'
let i: Int = 0
let running: Bool = true
while running {
@@ -87,38 +112,28 @@ fn sem_first_modifier(mods: String) -> String {
}
// Intent mapping
//
// Maps semantic intent names to the slot values expected by realize():
// "assert" -> intent="assert" declarative sentence
// "query" -> intent="question" yes/no question with do-support
// "describe" -> intent="assert" declarative; object holds predicate phrase
// "greet" -> handled specially "Hello, {subject}."
fn sem_intent_to_realize(intent: String) -> String {
if str_eq(intent, "assert") { return "assert" }
if str_eq(intent, "query") { return "question" }
if str_eq(intent, "describe") { return "assert" }
if str_eq(intent, "greet") { return "greet" }
// Default: treat unknown as assertion
return "assert"
}
// sem_to_spec: SemFrame -> realizer slot map
//
// Returns a [String] slot map suitable for passing directly to realize().
// Default tense is "present", aspect is "simple". Callers that need
// a different tense/aspect should use slots_set on the returned map.
// The "lang" key from the SemFrame is forwarded into the GramSpec so that
// realize() can resolve the correct language profile.
fn sem_to_spec(frame: [String]) -> [String] {
let intent: String = sem_intent(frame)
let subject: String = sem_subject(frame)
let obj: String = sem_object(frame)
let mods: String = sem_modifiers(frame)
let intent: String = sem_intent(frame)
let subject: String = sem_subject(frame)
let obj: String = sem_object(frame)
let mods: String = sem_modifiers(frame)
let lang_code: String = sem_lang(frame)
let location: String = sem_first_modifier(mods)
// Greet: no standard grammar slot, compose directly
// We still return a valid spec; sem_realize handles "greet" specially.
if str_eq(intent, "greet") {
let spec: [String] = native_list_empty()
let spec = native_list_append(spec, "intent")
@@ -135,11 +150,11 @@ fn sem_to_spec(frame: [String]) -> [String] {
let spec = native_list_append(spec, "present")
let spec = native_list_append(spec, "aspect")
let spec = native_list_append(spec, "simple")
let spec = native_list_append(spec, "lang")
let spec = native_list_append(spec, lang_code)
return spec
}
// Describe: subject is topic, object is predicate noun/adj phrase
// Realized as "Subject is Object." using the copula "be".
if str_eq(intent, "describe") {
let spec: [String] = native_list_empty()
let spec = native_list_append(spec, "intent")
@@ -156,10 +171,11 @@ fn sem_to_spec(frame: [String]) -> [String] {
let spec = native_list_append(spec, "present")
let spec = native_list_append(spec, "aspect")
let spec = native_list_append(spec, "simple")
let spec = native_list_append(spec, "lang")
let spec = native_list_append(spec, lang_code)
return spec
}
// Assert / Query: standard subject-verb-object
let realize_intent: String = sem_intent_to_realize(intent)
let spec: [String] = native_list_empty()
let spec = native_list_append(spec, "intent")
@@ -176,26 +192,20 @@ fn sem_to_spec(frame: [String]) -> [String] {
let spec = native_list_append(spec, "present")
let spec = native_list_append(spec, "aspect")
let spec = native_list_append(spec, "simple")
let spec = native_list_append(spec, "lang")
let spec = native_list_append(spec, lang_code)
return spec
}
// sem_to_spec_full: SemFrame -> realizer slot map with explicit verb
//
// For "assert" and "query" frames the object field carries the *noun phrase*
// patient, not the verb. Callers that have a separate verb should use this
// variant and supply it explicitly.
//
// verb - base form of the predicate verb
// tense - "present" | "past" | "future"
// aspect - "simple" | "progressive" | "perfect"
// sem_to_spec_full
fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String) -> [String] {
let intent: String = sem_intent(frame)
let subject: String = sem_subject(frame)
let obj: String = sem_object(frame)
let mods: String = sem_modifiers(frame)
let location: String = sem_first_modifier(mods)
let intent: String = sem_intent(frame)
let subject: String = sem_subject(frame)
let obj: String = sem_object(frame)
let mods: String = sem_modifiers(frame)
let lang_code: String = sem_lang(frame)
let location: String = sem_first_modifier(mods)
if str_eq(intent, "greet") {
return sem_to_spec(frame)
@@ -217,6 +227,8 @@ fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String
let spec = native_list_append(spec, tense)
let spec = native_list_append(spec, "aspect")
let spec = native_list_append(spec, aspect)
let spec = native_list_append(spec, "lang")
let spec = native_list_append(spec, lang_code)
return spec
}
@@ -236,6 +248,8 @@ fn sem_to_spec_full(frame: [String], verb: String, tense: String, aspect: String
let spec = native_list_append(spec, tense)
let spec = native_list_append(spec, "aspect")
let spec = native_list_append(spec, aspect)
let spec = native_list_append(spec, "lang")
let spec = native_list_append(spec, lang_code)
return spec
}
@@ -248,12 +262,7 @@ fn sem_realize_greet(subject: String) -> String {
return "Hello, " + subject + "."
}
// sem_realize: SemFrame -> English text
//
// End-to-end convenience: converts a SemFrame to a realized English string.
// For "assert" and "query" intents, the object field is treated as the
// predicate verb base form (intransitive use). For richer frames with both
// a verb and an object, use sem_realize_full.
// sem_realize: SemFrame -> text
fn sem_realize(frame: [String]) -> String {
let intent: String = sem_intent(frame)
@@ -266,11 +275,7 @@ fn sem_realize(frame: [String]) -> String {
return realize(spec)
}
// sem_realize_full: SemFrame + explicit verb -> English text
//
// Like sem_realize but accepts a separate verb, tense, and aspect.
// Use this when the SemFrame object field carries a noun phrase patient
// and you want to specify the predicate verb independently.
// sem_realize_full
fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String) -> String {
let intent: String = sem_intent(frame)
@@ -282,3 +287,22 @@ fn sem_realize_full(frame: [String], verb: String, tense: String, aspect: String
let spec: [String] = sem_to_spec_full(frame, verb, tense, aspect)
return realize(spec)
}
// sem_realize_lang: realize in an explicitly specified language
//
// Convenience for callers that want to specify the output language without
// constructing a full SemFrame. The lang_code overrides whatever "lang" is
// set in the frame.
fn sem_realize_lang(frame: [String], lang_code: String) -> String {
let intent: String = sem_intent(frame)
if str_eq(intent, "greet") {
return sem_realize_greet(sem_subject(frame))
}
// Inject the lang_code into the frame before converting to spec.
let patched: [String] = slots_set(frame, "lang", lang_code)
let spec: [String] = sem_to_spec(patched)
return realize(spec)
}