moonbtkit

Serializable behavior-tree assets, deterministic execution, and regression analysis for MoonBit.

behavior-tree
dsl
testing
game-ai
wasm
moon add liu666789987/moonbtkit@0.1.6
Download zip
Version
0.1.6
License
Apache-2.0
Last updated
3 hours ago
Downloads
12
README

#MoonBTKit

CI

MoonBTKit 是一个 MoonBit 原生行为树资产与确定性回归工具链,面向游戏 AI、机器人任务编排、NPC 行为控制、AI Agent 工作流分支和 Wasm 应用中的可测试决策逻辑。它把严格、可逆的文本 DSL 作为资产边界,并提供确定性执行、版本比较、回归基线和批量质量报告。

#项目目标

行为树常用于游戏引擎、仿真系统、机器人任务流和智能体编排。MoonBTKit 提供可复用的 MoonBit 实现,让开发者可以用类型安全、确定性、可测试、可运行到 Wasm/JS 的方式描述和验证决策逻辑。

本项目不绑定 Unity、Unreal、Godot、Raylib 等具体引擎;它提供的是可被这些系统调用的决策层。

#为什么不是重复项目

MoonBTKit 不是以闭包回调、事件总线和多树调度为中心的通用行为树运行时。它解决的是另一类工程问题:如何把行为逻辑保存为可审查的文本资产,并在 CI 中完成静态校验、确定性执行、分支回归、覆盖率分析和可视化交付。

文本 DSL / Builder ↓ 解析、重复 ID 检查、缺失引用检查、环检测、lint ↓ 显式 BehaviorTree 数据模型与确定性 tick ↓ trace digest / timeline / coverage / matrix / profile / audit ↓ asset diff / baseline / catalog / canonical fingerprint ↓ Graphviz DOT / Mermaid / Markdown 验收报告

Mooncakes 上的生态对比项目 mhh12345678/behavior_tree 仅用于说明功能边界,不是 MoonBTKit 的移植、参考源码或依赖来源。

对比维度MoonBTKitmhh12345678/behavior_tree 公开定位
核心用户维护行为树文本资产、测试基线和验收报告的工具开发者在宿主程序中直接组装并调度行为节点的应用开发者
建模核心可序列化 DSL、显式节点数据模型、Builder闭包节点与 Builder
主要处理链解析、静态校验、确定性执行、回归分析、报告导出运行时执行、事件路由、多树和预算调度
回归证据固定 fixture、trace digest、coverage、输入 matrix、profile、综合 audit场景运行、metrics、trace、benchmark
交付物可版本比较的 DSL、DOT、Mermaid、Markdown 报告可嵌入宿主应用的运行时对象和调度结果
明确不做EventBus、EventRouter、多 NPC Scheduler、宿主闭包脚本不以 MoonBTKit 的 DSL roundtrip 和多格式报告链为核心

MoonBTKit 的独立价值集中在三个方面:一是行为逻辑可以脱离具体引擎保存、规范化、比较和生成稳定指纹;二是同一输入在 Wasm-GC 与 JS 目标上可复现,并由 digest、回归基线和 164 个测试提供证据;三是执行 trace 可以继续生成覆盖率、场景矩阵、热点画像、目录审计和图形文件,形成从资产版本到验收结果的完整闭环。两个项目没有代码、fixture 或依赖关系。

#当前状态

项目状态
包名liu666789987/moonbtkit
版本0.1.6
MoonBit 实现核心功能均由 MoonBit 实现
代码规模7,700 余行有效 MoonBit 代码
测试164 个测试,覆盖核心执行、严格 DSL、类型无损 roundtrip、错误与边界、资产差异、回归基线、目录审计、规范指纹、fixture、可视化和白盒 helper
示例cmd/mainexamples/basicexamples/export 均可运行
CIGitHub Actions 覆盖格式、零警告检查、构建、测试、JS 目标、示例和包清单
许可证Apache-2.0

#安装

已发布到 Mooncakes:

moon add liu666789987/moonbtkit

moon.pkg 中引用:

import {
"liu666789987/moonbtkit",
}

当前 Mooncakes 包名为 liu666789987/moonbtkit

#最小示例

let source =
"root root\n" +
"blackboard enemy_visible true\n" +
"blackboard ammo 2\n" +
"selector root engage patrol\n" +
"sequence engage see_enemy has_ammo aim fire\n" +
"condition see_enemy enemy_visible eq true\n" +
"condition has_ammo ammo gt 0\n" +
"action aim aim_weapon running,success mode=aiming\n" +
"action fire fire_weapon success ammo=1 result=hit\n" +
"action patrol patrol_area success mode=patrol\n"

match @moonbtkit.parse_dsl(source) {
Ok(doc) => {
let engine = @moonbtkit.new_engine(doc.tree, blackboard=doc.blackboard)
match engine.run_until_done(max_ticks=6) {
Ok(result) => println(result.summary())
Err(err) => println(err.message())
}
}
Err(err) => println(err.message())
}

#运行示例

moon run cmd/main moon run examples/basic moon run examples/export

cmd/main 会运行内置 fixture 和 recipe;examples/basic 展示一个最小 NPC 战斗决策树,并输出 timeline;examples/export 展示 DOT、Mermaid、coverage、matrix、资产差异、基线、目录审计和指纹输出。

#主要功能

  • 行为树节点:SequenceSelectorParallelAllParallelAny
  • Decorator:InverterSucceederFailerRepeatRetry
  • Leaf:条件判断、黑板写入、脚本化 action、wait、emit
  • Blackboard:支持 bool、int、text、empty 值
  • DSL:使用行式文本描述树和初始黑板
  • 严格 DSL:检查未闭合引号、尾随转义、非法 action 状态和非法 Decorator 计数
  • 类型无损序列化:text:"..." 显式文本值不会与 bool、int、empty 混淆
  • Builder:使用 MoonBit API 直接构建行为树
  • Fixture:内置 NPC、机器人、Agent、Boss、教程、潜行等场景
  • Recipe:内置可参数化游戏/机器人/Agent 行为模板
  • Trace:tick 事件、digest、timeline、过滤与统计
  • Visualization:导出 Graphviz DOT、Mermaid flowchart 和 Mermaid sequence diagram
  • Coverage:统计 trace 覆盖节点、遗漏节点和执行覆盖率
  • Matrix:对黑板变量做场景矩阵回归测试
  • Profile:聚合节点执行次数、状态分布和热点节点
  • Audit:生成 fixture/catalog 级别的验收审计报告
  • Validation/Lint:结构校验、常见风险提示
  • 安全验证:拒绝重复节点 ID、缺失引用和环形子节点关系
  • Case Runner:批量运行行为树用例并输出断言报告
  • Asset Diff:比较两个 DSL/树版本的新增、删除、结构变化和兼容性
  • Regression Baseline:捕获并验证状态、trace digest、tick 和覆盖率基线
  • Asset Catalog:批量解析、规范化、lint、运行并审计任意 DSL 资产目录
  • Asset Identity:规范化 DSL 并生成与注释、空白和声明顺序无关的稳定指纹

