workgraph-core

Runtime-independent asynchronous graph compiler and runtime

agent
graph
runtime
moonbit
moon add totto2727/workgraph-core@0.1.3
Download zip
Author
Version
0.1.3
License
MIT
Last updated
5 days ago
Downloads
16
README

#Workgraph

Workgraph is a family of MoonBit modules for asynchronous typed graphs, LLM nodes, coding agents, CLI integrations, and visualization.

#Modules

ModuleResponsibilityPreferred targetSupported targets
totto2727/workgraph-coreGraph definitions, compiled graphs, sequential runtime, state reducers, events, and in-memory ResourceStorewasmjs, native, wasm
totto2727/workgraph-agent-cliCoding-agent node and session resource lifecyclewasmjs, native, wasm
totto2727/workgraph-llmProvider-neutral mizchi/llm@0.3.1 node boundaryjsjs, native
totto2727/workgraph-visualizationMermaid rendering from compiled graph snapshotswasmjs, native, wasm
totto2727/workgraph-codex-cliCodex CLI adapternativenative
totto2727/workgraph-opencode-cliOpenCode CLI adapternativenative

Production dependency direction is acyclic:

flowchart LR Core["workgraph-core"] Coding["workgraph-agent-cli"] --> Core LLM["workgraph-llm"] --> Core Visualization["workgraph-visualization"] --> Core Codex["workgraph-codex-cli"] --> Core Codex --> Coding OpenCode["workgraph-opencode-cli"] --> Core OpenCode --> Coding

Each module owns its unit and integration tests. The previous shared testing, aggregate test, and e2e packages are not part of the split module family.

#Examples

Run commands from the repository root.

moon run package/workgraph-core/src/examples/basic moon run package/workgraph-llm/src/examples/basic moon run package/workgraph-visualization/src/examples/basic moon run package/workgraph-codex-cli/src/examples/basic moon run package/workgraph-opencode-cli/src/examples/basic

The LLM example uses mizchi/llm.MockProvider and requires no credentials. The Codex and OpenCode examples use the corresponding installed CLI and local authentication. workgraph-agent-cli has no standalone example because the two CLI examples demonstrate its concrete use.

#Development

moon check moon test

#
GraphBuildError

pub suberror GraphBuildError {
DuplicateNode(NodeId)
DuplicateRouter(NodeId)
InvalidId(String)
} derive(
Debug
)

#
GraphRuntimeError

pub suberror GraphRuntimeError {
NodeTimedOut(node_id~ : NodeId, step~ : Int, timeout_ms~ : Int)
NodeFailed(node_id~ : NodeId, step~ : Int, cause~ : Error)
ReduceFailed(node_id~ : NodeId, step~ : Int, cause~ : Error)
RouteFailed(node_id~ : NodeId, step~ : Int, cause~ : Error)
RouteContractViolated(from~ : NodeId, to~ : NodeId)
StepLimitExceeded(limit~ : Int)
ExplicitFailure(node_id~ : NodeId, message~ : String)
ResourceCleanupFailed(failure~ : RunFailure)
NodeNotFound(NodeId)
RouterNotFound(NodeId)
} derive(
Debug
)

#
GraphValidationError

pub suberror GraphValidationError {
MissingEntry
UnknownEntry(NodeId)
MissingRouter(NodeId)
UnknownRouterSource(NodeId)
UnknownDestination(from~ : NodeId, to~ : NodeId)
UnreachableNode(NodeId)
} derive(
Debug
)

#
IdError

pub suberror IdError {
EmptyId(kind~ : String)
} derive(
Debug
)

#
ResourceStoreError

pub suberror ResourceStoreError {
NodeOwnerRequired(ResourceKey)
InvalidCleanupTimeout(Int)
CleanupTimedOut(Int)
CloseFailed(errors~ : ReadOnlyArray[Error])
} derive(
Debug
)

#
RunConfigurationError

pub suberror RunConfigurationError {
MaxStepsMustBePositive(Int)
NodeTimeoutMustBePositive(Int)
CleanupTimeoutMustBePositive(Int)
} derive(
Debug
)

#
CompiledGraph

pub struct CompiledGraph[S, P] {
reducer : Reducer[S, P]
nodes :
HashMap
[NodeId, Node[S, P]]
routers :
HashMap
[NodeId, Router[S]]
entry : NodeId
}

