JSoarUsersGuide - soartech/jsoar GitHub Wiki

See also:

For information about using the JSoar debugger, see JSoarDebugger

Introduction

JSoar is essentially a library for constructing agent-based systems. It includes many conveniences, but you must still write both Soar code do define your agent's behavior as well as Java (or some JVM-based language) code to connect the agent to some environment.

Essential JSoar Classes and Interfaces

JSoar's API is broken up into a number of classes and interfaces. Although this makes testing and extension easier, it can lead to confusion and code that's more verbose than necessary. In the spirit of helper classes like java.util.Collections and java.util.Arrays, JSoar provides a number of classes which should almost always be favored over their raw interface counterparts:

  • Wmes - Methods for searching and filtering WMEs
  • InputWmes - Methods for adding and updating input WMEs
  • Symbols - Methods for converting symbols to and from Java obejcts
  • SoarCommands - Methods for executing interpreter commands like "source"
  • SoarEvents - Methods for common Soar event handling patterns.

Project Setup

Setting up a JSoar project depends a lot on your environment, build mechanism, and how you want JSoar to fit into your system. We recommend using a dependency management system like Maven or Gradle; see the README for more information.

If you want to directly include the dependencies yourself, you can get them from the Releases. A typical project will include jsoar-core, jsoar-debugger, jsoar-tcl, and jsoar-soarunit. It's typically best, to put the jars in a lib folder in your project and then add them rather than referring to an external copy of JSoar

Regardless of your setup, create a class with a main and create an agent as described below.

Additionally, the JSoar distribution comes with "source" and "javadoc" jars. These are generally useful for both debugging and figuring out what methods do.

Constructing a Raw Agent

Constructing a new agent in jsoar is very straightforward:

import org.jsoar.kernel.Agent;

...
Agent agent = new Agent();
agent.setName("My Agent");
agent.getPrinter().pushWriter(new OutputStreamWriter(System.out));
agent.initialize();
agent.runForever(); // Call blocks until agent interrupts or halts
...

This constructs and initializes a raw Soar agent. The Agent class includes base functions for running the agent (runFor() and runForever()) as well as interfaces for loading productions, modifying input, etc. The Agent class makes no assumptions about how the agent will be run and is not thread-safe.

When you're done with the agent, clean it up:

agent.dispose();

ThreadedAgent

The ThreadedAgent class is a wrapper around a base Agent instance which provides some higher-level run control. In particular it creates a new thread for the agent to run in and provides primitives for interacting with the running agent in a thread-safe way:

import org.jsoar.runtime.ThreadedAgent;

...
ThreadedAgent threaded = ThreadedAgent.create();
threaded.setName("My Agent");
threaded.getPrinter().pushWriter(new OutputStreamWriter(System.out));
threaded.runForever(); // Agent begins running in its own thread. Returns immediately.
...

Because the agent managed by ThreadedAgent is run in its own thread, ThreadedAgent provides an asynchronous interface for interacting with the running agent. This style ensures that the agent's data structures are only accessed from a single thread and also prevents deadlock. To execute code in the agent's thread, pass a Callable to the execute() method:

final Agent agent = threaded.getAgent();
threaded.execute(new Callable<Void>() {
    public Void call() throws Exception {
       System.out.println("WMEs: " + agent.getAllWmesInRete());
       return null;
    }
}, null);

note that the call() method is called in the agent thread. execute() also takes an optional second callable which is always called after the first command is executed. It is also called in the agent's thread. Note that org.jsoar.runtime.SwingCompletionHandler can be used in this context to marshal data back from the agent's thread to the Swing UI thread.

When you're done with the threaded agent, clean it up:

threaded.dispose();

Opening the JSoar Debugger

The JSoar debugger is not displayed by default in a custom project. To open it, you can use the openDebugger() (or openDebuggerAndWait()) method on your ThreadedAgent object (sorry, the debugger only works on ThreadedAgent). Alternatively, you can start your agent running and have it call the (debug) RHS function.

SoarCommandInterpreter

JSoar uses an instance of org.jsoar.util.commands.SoarCommandInterpreter to process commands and load files. The interpreter is accessible through the getInterpreter() method of the Agent or ThreadedAgent class. A default interpreter (implemented by org.jsoar.util.commands.DefaultInterpreter) is created the first time this method is called.

JSoar includes an alternate, Tcl-based interpreter if you're so inclined. To enable it, make sure jsoar-tcl.jar is on your classpath, and set the jsoar.agent.interpreter system property to "tcl". See JSoarSystemProperties

Sourcing Soar Code

The interpreter can source either normal files, or files accessible through a URL:

import org.jsoar.util.commands.SoarCommands;
...
SoarCommands.source(agent.getInterpreter(), "/path/to/file.soar");
... or ...
SoarCommands.source(agent.getInterpreter(), "http://darevay.com/jsoar/waterjugs.soar");

SoarCommands.source() is a helper method which automatically determines whether the string (or object) given is a File or URL. Also, keep in mind that Java resources are accessible through a "jar" URL so your source code can be embedded in a jar or just present on the classpath:

SoarCommands.source(agent.getInterpreter(), MyClass.getResource("/path/to/resource.soar"));

The source command keeps track of the "current working directory", even with URLs, so code on a web-server, or embedded in a jar can refer to additional files through relative paths.

Note: that when using ThreadedAgent all interpreter commands should be executed on the agent's thread since they normally manipulate agent state.

Currently, JSoar includes at least partial implementations of most of the built-in Soar commands.

Agent Properties

Arbitrary properties can be associated with an agent. See org.jsoar.kernel.Agent.getProperties() and org.jsoar.kernel.SoarProperties for examples of built-in properties.

Property access is generally thread-safe, but may return structures that are not thread-safe.

Use the properties command to get a list of the current values of all agent properties.

JSoar-specific RHS Functions

See JSoarRhsFunctions for more info on JSoar-specific RHS functions and creating new RHS functions.

Providing Input to the Agent

See JSoarInput for more info on generating agent input.

Handling Agent Output

See JSoarOutput for more info on handling agent output.

System Properties

See JSoarSystemProperties for info on system properties used to control JSoar.

Tcl Support

See JSoarTclSupport for info on Tcl support in JSoar.

⚠️ **GitHub.com Fallback** ⚠️