sixty-nine / neuron-graph
Finite State Machine for AI
Requires
- psr/log: ^1.0|^2.0|^3.0
Requires (Dev)
- monolog/monolog: ^3.9
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^9
This package is not auto-updated.
Last update: 2025-05-16 20:20:49 UTC
README
Table of Contents
- Overview
- Installation
- Key Features
- Components
- Simple Graph Example
- Observability
- Export to Mermaid
- More Examples
- Contribution Guidelines
- License
Overview
Neuron Graph is a Finite State Machine (FSM) inspired by Pydantic Graphs.
It allows you to create "nodes" that perform single tasks and chain them together to achieve more complex workflows.
Key Features
- Modular Design: Build reusable and composable nodes.
- Finite State Machine: Define and execute directed graphs of nodes.
- Observability: Log and monitor graph execution events.
- Integration Ready: Easily integrate with external systems or libraries.
Installation
To install Neuron Graph, use Composer:
composer require sixty-nine/neuron-graph
Components
Graph
The Graph
class defines and executes the Finite State Machine. It manages the nodes and their connections.
Key Points:
- The
run
method takes an instance of the initial node and executes the graph. - Every graph must have at least one node that returns an
EndNode
. - There must be a path from every node to the
EndNode
.
Example:
$graph = new Graph([FirstNode::class, NodeLeadingToEnd::class]);
$result = $graph->run(new FirstNode());
Nodes
A Node is a class that extends the abstract Node
class. It represents a single task in the graph.
Key Points:
- The run method defines the node's behavior.
- It can receive a shared state and static data.
- The run method must return other nodes or the special
EndNode
. - The return type-hints of the run method define the graph's edges.
Example:
class MyNode extends Node
{
public function run($state, $data): MyOtherNode
{
return new MyOtherNode();
}
}
EndNode
The EndNode is a special type of node that marks the end of the graph execution.
Key Points:
- It can hold arbitrary data set by the previous node.
- Every graph must have at least one node that returns an EndNode.
Example:
class FinalNode extends Node
{
public function run($state, $data): EndNode
{
return new EndNode([
'some-data' => 'whatever',
]);
}
}
GraphState
The GraphState
is a mutable key/value store that holds the shared state of the graph during execution.
Key Points:
- The initial state is passed to the
Graph::run
method. - The state is shared across all nodes in the graph.
- Nodes can read and mutate the state as needed.
Example:
$initialState = new GraphState([
'counter' => 0,
]);
$graph->run(new FirstNode(), $initialState);
GraphResult
The GraphResult represents the outcome of the graph execution.
Key Points:
- It is returned by the Graph::run method.
- It contains:
- The final mutated state after all nodes have executed.
- The data passed to the EndNode.
Example:
$result = $graph->run(new FirstNode(), $initialState);
$finalState = $result->state; // Access the final state
$endNodeData = $result->data; // Access data from the EndNode
Simple graph example
This example demonstrates how to create and execute a simple graph using Neuron Graph
.
Diagram
flowchart LR;
Increment --> Check42;
Check42([Check42]) --> Increment & EndNode;
Code
<?php
use Sixtynine\NeuronGraph\Graph\Graph;
use Sixtynine\NeuronGraph\Graph\GraphState;
use Sixtynine\NeuronGraph\Nodes\Node;
use Sixtynine\NeuronGraph\Nodes\EndNode;
class Increment extends Node
{
public function __construct(
private readonly int $number
) {
}
public function run(GraphState $state): Check42
{
return new Check42($this->number + 1);
}
}
class Check42 extends Node
{
public function __construct(
private readonly int $number
) {
}
public function run(GraphState $state): Increment|EndNode
{
if ($this->number !== 42) {
return new Increment($this->number);
}
return new EndNode($this->number);
}
}
$graph = new Graph([Increment::class, Check42::class]);
$result = $graph->run(new Check42(2));
echo $result->data; // --> 42
Observability
Neuron Graph supports observability by allowing you to attach observers to monitor and log graph execution events.
Using and observer
A SplObserver
can be passed to the graph to log its events. For example, you can use the provided LogObserver to send events to a PSR-compatible logger.
Example:
// Create a PSR-compatible logger
$logger = new Logger('my_logger', [
new TestHandler(),
]);
// Create a LogObserver
$observer = new LogObserver($logger);
// Create and execute the graph with the observer
$graph = new Graph([Node1::class, /* ... */, NodeN::class]);
$result = $graph->observe($observer)->run(new Node1());
Logged events
The LogObserver
logs the following events during graph execution:
- graph-start - triggered at the start of the execution of the graph.
- graph-end - triggered when the execution of the graph is finished.
- graph-node-start - triggered before the execution of a node of the graph.
- graph-node-end - triggered when the execution of a node finishes.
Custom Observers
You can also create your own observer by implementing the SplObserver
interface. This allows you to customize how graph events are handled and logged.
Example:
<?php
use SplObserver;
use SplSubject;
class CustomObserver implements SplObserver
{
public function update(SplSubject $subject): void
{
// Handle the graph event
echo "Event triggered: " . $subject->getEventName();
}
}
Export to Mermaid
Neuron Graph allows you to export your graph to the Mermaid format, which can be used to visualize the graph as a diagram.
Example:
$graph = new Graph([Increment::class, Check42::class]);
echo $graph->toMermaid();
Output Example:
graph TD
Increment --> Check42
Check42 --> Increment & EndNode
How to Use:
1) Copy the output from the toMermaid method. 2) Paste it into the Mermaid Live Editor or embed it in your documentation.
More examples
Explore additional examples to see how Neuron Graph can be used in various scenarios:
Stateful Graph Example:
A vending machine simulation demonstrating how to use the state.
View ExampleData Transformation Pipeline Example:
This example demonstrate how to subclass theGraph
class to create custom, predefined graphs.
View ExampleIntegration with NeuronAI - Chain of Thought:
An example showcasing how Neuron Graph integrates with NeuronAI to implement a chain-of-thought reasoning process.
View ExampleIntegration with NeuronAI - Cadavre Exquis Generator:
A creative example that uses Neuron Graph and NeuronAI to generate a "cadavre exquis" (a collaborative storytelling game).
View Example
Contribution Guidelines
We welcome contributions to Neuron Graph! Whether it's fixing bugs, adding new features, improving documentation, or providing feedback, your help is greatly appreciated.
Sumitting a Pull Request
To ensure a smooth contribution process, please follow these steps:
Follow Conventional Commits
Commit messages in this repository adhere to the Conventional Commits Guidelines.
Ensure your commit messages follow this format for consistency and clarity.Write Tests
Ensure your code is well-tested by writing unit tests for any new features or bug fixes. Cover edge cases and ensure your tests validate the expected behavior.Run Tests
Before submitting your pull request, make sure all tests pass. You can run the tests using:composer run tests
Run PHPStan
Ensure that PHPStan does not report any issues. Run PHPStan with:composer run phpstan
Open a Pull Request
Once your changes are ready, open a pull request with a clear description of the problem you're solving or the feature you're adding. Include any relevant details or context.
License
This project is licensed under the MIT License.
You are free to use, modify, and distribute this software in accordance with the terms of the license.
For more details, see the LICENSE file.