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.

Next: Observing and acting through modules.

Further Details