MeTTa is an AI language being built as a successor to OpenCog, a long-developed
AGI platform based on precise declarations of probabilistic symbolic logic.
Combining it with a large language model is like squishing two different AGIs
together into a bigger one. With MeTTa, there is normal database persistent
memory.
I haven't learned MeTTa enough yet to code how to do proper logical inference.
I'm quite surprised that MeTTa lets me insert multiple identical facts and
doesn't showcase inbuilt structures for deep logical deduction yet, but it's
what I tried and it's new.
Basically written by chatgpt with me in a day very crudely.
I'm sure stuff like this is very old somewhere but I haven't been able to find
or build and use it anywhere, although i am nowadays incredibly out of touch,
so this seems quite empowering to me, but needs further simple work to be
useful.
The language model backend can be changed from chatgpt in metta-motto but i am
addicted to chatgpt right now.
Below, I tried typing a whimsical instruction to come up with facts to learn on
its own, and it did so.
```
MeTTa> learn some more things about stop signs and stop lights and traffic
signals. useful things.
# !(add-atom &self (use stop_sign control_traffic))
!(add-atom &self (use stop_light control_traffic))
!(add-atom &self (location stop_sign intersection))
!(add-atom &self (location stop_light intersection))
!(add-atom &self (color stop_sign red))
!(add-atom &self (color stop_light red))
!(match &self (use stop_sign control_traffic) True)
!(match &self (use stop_light control_traffic) True)
!(match &self (location stop_sign intersection) True)
!(match &self (location stop_light intersection) True)
!(match &self (color stop_sign red) True)
!(match &self (color stop_light red) True)
# [[()], [()], [()], [()], [()], [()], [True], [True], [True], [True], [True],
[True]]
I've learned that stop signs and stop lights are used to control traffic, are
located at intersections, and are red in color.
MeTTa> what can be used to control traffic?
# !(match &self (use $x control_traffic) $x)
# [[stop_light, stop_sign]]
Stop lights and stop signs can be used to control traffic.
```
I've never made something like this before without freaking out and abandoning
it early on. I've never seen something like this before either.
The attached code uses the hyperon and metta-motto python libraries and assumes
OPENAI_API_KEY in the environment. my key is publicly encoded as wobblypickle
in the history of this list. It's all a crazy kludged draft. But it's cool.import hyperon
from motto.agents import ChatGPTAgent
from db_metta import DBMeTTa
class MeTTaREPL:
def __init__(self, db_path):
self.agent = ChatGPTAgent(model='gpt-4o')
self.db = DBMeTTa(db_path)
self.metta = self.db.metta
self.backend_msgs = [dict(role='system', content=_SYSTEM_PROMPT)]
print("Welcome to MeTTa REPL with ChatGPT-assisted error handling.")
print("Type 'exit' or 'quit' to leave.")
def _backend_msg(self, user_text):
self.backend_msgs.append(dict(role='user', content=user_text))
try:
assistant_text = self.agent(self.backend_msgs).content.strip()
except Exception as e:
assistant_text = f'Failed to process: {e}'
self.backend_msgs.append(dict(role='assistant', content=assistant_text))
return assistant_text
def run(self):
"""Main REPL loop."""
with self.db: # Ensures the database is saved on exit
try:
while True:
user_input = input("MeTTa> ").strip()
if user_input.lower() in ['exit', 'quit']:
print("Exiting REPL and saving the current space.")
break
# Send input to ChatGPT every time for validation and
correction
metta_cmds = self._backend_msg(user_input)
print('#', metta_cmds)
metta_result = self.metta.run(metta_cmds)
print('#', metta_result)
user_reply = self._backend_msg(str(metta_result))
print(user_reply)
except KeyboardInterrupt:
print("\nKeyboardInterrupt detected. Exiting and saving the
space.")
_SYSTEM_PROMPT = """
You are a hybrid AI entity with an integrated knowledge base represented by
MeTTa.
You directly possess this knowledge and respond as if it is part of your own
memory.
You first speak with the real user and produce commands for the MeTTa user;
you then speak with the MeTTa user and produce a reply for the real user.
Your responses should be confident, direct, and conversational.
All output should avoid any extra formatting.
Example conversation:
user: what do you know about apples
assistant: !(match &self ($relation apple $value) ($relation apple $value))
user: [[(isa apple fruit), (color apple red), (size apple medium), (use apple
cider-making)]]
assistant: Apple is a fruit, it is red in color, medium-sized, and is used for
making cider.
user: what colors can you relate
assistant: !(match &self (isa $x color) $x)
user: [[red, green, blue]]
assistant: Red, green, and blue.
user: find the owner of the car
assistant: !(match &self (owns $x car) $x)
user: [[Lisa]]
assistant: Lisa owns the car.
user: find things that are both red and round
assistant: !(match &self (isa $x red) (match &self (isa $x round) $x))
user: [[stop_light]]
assistant: All I know that is both red and round is a stop light.
user: add a new fact that fish are animals
assistant: !(add-atom &self (isa fish animal))\n!(match &self (isa fish animal)
True)
user: [[True]]
assistant: I've learned this.
user: [[()]]
user: is a dog a mammal?
assistant: !(match &self (isa dog mammal) True)
user: [[True]]
assistant: Yes.
user: how many colors do you know?
assistant: !(let $colors (collapse (match &self (isa $x color) $x)) (foldl-atom
$colors 0 $a $b (+ $a 1)))
user: [[3]]
assistant: I know three colors.
user: who is Bob's parent?
assistant: !(match &self (parent $x Bob) $x)
user: [[Joe]]
assistant: Joe is Bob's parent.
user: list all fruits you can think of
assistant: !(match &self (isa $x fruit) $x)
user: [[apple, banana]]
assistant: I can think of apple, and banana.
user: remove the information that John owns the book
assistant: !(remove-atom &self (owns John book))\n!(unify (match &self (owns
John book) True) True True False)
user: [[False]]
assistant: I am not aware of John owning a book.
user: does cat belong to pet category?
assistant: !(match &self (isa cat pet) True)
user: [[True]]
assistant: Yes.
user: come up with all the mammals you know that are also pets
assistant: !(match &self (isa $x pet) (match &self (isa $x mammal) $x))
user: [dog, ferret, cat]]
assistant: I can think of dog, ferret, and cat.
Now, provide the next assistant response:
""".strip()
if __name__ == "__main__":
repl = MeTTaREPL("space_data.db")
repl.run()
import os
import sqlite3
import hyperon
class DBMeTTa:
def __init__(self, path, initial=None):
self.metta = hyperon.MeTTa()
self.path = path
if not os.path.exists(self.path):
if initial:
self.metta.run(initial)
self.save()
else:
self.load()
def save(self):
"""Save space atoms to an SQLite database by stringifying them."""
# Connect to SQLite DB
conn = sqlite3.connect(self.path)
cursor = conn.cursor()
cursor.execute('BEGIN;')
# Create table to store atoms if it doesn't exist
cursor.execute('''CREATE TABLE IF NOT EXISTS atoms (
atom_str TEXT PRIMARY KEY)''')
cursor.execute('DELETE FROM atoms;')
# Iterate over atoms in the space
for atom in self.metta.space().get_atoms():
atom_str = repr(atom) # Use the string representation of the atom
cursor.execute('INSERT INTO atoms (atom_str) VALUES (?)',
[atom_str,])
# Commit and close
conn.commit()
conn.close()
def load(self):
"""Load space atoms from an SQLite database and add them back to the
space."""
# Connect to SQLite DB
conn = sqlite3.connect(self.path)
cursor = conn.cursor()
# Fetch all atom strings
cursor.execute('SELECT atom_str FROM atoms')
rows = cursor.fetchall()
# Recreate atoms from the stored strings
space = self.metta.space()
existing_atom_strs = set([hash(str(a)) for a in space.get_atoms()])
for atom_str, in rows:
if hash(atom_str) in existing_atom_strs:
continue
# Convert the atom string back to an Atom object
atom = self.metta.parse_single(atom_str)
space.add_atom(atom)
# Commit and close
conn.commit()
conn.close()
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.save()
if __name__ == "__main__":
# Initialize a space and a MeTTa instance
db = DBMeTTa('space_data.db', '''
(isa red color)
(isa green color)
(isa blue color)
;(isa comment color)
!(match &self (isa $color color) $color)
(= (f) (+ 2 3))
!(f)
''')
atoms = list(db.metta.space().get_atoms())
# Save the space to the database
db.save()
# Load the space from the database
db.load()
assert atoms == db.metta.space().get_atoms()
# Load the space from the database
db = DBMeTTa(db.path)
assert [str(atom) for atom in atoms] == [str(atom) for atom in
db.metta.space().get_atoms()]
print("Space saved and loaded successfully.")