diff --git a/docs/README.md b/docs/README.md index 15dc3d5d..510b18d3 100644 --- a/docs/README.md +++ b/docs/README.md @@ -40,6 +40,7 @@ Numbered in suggested reading order. Each tutorial is self-contained. - [reference-lib-nal.md](./reference-lib-nal.md) — NAL rules with truth formulas; confirmed vs. non-functional patterns - [reference-lib-pln.md](./reference-lib-pln.md) — Modus Ponens, abduction, revision; current limits - [reference-lib-ona.md](./reference-lib-ona.md) — OpenNARS for Applications — planned real-time / temporal engine (experimental, not installed by default) +- [reference-lib-telos-goals.md](./reference-lib-telos-goals.md) — Optional goal graph: `goal` / `rel` schema, conflict / blocked / aligned lenses, `telos-enable` prompt extension (opt-in, not loaded by `lib_omega.metta`) - [reference-orchestration.md](./reference-orchestration.md) — Engine selection, stopping criteria, action thresholds, defense stack - [reference-failure-modes.md](./reference-failure-modes.md) — Documented failures, error rates, mitigations diff --git a/docs/reference-lib-telos-goals.md b/docs/reference-lib-telos-goals.md new file mode 100644 index 00000000..9dacf177 --- /dev/null +++ b/docs/reference-lib-telos-goals.md @@ -0,0 +1,118 @@ +# Reference — `lib_telos_goals.metta` + +An optional goal-graph module. Omega is goal-autonomous (it creates goals, pursues them, tracks progress) but the core ships no inspectable model of *what the goals are*. This module adds one in Omega's own idiom: AtomSpace atoms plus derivation rules, so an agent can represent individual and collective goals, surface conflicts and blockers, and reason about alignment symbolically instead of guessing. + +It is **opt-in** and **side-effect-free on load**. `lib_omega.metta` does not import it, and nothing in the file runs at import time: it only defines the schema contract, the query rules, and two functions that install or remove a prompt extension when you call them. + +--- + +## Loading + +```metta +!(import! &self (library Omega lib_telos_goals)) +``` + +--- + +## Schema + +Two atom shapes. Every relation reads **source → destination**, and the direction matters for the rules below. + +| Atom | Meaning | +|---|---| +| `(goal )` | A goal. `scope` is `individual` or `collective`. `status` is `active`, `proposed`, `achieved`, or `abandoned`. | +| `(rel supports )` | Achieving `src` advances `dst`. | +| `(rel conflicts )` | `src` and `dst` cannot both be achieved. Assert once per pair; the conflict lens does not symmetrise. | +| `(rel subsumes )` | `parent` is the broader goal and `child` is a sub-goal of it. | +| `(rel depends-on )` | `src` cannot progress until `dst` is achieved. | + +--- + +## Who asserts the atoms + +**Omega does not infer or assert `goal` / `rel` atoms on its own.** The module is a representation and a set of queries. The LLM layer populates it through the existing `metta` skill while it reads a conversation, and reads it back the same way: + +``` +metta (add-atom &self (goal alice-train individual alice active)) +metta (add-atom &self (rel conflicts alice-train dao-fair-access)) +metta (telos-reading) +``` + +`(telos-enable)` teaches the LLM to do exactly that. It calls the core `add-prompt-extension` hook from `src/skills.metta` to insert a `GOAL GRAPH` section into the prompt, after the SKILL section and before OUTPUT_FORMAT, describing the schema, the `add-atom` calls, the read lenses, and the rule that every `conflict-between` and `blocked` result is reported to the user before the agent acts on a goal. `(telos-disable)` removes the section again. Neither runs until called. + +--- + +## Lenses + +### Zero-arity lenses + +Each of these queries the whole graph and is folded into `(telos-reading)`. + +| Rule | Yields | Meaning | +|---|---|---| +| `(telos-conflicts)` | `(conflict-between $a $b)` | Every asserted conflict pair. | +| `(telos-collective-goals)` | `(collective-goal $g $owner)` | Every collective goal, any status. | +| `(telos-achieved-goals)` | `(achieved-goal $g $owner)` | Every achieved goal, any scope. | +| `(telos-abandoned-goals)` | `(abandoned-goal $g $owner)` | Every abandoned goal. Surfacing these stops the agent chasing a goal its owner dropped. | +| `(telos-subgoals)` | `(subgoal $child of $parent)` | The sub-goal structure declared by `subsumes`. | +| `(telos-blocked)` | `(blocked $g on $dep)` | A goal whose `depends-on` target is not yet achieved. An abandoned dependency still blocks. | +| `(telos-aligned)` | `(aligns $i with $c)` | An individual goal that `supports` a collective goal of some owner. | + +### The full reading + +```metta +!(telos-reading) +``` + +The superposition of every zero-arity lens above. Call it after the goal and relation atoms are in place. + +### Parameterised probes + +These take an owner or a goal id, so they are queried on their own and are **not** part of `(telos-reading)`. + +| Rule | Yields | Meaning | +|---|---|---| +| `(telos-goals-of $owner)` | `(goal-of $owner $g)` | The individual goals of one stakeholder. | +| `(telos-achieved $g)` | `True` or empty | Whether one goal's status atom says `achieved`. | + +--- + +## Worked example + +```metta +!(import! &self (library Omega lib_telos_goals)) + +(goal alice-train individual alice active) +(goal bob-share individual bob active) +(goal grant individual alice achieved) +(goal dao-fair-access collective dao active) +(goal gpu-quota collective dao proposed) +(rel conflicts alice-train bob-share) +(rel supports bob-share dao-fair-access) +(rel depends-on dao-fair-access gpu-quota) +(rel subsumes dao-fair-access gpu-quota) + +!(telos-conflicts) ; (conflict-between alice-train bob-share) +!(telos-achieved-goals) ; (achieved-goal grant alice) +!(telos-subgoals) ; (subgoal gpu-quota of dao-fair-access) +!(telos-blocked) ; (blocked dao-fair-access on gpu-quota) +!(telos-aligned) ; (aligns bob-share with dao-fair-access) +!(telos-goals-of alice) ; (goal-of alice alice-train) (goal-of alice grant) +!(telos-reading) ; all of the zero-arity results at once +``` + +--- + +## Tests + +`tests/tests_lib_telos_goals.metta` covers every lens, both probes, the direction of `subsumes`, the membership of each lens in `(telos-reading)`, and the `telos-enable` / `telos-disable` round trip through `getPromptExtensions`. It runs with the rest of the MeTTa unit tests: + +```sh +PETTA_PATH=/PeTTa sh tests/mettatest.sh +``` + +--- + +## Origin + +Contributed from the BGI Sprint I project Telos (https://github.com/arielagor/telos, MIT), which also ships a 14-scenario goal-understanding benchmark that can score Omega or any other agent on goal *misunderstanding*: pursuing the literal request and missing the real goal, serving one person while externalising cost onto the group, or chasing an abandoned goal. diff --git a/lib_telos_goals.metta b/lib_telos_goals.metta new file mode 100644 index 00000000..974ec8c6 --- /dev/null +++ b/lib_telos_goals.metta @@ -0,0 +1,85 @@ +; lib_telos_goals -- optional goal-graph module for Omega. Not loaded by lib_omega.metta. +; Load with: !(import! &self (library Omega lib_telos_goals)) +; Reference: docs/reference-lib-telos-goals.md +; +; Omega does not infer or assert goal atoms by itself. The LLM layer asserts them through +; the `metta` skill (metta (add-atom &self (goal ...))) and reads them back through the +; lenses below; (telos-enable) installs a prompt extension that tells the LLM how. +; +; Schema (all relations read src -> dst): +; (goal ) scope: individual | collective +; status: active | proposed | achieved | abandoned +; (rel supports ) achieving src advances dst +; (rel conflicts ) src and dst cannot both be achieved (assert once) +; (rel subsumes ) parent is the broader goal, child is a sub-goal of it +; (rel depends-on ) src cannot progress until dst is achieved + +; ---- Zero-arity lenses: every one of these is included in (telos-reading) ---- + +; All conflict pairs the agent must surface (across ALL goals). +(= (telos-conflicts) + (match &self (rel conflicts $a $b) (conflict-between $a $b))) + +; Every collective goal (what the commons wants). +(= (telos-collective-goals) + (match &self (goal $g collective $owner $status) (collective-goal $g $owner))) + +; Every achieved goal, any scope, any owner. +(= (telos-achieved-goals) + (match &self (goal $g $scope $owner achieved) (achieved-goal $g $owner))) + +; Every abandoned goal. Surfacing these stops the agent chasing a goal its owner dropped. +(= (telos-abandoned-goals) + (match &self (goal $g $scope $owner abandoned) (abandoned-goal $g $owner))) + +; Sub-goal structure: (rel subsumes ) yields (subgoal of ). +(= (telos-subgoals) + (match &self (rel subsumes $parent $child) (subgoal $child of $parent))) + +; BLOCKED: a goal that depends-on another goal that is not yet achieved. +; An abandoned dependency still blocks: it will never become achieved. +(= (telos-blocked) + (match &self (rel depends-on $g $dep) + (match &self (goal $dep $s2 $o2 $st2) + (if (== $st2 achieved) (empty) (blocked $g on $dep))))) + +; Cross-level ALIGNMENT: an individual goal that SUPPORTS a collective goal. +(= (telos-aligned) + (match &self (rel supports $i $c) + (match &self (goal $i individual $o1 $s1) + (match &self (goal $c collective $o2 $s2) + (aligns $i with $c))))) + +; The full goal reading: the superposition of every zero-arity lens above. +; The parameterised probes below (telos-goals-of, telos-achieved) take an owner or a goal +; id, so they are queried on their own rather than folded into the reading. +(= (telos-reading) + (superpose ((telos-conflicts) + (telos-collective-goals) + (telos-achieved-goals) + (telos-abandoned-goals) + (telos-subgoals) + (telos-blocked) + (telos-aligned)))) + +; ---- Parameterised probes: not part of (telos-reading) ---- + +; Goals owned by ANY given stakeholder (individual goal understanding). +(= (telos-goals-of $owner) + (match &self (goal $g individual $owner $status) (goal-of $owner $g))) + +; A goal is ACHIEVED when its status atom says so. +(= (telos-achieved $g) + (match &self (goal $g $scope $owner achieved) True)) + +; ---- Agent integration (opt-in; nothing here runs at import) ---- + +; Teach the LLM the schema and the metta-skill calls that populate and read the graph. +; Uses the core prompt-extension hook from src/skills.metta; no effect until called. +(= (telos-enable) + (add-prompt-extension telos-goals + "GOAL GRAPH: when a message reveals what someone wants, record it as atoms and reason over them symbolically instead of guessing. Assert a goal with: metta (add-atom &self (goal )). Assert a relation with: metta (add-atom &self (rel )); subsumes reads parent then child, depends-on reads goal then prerequisite. Read the graph with: metta (telos-reading) for every lens, or metta (telos-conflicts), metta (telos-blocked), metta (telos-aligned), metta (telos-goals-of ). Tell the user about every conflict-between and blocked result before acting on a goal.")) + +; Remove the extension again. +(= (telos-disable) + (remove-prompt-extension telos-goals)) diff --git a/tests/tests_lib_telos_goals.metta b/tests/tests_lib_telos_goals.metta new file mode 100644 index 00000000..b29b8d6c --- /dev/null +++ b/tests/tests_lib_telos_goals.metta @@ -0,0 +1,75 @@ +!(import! &self ./tests/lib/utils) +!(import! &self ../src/helper.py) +!(import! &self ./src/utils) +!(import! &self ./src/skills) +!(import! &self ./src/loop) +!(import! &self ./lib_telos_goals) + +; Fixture: the atoms an agent would assert through the metta skill. +(goal alice-train individual alice active) +(goal bob-share individual bob active) +(goal old-rust individual alice abandoned) +(goal grant individual alice achieved) +(goal dao-fair-access collective dao active) +(goal gpu-quota collective dao proposed) +(rel conflicts alice-train bob-share) +(rel supports bob-share dao-fair-access) +(rel depends-on dao-fair-access gpu-quota) +(rel subsumes dao-fair-access gpu-quota) + +; ---- Zero-arity lenses ---- + +!(test (expression-count-item (collapse (telos-conflicts)) (conflict-between alice-train bob-share)) 1) +!(test (expression-count-item (collapse (telos-conflicts)) (conflict-between bob-share alice-train)) 0) + +!(test (expression-count-item (collapse (telos-collective-goals)) (collective-goal dao-fair-access dao)) 1) +!(test (expression-count-item (collapse (telos-collective-goals)) (collective-goal gpu-quota dao)) 1) +!(test (expression-count-item (collapse (telos-collective-goals)) (collective-goal alice-train alice)) 0) + +!(test (expression-count-item (collapse (telos-achieved-goals)) (achieved-goal grant alice)) 1) +!(test (expression-count-item (collapse (telos-achieved-goals)) (achieved-goal alice-train alice)) 0) + +!(test (expression-count-item (collapse (telos-abandoned-goals)) (abandoned-goal old-rust alice)) 1) +!(test (expression-count-item (collapse (telos-abandoned-goals)) (abandoned-goal grant alice)) 0) + +; (rel subsumes ) reads parent then child. +!(test (expression-count-item (collapse (telos-subgoals)) (subgoal gpu-quota of dao-fair-access)) 1) +!(test (expression-count-item (collapse (telos-subgoals)) (subgoal dao-fair-access of gpu-quota)) 0) + +; dao-fair-access depends on gpu-quota, which is only proposed, so it is blocked. +!(test (expression-count-item (collapse (telos-blocked)) (blocked dao-fair-access on gpu-quota)) 1) + +!(test (expression-count-item (collapse (telos-aligned)) (aligns bob-share with dao-fair-access)) 1) +!(test (expression-count-item (collapse (telos-aligned)) (aligns alice-train with dao-fair-access)) 0) + +; ---- Parameterised probes ---- + +!(test (expression-count-item (collapse (telos-goals-of alice)) (goal-of alice alice-train)) 1) +!(test (expression-count-item (collapse (telos-goals-of alice)) (goal-of alice old-rust)) 1) +!(test (expression-count-item (collapse (telos-goals-of alice)) (goal-of alice bob-share)) 0) +!(test (expression-count-item (collapse (telos-goals-of dao)) (goal-of dao dao-fair-access)) 0) + +!(test (telos-achieved grant) True) +!(test (collapse (telos-achieved alice-train)) ()) + +; ---- The full reading includes every zero-arity lens ---- + +!(test (expression-count-item (collapse (telos-reading)) (conflict-between alice-train bob-share)) 1) +!(test (expression-count-item (collapse (telos-reading)) (collective-goal dao-fair-access dao)) 1) +!(test (expression-count-item (collapse (telos-reading)) (achieved-goal grant alice)) 1) +!(test (expression-count-item (collapse (telos-reading)) (abandoned-goal old-rust alice)) 1) +!(test (expression-count-item (collapse (telos-reading)) (subgoal gpu-quota of dao-fair-access)) 1) +!(test (expression-count-item (collapse (telos-reading)) (blocked dao-fair-access on gpu-quota)) 1) +!(test (expression-count-item (collapse (telos-reading)) (aligns bob-share with dao-fair-access)) 1) + +; ---- Prompt extension round trip (the agent-integration hook) ---- + +!(test (progn + (telos-enable) + (contains-text (getPromptExtensions) "GOAL GRAPH")) + True) + +!(test (progn + (telos-disable) + (contains-text (getPromptExtensions) "GOAL GRAPH")) + False)