#API 概览

分类API
黑板new_blackboard, blackboard_from_pairs, Blackboard::set, Blackboard::get_*
节点node, sequence, selector, condition, set_value, wait, action_success
new_tree, tree_from_nodes, BehaviorTree::add, BehaviorTree::validate
引擎new_engine, BtEngine::tick, BtEngine::run_until_done, BtEngine::trace_digest
DSLparse_dsl, parse_tree_dsl, serialize_tree, parse_blackboard_dsl
分析analyze_tree, lint_tree, tree_markdown_report, smoke_run
测试run_case, run_cases, fixture_cases, recipe_cases, assert_*
示例fixture_catalog, run_fixture, recipe_catalog, run_recipe_catalog
Timelinetimeline_from_trace, timeline_text, summarize_trace, compact_trace
Visualizationtree_to_dot, tree_to_mermaid, trace_to_mermaid_sequence, visualization_bundle
Coveragecoverage_from_trace, fixture_coverage, fixture_catalog_coverage
Matrixrun_matrix, boolean_matrix, int_sweep_matrix, fixture_matrix_report
Profileprofile_trace, profile_fixture, fixture_profile_report, profile_markdown
Auditaudit_fixture, audit_fixture_catalog, audit_catalog_markdown
Asset Diffdiff_trees, diff_dsl, TreeDiff::compatibility, TreeDiff::markdown
Baselinecapture_baseline, verify_baseline, regression_baseline, BaselineReport::markdown
Asset Catalogasset_spec, audit_asset, audit_asset_catalog, AssetCatalogReport::markdown
Asset Identitycanonicalize_dsl, asset_fingerprint, inspect_asset, AssetIdentity::markdown

#支持范围

  • 内存版行为树执行
  • 确定性 tick
  • 文本 DSL 和 MoonBit Builder 两种构建方式
  • 注释、引号、反斜杠、换行和标量样文本值的可逆 DSL roundtrip
  • 可复现 trace digest
  • 可导出的 DOT / Mermaid 结构图和 trace 图
  • 可统计的节点执行覆盖率
  • 可参数化的场景矩阵回归测试
  • 可输出节点热点画像和 catalog 审计报告
  • 可比较资产版本并识别 breaking 结构变化
  • 可捕获和验证确定性回归基线
  • 可批量审计任意 DSL 资产目录
  • 可生成与格式和声明顺序无关的规范 DSL 与稳定指纹
  • 游戏 AI、Agent 分支、机器人任务流等通用决策场景
  • Wasm-GC 和 JS 目标构建测试

#暂不支持范围

  • 不直接绑定具体游戏引擎
  • 不内置图形渲染、物理引擎或导航网格
  • 不提供多线程任务调度
  • 不执行外部脚本或不可信代码
  • 不承诺兼容某个第三方行为树编辑器格式

#测试与验收命令

moon fmt --check moon check moon build moon test moon check --deny-warn moon test --deny-warn moon check --target js moon build --target js moon test --target js moon run cmd/main moon run examples/basic moon run examples/export moon info moon package --list

以上命令覆盖格式、检查、构建、测试、JS 目标、示例运行、公开接口和包结构检查。

#文档

#开源许可证

本项目采用 Apache-2.0 许可证。项目为原创 MoonBit 开源库,不移植或复制第三方代码;行为树概念来自公开的通用技术,测试数据和示例场景均为项目自有内容。

#
AgentRecipeOptions

pub(all) struct AgentRecipeOptions {
needs_current_info : Bool
tool_allowed : Bool
ambiguity : Int
} derive(Eq,
Debug
)

#
AssertionReport

pub(all) struct AssertionReport {
name : String
assertions : Array[BtAssertion]
} derive(Eq,
Debug
)

#
AssertionReport::add

fn AssertionReport::add(self : AssertionReport, assertion : BtAssertion) -> Unit

#
AssertionReport::failed_count

fn AssertionReport::failed_count(self : AssertionReport) -> Int

#
AssertionReport::lines

fn AssertionReport::lines(self : AssertionReport) -> Array[String]

#
AssertionReport::ok

fn AssertionReport::ok(self : AssertionReport) -> Bool

#
AssertionReport::summary

fn AssertionReport::summary(self : AssertionReport) -> String

#
AssetCatalogReport

pub(all) struct AssetCatalogReport {
name : String
assets : Array[AssetReport]
duplicate_names : Array[String]
} derive(Eq,
Debug
)

Batch report that keeps valid and invalid assets in one deterministic order.

#
AssetCatalogReport::failed

fn AssetCatalogReport::failed(self : AssetCatalogReport) -> Int

#
AssetCatalogReport::lines

fn AssetCatalogReport::lines(self : AssetCatalogReport) -> Array[String]

#
AssetCatalogReport::markdown

fn AssetCatalogReport::markdown(self : AssetCatalogReport) -> String

#
AssetCatalogReport::ok

fn AssetCatalogReport::ok(self : AssetCatalogReport) -> Bool

#
AssetCatalogReport::passed

fn AssetCatalogReport::passed(self : AssetCatalogReport) -> Int

#
AssetCatalogReport::summary

fn AssetCatalogReport::summary(self : AssetCatalogReport) -> String

#
AssetIdentity

pub(all) struct AssetIdentity {
root : String
node_count : Int
blackboard_entries : Int
canonical_dsl : String
fingerprint : String
} derive(Eq,
Debug
)

Stable, reviewable identity for one validated behavior tree asset.

#
AssetIdentity::markdown