#
CompiledGraph::entry

fn[S, P] CompiledGraph::entry(self : CompiledGraph[S, P]) -> NodeId

#
CompiledGraph::get_node

fn[S, P] CompiledGraph::get_node(self : CompiledGraph[S, P], id : NodeId) -> Node[S, P] raise GraphRuntimeError

#
CompiledGraph::get_router

fn[S, P] CompiledGraph::get_router(self : CompiledGraph[S, P], id : NodeId) -> Router[S] raise GraphRuntimeError

#
CompiledGraph::snapshot

fn[S, P] CompiledGraph::snapshot(self : CompiledGraph[S, P]) -> CompiledGraphSnapshot

Returns a deterministic, callback-free snapshot for inspection and tooling.

#
CompiledGraphSnapshot

pub struct CompiledGraphSnapshot {
entry : NodeId
nodes : ReadOnlyArray[CompiledNodeSnapshot]
} derive(
Debug
)

Contains the callback-free static structure of a compiled graph.

#
CompiledNodeSnapshot

pub struct CompiledNodeSnapshot {
id : NodeId
metadata : NodeMetadata
router_metadata : RouterMetadata
declared_routes : ReadOnlyArray[DeclaredRoute]
} derive(
Debug
)

Describes one node in a compiled graph without exposing its callbacks.

#
DeclaredRoute

pub struct DeclaredRoute {
target : NodeId
metadata : DeclaredRouteMetadata
} derive(
Debug
)

Declares one possible runtime destination and its optional metadata.

#
DeclaredRoute::DeclaredRoute

fn DeclaredRoute::DeclaredRoute(target : NodeId, metadata? : DeclaredRouteMetadata) -> DeclaredRoute

Declares a possible runtime destination.

#
DeclaredRouteMetadata

pub struct DeclaredRouteMetadata {
label : String?
} derive(
Debug
)

Contains optional display metadata for one statically declared route.

#
DeclaredRouteMetadata::DeclaredRouteMetadata

fn DeclaredRouteMetadata::DeclaredRouteMetadata(label? : String) -> DeclaredRouteMetadata

Creates display metadata for a statically declared route.

#
EventSink

pub struct EventSink {
emit : (GraphEvent) -> Unit raise
}

#
EventSink::EventSink

fn EventSink::EventSink(emit : (GraphEvent) -> Unit raise) -> EventSink

#
EventSink::discard

fn EventSink::discard() -> EventSink

#
EventSink::try_emit

fn EventSink::try_emit(self : EventSink, event : GraphEvent) -> Unit

#
GraphDefinition

pub struct GraphDefinition[S, P] {
reducer : Reducer[S, P]
nodes : Map[NodeId, Node[S, P]]
routers : Map[NodeId, Router[S]]
entry : NodeId?
}

#
GraphDefinition::GraphDefinition

fn[S, P] GraphDefinition::GraphDefinition(reducer : Reducer[S, P]) -> GraphDefinition[S, P]

#
GraphDefinition::add_node

fn[S, P] GraphDefinition::add_node(self : GraphDefinition[S, P], node : Node[S, P]) -> Unit raise GraphBuildError

#
GraphDefinition::compile

fn[S, P] GraphDefinition::compile(self : GraphDefinition[S, P]) -> CompiledGraph[S, P] raise GraphValidationError

#
GraphDefinition::set_entry

fn[S, P] GraphDefinition::set_entry(self : GraphDefinition[S, P], entry : NodeId) -> Unit raise GraphBuildError

#
GraphDefinition::set_router

fn[S, P] GraphDefinition::set_router(self : GraphDefinition[S, P], from : NodeId, value : Router[S]) -> Unit raise GraphBuildError

#
GraphEvent

