Experimental

BeliefLang Syntax, Explained Step by Step

This page explains the language in simple words, one syntax piece at a time. Start from basic blocks, then move to dynamic updates like observe, infer, and merge.

Core Pitch

BeliefLang compresses natural-language reasoning into atomic belief state. Instead of repeatedly sending long conversation history to an LLM, BeliefLang stores intermediate reasoning as probability-weighted beliefs and executes deterministic rules over them.

Typical agent flow (token heavy)

Step 1 LLM: parse user message
Step 2 LLM: decide intent
Step 3 LLM: decide tool
Step 4 LLM: interpret result
Step 5 LLM: decide next action

BeliefLang flow (state-first)

natural language -> belief extraction
beliefs -> rules -> tools

Architecture in one line

LLM for extraction.
BeliefLang for state.
Rules for control.
Tools for action.

Why this matters

  • Less token usage
  • More deterministic execution
  • Better debugging with trace and provenance
  • Clear thresholds instead of vague prompting
  • Lower hallucination risk after extraction
  • Reusable, auditable intermediate state

Quick Start

Install, build, and run:

npm install -g belieflang
npm run build
bel run examples/intent.bel --trace

Your first tiny BeliefLang program:

belief intent exclusive closed {
  book_flight: 0.8
  unknown: 0.2
}

when confidence(intent.book_flight) > 0.7:
  ask_user("I can help you with flights.")

Syntax One by One

Read this top to bottom once, and you can already write useful BeliefLang.

1. Start a belief block with belief

A belief block stores uncertain state. It has a name and a set of labels with numeric confidence values.

belief intent exclusive closed {
  book_flight: 0.82
  book_hotel: 0.12
  unknown: 0.06
}

2. Use let to create variables

Variables hold numbers, strings, booleans, or tool output objects.

let threshold = 0.7
let message = "I need a flight"
let flights = call search_flights()

3. Read nested values with dot paths

Use dot notation for object fields, for example flights.count.

when flights.count > 0:
  ask_user("I found options.")

4. Write rules with when ... :

A rule has a condition and one action line under it.

when confidence(intent.book_flight) > threshold:
  call rank_flights()

5. Use metrics: confidence(...) and entropy(...)

confidence reads one label score. entropy tells how uncertain a belief is.

when confidence(intent.book_flight) > 0.7 || entropy(intent) > 0.5:
  ask_user("Please clarify your intent.")

6. Add comments with #

# This rule runs only for strong flight intent
when confidence(intent.book_flight) > 0.7:
  call rank_flights()

Belief Block Breakdown

belief intent exclusive closed {
  book_flight: 0.82
  book_hotel: 0.12
  unknown: 0.06
}
  • belief: starts a belief definition
  • intent: belief name
  • exclusive: one label is treated as the winning class
  • closed: no hidden label outside the block
  • { ... }: block body
  • book_flight: 0.82: label and confidence value

What exclusive, open, closed, and multi mean

exclusive

Use this when labels are alternatives. Example: flight or hotel intent.

multi

Use this when labels are independent. Example: user can be both cheap and direct focused.

closed

Means your listed labels are complete. No extra hidden class exists.

open

Means there can be an unlisted class. Remaining mass is exposed as other.

Common combinations

Combination Simple meaning Example
exclusive closed Pick one from listed labels only intent
exclusive open Pick one from listed labels or unknown outside list destination
multi closed Independent label strengths user_preferences
belief destination exclusive open {
  berlin: 0.60
  paris: 0.25
}

# remaining 0.15 is treated as destination.other

Conditions and Rules

Conditions decide if an action should run.

when confidence(intent.book_flight) > 0.7 && (flights.count > 0 || !false):
  ask_user("I found flight options.")

Operators

  • Comparison: >, >=, <, <=, ==, !=
  • Boolean: &&, ||, !
  • Metrics: confidence(name.label), entropy(name)

Actions and Tools

A rule body can run one action line.

call tool()

when confidence(intent.book_flight) > 0.7:
  call rank_flights()

ask_user("...")

when entropy(intent) > 0.5:
  ask_user("Can you clarify your intent?")

let x = call tool()

let flights = call search_flights()

when flights.count > 0:
  ask_user("Flights found.")

Observe, Infer, Merge

These three lines are the dynamic update cycle.

let message = "I need a cheap direct flight"

observe user_message(message)
infer beliefs from user_message

let extracted = call extract_patch()
merge beliefs from extracted

observe event(value)

Stores an observation record and also writes the latest value into a variable named event.

infer beliefs from source

Calls the inference adapter and produces a belief patch object.

merge beliefs from source

Combines patch values into existing beliefs. Existing labels stay unless overwritten.

Trace and Provenance

Run with --trace to inspect evaluation and actions:

bel run examples/observe_infer_merge.bel --trace

Provenance keeps a history of how each belief value was created (load, infer, merge).

runtime.getProvenance()
runtime.explainBelief("intent.book_flight")

Runtime API

State Access

  • getState()
  • getVars()
  • confidence(path)
  • entropy(beliefName)

Dynamic Data

  • observe(eventName, value)
  • infer(source)
  • mergeBeliefsFromRuntimeValue(patch, source)

Auditability

  • getObservations()
  • getProvenance()
  • explainBelief(path)

Full Example

let message = "I need a cheap direct flight to Berlin"

belief intent exclusive closed {
  unknown: 1
}

observe user_message(message)
infer beliefs from user_message

let extracted = call extract_patch()
merge beliefs from extracted

when confidence(intent.book_flight) > 0.7 && confidence(user.budget_sensitive) > 0.5:
  call rank_flights()

when entropy(intent) > 0.5:
  ask_user("Can you clarify your travel intent?")