fn AssetIdentity::markdown(self : AssetIdentity) -> String

#
AssetIdentity::summary

fn AssetIdentity::summary(self : AssetIdentity) -> String

#
AssetReport

pub(all) struct AssetReport {
name : String
parsed : Bool
lint_ok : Bool
run_ok : Bool
expected_status : BtStatus
actual_status : BtStatus
node_count : Int
blackboard_entries : Int
digest : String
coverage : Int
canonical_dsl : String
issues : Array[String]
} derive(Eq,
Debug
)

Compile and execution evidence for one catalog asset.

#
AssetReport::lines

fn AssetReport::lines(self : AssetReport) -> Array[String]

#
AssetReport::ok

fn AssetReport::ok(self : AssetReport) -> Bool

#
AssetReport::summary

fn AssetReport::summary(self : AssetReport) -> String

#
AssetSpec

pub(all) struct AssetSpec {
name : String
source : String
expected_status : BtStatus
max_ticks : Int
} derive(Eq,
Debug
)

One named behavior tree asset and its acceptance expectation.

#
AuditReport

pub(all) struct AuditReport {
name : String
run : RunSummary
coverage : TraceCoverage
profile : ProfileReport
lint : LintReport
visual_assets : Int
} derive(Eq,
Debug
)

A compact audit report for one behavior tree run.

#
AuditReport::markdown

fn AuditReport::markdown(self : AuditReport) -> String

#
AuditReport::ok

fn AuditReport::ok(self : AuditReport) -> Bool

#
AuditReport::summary

fn AuditReport::summary(self : AuditReport) -> String

#
BaselineReport

pub(all) struct BaselineReport {
name : String
expected_status : BtStatus
actual_status : BtStatus
expected_digest : String
actual_digest : String
expected_ticks : Int
actual_ticks : Int
minimum_coverage : Int
actual_coverage : Int
status_matches : Bool
digest_matches : Bool
ticks_match : Bool
coverage_meets : Bool
} derive(Eq,
Debug
)

Result of checking an asset against a deterministic baseline.

#
BaselineReport::failed_checks

fn BaselineReport::failed_checks(self : BaselineReport) -> Int

#
BaselineReport::lines

fn BaselineReport::lines(self : BaselineReport) -> Array[String]

#
BaselineReport::markdown

fn BaselineReport::markdown(self : BaselineReport) -> String

#
BaselineReport::ok

fn BaselineReport::ok(self : BaselineReport) -> Bool

#
BaselineReport::summary

fn BaselineReport::summary(self : BaselineReport) -> String

#
BehaviorTree

pub(all) struct BehaviorTree {
root : String
nodes : Array[BtNode]
} derive(Eq,
Debug
)

#
BehaviorTree::add

fn BehaviorTree::add(self : BehaviorTree, node : BtNode) -> Result[Unit, BtError]

#
BehaviorTree::has_node

fn BehaviorTree::has_node(self : BehaviorTree, id : String) -> Bool

#
BehaviorTree::ids

fn BehaviorTree::ids(self : BehaviorTree) -> Array[String]

#
BehaviorTree::leaf_count

fn BehaviorTree::leaf_count(self : BehaviorTree) -> Int

#
BehaviorTree::node

fn BehaviorTree::node(self : BehaviorTree, id : String) -> BtNode?

#
BehaviorTree::node_count

fn BehaviorTree::node_count(self : BehaviorTree) -> Int

#
BehaviorTree::validate

#
Blackboard

pub(all) struct Blackboard {
values : Array[(String, BtValue)]
} derive(Eq,
Debug
)

Key-value state shared by all nodes.

#
Blackboard::get

fn Blackboard::get(self : Blackboard, key : String) -> BtValue?

#
Blackboard::get_bool

fn Blackboard::get_bool(self : Blackboard, key : String) -> Bool?

#
Blackboard::get_int

fn Blackboard::get_int(self : Blackboard, key : String) -> Int?

#
Blackboard::get_text

fn Blackboard::get_text(self : Blackboard, key : String) -> String?

#
Blackboard::has

fn Blackboard::has(self : Blackboard, key : String) -> Bool

#
Blackboard::is_empty

fn Blackboard::is_empty(self : Blackboard) -> Bool

#
Blackboard::keys

fn Blackboard::keys(self : Blackboard) -> Array[String]

#
Blackboard::len

fn Blackboard::len(self : Blackboard) -> Int

#
Blackboard::remove

fn Blackboard::remove(self : Blackboard, key : String) -> Bool

#
Blackboard::set

fn Blackboard::set(self : Blackboard, key : String, value : BtValue) -> Unit

#
Blackboard::snapshot

fn Blackboard::snapshot(self : Blackboard) -> Array[(String, BtValue)]

#
Blackboard::to_lines

fn Blackboard::to_lines(self : Blackboard) -> Array[String]

#
BtAssertion

pub(all) struct BtAssertion {
name : String
ok : Bool
detail : String
} derive(Eq,
Debug
)

#
BtAssertion::to_line

fn BtAssertion::to_line(self : BtAssertion) -> String

#
BtEngine

pub(all) struct BtEngine {
tree : BehaviorTree
blackboard : Blackboard
config : TickConfig
tick_count : Int
memory : Array[NodeMemory]
trace : Array[TickEvent]
} derive(Eq,
Debug
)

#
BtEngine::reset

fn BtEngine::reset(self : BtEngine) -> Unit

#
BtEngine::run_until_done

fn BtEngine::run_until_done(self : BtEngine, max_ticks? : Int) -> Result[TickResult, BtError]

#
BtEngine::tick

fn BtEngine::tick(self : BtEngine) -> Result[TickResult, BtError]

#
BtEngine::trace_digest

fn BtEngine::trace_digest(self : BtEngine) -> String

#
BtEngine::trace_lines

fn BtEngine::trace_lines(self : BtEngine) -> Array[String]

#
BtError

pub(all) enum BtError {
DuplicateNode(String)
MissingNode(String)
InvalidTree(String)
ParseError(String)
LimitExceeded(String)
} derive(Eq,
Debug
)

#
BtError::message

fn BtError::message(self : BtError) -> String

#
BtNode

pub(all) struct BtNode {
id : String
name : String
kind : NodeKind
children : Array[String]
} derive(Eq,
Debug
)

#
BtStatus

