Gopherbot comes with brain methods allowing plugin authors to store information long-term information like a TODO list, or short-term contextual
information, such as a particular list item under discussion. An important supplement to this guide can be found in the example scripting
plugins in the plugins/ directory, and the links and lists Go plugins in the goplugins directory (from the source,
not included in the distributed .zip files).
Table of Contents
Memory Scoping
Long-term memories are scoped per-plugin by key, and so the data is not shareable between plugins. Short-term memories are stored for each user/channel combination, and can be freely shared between plugins.
Sharing Memories
For multiple jobs and/or plugins to share the same memory namespace, create an entry in the robot's NameSpaces:, and set the NameSpace: for each job or plugin.
Simple Task Memory NameSpace
By default, simple tasks in a job or plugin pipeline inherit the NameSpace from the pipeline, allowing memory-using tasks to be re-used. If a particular task needs to use the same memories for different plugins and jobs, create a unique entry for the task in the robot's NameSpaces:, and set that task's NameSpace: accordingly.
Long-Term Memories
The following methods are available for manipulating long-term memories:
CheckoutDatum(key, RWflag)- returns a complex data item (memory) with a short-term exclusive lock on the datum if RW istrueCheckinDatum(memory)- signals the robot to release the lock without updatingUpdateDatum(memory)- updates the memory and releases the lock
When checking out a memory read-write, the engine grants a short-term lock on the memory lasting 1-2 seconds. For tasks where the time between checkout and update could be longer than one second, you should check the return value on UpdateDatum - DatumLockExpired indicates another waiting task took the lock. It's worth noting that for low-contention memories, a given task can keep the memory checked out indefinitely and still update successfully; the 1-2 seconds is guaranteed, but the lock isn't actually lost unless another task checks out the memory read-write. This also means that a read-only checkout may get an outdated memory.
Long-Term Memory Code Examples
The memory stored can be an arbitrarily complex data item; a hash, array, or combination - anything that can be serialized to/from
JSON. The example plugins for Python and Ruby implement a remember function that remembers a list (array)
of items. For the code examples, we'll start with a memory whose key is memory, and has two items defined by this snippet of JSON:
["the Alamo", "Ferris Bueller"]
The examples will check if the memory exists, add "the answer is 42", and then update the memory.
Note that long-term memory commands aren't current implemented for bash.
Python
memory = bot.CheckoutDatum("memory", True)
if memory.exists:
memory.datum.append("the answer is 42")
else:
memory.datum = [ thing ]
ret = bot.UpdateDatum(memory)
if ret != Robot.Ok:
bot.Say("Uh-oh, I must be gettin' old - having memory problems!")
Ruby
Note: the Ruby example is a little more complicated; adapted from plugins/rubydemo.rb.
memory = bot.CheckoutDatum("memory", true)
remembered = false
if memory.exists
if memory.datum.include?(thing)
bot.Say("That's already one of my fondest memories")
bot.CheckinDatum(memory)
else
remembered = true
memory.datum.push("the answer is 42")
end
else
remembered = true
memory.datum = [ "the answer is 42" ]
end
if remembered
ret = bot.UpdateDatum(memory)
if ret != Robot::Ok
bot.Say("Dang it, having problems with my memory")
end
end
Long-Term Memory Sample Transcript
Using the terminal connector, you can see the remember function in action:
c:general/u:alice -> floyd, remember the answer is 42
general: Ok, I'll remember "the answer is 42"
c:general/u:alice -> |ubob
Changed current user to: bob
c:general/u:bob -> floyd, recall
general: Here's everything I can remember:
#1: the Alamo
#2: Ferris Bueller
#3: the answer is 42
From the transcript you can see that alice added the item to the list, which
was then visible to bob. The links and lists plugins are more useful, and
allow easy sharing of bookmark items or TODO lists, for example.
Short-Term Memories
Short term memories are simple key -> string values stored for each user / channel combination, and expiring
after a time. The best example of this uses the built-in links and lists plugins, shown in this example
using the terminal plugin:
c:general/u:alice -> link tuna casserole to https://www.allrecipes.com/recipe/17219/best-tuna-casserole/, floyd
general: Link added
c:general/u:alice -> add it to the dinner meals list
c:general/u:alice -> floyd
general: Ok, I added tuna casserole to the dinner meals list
c:general/u:alice -> floyd
general: Yes?
c:general/u:bob -> floyd, pick a random item from the dinner meals list
general: Here you go: tuna casserole
c:general/u:bob -> look it up, floyd
general: Here's what I have for "tuna casserole":
https://www.allrecipes.com/recipe/17219/best-tuna-casserole/: tuna casserole
Here, the robot is using short-term memories several times. When I forgot to address my command to the robot, the command
add it to the dinner meals list was stored in short-term memory for user alice in the general channel; then, when
I typed the robot's name, it checked short-term memory for the last thing alice said (stored automatically). Then,
the links plugin stored tuna casserole in the item short-term contextual memory; when I used it in the lists command,
the lists plugin checked the item short-term memory (see contexts in the plugin config for lists) and
substituted the value from the short-term memory.
Method Summary
These methods are available for short-term memories:
Remember(key, value)- associate the stringvaluetokey, always returnsOkRememberContext(context, value)- store a short-term contextual memory for use with other pluginsRecall(key)- return the short-term memory associated withkey, or the empty string when the memory doesn't exist
Note that the short-term memory API doesn't have complicated return values. They are always stored in the robot's working memory and never persisted, and expire after several minutes - so plugins should always be prepared to get blank return values.
Short-Term Memory Code Examples
Note that the short-term memory API is super trivial, so I didn't go to great lengths to provide
detailed examples. The bash example comes from the bashdemo.sh plugin.
Bash
Remember "$1" "$2"
Say "I'll remember \"$1\" is \"$2\" - but eventually I'll forget!"
MEMORY=$(Recall "$1")
if [ -z "$MEMORY" ]
then
Reply "Gosh, I have no idea - I'm so forgetful!"
else
Say "$1 is $MEMORY"
fi
Python
bot.Remember(key, value)
mem = bot.Recall(key)
Ruby
bot.Remember(key, value)
mem = bot.Recall(key)
Short-Term Memory Sample Transcript
Here you can see the robot's short term memories of Ferris Bueller in action (using
the bashdemo.sh plugin):
c:general/u:bob -> floyd, what is Ferris Bueller
general: @bob Gosh, I have no idea - I'm so forgetful!
c:general/u:bob -> floyd, store Ferris Bueller is a Righteous Dude
general: I'll remember "Ferris Bueller" is "a Righteous Dude" - but eventually I'll forget!
c:general/u:bob -> floyd, what is Ferris Bueller
general: Ferris Bueller is a Righteous Dude
c:general/u:bob -> |ualice
Changed current user to: alice
c:general/u:alice -> floyd, what is Ferris Bueller
general: @alice Gosh, I have no idea - I'm so forgetful!
c:general/u:alice -> |ubob
Changed current user to: bob
c:general/u:bob -> floyd, what is Ferris Bueller
general: Ferris Bueller is a Righteous Dude