Interact with your Agent using String Data

Data Preparation

All data provided to a GAIuS Agent is supplied as sequences of events. The way a sequence is delimited depends on the problem domain

An event is a single occurrence of a process.

A sequence is a particular order in which related events, movements, or things follow each other.

sequence = [event_1, event_2, …, event_n]

Even problems that don’t initially appear to be sequence problems can be cast into this form. For example, customer profile data can be converted into a sequence of a single event. It is common to call such single-evented sequences profile data to distinguish them from other sequences.

sequence = [event_1]

can be represented as

sequence = [profile_data]

Each event must be formatted into our universal input format, the GAIuS Data Format (GDF) object.

The GDF object is a JSON object that has three core fields: strings, vectors, and emotives. Each field’s value is an array of relevant data. All three fields must be provided even if they are empty. GDFs are easily shared between systems because they are JSON objects.

Here is an empty GDF:

{"strings": [], "vectors": [], "emotives": {}}

In general and simply put, the strings field is for text-based data, the vectors field is for arrays of numerical data, and the emotives field is for emotional data, a non-vector number, positive or negative. The GDF object is the key for using our AGI platform. Practically any data can be converted into this form.

For now let’s focus on string data:

A string is simply any character, e.g. “h”, or sequential characters, “hello”. Strings must be properly delimited with double-quotes. This conforms with the JSON standard for strings.

GDFs provide the ability to observe single events. Multiple events build sequences. For example, the following is one sequence:

[{"strings": ["hello"], "vectors": [], "emotives": {}},
 {"strings": ["world"], "vectors": [], "emotives": {}}]

This sequence consists of two events. The first event consists of the symbol “hello” in the "strings" field. The second event consists of the symbol “world” in the "strings" field.

Here’s another example of a sequence:

[{"strings": ["goodbye"], "vectors": [], "emotives": {}},
 {"strings": ["cruel"], "vectors": [], "emotives": {}},
 {"strings": ["world"], "vectors": [], "emotives": {}}]

Having defined the ingress and query nodes earlier, let’s use your AgentClient to send data and query the agent.

Observing data

Sending data requires the observe API call. The AgentClient provides this using a similarly named function.

In order to acquire and process data you need to first make an observation. When the GAIuS Agent observes data it observes each event of a sequence one-by-one where the data is processed into the working memory (WM). Data processed into the WM can later be used to make predictions or be learned where it will update its knowlege base (KB). Data stored in the KB will be used to pattern match and make predictions. Analogously, you can think of WM as short term memory and KB as long term memory. It is good practice to clear the WM before the Agent observes new data to ensure that the state of the Agent is as expected.

Let’s follow this sequence of steps to observe and process new data:

  1. agent.clear_wm() - clear wm to make sure nothing is in the wm

  2. agent.observe(event) - observe new data

  3. agent.get_wm() - to look at what’s in the wm after an observation was made

  4. agent.clear_all_memory - when we want a fresh start we would want to clear everything in the wm and the kb

If starting from here, lets initialize the agent

[1]:
from ia.gaius.agent_client import AgentClient
agent_info = {'api_key': 'ABCD-1234',
              'name': '',
              'domain': 'gaius-api:80',
              'secure': False}

agent = AgentClient(agent_info)
agent.connect()
agent

# Let's use only one node
ingress_nodes = ['P1']
query_nodes   = ['P1']

agent.set_ingress_nodes(ingress_nodes)
agent.set_query_nodes(query_nodes)
[1]:
[{'id': 'p46b6b076c', 'name': 'P1'}]
[ ]:

[2]:
agent.clear_wm(nodes=ingress_nodes)
[2]:
'wm-cleared'
[3]:
agent.observe(data={"strings": ["hello"], "vectors": [], "emotives": {}},nodes=ingress_nodes)
[3]:
'observed'
[4]:
agent.get_wm(nodes=ingress_nodes)
[4]:
[['hello']]
[5]:
agent.clear_all_memory(nodes=ingress_nodes)
[5]:
'all-cleared'

The reason for the Gaius platform is for it to observe data, learn from it, and to provide predictions. Let’s go ahead and put this all together using what we’ve learned above.

Let’s train on the two sequences:

[{"strings": ["hello"], "vectors": [], "emotives": {}},
 {"strings": ["world"], "vectors": [], "emotives": {}}]

and

[{"strings": ["goodbye"], "vectors": [], "emotives": {}},
 {"strings": ["cruel"], "vectors": [], "emotives": {}},
 {"strings": ["world"], "vectors": [], "emotives": {}}]

Observe 1st Sequence

[6]:
agent.clear_all_memory(nodes=ingress_nodes) ### Start with a clean slate.

sequence_1 = [{"strings": ["hello"], "vectors": [], "emotives": {}},
              {"strings": ["world"], "vectors": [], "emotives": {}}]

for event in sequence_1:
    agent.observe(data=event,nodes=ingress_nodes)
[7]:
agent.get_wm(nodes=ingress_nodes)
[7]:
[['hello'], ['world']]

Learn 1st Sequence

[8]:
# The first sequence is fully in working memory (WM) now.  Let's learn it!
agent.learn(nodes=ingress_nodes)
[8]:
'MODEL|7d0678ba6305341ce0d25133ab086208656a562f'

Observe 2nd Sequence

[9]:
## Let's now observe and learn the next sequence.

## Just in case, let's clear out the working memory (WM), though 'learn' does that for us already.
## Don't clear out ALL the memory, otherwise it will forget the sequences it learned!
agent.clear_wm(nodes=ingress_nodes)