pub(all) enum BtStatus {
Success
Failure
Running
} derive(Eq,
Debug
)

Result of one behavior tree node tick.

#
BtStatus::is_done

fn BtStatus::is_done(self : BtStatus) -> Bool

#
BtStatus::to_text

fn BtStatus::to_text(self : BtStatus) -> String

#
BtValue

pub(all) enum BtValue {
BoolValue(Bool)
IntValue(Int)
TextValue(String)
EmptyValue
} derive(Eq,
Debug
)

Small value type used by the blackboard and the line-based DSL.

#
BtValue::kind

fn BtValue::kind(self : BtValue) -> String

#
BtValue::to_text

fn BtValue::to_text(self : BtValue) -> String

#
CaseExpectation

pub(all) struct CaseExpectation {
final_status : BtStatus
required_board : Array[(String, BtValue)]
max_ticks : Int
} derive(Eq,
Debug
)

#
CaseReport

pub(all) struct CaseReport {
name : String
parsed : Bool
run : RunSummary
assertions : AssertionReport
} derive(Eq,
Debug
)

#
CaseReport::ok

fn CaseReport::ok(self : CaseReport) -> Bool

#
CaseReport::to_line

fn CaseReport::to_line(self : CaseReport) -> String

#
CaseSpec

pub(all) struct CaseSpec {
name : String
dsl : String
expectation : CaseExpectation
} derive(Eq,
Debug
)

#
CatalogAudit

pub(all) struct CatalogAudit {
reports : Array[AuditReport]
} derive(Eq,
Debug
)

#
CatalogAudit::failed

fn CatalogAudit::failed(self : CatalogAudit) -> Int

#
CatalogAudit::lines

fn CatalogAudit::lines(self : CatalogAudit) -> Array[String]

#
CatalogAudit::passed

fn CatalogAudit::passed(self : CatalogAudit) -> Int

#
CatalogAudit::summary

fn CatalogAudit::summary(self : CatalogAudit) -> String

#
CatalogCoverage

pub(all) struct CatalogCoverage {
fixtures : Int
full_coverage : Int
partial_coverage : Int
lines : Array[String]
} derive(Eq,
Debug
)

#
CatalogCoverage::summary

fn CatalogCoverage::summary(self : CatalogCoverage) -> String

#
CombatRecipeOptions

pub(all) struct CombatRecipeOptions {
enemy_visible : Bool
ammo : Int
stamina : Int
aim_ticks : Int
reload_ticks : Int
} derive(Eq,
Debug
)

#
CompareOp

pub(all) enum CompareOp {
Eq
NotEq
Greater
GreaterEq
Less
LessEq
Exists
Missing
} derive(Eq,
Debug
)

#
CompareOp::to_text

fn CompareOp::to_text(self : CompareOp) -> String

#
CompatibilityLevel

pub(all) enum CompatibilityLevel {
Compatible
ReviewRequired
Breaking
} derive(Eq,
Debug
)

Compatibility result for two versions of a behavior tree asset.

#
CompatibilityLevel::to_text

fn CompatibilityLevel::to_text(self : CompatibilityLevel) -> String

#
DslDocument

pub(all) struct DslDocument {
tree : BehaviorTree
blackboard : Blackboard
warnings : Array[String]
} derive(Eq,
Debug
)

#
DslDocument::summary

fn DslDocument::summary(self : DslDocument) -> String

#
DslOptions

pub(all) struct DslOptions {
allow_comments : Bool
validate_after_parse : Bool
default_root : String
} derive(Eq,
Debug
)

Parser options for the line-based MoonBTKit DSL.

#
FixtureSpec

pub(all) struct FixtureSpec {
name : String
description : String
dsl : String
expected : BtStatus
max_ticks : Int
} derive(Eq,
Debug
)

#
FixtureSpec::summary

fn FixtureSpec::summary(self : FixtureSpec) -> String

#
LintIssue

pub(all) struct LintIssue {
severity : String
node_id : String
message : String
} derive(Eq,
Debug
)

#
LintIssue::to_line

fn LintIssue::to_line(self : LintIssue) -> String

#
LintReport

pub(all) struct LintReport {
ok : Bool
issues : Array[LintIssue]
} derive(Eq,
Debug
)

#
LintReport::lines

fn LintReport::lines(self : LintReport) -> Array[String]

#
LintReport::summary

fn LintReport::summary(self : LintReport) -> String

#
MarkdownReport

pub(all) struct MarkdownReport {
title : String
lines : Array[String]
} derive(Eq,
Debug
)

#
MarkdownReport::text

fn MarkdownReport::text(self : MarkdownReport) -> String

#
MatrixReport

pub(all) struct MatrixReport {
name : String
results : Array[VariantResult]
} derive(Eq,
Debug
)

#
MatrixReport::failed

fn MatrixReport::failed(self : MatrixReport) -> Int

#
MatrixReport::lines

fn MatrixReport::lines(self : MatrixReport) -> Array[String]

#
MatrixReport::ok

fn MatrixReport::ok(self : MatrixReport) -> Bool

#
MatrixReport::passed

fn MatrixReport::passed(self : MatrixReport) -> Int

#
MatrixReport::summary

fn MatrixReport::summary(self : MatrixReport) -> String

#
NodeDelta

pub(all) struct NodeDelta {
id : String
before_kind : String
after_kind : String
kind_changed : Bool
children_changed : Bool
name_changed : Bool
} derive(Eq,
Debug
)

A structural change for one node that exists in both tree versions.

#
NodeDelta::is_breaking

fn NodeDelta::is_breaking(self : NodeDelta) -> Bool

#
NodeDelta::summary

fn NodeDelta::summary(self : NodeDelta) -> String

#
NodeKind

pub(all) enum NodeKind {
Sequence
Selector
ParallelAll
ParallelAny
Inverter
Succeeder
Failer
Repeat(Int)
Retry(Int)
Condition(String, CompareOp, BtValue)
SetValue(String, BtValue)
ActionPlan(String, Array[BtStatus], Array[(String, BtValue)])
Wait(Int)
Emit(String)
} derive(Eq,
Debug
)

Behavior tree node kind.

#
NodeKind::to_text

fn NodeKind::to_text(self : NodeKind) -> String

#
NodeMemory

