Custom Actions and Output Parameters
An action gives an agent a concrete operation implemented in Java. Observing and Acting introduces the complete example.LightDevice module; this page explains its action contract and how to return an output value.
Declaring a Custom Module
Extend astra.core.Module, not astra.lang.Module. Put the Java file in a directory matching its package under src/main/java. The inherited agent field refers to the agent associated with the module instance.
package example;
import astra.core.Module;
public class Echo extends Module {
@ACTION
public boolean print(String message) {
java.lang.System.out.println(message);
return true;
}
}
Declare it with module example.Echo echo;, then call echo.print("hello"); inside a plan. ASTRA module identifiers are names you choose; they do not have to match the Java class name.
Creating an Action
A callable action method is public, carries @ACTION and returns a Java boolean. true means the action completed successfully; false fails the calling statement. A runtime exception also fails the action. ASTRA invokes it as a statement, so its boolean is not an assignable result term.
Match Java parameter types to ASTRA argument types. Use primitives such as int and boolean, String for strings, astra.term.ListTerm for ASTRA lists and astra.term.Funct for function terms. A Java object argument uses the corresponding Java class type.
Validate input before changing state. In LightDevice.set, only "on" and "off" are accepted. Unsupported input returns failure without changing the simulated device. A successful action means the Java operation succeeded; it does not establish that a subsequent observation has arrived.
Returning an Output Value
Use astra.core.ActionParam<T> for an action’s output parameter:
package example;
import astra.core.ActionParam;
import astra.core.Module;
public class Parser extends Module {
@ACTION
public boolean integer(String text, ActionParam<Integer> result) {
try {
result.set(Integer.parseInt(text.trim()));
return true;
} catch (NumberFormatException failure) {
return false;
}
}
}
In an ASTRA plan, call parser.integer("42", int Value); using a typed unbound variable. The module binds it through result.set(...). Returning success without providing the promised output leaves the caller without a usable result. For a simple value-producing expression, an @TERM method may be more natural.
Using the Module
Use a goal to express the application’s desired result and an action as the concrete step:
plan +!light(string Target) : light(Target) { }
plan +!light(string Target) {
device.set(Target);
wait(light(Target), 2000);
}
The first plan recognizes an already observed result. The second performs the action and confirms an observation. The full agent and Java module are in Chapter 5, with a runnable sample project.
Next, read Custom Terms and Formulae to expose queryable state, or Sensors to publish observations.