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.")

Reply via email to