pub(all) struct NodeMemory {
id : String
cursor : Int
ticks : Int
attempts : Int
last_status : BtStatus
} derive(Eq,
Debug
)

#
NodeProfile

pub(all) struct NodeProfile {
node_id : String
kind : String
total : Int
success : Int
failure : Int
running : Int
first_tick : Int
last_tick : Int
} derive(Eq,
Debug
)

Aggregated execution data for one node.

#
NodeProfile::dominant_status

fn NodeProfile::dominant_status(self : NodeProfile) -> BtStatus

#
NodeProfile::to_line

fn NodeProfile::to_line(self : NodeProfile) -> String

#
ParsedLine

type ParsedLine derive(Eq,
Debug
)

#
ProfileReport

pub(all) struct ProfileReport {
name : String
profiles : Array[NodeProfile]
total_events : Int
total_ticks : Int
} derive(Eq,
Debug
)

#
ProfileReport::hotspot_lines

fn ProfileReport::hotspot_lines(self : ProfileReport, limit : Int) -> Array[String]

#
ProfileReport::hotspots

fn ProfileReport::hotspots(self : ProfileReport, limit : Int) -> Array[NodeProfile]

#
ProfileReport::lines

fn ProfileReport::lines(self : ProfileReport) -> Array[String]

#
ProfileReport::summary

fn ProfileReport::summary(self : ProfileReport) -> String

#
RecipeBundle

pub(all) struct RecipeBundle {
name : String
description : String
tree : BehaviorTree
blackboard : Blackboard
expected : BtStatus
max_ticks : Int
} derive(Eq,
Debug
)

#
RecipeBundle::run

#
RecipeBundle::summary

fn RecipeBundle::summary(self : RecipeBundle) -> String

#
RegressionBaseline

pub(all) struct RegressionBaseline {
name : String
expected_status : BtStatus
expected_digest : String
expected_ticks : Int
minimum_coverage : Int
max_ticks : Int
} derive(Eq,
Debug
)

Deterministic expectations captured from one behavior tree asset run.

#
RegressionBaseline::summary

fn RegressionBaseline::summary(self : RegressionBaseline) -> String

#
RobotRecipeOptions

pub(all) struct RobotRecipeOptions {
battery : Int
package_ready : Bool
charge_threshold : Int
charge_ticks : Int
navigate_ticks : Int
} derive(Eq,
Debug
)

#
RunSummary

pub(all) struct RunSummary {
name : String
final_status : BtStatus
ticks : Int
trace_events : Int
digest : String
ok : Bool
detail : String
} derive(Eq,
Debug
)

#
RunSummary::to_line

fn RunSummary::to_line(self : RunSummary) -> String

#
TickConfig

pub(all) struct TickConfig {
max_ticks : Int
max_trace_events : Int
record_trace : Bool
} derive(Eq,
Debug
)

#
TickEvent

pub(all) struct TickEvent {
tick : Int
node_id : String
node_name : String
kind : String
status : BtStatus
detail : String
} derive(Eq,
Debug
)

#
TickEvent::to_line

fn TickEvent::to_line(self : TickEvent) -> String

#
TickResult

pub(all) struct TickResult {
tick : Int
status : BtStatus
events : Array[TickEvent]
blackboard : Array[(String, BtValue)]
} derive(Eq,
Debug
)

#
TickResult::summary

fn TickResult::summary(self : TickResult) -> String

#
TimelineFrame

pub(all) struct TimelineFrame {
tick : Int
events : Array[TickEvent]
} derive(Eq,
Debug
)

#
TimelineFrame::lines

fn TimelineFrame::lines(self : TimelineFrame) -> Array[String]

#
TimelineFrame::summary

fn TimelineFrame::summary(self : TimelineFrame) -> String

#
TraceCoverage

pub(all) struct TraceCoverage {
total_nodes : Int
visited_nodes : Array[String]
missed_nodes : Array[String]
success_nodes : Array[String]
failure_nodes : Array[String]
running_nodes : Array[String]
} derive(Eq,
Debug
)

Coverage report for one behavior tree execution trace.

#
TraceCoverage::is_full

fn TraceCoverage::is_full(self : TraceCoverage) -> Bool

#
TraceCoverage::lines

fn TraceCoverage::lines(self : TraceCoverage) -> Array[String]

#
TraceCoverage::missed_count

fn TraceCoverage::missed_count(self : TraceCoverage) -> Int

#
TraceCoverage::percent

fn TraceCoverage::percent(self : TraceCoverage) -> Int

#
TraceCoverage::summary

fn TraceCoverage::summary(self : TraceCoverage) -> String

#
TraceCoverage::visited_count

fn TraceCoverage::visited_count(self : TraceCoverage) -> Int

#
TraceSummary

pub(all) struct TraceSummary {
total : Int
success : Int
failure : Int
running : Int
unique_nodes : Int
} derive(Eq,
Debug
)

#
TraceSummary::to_line

fn TraceSummary::to_line(self : TraceSummary) -> String

#
TreeBuilder

pub(all) struct TreeBuilder {
root : String
nodes : Array[BtNode]
notes : Array[String]
} derive(Eq,
Debug
)

Programmatic builder for users who prefer typed MoonBit code over DSL text.

#
TreeBuilder::action

fn TreeBuilder::action(self : TreeBuilder, id : String, name : String, statuses : Array[BtStatus], writes? : Array[(String, BtValue)]) -> Result[TreeBuilder, BtError]

#
TreeBuilder::add_node

fn TreeBuilder::add_node(self : TreeBuilder, n : BtNode) -> Result[TreeBuilder, BtError]

#
TreeBuilder::condition

fn TreeBuilder::condition(self : TreeBuilder, id : String, key : String, op : CompareOp, expected : BtValue) -> Result[TreeBuilder, BtError]

#
TreeBuilder::decorator

fn TreeBuilder::decorator(self : TreeBuilder, id : String, kind : NodeKind, child : String) -> Result[TreeBuilder, BtError]

#
TreeBuilder::emit

fn TreeBuilder::emit(self : TreeBuilder, id : String, label : String) -> Result[TreeBuilder, BtError]

#
TreeBuilder::finish

fn TreeBuilder::finish(self : TreeBuilder) -> Result[BehaviorTree, BtError]

#
TreeBuilder::has_node

fn TreeBuilder::has_node(self : TreeBuilder, id : String) -> Bool

