asterixcapri / neuron-interaction
Sessions, commands, selections and user preferences for applications built with Neuron AI.
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)
- friendsofphp/php-cs-fixer: ^3.95
- phpstan/phpstan: ^2.1
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Neuron Interaction provides conversation sessions, commands, input history, user preferences and response stopping for applications built with Neuron AI.
Use it to save and resume conversations, offer reusable commands, ask users to choose an option, recall previous inputs and persist their preferences. Use the modules independently in a terminal or web application. Your application controls the UI, Agent execution and streaming; commands use an Adapter to connect to its input and output.
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
- Sessions save, list and resume Neuron AI conversations.
- Input history records submissions and supports recalling previous inputs.
- Commands provide
/clear,/resume,/help,/exitand custom behavior. - Selections let commands ask users to choose an option, including across HTTP requests.
- Configuration stores user preferences such as the selected model.
- Response stop interrupts HTTP streaming while letting Neuron finalize its partial response.
- Storage provides memory and JSON-file implementations, with an interface for your own storage.
SessionStore and Storage
Install a stored conversation as the Agent's chat history. Subsequent history updates are persisted automatically:
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());
Use summaries() to list conversations and read($key) to reopen one, then
install it with $agent->setChatHistory($history). Supply the current user's
identity instead of local-user; reads and listings are scoped to that user.
Use InMemoryStorage for transient state, or implement StorageInterface
for your application's persistence. See Sessions and Storage
for listing, deletion, metadata and filtering.
Stop a response
Share a StopSignal between the provider's HTTP client and the code handling
stop requests. The application chooses the key identifying the response:
use NeuronAI\Agent\Agent; use NeuronAI\Chat\Messages\Stream\Chunks\TextChunk; use NeuronAI\Chat\Messages\UserMessage; use NeuronAI\HttpClient\GuzzleHttpClient; use NeuronAI\Providers\OpenAI\Responses\OpenAIResponses; use NeuronInteraction\Http\StoppableHttpClient; use NeuronInteraction\Http\StopSignal; use NeuronInteraction\Storage\FileStorage; $storage = new FileStorage(__DIR__ . '/interaction-state'); $stopSignal = new StopSignal(storage: $storage, key: $chatId); $client = new StoppableHttpClient( inner: new GuzzleHttpClient(), stopSignal: $stopSignal, ); $agent = new Agent(); $agent->setAiProvider(new OpenAIResponses( key: $apiKey, model: $model, httpClient: $client, )); $stopSignal->clear(); foreach ($agent->stream(new UserMessage($prompt))->events() as $event) { if ($event instanceof TextChunk) { echo $event->content; } }
In a separate stop endpoint, use the same storage location and authorized key:
$stopSignal = new StopSignal( storage: new FileStorage(__DIR__ . '/interaction-state'), key: $chatId, ); $stopSignal->request();
The stream detects and consumes the signal, allowing Neuron to finalize the
partial response. No stop check is needed in the consumer loop. Only request()
writes a stop document; clear() removes it and isRequested() reads its state.
Use the same InMemoryStorage instance when both handlers run in one process.
Concurrent responses need distinct keys, and separate HTTP requests need workers that can run concurrently. Stopping does not cancel local tools or guarantee remote generation has stopped. See the response stop guide for polling, terminal integration and lifecycle details.
Input history
Record user submissions and recall them later:
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 sessions. $recalled = $inputs->older('Unsubmitted draft'); $newer = $inputs->newer(); // Restores the draft past the newest input.
Your application decides when to record input and handles keyboard events.
A web frontend can use entries() and navigate locally. See
Input history for navigation state and storage behavior.
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\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', '', $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', $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, string $value): 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 | Ask the application to end the interaction. |
| 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.
Configuration
Store preferences for the current user:
use NeuronInteraction\Configuration\ConfigurationStore; $settings = new ConfigurationStore($storage, 'local-user'); $settings->write('model', 'chosen-model'); $model = $settings->read('model', 'default-model');
The fallback determines the expected value type. Commands access the same store
through $adapter->configurationStore(). See
ConfigurationStore for validation and the full API.
Development
composer install
composer test
composer stan
composer cs