Debugging in VS Code
From ASTRA 2.8.0, programs can be debugged in Visual Studio Code with the ASTRA extension (1.4.0 or later): set breakpoints on the lines of .astra files, step through plans statement by statement, and look at the agents’ variables, beliefs, events and intentions while they are stopped. The GUI shows what a whole system did over time; the debugger stops agents at a point in their code.
Starting a debug session
Open the project in VS Code, click in the margin of an .astra file to set a breakpoint, and press F5 (or choose Debug ASTRA Program in the editor’s run menu). The extension runs
mvn compile astra:debug
in the project, which starts the program under the debugger. The program waits until VS Code has set its breakpoints, and then starts its main agent. Its output appears in the Debug Console. Stop the session with the stop button, which ends the program.
To choose the main agent’s class or pass more Maven arguments, add a launch.json (Run > Add Configuration… > ASTRA: Launch):
{
"type": "astra",
"request": "launch",
"name": "Debug ASTRA program",
"cwd": "${workspaceFolder}",
"mainClass": "examples.Main",
"mavenArgs": ["-Dastra.name=coordinator"]
}
Setting |
Default |
Meaning |
|---|---|---|
|
the project of the open file |
The Maven project (the folder with its |
|
the project’s |
The main agent’s class. |
|
none |
More arguments for Maven. |
|
|
Stop at the first statement any agent executes. |
|
|
When an agent stops, pause all the other agents too. |
|
|
|
When an agent stops
VS Code shows ASTRA’s state in its usual views:
Threads are agents. When one agent stops, the others are paused too, so you see the system as it was at that point, and continuing resumes them all. With
"stopAll": false, only the agent that stopped is paused; messages to it wait until it resumes.The call stack is the stopped agent’s plans, innermost first: the plan that stopped (for example
+!visit(0)), then the plans whose subgoals it is working for (+!main([])), and then, greyed out, the agent’s other intentions.Variables shows the selected plan’s variables, and the agent’s beliefs, events and intentions. Lists can be expanded. Hovering over a variable in the editor shows its value.
In the Debug Console, a variable’s name shows its value, and a formula is queried against the agent’s beliefs (and inference rules), listing each answer:
> visited(int X)
X=0
X=1
> visited(5)
false
Agents with several intentions
An agent can work on several intentions at once, for example a goal it adopted with !! alongside its main plan. By default, the call stack lists the intention that stopped first and the agent’s other intentions after it, greyed out, each at the statement it will run next; selecting one of their frames shows that plan’s variables. Breakpoints stop the agent in any intention.
With "threads": "intentions" in launch.json (ASTRA 2.8.1 or later), each intention is a thread of its own, named after its agent and goal (main / +!work()). Select any intention to see its plans and step it; while it steps, the agent’s other intentions wait, so that nothing changes behind your back. If the intention you step waits for something only another intention would do, the step does not end: use Pause or Continue.
Stepping
Stepping follows the intention that stopped:
Command |
Stops at |
|---|---|
Step Into |
the intention’s next statement. If the current statement adopts a subgoal ( |
Step Over |
the next statement of the same plan (or of a plan that adopted it, if this plan ends): a subgoal runs to completion. |
Step Out |
the next statement of the plan that adopted this plan’s goal. |
Continue |
the next breakpoint. |
The agent’s other intentions keep running while you step, and stop only at breakpoints. A breakpoint on the first line of a rule stops when the rule’s plan starts; one on a blank line or a comment moves to the next statement.
Rules added to an agent while it runs have no file. From ASTRA 2.8.1, stepping into one opens its text as a read-only document, and breakpoints can be set in it while the rule exists.
Classes from libraries, such as MAMS’s mams.javatypes.Passive, have their source in a jar rather than in your project. From ASTRA 2.8.2, a frame in such a class opens the jar’s copy as a read-only document, in which you can also set breakpoints.
When other agents are waiting
An agent stopped at a breakpoint does not reply to messages, so agents waiting for it may time out. From ASTRA 2.8.1, agents can be told: an agent that declares the Debug module receives events when agents stop and resume, and can, for example, wait longer for their replies.
module Debug debug;
rule $debug.stopped(string name, string reason) {
// name has stopped (reason: breakpoint, step, pause or entry)
}
rule $debug.resumed(string name) {
// name runs again
}
$debug.attached() and $debug.detached() follow the debugger connecting and disconnecting, and debug.active() and debug.isStopped(name) can be tested in rules. Only agents that declare the module hear about debugging, and when all agents are stopped, the events wait until they resume. The trace records the same moments as debug-attached, debug-detached, debug-stopped and debug-resumed events.
Debugging a program that is already running
Start the program so that it does not wait for VS Code:
mvn compile astra:debug -Dastra.debug.wait=false
It listens on port 4711 (-Dastra.debug.port changes it), and an ASTRA: Attach configuration connects to it:
{
"type": "astra",
"request": "attach",
"name": "Attach to ASTRA program",
"port": 4711
}
Disconnecting leaves the program running, and you can attach again later.
A program in a container can start the debugger itself (from ASTRA 2.8.1, with DebugLauncher.startFromEnvironment in astra-debug), when its ASTRA_DEBUG_PORT environment variable is set; MAMS Infrastructure does this for every pod from 1.3.0. Forward the port to your machine (for example kubectl port-forward <pod> 4711) and attach to localhost. The attach configuration’s sourceRoot (by default the project’s src/main/astra) tells the debugger where your own copy of the sources is, so that breakpoints and frames use your files.
The debugger accepts connections only from the same machine (in a container, from inside it, which is where kubectl port-forward connects). To accept others, set ASTRA_DEBUG_HOST (or -Dastra.debug.host) to 0.0.0.0; anyone who can connect can stop and inspect the program, so only do that on a network you trust.
Limitations
Breakpoints work in rules’ plans. Teleo-reactive functions and inference rules cannot have breakpoints yet.
There are no conditional breakpoints or logpoints yet.
Java code in modules is not debugged; use a Java debugger for that.