#
TreeBuilder::node_count

fn TreeBuilder::node_count(self : TreeBuilder) -> Int

#
TreeBuilder::note

fn TreeBuilder::note(self : TreeBuilder, text : String) -> TreeBuilder

#
TreeBuilder::note_lines

fn TreeBuilder::note_lines(self : TreeBuilder) -> Array[String]

#
TreeBuilder::parallel_all

fn TreeBuilder::parallel_all(self : TreeBuilder, id : String, children : Array[String]) -> Result[TreeBuilder, BtError]

#
TreeBuilder::parallel_any

fn TreeBuilder::parallel_any(self : TreeBuilder, id : String, children : Array[String]) -> Result[TreeBuilder, BtError]

#
TreeBuilder::selector

fn TreeBuilder::selector(self : TreeBuilder, id : String, children : Array[String]) -> Result[TreeBuilder, BtError]

#
TreeBuilder::sequence

fn TreeBuilder::sequence(self : TreeBuilder, id : String, children : Array[String]) -> Result[TreeBuilder, BtError]

#
TreeBuilder::set

fn TreeBuilder::set(self : TreeBuilder, id : String, key : String, value : BtValue) -> Result[TreeBuilder, BtError]

#
TreeBuilder::wait

fn TreeBuilder::wait(self : TreeBuilder, id : String, ticks : Int) -> Result[TreeBuilder, BtError]

#
TreeDiff

pub(all) struct TreeDiff {
before_root : String
after_root : String
added_nodes : Array[String]
removed_nodes : Array[String]
changed_nodes : Array[NodeDelta]
} derive(Eq,
Debug
)

Structural difference between two behavior tree assets.

#
TreeDiff::change_count

fn TreeDiff::change_count(self : TreeDiff) -> Int

#
TreeDiff::compatibility

fn TreeDiff::compatibility(self : TreeDiff) -> CompatibilityLevel

#
TreeDiff::is_empty

fn TreeDiff::is_empty(self : TreeDiff) -> Bool

#
TreeDiff::lines

fn TreeDiff::lines(self : TreeDiff) -> Array[String]

#
TreeDiff::markdown

fn TreeDiff::markdown(self : TreeDiff, title? : String) -> String

#
TreeDiff::root_changed

fn TreeDiff::root_changed(self : TreeDiff) -> Bool

#
TreeDiff::summary

fn TreeDiff::summary(self : TreeDiff) -> String

#
TreeStats

pub(all) struct TreeStats {
nodes : Int
leaves : Int
composites : Int
decorators : Int
conditions : Int
actions : Int
waits : Int
max_children : Int
max_depth : Int
} derive(Eq,
Debug
)

#
TreeStats::to_line

fn TreeStats::to_line(self : TreeStats) -> String

#
ValidationReport

pub(all) struct ValidationReport {
ok : Bool
issues : Array[String]
} derive(Eq,
Debug
)

#
ValidationReport::message

fn ValidationReport::message(self : ValidationReport) -> String

#
VariantResult

pub(all) struct VariantResult {
name : String
status : BtStatus
expected : BtStatus
ticks : Int
digest : String
ok : Bool
detail : String
} derive(Eq,
Debug
)

#
VariantResult::to_line

fn VariantResult::to_line(self : VariantResult) -> String

#
VariantSpec

pub(all) struct VariantSpec {
name : String
overrides : Array[(String, BtValue)]
expected : BtStatus
max_ticks : Int
} derive(Eq,
Debug
)

#
VisualOptions

pub(all) struct VisualOptions {
include_node_names : Bool
include_node_kinds : Bool
show_leaf_shape : Bool
} derive(Eq,
Debug
)

Options for rendering behavior trees into graph descriptions.

#
action_failure

fn action_failure(id : String, name? : String) -> BtNode

#
action_running_then

fn action_running_then(id : String, name : String, running_ticks : Int, final_status : BtStatus, writes? : Array[(String, BtValue)]) -> BtNode

#
action_success

fn action_success(id : String, name? : String, writes? : Array[(String, BtValue)]) -> BtNode

#
agent_recipe

fn agent_recipe(options? : AgentRecipeOptions) -> Result[RecipeBundle, BtError]

#
agent_tool_dsl

fn agent_tool_dsl() -> String

#
agent_tool_fixture

fn agent_tool_fixture() -> FixtureSpec

#
all_cases_ok

fn all_cases_ok(reports : Array[CaseReport]) -> Bool

#
analyze_tree

fn analyze_tree(tree : BehaviorTree) -> TreeStats

#
append_status

fn append_status(base : Array[BtStatus], tail : BtStatus) -> Array[BtStatus]

#
apply_overrides

fn apply_overrides(source : String, overrides : Array[(String, BtValue)]) -> String

#
assert_board_value

fn assert_board_value(board : Array[(String, BtValue)], key : String, value : BtValue) -> BtAssertion

#
assert_has_node

fn assert_has_node(tree : BehaviorTree, id : String) -> BtAssertion

#
assert_lint_ok

fn assert_lint_ok(tree : BehaviorTree) -> BtAssertion

#
assert_node_count

fn assert_node_count(tree : BehaviorTree, expected : Int) -> BtAssertion

#
assert_status

fn assert_status(actual : BtStatus, expected : BtStatus) -> BtAssertion

#
assert_trace_has

fn assert_trace_has(events : Array[TickEvent], node_id : String, status : BtStatus) -> BtAssertion

#
assert_tree_valid

fn assert_tree_valid(tree : BehaviorTree) -> BtAssertion

#
assert_true

fn assert_true(name : String, condition : Bool, detail : String) -> BtAssertion

#
asset_fingerprint

fn asset_fingerprint(source : String) -> Result[String, BtError]

Produce a deterministic, non-cryptographic fingerprint for cache keys, version comparisons, and regression asset identity.

#
asset_spec

fn asset_spec(name : String, source : String, expected_status? : BtStatus, max_ticks? : Int) -> AssetSpec

#
audit_asset

fn audit_asset(spec : AssetSpec) -> AssetReport

Compile, lint, execute, and measure one behavior tree asset.

#
audit_asset_catalog

fn audit_asset_catalog(name : String, specs : Array[AssetSpec]) -> AssetCatalogReport

Audit every catalog entry without stopping after an invalid asset.

