4. Designing goal-directed behaviour
Start with the state the agent should achieve. Then identify what it must know, which actions can change the situation and how it will confirm the result. This turns a collection of event handlers into an understandable goal-directed program.
For the light controller, the policy is simple: the light should match the observed switch. switch(State) is an observation, !light(State) is the desired result and light(State) is evidence that the result has been achieved.
Develop the mental model
The following program extends Chapter 1 with a switch observation and an explicit decomposition. It still simulates changes through beliefs; the next chapter replaces that implementation with a Java device.
agent LightController {
module Console console;
module System system;
types lighting {
formula light(string);
formula switch(string);
}
initial light("off"), switch("off");
plan +!main(list args) {
-switch("off");
+switch("on");
wait(light("on"), 2000);
console.println("light follows switch: on");
system.exit();
}
plan +switch(string State) {
!light(State);
}
plan +!light(string Target) : light(Target) { }
plan +!light(string Target) {
!setLight(Target);
query(light(Target));
}
plan +!setLight(string Target) : light(string Current) {
-light(Current);
+light(Target);
}
}
Run with -Dastra.main=LightController. The startup plan changes the simulated switch. A reaction adopts the light goal. An already satisfied goal completes without work; otherwise, the agent delegates the change and checks the result.
Here setLight is deliberately a procedural helper for the simulation. The application’s public goal remains light(Target). Once a device module is available, an achievement plan can call its action directly and confirm the observed result.
Give each plan a role
Role |
Question it answers |
Light-controller example |
|---|---|---|
Deliberation |
Which desired state follows from this observation? |
A switch event adopts a light goal. |
Decomposition |
Which smaller goals establish the result? |
A larger room-readiness goal asks for lighting and other conditions. |
Achievement |
Which actions establish this state? |
Set the device, then confirm the light observation. |
Serendipity |
Is the desired result already true? |
The guarded empty light plan. |
Repair |
Which missing prerequisite must be established first? |
Restore power before retrying a light goal. |
Recovery |
What should happen when achieving the goal fails? |
Report failure or make a bounded retry. |
Reaction |
What response is needed while another activity continues? |
Handle an external switch change. |
These are programming conventions, not distinct ASTRA declaration types. They give plans a purpose and help you decide where behaviour belongs.
Model prerequisites explicitly
If a device needs power, introduce knowledge describing power availability. A repair plan can first achieve a power goal, then re-adopt the light goal. Avoid a repair loop that retries without changing the condition that caused it to fail.
Plan completion and achievement of a real-world state are different. In the mental model, a query is enough because the program has just updated its belief. With asynchronous observation, use a bounded wait for the result. An empty fallback must be guarded by actual evidence if it is meant to signify success.
Keep the boundary visible
Do not hide device operations in inferred beliefs, or update an observed-state belief merely to make a goal appear complete. The agent chooses what should happen; its module changes the device; observation supplies evidence of what did happen.
The detailed practical-reasoning page develops these conventions further, including repair and Towerworld examples. Read it after this chapter, then return to it as your programs grow.