pub enum GraphEvent {
RunStarted(RunId)
RunCompleted(run_id~ : RunId, steps~ : Int)
RunFailed(run_id~ : RunId, cause~ : Error)
RunCancelled(RunId)
NodeStarted(run_id~ : RunId, node_id~ : NodeId, step~ : Int)
NodeCompleted(run_id~ : RunId, node_id~ : NodeId, step~ : Int, completion~ : NodeCompletion)
NodeFailed(run_id~ : RunId, node_id~ : NodeId, step~ : Int, cause~ : Error)
StateUpdated(run_id~ : RunId, node_id~ : NodeId, step~ : Int)
RouteSelected(run_id~ : RunId, from~ : NodeId, route~ : Route)
ResourceOpening(run_id~ : RunId, key~ : ResourceKey)
ResourceOpened(run_id~ : RunId, key~ : ResourceKey)
ResourceClosed(run_id~ : RunId, key~ : ResourceKey)
} derive(
Debug
)

#
GraphRuntime

pub struct GraphRuntime[S, P] {
graph : CompiledGraph[S, P]
events : EventSink
ids :
Rand

}

#
GraphRuntime::GraphRuntime

fn[S, P] GraphRuntime::GraphRuntime(graph : CompiledGraph[S, P], events? : EventSink) -> GraphRuntime[S, P]

#
GraphRuntime::fresh_run_id

fn[S, P] GraphRuntime::fresh_run_id(self : GraphRuntime[S, P]) -> RunId

#
GraphRuntime::invoke

async fn[S, P] GraphRuntime::invoke(self : GraphRuntime[S, P], initial_state : S, options? : RunOptions) -> RunResult[S]

#
Node

pub struct Node[S, P] {
id : NodeId
metadata : NodeMetadata
execute : async (NodeContext, S) -> NodeOutput[P]
}

#
Node::Node

fn[S, P] Node::Node(id : NodeId, metadata : NodeMetadata, execute : async (NodeContext, S) -> NodeOutput[P]) -> Node[S, P]

#
NodeCompletion

pub struct NodeCompletion {
node_id : NodeId
value : Json?
} derive(
Debug
)

#
NodeCompletion::NodeCompletion

fn NodeCompletion::NodeCompletion(node_id : NodeId, value : Json?) -> NodeCompletion

Creates the completion value passed to a router.

#
NodeContext

pub struct NodeContext {
run_id : RunId
node_id : NodeId
step : Int
deadline_ms : Int64?
task_group :
TaskGroup
[Unit]
events : EventSink
resources : ResourceStore
}

#
NodeContext::NodeContext

fn NodeContext::NodeContext(run_id : RunId, node_id : NodeId, step : Int, task_group :
TaskGroup
[Unit], events? : EventSink, resources? : ResourceStore, deadline_ms? : Int64) -> NodeContext

#
NodeId

pub struct NodeId {
value : String
} derive(Eq, Hash)

#
NodeId::NodeId

fn NodeId::NodeId(value : String) -> NodeId raise IdError

#
NodeId::to_string

fn NodeId::to_string(self : NodeId) -> String

#
NodeKind

pub(all) enum NodeKind {
Function
Llm
CodingAgent
Custom(String)
} derive(Eq,
Debug
)

#
NodeMetadata

pub struct NodeMetadata {
name : String
description : String?
kind : NodeKind
tags : ReadOnlyArray[String]
} derive(
Debug
)

#
NodeMetadata::NodeMetadata

fn NodeMetadata::NodeMetadata(name~ : String, description~ : String?, kind~ : NodeKind, tags~ : ReadOnlyArray[String]) -> NodeMetadata

Creates metadata describing a graph node.

#
NodeOutput

pub struct NodeOutput[P] {
patch : P?
value : Json?
} derive(
Debug
)

#
NodeOutput::NodeOutput

fn[P] NodeOutput::NodeOutput(patch : P?, value : Json?) -> NodeOutput[P]

Creates the output produced by a graph node.

#
Reducer

pub struct Reducer[S, P] {
apply : (S, P) -> S raise
}

#
Reducer::Reducer

fn[S, P] Reducer::Reducer(apply : (S, P) -> S raise) -> Reducer[S, P]

Creates a state reducer from its transition function.

#
ResourceKey

pub struct ResourceKey {
value : String
} derive(Eq, Hash)

#
ResourceKey::ResourceKey

fn ResourceKey::ResourceKey(value : String) -> ResourceKey raise IdError

#
ResourceKey::to_string

fn ResourceKey::to_string(self : ResourceKey) -> String

#
ResourceScope

pub(all) enum ResourceScope {
Node
Run
} derive(Eq,
Debug
)