#
audit_catalog_markdown

fn audit_catalog_markdown() -> String

#
audit_fixture

fn audit_fixture(name : String) -> Result[AuditReport, BtError]

#
audit_fixture_assets

fn audit_fixture_assets() -> AssetCatalogReport

#
audit_fixture_catalog

fn audit_fixture_catalog() -> CatalogAudit

#
blackboard_from_pairs

fn blackboard_from_pairs(pairs : Array[(String, BtValue)]) -> Blackboard

#
board_contains

fn board_contains(board : Array[(String, BtValue)], key : String, value : BtValue) -> Bool

#
bool_value

fn bool_value(value : Bool) -> BtValue

#
boolean_matrix

fn boolean_matrix(name : String, source : String, key : String, true_expected : BtStatus, false_expected : BtStatus, max_ticks? : Int) -> MatrixReport

#
boolean_variants

fn boolean_variants(base_name : String, source : String, key : String, expected_true : BtStatus, expected_false : BtStatus, max_ticks : Int) -> Array[CaseSpec]

#
boss_phase_dsl

fn boss_phase_dsl() -> String

#
boss_phase_fixture

fn boss_phase_fixture() -> FixtureSpec

#
canonicalize_dsl

fn canonicalize_dsl(source : String) -> Result[String, BtError]

Normalize comments, whitespace, blackboard order, and declaration order. Child order remains unchanged because it affects behavior tree semantics.

#
capture_baseline

fn capture_baseline(name : String, source : String, max_ticks? : Int) -> Result[RegressionBaseline, BtError]

Capture a baseline from a successful deterministic DSL execution.

#
case_from_fixture

fn case_from_fixture(spec : FixtureSpec) -> CaseSpec

#
case_report_lines

fn case_report_lines(reports : Array[CaseReport]) -> Array[String]

#
combat_recipe

fn combat_recipe(options? : CombatRecipeOptions) -> Result[RecipeBundle, BtError]

#
combine_assertion_reports

fn combine_assertion_reports(name : String, reports : Array[AssertionReport]) -> AssertionReport

#
compact_trace

fn compact_trace(events : Array[TickEvent]) -> Array[String]

#
compact_visual_options

fn compact_visual_options() -> VisualOptions

#
compare_values

fn compare_values(actual : BtValue?, op : CompareOp, expected : BtValue) -> Bool

#
condition

fn condition(id : String, key : String, op : CompareOp, expected : BtValue) -> BtNode

#
count_status

fn count_status(events : Array[TickEvent], status : BtStatus) -> Int

#
coverage_from_trace

fn coverage_from_trace(tree : BehaviorTree, events : Array[TickEvent]) -> TraceCoverage

#
coverage_markdown

fn coverage_markdown(name : String, coverage : TraceCoverage) -> String

#
default_agent_options

fn default_agent_options() -> AgentRecipeOptions

#
default_combat_options

fn default_combat_options() -> CombatRecipeOptions

#
default_dsl_options

fn default_dsl_options() -> DslOptions

#
default_robot_options

fn default_robot_options() -> RobotRecipeOptions

#
default_tick_config

fn default_tick_config() -> TickConfig

#
default_visual_options

fn default_visual_options() -> VisualOptions

#
diff_dsl

fn diff_dsl(before_source : String, after_source : String) -> Result[TreeDiff, BtError]

Parse and compare two DSL assets. Invalid assets return their parse error.

#
diff_trees

fn diff_trees(before : BehaviorTree, after : BehaviorTree) -> TreeDiff

Compare two validated behavior tree models by stable node identifiers.

#
empty_value

fn empty_value() -> BtValue

#
explain_trace

fn explain_trace(events : Array[TickEvent]) -> Array[String]

#
filter_trace_by_node

fn filter_trace_by_node(events : Array[TickEvent], node_id : String) -> Array[TickEvent]

#
filter_trace_by_status

fn filter_trace_by_status(events : Array[TickEvent], status : BtStatus) -> Array[TickEvent]

#
find_fixture

fn find_fixture(name : String) -> FixtureSpec?

#
fixture_asset_specs

fn fixture_asset_specs() -> Array[AssetSpec]

#
fixture_cases

fn fixture_cases() -> Array[CaseSpec]

#
fixture_catalog

fn fixture_catalog() -> Array[FixtureSpec]

#
fixture_catalog_coverage

fn fixture_catalog_coverage() -> CatalogCoverage

#
fixture_coverage

fn fixture_coverage(name : String) -> Result[TraceCoverage, BtError]

#
fixture_matrix_report

fn fixture_matrix_report() -> MatrixReport

#
fixture_names

fn fixture_names() -> Array[String]

#
fixture_profile_report

fn fixture_profile_report() -> Array[String]

#
fixture_report_lines

fn fixture_report_lines() -> Array[String]

#
guarded_attack_dsl

fn guarded_attack_dsl() -> String

#
guarded_attack_fixture

fn guarded_attack_fixture() -> FixtureSpec

#
harvest_worker_dsl

fn harvest_worker_dsl() -> String

#
harvest_worker_fixture

fn harvest_worker_fixture() -> FixtureSpec

#
inspect_asset

fn inspect_asset(source : String) -> Result[AssetIdentity, BtError]

#
int_sweep_matrix

fn int_sweep_matrix(name : String, source : String, key : String, values : Array[Int], expected : BtStatus, max_ticks? : Int) -> MatrixReport

#
int_value

fn int_value(value : Int) -> BtValue

#
last_event_for_node

fn last_event_for_node(events : Array[TickEvent], node_id : String) -> TickEvent?

#
lint_tree

fn lint_tree(tree : BehaviorTree) -> LintReport

#
load_fixture

fn load_fixture(name : String) -> Result[DslDocument, BtError]

#
matrix_markdown

fn matrix_markdown(report : MatrixReport) -> String

#
mission_selector_dsl

fn mission_selector_dsl() -> String

#
mission_selector_fixture

fn mission_selector_fixture() -> FixtureSpec

#
new_assertion_report

fn new_assertion_report(name : String) -> AssertionReport

#
new_blackboard

fn new_blackboard() -> Blackboard

#
new_builder

fn new_builder(root : String) -> TreeBuilder

#
new_engine

fn new_engine(tree : BehaviorTree, blackboard? : Blackboard, config? : TickConfig) -> BtEngine