sequence_2 = [{"strings": ["goodbye"], "vectors": [], "emotives": {}},
              {"strings": ["cruel"], "vectors": [], "emotives": {}},
              {"strings": ["world"], "vectors": [], "emotives": {}}]

for event in sequence_2:
    agent.observe(data=event,nodes=ingress_nodes)

Learn 2nd Sequence

[10]:
## The second sequence is fully in working memory (WM) now.  Let's learn it!
agent.learn(nodes=ingress_nodes)
[10]:
'MODEL|3b5c9cdc4424988308922d2ec8c7bc06b7c6ac21'

At this point, we’ve taught the agent two sequences. Let us check how much sequences were learned in its kb. Now let’s now observe new data, and request some predictions back:

Show Agent Status

Sometimes it is helpful to view information about the agent’s current state, especially how many sequences are in the KB. You can do this using the API command agent.show_status()

[11]:
agent.show_status(nodes=ingress_nodes)
[11]:
{'PREDICT': True,
 'SLEEPING': False,
 'emotives': {},
 'last_learned_model_name': '3b5c9cdc4424988308922d2ec8c7bc06b7c6ac21',
 'models_kb': '{KB| objects: 2}',
 'name': 'P1',
 'size_WM': 0,
 'target': '',
 'time': 5,
 'vectors_kb': '{KB| objects: 0}'}
[12]:
# look at how many sequences the agent has learned
agent.show_status(nodes=ingress_nodes)['models_kb']
[12]:
'{KB| objects: 2}'

Get Predictions

Observe 1st event in New Sequence

[13]:
## Again, we want to ensure there's nothing in the working memory (WM) before we send it new sequences:
agent.clear_wm(nodes=ingress_nodes)
data = {"strings": ["hello"], "vectors": [], "emotives": {}}
agent.observe(data=data,nodes=ingress_nodes)
[13]:
'observed'

Get Predictions

[14]:
agent.get_predictions(nodes=query_nodes)
[14]:
[{'confidence': 1,
  'confluence': 0.4,
  'emotives': {},
  'entropy': 0.464385629,
  'evidence': 0.5,
  'extras': [],
  'fragmentation': 0,
  'frequency': 1,
  'future': [['world']],
  'grand_hamiltonian': 0.232192814,
  'hamiltonian': 0,
  'itfdf_similarity': 1,
  'matches': ['hello'],
  'missing': [],
  'name': '7d0678ba6305341ce0d25133ab086208656a562f',
  'past': [],
  'potential': 3.5,
  'present': [['hello']],
  'similarity': 0.666666687,
  'snr': 1,
  'type': 'prototypical'}]

‘P1’ has provided an ensemble of predictions for us! This ensemble, however, only has one prediction. The prediction is the first sequence that we taught it. It is represented as a prediction object. This is our universal output format. Let’s look at some of the fields and values it provides:

It states that it has matched on the 'hello' symbol:

'matches': ['hello']

From this, it believes that the current present state of affairs is:

'present': [['hello']]

That’s one event with the 'hello' symbol and nothing else.

Having identified it’s believed present state, it predicts that the future will consist of the following event states:

'future': [['world']]

That’s just one more event consisting of the 'world' symbol.

Let’s now complete this sequence for the agent:

Observe 2nd event in New Sequence

[15]:
data = {"strings": ["world"], "vectors": [], "emotives": {}}
agent.observe(data=data,nodes=ingress_nodes)
[15]:
'observed'

Get Predictions

[16]:
agent.get_predictions(nodes=query_nodes)
[16]:
[{'confidence': 1,
  'confluence': 0.46,
  'emotives': {},
  'entropy': 0.99315685,
  'evidence': 1,
  'extras': [],
  'fragmentation': 0,
  'frequency': 1,
  'future': [],
  'grand_hamiltonian': 0.496578425,
  'hamiltonian': 0.5,
  'itfdf_similarity': 1,
  'matches': ['hello', 'world'],
  'missing': [],
  'name': '7d0678ba6305341ce0d25133ab086208656a562f',
  'past': [],
  'potential': 4,
  'present': [['hello'], ['world']],
  'similarity': 1,
  'snr': 1,
  'type': 'prototypical'},
 {'confidence': 1,
  'confluence': 0.3,
  'emotives': {},
  'entropy': 0.528771222,
  'evidence': 0.333333343,
  'extras': ['hello'],
  'fragmentation': 0,
  'frequency': 1,
  'future': [],
  'grand_hamiltonian': 0.264385611,
  'hamiltonian': 0,
  'itfdf_similarity': 0.94721359,
  'matches': ['world'],
  'missing': [],
  'name': '3b5c9cdc4424988308922d2ec8c7bc06b7c6ac21',
  'past': [['goodbye'], ['cruel']],
  'potential': 2.39165807,
  'present': [['world']],
  'similarity': 0.4,
  'snr': 0.333333343,
  'type': 'prototypical'}]

This time around, ‘P1’ produced two predictions. The first is still a prediction of “hello world”, but now the prediction object’s fields have changed. It now believes the current present state to be:

'present': [['hello'], ['world']]

based on its matches:

'matches': ['hello', 'world']

It no longer expects to find anything in the future.

'future': []

However, it’s second prediction object sees things a little differently. It is based on the “goodbye cruel world” sequence. Therefore, based on that sequence, it believes the present state to be:

'present': [['world']]

since it only matched on:

'matches': ['world']

Since this is its belief for the present state, it is surprised to find the symbol 'hello' and shows this as an ‘extra’ item:

'extras': ['hello']

Additionally, based on its belief of the present state, it predicts backwards into the past and says that the events containing the symbols 'goodbye' and 'cruel' must have occurred although it did not get a chance to observe them.