asterixcapri / neuron-interaction
Presentation-independent interaction modules for Neuron AI Agents.
Package info
github.com/asterixcapri/neuron-interaction
pkg:composer/asterixcapri/neuron-interaction
Requires
- php: >=8.4.1
- neuron-core/neuron-ai: ^3.0
Requires (Dev)
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Neuron Interaction is a small PHP library for building reusable interaction flows around Neuron AI Agents. It provides the state and application-level behavior common to conversational interfaces while leaving presentation, Agent execution and response streaming to the Host Application.
The same interaction logic can therefore serve a terminal, web backend or another delivery mechanism. Each Host Application supplies an Adapter that translates the library's operations into its own UI and response model.
Installation
Requires PHP 8.4.1+. The 0.8.x branch supports Neuron AI 3.
Run this command in your application's directory:
composer require asterixcapri/neuron-interaction
Composer also installs Neuron AI as a required dependency. If you install Neuron TUI, Neuron Interaction is already included as its dependency.
What it provides
- SessionStore persists Neuron AI chat Histories and make conversations discoverable, resumable and replaceable without discarding earlier ones.
- Input history records original submissions across Sessions and optionally provides shell-style recall navigation with independent cursor state per UI.
- Commands provide presentation-independent dispatch, admission and
completion, together with reusable
/clear,/resume,/helpand/exitbehavior. - Selections describe choices as serializable values, labels and descriptions, so multi-step interactions can cross backend request boundaries.
- Storage offers in-memory and JSON-file implementations behind a small interface that applications can replace with their own persistence.
Design strengths
- Presentation independence. Commands express interaction effects through an Adapter instead of printing to a terminal or returning a fixed HTTP shape.
- Explicit application ownership. The Host Application controls the active Agent, turn execution, authorization, scheduling, streaming and lifecycle.
- Composable modules. SessionStore, Commands, Input history and Storage can be adopted together or independently; no application facade is required.
- Native Neuron AI integration. Persisted Sessions expose Neuron AI's own
ChatHistoryInterface, so they can be installed directly on an Agent. - Request-safe workflows. Selection state is carried as data and resumed by a later Command invocation; an Adapter does not need to survive between requests.
- Replaceable boundaries. Both presentation and persistence sit behind focused interfaces, keeping framework and infrastructure choices outside the shared interaction model.
SessionStore and Storage
use NeuronAI\Agent\Agent; use NeuronInteraction\Session\SessionStore; use NeuronInteraction\Storage\FileStorage; $storage = new FileStorage(__DIR__ . '/interaction-state'); $sessionStore = new SessionStore($storage, 'local-user'); $agent = new Agent(); $agent->setChatHistory($sessionStore->create()); // After the Agent has exchanged messages, list recognizable Sessions. foreach ($sessionStore->summaries() as $session) { // Render $session->title according to your Adapter's rules. // Resume a chosen Session by installing its History on the Agent: // $history = $sessionStore->read($session->key); // if ($history !== null) { $agent->setChatHistory($history); } }
Host Applications explicitly install a History from create() or read($key)
on the Agent when they want that conversation managed by this SessionStore.
SessionStore does not import arbitrary Agent Histories or automatically select the
latest conversation. Only Histories managed through this Store appear in
its listing, subject to the existing title rules.
Use InMemoryStorage for transient state, or implement StorageInterface
for application-specific persistence. Storage holds namespaced JSON documents
identified by logical keys. It preserves string metadata together with data;
StoredDocument::size() reports the JSON size of its data.
SessionStore::create() creates a distinct empty History. SessionStore::summaries()
returns Sessions with user-authored text, ordered by most recent use and then
key. Titles preserve the first non-blank user-authored textual content without
terminal placeholders, escaping or truncation. SessionStore::read($key)
reopens its stored History or returns null for absent or other-user keys.
SessionStore::delete($key) deletes only the current user’s Session and is a
no-op when absent. Sessions expose getKey() and getUserId(); History updates
persist automatically. Supply a stable local or authenticated identity when
constructing the Store. Ownerless documents are never assigned implicitly.
Application metadata use camelCase names and string values. Pass initial values
when creating a Session, then update individual values; these changes persist
immediately and preserve its messages. Application fields named userId or
lastUsedAt remain ordinary metadata and cannot change ownership or ordering.
$session = $sessionStore->create(['projectId' => 'alpha', 'branchName' => 'main']); $session->setMetadata('branchName', 'release'); $metadata = $session->getMetadata(); // The complete application metadata map. $session->removeMetadata('branchName'); $matches = $sessionStore->summaries(['projectId' => 'alpha']);
Multiple filters are combined with AND using exact string equality. Missing keys do not match; extra metadata are ignored. Results always belong to the Store's user and retain the same title, empty-conversation and ordering rules. Metadata edits preserve the last History-use time; adding or clearing messages updates it and retains application metadata.
Input history
use NeuronInteraction\InputHistory\InputHistory; $inputs = new InputHistory($storage); $inputs->record('/resume session-key'); $inputs->record('A message exactly as submitted'); $submitted = $inputs->entries(); // Oldest first, across all Sessions.
Adapters record original submissions, including their Command invocation syntax, and exclude prompts generated by Commands. Blank inputs are ignored; only consecutive exact duplicates collapse. Each read and append uses the current Storage sequence, so existing instances see one another's submissions. Simultaneous writes are not coordinated by this module; Adapters must serialize them when sharing Storage across concurrent writers.
The same InputHistory instance optionally provides recall navigation:
$recalled = $inputs->older('Unsubmitted draft'); $newer = $inputs->newer(); // Restores the draft past the newest input. $navigating = $inputs->isNavigating(); $inputs->leave(); // Discards the navigation position and saved draft.
Each instance keeps its own position and draft in memory; only the input
sequence is persisted and shared. Adapters own keyboard handling and decide
when to leave navigation, such as on editing or submitting input. A web
frontend can use only entries() and navigate locally in JavaScript, without
a backend call for each arrow key.
No Neuron TUI dependency, legacy reader, format fallback or automatic migration is supplied. Existing legacy files are left untouched.
Commands
Commands let users perform actions such as starting a new conversation or reopening a saved one. The library includes:
| Command | What it does |
|---|---|
/clear |
Start an empty Session, keeping the previous conversation. |
/resume |
Choose a saved conversation, or reopen one by its key. |
/help |
List the available Commands. |
/exit |
Ask the application to end the interaction. |
Choose which Commands your application offers and mount them explicitly:
use NeuronInteraction\Command\CommandArguments; use NeuronInteraction\Command\Commands; use NeuronInteraction\Command\HelpCommand; use NeuronInteraction\Command\LeaveCommand; use NeuronInteraction\Command\ClearCommand; use NeuronInteraction\Command\ResumeCommand; $commands = new Commands([ new ClearCommand(), new ResumeCommand(), new HelpCommand(), new LeaveCommand(), ]); // $adapter connects the Commands to your application. $output = $commands->run('/resume', new CommandArguments(), $adapter);
The Adapter decides how to display messages, offer choices and end the interaction. A terminal Adapter can update the screen; a backend Adapter can return response data. The Commands work with either.
To reopen a known Session, pass its key as the arguments:
$output = $commands->run('/resume', new CommandArguments($sessionKey), $adapter);
Write a Command
A Command provides its name, a short description and the action to perform:
use NeuronInteraction\Command\CommandAdapterInterface; use NeuronInteraction\Command\CommandInterface; final class HelloCommand implements CommandInterface { public function name(): string { return '/hello'; } public function describe(): string { return 'Say hello.'; } public function run(CommandAdapterInterface $adapter, CommandArguments $arguments): void { $adapter->notify('Hello!'); } } $commands->addCommand(new HelloCommand());
See the Command and Adapter reference for custom Adapters, mounting, execution outcomes and error handling.
Backend examples
These examples use BackendAdapter to collect Command messages and choices into response data. They run locally without an HTTP server, API credentials or model requests.
Each backend example is self-contained and demonstrates one flow:
| Example | What it shows |
|---|---|
| help.php | Execute Help and print the response. |
| exit.php | Return the stop effect to the Host Application. |
| clear.php | Start an empty Session while keeping the previous conversation. |
| resume-by-key.php | Reopen a conversation whose key is already known. |
| resume-selection.php | Offer conversations, then receive the user's choice in a second request. |
Run any file after installing development dependencies:
php examples/help.php php examples/resume-selection.php
In resume-selection.php, the first request offers saved conversations. The
second simulates the user's choice and reopens that conversation with a fresh
Agent and Adapter. The example provides its own sample data in memory.
Development
composer install
composer test
composer stan
Commands during Agent work
ConcurrentCommandInterface extends CommandInterface without adding methods.
Implement it when a Command can execute while the Agent is working without
interfering with state used by that work. Help and Leave implement this marker.
Adapters decide whether to admit these Commands and still provide the ordinary
CommandAdapterInterface; the marker does not enforce restricted controls.