#
new_tree

fn new_tree(root : String) -> BehaviorTree

#
node

fn node(id : String, kind : NodeKind, children? : Array[String], name? : String) -> BtNode

#
parse_blackboard_dsl

fn parse_blackboard_dsl(source : String) -> Result[Blackboard, BtError]

#
parse_compare_op

fn parse_compare_op(raw : String) -> CompareOp?

#
parse_dsl

fn parse_dsl(source : String, options? : DslOptions) -> Result[DslDocument, BtError]

Parse a behavior tree and initial blackboard from a compact line DSL.

Supported examples:

  • root root
  • selector root engage patrol
  • condition see_enemy enemy_visible eq true
  • action chase chase_enemy running,success mode=chasing
  • blackboard ammo 3

#
parse_tree_dsl

fn parse_tree_dsl(source : String) -> Result[BehaviorTree, BtError]

#
parse_value

fn parse_value(raw : String) -> BtValue

#
patrol_dsl

fn patrol_dsl() -> String

#
patrol_fixture

fn patrol_fixture() -> FixtureSpec

#
profile_fixture

fn profile_fixture(name : String) -> Result[ProfileReport, BtError]

#
profile_markdown

fn profile_markdown(report : ProfileReport, hotspot_limit? : Int) -> String

#
profile_trace

fn profile_trace(name : String, events : Array[TickEvent]) -> ProfileReport

#
qa_agent_dsl

fn qa_agent_dsl() -> String

#
qa_agent_fixture

fn qa_agent_fixture() -> FixtureSpec

#
recipe_cases

fn recipe_cases() -> Array[CaseSpec]

#
recipe_catalog

fn recipe_catalog() -> Array[RecipeBundle]

#
recipe_report_lines

fn recipe_report_lines() -> Array[String]

#
recipe_to_case

fn recipe_to_case(bundle : RecipeBundle) -> CaseSpec

#
regression_baseline

fn regression_baseline(name : String, expected_status : BtStatus, expected_digest : String, expected_ticks : Int, minimum_coverage : Int, max_ticks? : Int) -> RegressionBaseline

#
repeat_status

fn repeat_status(status : BtStatus, count : Int) -> Array[BtStatus]

#
replace_blackboard_line

fn replace_blackboard_line(source : String, key : String, value : BtValue) -> String

#
robot_delivery_dsl

fn robot_delivery_dsl() -> String

#
robot_delivery_fixture

fn robot_delivery_fixture() -> FixtureSpec

#
robot_recipe

fn robot_recipe(options? : RobotRecipeOptions) -> Result[RecipeBundle, BtError]

#
run_case

fn run_case(spec : CaseSpec) -> CaseReport

#
run_cases

fn run_cases(cases : Array[CaseSpec]) -> Array[CaseReport]

#
run_fixture

fn run_fixture(name : String) -> RunSummary

#
run_fixture_catalog

fn run_fixture_catalog() -> Array[RunSummary]

#
run_matrix

fn run_matrix(name : String, base_dsl : String, variants : Array[VariantSpec]) -> MatrixReport

#
run_recipe_catalog

fn run_recipe_catalog() -> Array[RunSummary]

#
run_variant_dsl

fn run_variant_dsl(base_dsl : String, spec : VariantSpec) -> VariantResult

#
running_then_failure

fn running_then_failure(running_ticks : Int) -> Array[BtStatus]

#
running_then_success

fn running_then_success(running_ticks : Int) -> Array[BtStatus]

#
selector

fn selector(id : String, children : Array[String]) -> BtNode

#
sequence

fn sequence(id : String, children : Array[String]) -> BtNode

#
serialize_blackboard

fn serialize_blackboard(board : Blackboard) -> Array[String]

#
serialize_tree

fn serialize_tree(tree : BehaviorTree) -> Array[String]

#
set_value

fn set_value(id : String, key : String, value : BtValue) -> BtNode

#
smoke_run

fn smoke_run(name : String, tree : BehaviorTree, board : Blackboard, expected : BtStatus, max_ticks? : Int) -> RunSummary

#
stealth_guard_dsl

fn stealth_guard_dsl() -> String

#
stealth_guard_fixture

fn stealth_guard_fixture() -> FixtureSpec

#
strict_tick_config

fn strict_tick_config() -> TickConfig

#
summarize_trace

fn summarize_trace(events : Array[TickEvent]) -> TraceSummary

#
text_value

fn text_value(value : String) -> BtValue

#
timeline_from_trace

fn timeline_from_trace(events : Array[TickEvent]) -> Array[TimelineFrame]

#
timeline_text

fn timeline_text(events : Array[TickEvent]) -> String

#
trace_contains

fn trace_contains(events : Array[TickEvent], node_id : String, status : BtStatus) -> Bool

#
trace_to_mermaid_sequence

fn trace_to_mermaid_sequence(events : Array[TickEvent]) -> String

Render trace events as a Mermaid sequence diagram.

#
tree_from_nodes

fn tree_from_nodes(root : String, nodes : Array[BtNode]) -> BehaviorTree

#
tree_markdown_report

fn tree_markdown_report(title : String, tree : BehaviorTree, board : Blackboard) -> MarkdownReport

#
tree_to_dot

fn tree_to_dot(tree : BehaviorTree, options? : VisualOptions) -> String

Export a behavior tree to Graphviz DOT.

#
tree_to_mermaid

fn tree_to_mermaid(tree : BehaviorTree, options? : VisualOptions) -> String

Export a behavior tree to Mermaid flowchart syntax.

#
tutorial_hint_dsl

fn tutorial_hint_dsl() -> String

#
tutorial_hint_fixture

fn tutorial_hint_fixture() -> FixtureSpec

#
variant

fn variant(name : String, overrides : Array[(String, BtValue)], expected? : BtStatus, max_ticks? : Int) -> VariantSpec

#
verify_baseline

fn verify_baseline(source : String, baseline : RegressionBaseline) -> Result[BaselineReport, BtError]

Verify a DSL asset against status, digest, tick, and coverage expectations.

#
visualization_bundle

fn visualization_bundle(tree : BehaviorTree, events : Array[TickEvent]) -> Array[(String, String)]

Return a short visualization bundle suitable for docs and issue comments.

#
wait

fn wait(id : String, ticks : Int) -> BtNode