Dialogue Branch Core Java Library
Introduction
The "Core" of the Dialogue Branch software is a library that can read and execute Dialogue Branch (.dlb) scripts. This core library is written in Java, and its source lives in this monorepo under packages/core. Its Maven coordinates are com.dialoguebranch:dlb-core-java.
Not on Maven Central for now
The current 0.x releases are not published to Maven Central. Maven Central has older versions, up to 1.3.0, published before the version numbering was reset to 0.x, so a dependency on the latest version there gets you that old library, which doesn't match this documentation. To use a current release, install it in your local Maven repository from its release tag:
git clone --branch v0.10.0 https://github.com/dialoguebranch/platform.git
cd platform/packages/core
./gradlew publishToMavenLocaland depend on it from there:
repositories {
mavenLocal()
}
dependencies {
implementation 'com.dialoguebranch:dlb-core-java:0.10.0'
}Playing a Dialogue
Load a project from its dlb-project.xml, start one of its dialogues, and show each step and select replies until it finishes:
ExecutableProject project = ExecutableProject.load(Path.of("dlb-project.xml"));
ActiveDialogue dialogue = project.startDialogue("welcome", new User("sam"));
DialogueMessage step = dialogue.getCurrentMessage();
while (step != null) {
System.out.println(step.getSpeaker() + ": " + step.getStatement().getText());
if (dialogue.isFinished()) break;
dialogue.selectReply(chooseReply(step.getReplies())); // e.g. ask the user
step = dialogue.getCurrentMessage();
}chooseReply stands for your own code: it shows the replies (reply.getText(), or a "Continue" button where reply.isAutoForward()) and returns the one the user picks.
ExecutableProject.loadthrows aProjectParseExceptionthat lists every parse error, per file; warnings are available fromproject.getWarnings().startDialoguehas overloads that take a language, an existingVariableStoreand the start time. A dialogue that isn't available in the given language runs in the project's source language.getCurrentMessagereturns the current step as aDialogueMessage, the same shape the Web Service sends: the speaker, the statement with its variables filled in, its actions and input fields, and the replies with their IDs.getStatement().getText()andreply.getText()give the text without the input fields and actions, whichgetSegments()has. The step'sloggedDialogueIdandloggedInteractionIndexsay where it is in the log, when a log is kept (see below); without a log they arenulland 0, which has no meaning.getCurrentMessagereturnsnullonly after a reply toEnd: there is nothing left to show then. That is why the loop checks fornulland forisFinishedseparately.isFinishedis true once a reply led toEnd, or the dialogue is at a node without replies. That last node still has a statement to show.selectReplyruns the reply'ssetcommands and returns the next node, ornullwhen the reply ends the dialogue. It takes the reply, or its ID, and optionally the time of the selection; without one, it uses now, in the time zone of theVariableStore's user, asstartDialoguedoes. When a reply leads into another dialogue, theActiveDialogueswitches to it, in the same language and with the same variables; aDialogueSwitchListenerhears of the switch, before the first node there runs.- Where a translation depends on the end user's gender, the dialogue follows the value of
$dlb.userGenderin its variables at every step. - To look up a dialogue without starting it, use
project.getDialogue(name)orgetDialogue(name, language).
Keeping a log, going back and resuming
An ActiveDialogue can keep a log of the conversation, as the Web Service does: the agent's statements and the user's replies, across dialogues. The log is a LoggedDialogue that you give it, so you decide where it lives; InMemoryLoggedDialogue is a simple one for a transcript or a back button.
ActiveDialogue dialogue = project.createDialogue("welcome", null,
new VariableStore(new User("sam"))); // not started yet
InMemoryLoggedDialogue log = dialogue.keepInMemoryLog(); // before starting
dialogue.startDialogue();
// ... select replies; every step is recorded. A reply into another dialogue starts a new log in
// the same session: the current one is dialogue.getLoggedDialogue(), and each in-memory log
// points back to the one before it with getPrevious().
dialogue.back(); // the previous agent step, shown again: nothing is added to the log
dialogue.cancel(); // marks the log cancelled- A log is set before the dialogue starts, so
createDialoguegives the dialogue without starting it;startDialogueis the same with the start included. - Each step is an interaction of the log,
AGENTfor what the agent said andUSERfor the reply, with the index of the interaction before it. The log is marked completed when the dialogue ends. - A reply that leads into another dialogue completes the log, and the conversation continues in a new one, made by the
LoggedDialogueFactoryyou pass tosetLoggedDialogue(log, factory);InMemoryLoggedDialogue.factory()makes in-memory logs of the same session. back()goes to the previous agent step in the current dialogue and executes it again, so itssetcommands run again. A later reply continues from that step. It refuses a log that is completed or cancelled.ActiveDialogue.restore(resolver, log, index, variables, factory)rebuilds a dialogue from a log at a step, to resume later: the Web Service does this on every request. It leaves the step's node unexecuted so a reply can be selected right away;executeCurrentNodeexecutes it to show it again. Until thengetCurrentMessageandisFinishedthrow anIllegalStateException, since the replies a node has depend on its<<if>>s. Only the position is restored: the variables are those of theVariableStoreyou pass.
Package Overview
The com.dialoguebranch package is organised as follows:
model/common— Shared types used by the execution model, e.g.ProjectMetaData,StorageSource.model/execute— The immutable runtime model (ExecutableProject,Dialogue,Node,NodeHeader,NodeBody,ResolvedNodeBody,Reply,VariableString,LoggedDialogue), the command types executed within a node body (SetCommand,IfCommand,RandomCommand,ActionCommand, theInputCommandvariants), and the API protocol types used to serialise dialogue state (DialogueMessage,DialogueStatement,ReplyMessage).execution— The runtime engine itself:ActiveDialoguedrives a live conversation, following replies into other dialogues through aDialogueResolver,VariableStoreholds session variables, andparser/contains the parsers used at execution time (DialogueBranchParser,BodyParser,CommandParser,ProjectParser,ProjectScriptLoader, and others).editing—ProjectMetaDataWriter, used to export a project's metadata.i18n— Translation support:Translatorapplies a.jsontranslation file to aDialogue, andTranslatableExtractorwalks a node's body to extract translatable segments.exception— Typed exceptions used throughout the library (NodeParseException,ExecutionException, and others).cli—DialogueBranchCLI(the module's default main class): an interactive, menu-driven inspector when run with no arguments, or a non-interactive, scriptable validator/executor (suited to CI) when run with a project path and flags — see its own--help.
For the exact syntax of the .dlb script format this library parses and executes, see the Dialogue Branch Language Definition.
Command-Line Tool
cli.DialogueBranchCLI (the module's default main class) can be run two ways:
# Interactive, menu-driven session (default with no arguments)
./gradlew run -q --console=plain
# Non-interactive: parse a project and print its summary, exiting non-zero on parse errors
./gradlew run -q --console=plain --args="<path-to-dlb-project.xml> [--validate]"
# Non-interactive: run a specific dialogue interactively on the terminal
./gradlew run -q --console=plain --args="<path-to-dlb-project.xml> --execute <language> <dialogue>"
# Full syntax
./gradlew run -q --console=plain --args="--help"The non-interactive validate mode is suited to CI. Alongside parse errors, it also reports warnings for issues that can never cause a runtime error but likely indicate an authoring mistake — such as an orphaned node: a node that no reply link points to and that isn't its own dialogue's Start node, or a node whose speaker isn't one of the project's speakers (only when the project defines speakers). Warnings are printed but do not affect the exit status.
Documentation
Javadoc for the library can be generated locally with ./gradlew javadoc (output in packages/core/build/reports/javadoc/). The versions on Maven Central (up to 1.3.0, older than the 0.x releases) also have their Javadoc on javadoc.io; for a current release, generate it locally.