#
ResourceStore

#
ResourceStore::ResourceStore

fn ResourceStore::ResourceStore() -> ResourceStore

#
ResourceStore::acquire_resource

async fn[T] ResourceStore::acquire_resource(self : ResourceStore, reference :
AnyRef
[ResourceKey, T], scope : ResourceScope, open : async () -> T, cleanup : async (T) -> Unit, owner? : NodeId) -> T

Acquires any typed resource and records its cleanup independently of the resource's concrete type.

#
ResourceStore::close_all

async fn ResourceStore::close_all(self : ResourceStore) -> Unit

#
ResourceStore::finalize

async fn ResourceStore::finalize(self : ResourceStore, timeout_ms : Int) -> Unit

#
ResourceStore::get

fn[T] ResourceStore::get(self : ResourceStore, reference :
AnyRef
[ResourceKey, T]) -> T? raise

Returns an invocation-local value through its typed resource reference.

A missing key returns None; reusing a key with a different value type raises the conversion error from AnyRef.

#
ResourceStore::release_node

async fn ResourceStore::release_node(self : ResourceStore, node_id : NodeId) -> Unit

#
ResourceStore::remove

fn[T] ResourceStore::remove(self : ResourceStore, reference :
AnyRef
[ResourceKey, T]) -> Unit

Removes the invocation-local value selected by reference.

#
ResourceStore::set

fn[T] ResourceStore::set(self : ResourceStore, reference :
AnyRef
[ResourceKey, T], value : T) -> Unit

Stores an invocation-local value through a typed resource reference.

#
Route

pub(all) enum Route {
To(NodeId)
End
Fail(String)
} derive(
Debug
)

#
Router

pub struct Router[S] {
metadata : RouterMetadata
declared_routes : ReadOnlyArray[DeclaredRoute]
evaluate : (S, NodeCompletion) -> Route raise
}

#
RouterMetadata

pub struct RouterMetadata {
description : String?
} derive(
Debug
)

Contains optional display metadata for a router.

#
RouterMetadata::RouterMetadata

fn RouterMetadata::RouterMetadata(description? : String) -> RouterMetadata

Creates display metadata for a router.

#
RunFailure

pub struct RunFailure {
primary : Error
cleanup : ReadOnlyArray[Error]
} derive(
Debug
)

#
RunId

pub struct RunId {
value : String
} derive(Eq, Hash)

#
RunId::RunId

fn RunId::RunId(value : String) -> RunId raise IdError

#
RunId::to_string

fn RunId::to_string(self : RunId) -> String

#
RunOptions

pub struct RunOptions {
max_steps : Int
node_timeout_ms : Int?
cleanup_timeout_ms : Int
} derive(
Debug
)

#
RunOptions::RunOptions

fn RunOptions::RunOptions(max_steps? : Int, node_timeout_ms? : Int, cleanup_timeout_ms? : Int) -> RunOptions raise RunConfigurationError

#
RunResult

pub struct RunResult[S] {
run_id : RunId
final_state : S
steps : Int
} derive(
Debug
)

#
StoredResourceCleanup

type StoredResourceCleanup

#
resource_closed_event

fn resource_closed_event(run_id : RunId, key : ResourceKey) -> GraphEvent

Creates the event emitted after a runtime resource is closed.

#
resource_opened_event

fn resource_opened_event(run_id : RunId, key : ResourceKey) -> GraphEvent

Creates the event emitted after a runtime resource is opened.

#
resource_opening_event

fn resource_opening_event(run_id : RunId, key : ResourceKey) -> GraphEvent

Creates the event emitted before a runtime resource is opened.

#
router

fn[S] router(declared_routes : ReadOnlyArray[DeclaredRoute], evaluate : (S, NodeCompletion) -> Route raise, metadata? : RouterMetadata) -> Router[S]

#
run_completed_event

fn run_completed_event(run_id : RunId, steps : Int) -> GraphEvent

Creates the event emitted when a run completes.

#
run_started_event

fn run_started_event(run_id : RunId) -> GraphEvent

Creates the event emitted when a run starts.

Powered by MoonBit

Site sourceReport issuePackagesBuild queueSkillsStatistics

© 2026 mooncakes.io