From 0beca21f0b695b09a48f2faa97e41ec3ebfcd430 Mon Sep 17 00:00:00 2001 From: Pavel Buchnev Date: Wed, 4 Sep 2024 01:36:32 +0400 Subject: [PATCH] Moves Smart home control to a separate package --- app/config/cache.php | 5 + .../SmartHomeControl/ControlDeviceInput.php | 25 ---- .../SmartHomeControl/ControlDeviceTool.php | 41 ------ .../Agents/SmartHomeControl/DeviceAction.php | 18 --- .../Agents/SmartHomeControl/DeviceParam.php | 17 --- .../GetDeviceDetailsInput.php | 15 -- .../SmartHomeControl/GetDeviceDetailsTool.php | 44 ------ .../SmartHomeControl/GetRoomListInput.php | 17 --- .../SmartHomeControl/GetRoomListTool.php | 35 ----- .../SmartHomeControl/ListRoomDevicesInput.php | 15 -- .../SmartHomeControl/ListRoomDevicesTool.php | 48 ------- .../SmartHome/Devices/Light.php | 80 ----------- .../SmartHome/Devices/SmartAppliance.php | 128 ------------------ .../SmartHome/Devices/SmartDevice.php | 47 ------- .../SmartHomeControl/SmartHome/Devices/TV.php | 78 ----------- .../SmartHome/Devices/Thermostat.php | 78 ----------- .../SmartHome/SmartHomeSystem.php | 85 ------------ .../SmartHomeControlAgent.php | 112 --------------- .../Bootloader/SmartHomeBootloader.php | 45 ++++-- app/src/Application/Kernel.php | 2 + .../Console/DisplaySmartHomeStatusCommand.php | 16 ++- .../SmartHome/DeviceStateManager.php | 45 ++++++ composer.json | 1 + 23 files changed, 100 insertions(+), 897 deletions(-) delete mode 100644 app/src/Agents/SmartHomeControl/ControlDeviceInput.php delete mode 100644 app/src/Agents/SmartHomeControl/ControlDeviceTool.php delete mode 100644 app/src/Agents/SmartHomeControl/DeviceAction.php delete mode 100644 app/src/Agents/SmartHomeControl/DeviceParam.php delete mode 100644 app/src/Agents/SmartHomeControl/GetDeviceDetailsInput.php delete mode 100644 app/src/Agents/SmartHomeControl/GetDeviceDetailsTool.php delete mode 100644 app/src/Agents/SmartHomeControl/GetRoomListInput.php delete mode 100644 app/src/Agents/SmartHomeControl/GetRoomListTool.php delete mode 100644 app/src/Agents/SmartHomeControl/ListRoomDevicesInput.php delete mode 100644 app/src/Agents/SmartHomeControl/ListRoomDevicesTool.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHome/Devices/Light.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartAppliance.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartDevice.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHome/Devices/TV.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHome/Devices/Thermostat.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHome/SmartHomeSystem.php delete mode 100644 app/src/Agents/SmartHomeControl/SmartHomeControlAgent.php create mode 100644 app/src/Infrastructure/RoadRunner/SmartHome/DeviceStateManager.php diff --git a/app/config/cache.php b/app/config/cache.php index d076175..2c5d321 100644 --- a/app/config/cache.php +++ b/app/config/cache.php @@ -8,6 +8,11 @@ 'aliases' => [ 'chat-messages' => [ 'storage' => 'rr-local', + 'prefix' => 'chat:', + ], + 'smart-home' => [ + 'storage' => 'rr-local', + 'prefix' => 'smart-home:', ], ], diff --git a/app/src/Agents/SmartHomeControl/ControlDeviceInput.php b/app/src/Agents/SmartHomeControl/ControlDeviceInput.php deleted file mode 100644 index 9267f04..0000000 --- a/app/src/Agents/SmartHomeControl/ControlDeviceInput.php +++ /dev/null @@ -1,25 +0,0 @@ - - */ - #[Field(title: 'Parameters', description: 'Additional parameters for the action. If the action does not require parameters, this field should be an empty array')] - public array $params, - ) {} -} diff --git a/app/src/Agents/SmartHomeControl/ControlDeviceTool.php b/app/src/Agents/SmartHomeControl/ControlDeviceTool.php deleted file mode 100644 index e577304..0000000 --- a/app/src/Agents/SmartHomeControl/ControlDeviceTool.php +++ /dev/null @@ -1,41 +0,0 @@ - - */ -final class ControlDeviceTool extends PhpTool -{ - public const NAME = 'control_device'; - - public function __construct( - private SmartHomeSystem $smartHome, - ) { - parent::__construct( - name: self::NAME, - inputSchema: ControlDeviceInput::class, - description: 'Controls a specific device by performing the specified action with given parameters.', - ); - } - - public function execute(object $input): string - { - try { - $result = $this->smartHome->controlDevice($input->deviceId, $input->action, $input->params); - - return json_encode([ - 'id' => $input->deviceId, - 'action' => $input->action->value, - 'result' => $result, - ]); - } catch (\InvalidArgumentException $e) { - return json_encode(['error' => $e->getMessage()]); - } - } -} diff --git a/app/src/Agents/SmartHomeControl/DeviceAction.php b/app/src/Agents/SmartHomeControl/DeviceAction.php deleted file mode 100644 index fcfd326..0000000 --- a/app/src/Agents/SmartHomeControl/DeviceAction.php +++ /dev/null @@ -1,18 +0,0 @@ - - */ -final class GetDeviceDetailsTool extends PhpTool -{ - public const NAME = 'get_device_details'; - - public function __construct( - private readonly SmartHomeSystem $smartHome, - ) { - parent::__construct( - name: self::NAME, - inputSchema: GetDeviceDetailsInput::class, - description: 'Retrieves detailed information about a specific device.', - ); - } - - public function execute(object $input): string - { - $device = $this->smartHome->getDevice($input->deviceId); - - if (!$device) { - return json_encode(['error' => 'Device not found']); - } - - return json_encode([ - 'id' => $device->id, - 'name' => $device->name, - 'room' => $device->room, - 'type' => get_class($device), - 'params' => $device->getDetails(), - 'controlSchema' => $device->getControlSchema(), - ]); - } -} diff --git a/app/src/Agents/SmartHomeControl/GetRoomListInput.php b/app/src/Agents/SmartHomeControl/GetRoomListInput.php deleted file mode 100644 index 91b90ec..0000000 --- a/app/src/Agents/SmartHomeControl/GetRoomListInput.php +++ /dev/null @@ -1,17 +0,0 @@ - - */ -final class GetRoomListTool extends PhpTool -{ - public const NAME = 'get_room_list'; - - public function __construct( - private readonly SmartHomeSystem $smartHome, - ) { - parent::__construct( - name: self::NAME, - inputSchema: GetRoomListInput::class, - description: 'Retrieves a list of all room names in the smart home system.', - ); - } - - public function execute(object $input): string - { - $rooms = $this->smartHome->getRoomList(); - - return \json_encode([ - 'rooms' => $rooms, - ]); - } -} diff --git a/app/src/Agents/SmartHomeControl/ListRoomDevicesInput.php b/app/src/Agents/SmartHomeControl/ListRoomDevicesInput.php deleted file mode 100644 index 5abea7a..0000000 --- a/app/src/Agents/SmartHomeControl/ListRoomDevicesInput.php +++ /dev/null @@ -1,15 +0,0 @@ - - */ -final class ListRoomDevicesTool extends PhpTool -{ - public const NAME = 'list_room_devices'; - - public function __construct( - private readonly SmartHomeSystem $smartHome, - ) { - parent::__construct( - name: self::NAME, - inputSchema: ListRoomDevicesInput::class, - description: 'Lists all smart devices in a specified room.', - ); - } - - public function execute(object $input): string - { - $devices = $this->smartHome->getRoomDevices($input->roomName); - $deviceList = []; - - foreach ($devices as $device) { - $deviceList[] = [ - 'id' => $device->id, - 'name' => $device->name, - 'type' => get_class($device), - 'status' => $device->getStatus() ? 'on' : 'off', - 'params' => $device->getDetails(), - 'controlSchema' => $device->getControlSchema(), - ]; - } - - return json_encode([ - 'room' => $input->roomName, - 'devices' => $deviceList, - ]); - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHome/Devices/Light.php b/app/src/Agents/SmartHomeControl/SmartHome/Devices/Light.php deleted file mode 100644 index 69c0b23..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHome/Devices/Light.php +++ /dev/null @@ -1,80 +0,0 @@ -brightness = max(0, min(100, $level)); - $this->status = $this->brightness > 0; - } - - public function setColor(?string $color): void - { - $this->color = $color; - } - - public function getDetails(): array - { - return [ - 'type' => $this->type, - 'status' => $this->status ? 'on' : 'off', - 'brightness' => $this->brightness, - 'color' => $this->color, - ]; - } - - public function getControlSchema(): array - { - return [ - 'type' => 'object', - 'properties' => [ - 'action' => [ - 'type' => 'string', - 'enum' => [ - DeviceAction::TurnOn->value, - DeviceAction::TurnOff->value, - DeviceAction::SetBrightness->value, - DeviceAction::SetColor->value, - ], - ], - 'brightness' => [ - 'type' => 'integer', - 'minimum' => 0, - 'maximum' => 100, - ], - 'color' => [ - 'type' => 'string', - ], - ], - 'required' => ['action'], - ]; - } - - public function executeAction(DeviceAction $action, array $params): static - { - match ($action) { - DeviceAction::SetBrightness => $this->setBrightness($params['brightness']), - DeviceAction::SetColor => $this->setColor($params['color']), - default => parent::executeAction($action, $params) - }; - - return $this; - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartAppliance.php b/app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartAppliance.php deleted file mode 100644 index dbf7672..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartAppliance.php +++ /dev/null @@ -1,128 +0,0 @@ -attributes[$key] = $value; - } - - /** - * @param array $attributes - */ - public function setAttributes(array $attributes): void - { - foreach ($attributes as $attribute) { - $this->setAttribute($attribute->name, $attribute->value); - } - } - - public function getAttribute(string $key) - { - return $this->attributes[$key] ?? null; - } - - public function getDetails(): array - { - return array_merge( - $this->attributes, - [ - 'status' => $this->status ? 'on' : 'off', - 'type' => $this->type, - ], - ); - } - - public function getControlSchema(): array - { - $schema = [ - 'type' => 'object', - 'properties' => [ - 'action' => [ - 'type' => 'string', - 'enum' => [ - DeviceAction::TurnOn->value, - DeviceAction::TurnOff->value, - DeviceAction::SetAttribute->value, - ], - ], - 'params' => [ - 'type' => 'object', - 'properties' => [ - 'name' => [ - 'type' => 'string', - ], - 'value' => [ - 'type' => ['string', 'number', 'boolean'], - ], - ], - 'required' => ['name', 'value',], - ], - ], - 'required' => ['action'], - ]; - - // Add specific schemas based on the appliance type - switch ($this->type) { - case 'fireplace': - $schema['properties']['intensity'] = [ - 'type' => 'integer', - 'minimum' => 1, - 'maximum' => 5, - ]; - break; - case 'speaker': - $schema['properties']['volume'] = [ - 'type' => 'integer', - 'minimum' => 0, - 'maximum' => 100, - ]; - $schema['properties']['radio_station'] = [ - 'type' => 'string', - 'enum' => ['rock', 'pop', 'jazz', 'classical', 'news', 'talk', 'sports'], - ]; - $schema['properties']['playback'] = [ - 'type' => 'string', - 'enum' => ['play', 'pause', 'stop', 'next', 'previous'], - ]; - break; - case 'fan': - $schema['properties']['speed'] = [ - 'type' => 'integer', - 'minimum' => 0, - 'maximum' => 5, - ]; - break; - } - - return $schema; - } - - public function executeAction(DeviceAction $action, array $params): static - { - match ($action) { - DeviceAction::SetAttribute => $this->setAttributes($params), - default => parent::executeAction($action, $params), - }; - - return $this; - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartDevice.php b/app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartDevice.php deleted file mode 100644 index 5cc5a66..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHome/Devices/SmartDevice.php +++ /dev/null @@ -1,47 +0,0 @@ -status = true; - } - - public function turnOff(): void - { - $this->status = false; - } - - public function getStatus(): bool - { - return $this->status; - } - - abstract public function getDetails(): array; - - abstract public function getControlSchema(): array; - - public function executeAction(DeviceAction $action, array $params): static - { - match ($action) { - DeviceAction::TurnOn => $this->turnOn(), - DeviceAction::TurnOff => $this->turnOff(), - default => throw new \InvalidArgumentException("Unsupported action: {$action->value}"), - }; - - return $this; - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHome/Devices/TV.php b/app/src/Agents/SmartHomeControl/SmartHome/Devices/TV.php deleted file mode 100644 index 448f947..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHome/Devices/TV.php +++ /dev/null @@ -1,78 +0,0 @@ -volume = max(0, min(100, $volume)); - } - - public function setInput(string $input): void - { - $this->input = $input; - } - - public function getDetails(): array - { - return [ - 'status' => $this->status ? 'on' : 'off', - 'volume' => $this->volume, - 'input' => $this->input, - ]; - } - - public function getControlSchema(): array - { - return [ - 'type' => 'object', - 'properties' => [ - 'action' => [ - 'type' => 'string', - 'enum' => [ - DeviceAction::TurnOn->value, - DeviceAction::TurnOff->value, - DeviceAction::SetVolume->value, - DeviceAction::SetInput->value, - ], - ], - 'volume' => [ - 'type' => 'integer', - 'minimum' => 0, - 'maximum' => 100, - ], - 'input' => [ - 'type' => 'string', - 'enum' => ['HDMI 1', 'HDMI 2', 'HDMI 3', 'TV', 'AV'], - ], - ], - 'required' => ['action'], - ]; - } - - public function executeAction(DeviceAction $action, array $params): static - { - match ($action) { - DeviceAction::SetVolume => $this->setVolume($params['volume']), - DeviceAction::SetInput => $this->setInput($params['input']), - default => parent::executeAction($action, $params), - }; - - return $this; - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHome/Devices/Thermostat.php b/app/src/Agents/SmartHomeControl/SmartHome/Devices/Thermostat.php deleted file mode 100644 index a28e2cc..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHome/Devices/Thermostat.php +++ /dev/null @@ -1,78 +0,0 @@ -temperature = $temperature; - } - - public function setMode(string $mode): void - { - $this->mode = $mode; - } - - public function getDetails(): array - { - return [ - 'status' => $this->status ? 'on' : 'off', - 'temperature' => $this->temperature, - 'mode' => $this->mode, - ]; - } - - public function getControlSchema(): array - { - return [ - 'type' => 'object', - 'properties' => [ - 'action' => [ - 'type' => 'string', - 'enum' => [ - DeviceAction::TurnOn->value, - DeviceAction::TurnOff->value, - DeviceAction::SetTemperature->value, - DeviceAction::SetMode->value, - ], - ], - 'temperature' => [ - 'type' => 'integer', - 'minimum' => 60, - 'maximum' => 90, - ], - 'mode' => [ - 'type' => 'string', - 'enum' => ['auto', 'cool', 'heat', 'fan'], - ], - ], - 'required' => ['action'], - ]; - } - - public function executeAction(DeviceAction $action, array $params): static - { - match ($action) { - DeviceAction::SetTemperature => $this->setTemperature($params['temperature']), - DeviceAction::SetMode => $this->setMode($params['mode']), - default => parent::executeAction($action, $params), - }; - - return $this; - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHome/SmartHomeSystem.php b/app/src/Agents/SmartHomeControl/SmartHome/SmartHomeSystem.php deleted file mode 100644 index 6b069ae..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHome/SmartHomeSystem.php +++ /dev/null @@ -1,85 +0,0 @@ - */ - private array $devices = []; - - public function __construct( - private readonly CacheInterface $cache, - ) {} - - public function addDevice(SmartDevice $device): void - { - $this->devices[$device->id] = $device; - } - - public function getDevice(string $id): ?SmartDevice - { - $device = $this->cache->get('device_' . $id, $this->devices[$id] ?? null); - - return $device; - } - - public function getRoomList(): array - { - $rooms = \array_unique(\array_map(fn($device) => $device->room, $this->devices)); - \sort($rooms); - return $rooms; - } - - public function getRoomDevices(string $room): array - { - return \array_filter($this->getCachedDevices(), static fn($device): bool => $device->room === $room); - } - - private function getCachedDevices(): array - { - $devices = []; - foreach ($this->devices as $id => $device) { - $devices[$id] = $this->getDevice($id); - } - - return \array_filter($devices); - } - - public function controlDevice(string $id, DeviceAction $action, array $params = []): array - { - $device = $this->getDevice($id); - if ($device === null) { - return ['error' => 'Device not found']; - } - - $this->cache->set( - 'device_' . $id, - $device->executeAction($action, $params), - CarbonInterval::hour(), - ); - - $this->cache->set('last_action', \time(), CarbonInterval::hour()); - - return [ - 'id' => $device->id, - 'name' => $device->name, - 'room' => $device->room, - 'type' => \get_class($device), - 'params' => $device->getDetails(), - ]; - } - - public function getLastActionTime(): ?int - { - return $this->cache->get('last_action') ?? null; - } -} diff --git a/app/src/Agents/SmartHomeControl/SmartHomeControlAgent.php b/app/src/Agents/SmartHomeControl/SmartHomeControlAgent.php deleted file mode 100644 index fc00f31..0000000 --- a/app/src/Agents/SmartHomeControl/SmartHomeControlAgent.php +++ /dev/null @@ -1,112 +0,0 @@ -addMetadata( - new SolutionMetadata( - type: MetadataType::Memory, - key: 'room_validation', - content: 'Important! Before request devices in any room, use the get_room_list tool to know correct room names.', - ), - new SolutionMetadata( - type: MetadataType::Memory, - key: 'energy_efficiency', - content: 'Remember to suggest energy-efficient settings when appropriate.', - ), - new SolutionMetadata( - type: MetadataType::Memory, - key: 'device_status', - content: 'Important! Check device status before performing any action. Because a state can be changed by another user or system.', - ), - new SolutionMetadata( - type: MetadataType::Memory, - key: 'home_name', - content: 'We are currently in the "Home" home.', - ), - new SolutionMetadata( - type: MetadataType::Memory, - key: 'store_important_memory', - content: 'Store important information in memory for future reference. For example if user tells that he likes some specific setting, store it in memory.', - ), - - new SolutionMetadata( - type: MetadataType::Configuration, - key: Option::MaxTokens->value, - content: 3000, - ), - - new SolutionMetadata( - type: MetadataType::Prompt, - key: 'query_devices', - content: 'What devices are in the living room?', - ), - new SolutionMetadata( - type: MetadataType::Prompt, - key: 'control_light', - content: 'Turn on the lights in the bedroom.', - ), - new SolutionMetadata( - type: MetadataType::Prompt, - key: 'control_fireplace', - content: 'Set the fireplace in the living room to medium intensity.', - ), - new SolutionMetadata( - type: MetadataType::Prompt, - key: 'control_tv', - content: 'Today is rainy. I\'m in the living room and in a bad mood, could you do something to cheer me up?', - ), - new SolutionMetadata( - type: MetadataType::Prompt, - key: 'check_device_status', - content: 'Is the kitchen light on?', - ), - new SolutionMetadata( - type: MetadataType::Prompt, - key: 'control_multiple_devices', - content: 'Turn off all devices in the master bedroom.', - ), - ); - - $model = new Model(model: OpenAIModel::Gpt4oMini->value); - $aggregate->addAssociation($model); - - $aggregate->addAssociation(new ToolLink(name: ListRoomDevicesTool::NAME)); - $aggregate->addAssociation(new ToolLink(name: GetDeviceDetailsTool::NAME)); - $aggregate->addAssociation(new ToolLink(name: ControlDeviceTool::NAME)); - $aggregate->addAssociation(new ToolLink(name: GetRoomListTool::NAME)); - $aggregate->addAssociation(new ToolLink(name: DynamicMemoryTool::NAME)); - - return $aggregate; - } -} diff --git a/app/src/Application/Bootloader/SmartHomeBootloader.php b/app/src/Application/Bootloader/SmartHomeBootloader.php index 67188ab..c166e50 100644 --- a/app/src/Application/Bootloader/SmartHomeBootloader.php +++ b/app/src/Application/Bootloader/SmartHomeBootloader.php @@ -4,23 +4,43 @@ namespace App\Application\Bootloader; -use App\Agents\SmartHomeControl\SmartHome\Devices\Light; -use App\Agents\SmartHomeControl\SmartHome\Devices\SmartAppliance; -use App\Agents\SmartHomeControl\SmartHome\Devices\Thermostat; -use App\Agents\SmartHomeControl\SmartHome\Devices\TV; -use App\Agents\SmartHomeControl\SmartHome\SmartHomeSystem; -use Psr\SimpleCache\CacheInterface; +use App\Agents\DynamicMemoryTool\DynamicMemoryTool; +use App\Infrastructure\RoadRunner\SmartHome\DeviceStateManager; +use LLM\Agents\Agent\AgentRepositoryInterface; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\Devices\Light; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\Devices\SmartAppliance; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\Devices\Thermostat; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\Devices\TV; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\DeviceStateRepositoryInterface; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\DeviceStateStorageInterface; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\SmartHomeSystem; +use LLM\Agents\Agent\SmartHomeControl\SmartHomeControlAgent; +use LLM\Agents\Solution\ToolLink; use Spiral\Boot\Bootloader\Bootloader; +use Spiral\Cache\CacheStorageProviderInterface; final class SmartHomeBootloader extends Bootloader { public function defineSingletons(): array { return [ + DeviceStateManager::class => static function ( + CacheStorageProviderInterface $provider, + ): DeviceStateManager { + return new DeviceStateManager($provider->storage('smart-home')); + }, + + DeviceStateStorageInterface::class => DeviceStateManager::class, + DeviceStateRepositoryInterface::class => DeviceStateManager::class, + SmartHomeSystem::class => static function ( - CacheInterface $cache, + DeviceStateStorageInterface $stateStorage, + DeviceStateRepositoryInterface $stateRepository, ): SmartHomeSystem { - $smartHome = new SmartHomeSystem($cache); + $smartHome = new SmartHomeSystem( + stateStorage: $stateStorage, + stateRepository: $stateRepository, + ); // Living Room Devices $livingRoomAirConditioner = new SmartAppliance( @@ -120,4 +140,13 @@ public function defineSingletons(): array }, ]; } + + public function boot( + AgentRepositoryInterface $agents, + ): void { + /** @var SmartHomeControlAgent $agent */ + $agent = $agents->get(SmartHomeControlAgent::NAME); + + $agent->addAssociation(new ToolLink(name: DynamicMemoryTool::NAME)); + } } diff --git a/app/src/Application/Kernel.php b/app/src/Application/Kernel.php index 8b95d8d..ca30423 100644 --- a/app/src/Application/Kernel.php +++ b/app/src/Application/Kernel.php @@ -5,6 +5,7 @@ namespace App\Application; use LLM\Agents\Agent\SiteStatusChecker\Integrations\Spiral\SiteStatusCheckerBootloader; +use LLM\Agents\Agent\SmartHomeControl\Integrations\Spiral\SmartHomeControlBootloader; use LLM\Agents\JsonSchema\Mapper\Integration\Spiral\SchemaMapperBootloader; use LLM\Agents\OpenAI\Client\Integration\Spiral\OpenAIClientBootloader; use Spiral\Boot\Bootloader\CoreBootloader; @@ -48,6 +49,7 @@ public function defineBootloaders(): array OpenAIClientBootloader::class, SchemaMapperBootloader::class, SiteStatusCheckerBootloader::class, + SmartHomeControlBootloader::class, ]; } } diff --git a/app/src/Endpoint/Console/DisplaySmartHomeStatusCommand.php b/app/src/Endpoint/Console/DisplaySmartHomeStatusCommand.php index 00a58b3..83f1d0e 100644 --- a/app/src/Endpoint/Console/DisplaySmartHomeStatusCommand.php +++ b/app/src/Endpoint/Console/DisplaySmartHomeStatusCommand.php @@ -4,7 +4,9 @@ namespace App\Endpoint\Console; -use App\Agents\SmartHomeControl\SmartHome\SmartHomeSystem; +use App\Infrastructure\RoadRunner\SmartHome\DeviceStateManager; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\DeviceStateRepositoryInterface; +use LLM\Agents\Agent\SmartHomeControl\SmartHome\SmartHomeSystem; use Spiral\Console\Attribute\AsCommand; use Spiral\Console\Attribute\Option; use Spiral\Console\Command; @@ -19,17 +21,20 @@ final class DisplaySmartHomeStatusCommand extends Command #[Option(name: 'interactive', description: 'Enable interactive mode')] public bool $interactive = false; - public function __invoke(SmartHomeSystem $smartHome): int - { + public function __invoke( + SmartHomeSystem $smartHome, + DeviceStateRepositoryInterface $stateRepository, + ): int { + \assert($stateRepository instanceof DeviceStateManager); $lastUpdate = false; while (true) { - if ($smartHome->getLastActionTime() === $lastUpdate) { + if ($stateRepository->getLastActionTime() === $lastUpdate) { \sleep(1); continue; } - $lastUpdate = $smartHome->getLastActionTime(); + $lastUpdate = $stateRepository->getLastActionTime(); // Clear the console screen $this->output->write("\033\143"); @@ -51,7 +56,6 @@ public function __invoke(SmartHomeSystem $smartHome): int $table->render(); $this->output->writeln(''); } - } return self::SUCCESS; diff --git a/app/src/Infrastructure/RoadRunner/SmartHome/DeviceStateManager.php b/app/src/Infrastructure/RoadRunner/SmartHome/DeviceStateManager.php new file mode 100644 index 0000000..d4b9ecc --- /dev/null +++ b/app/src/Infrastructure/RoadRunner/SmartHome/DeviceStateManager.php @@ -0,0 +1,45 @@ +cache->get('device_' . $id); + } + + public function update(SmartDevice $device): void + { + $this->cache->set( + 'device_' . $device->id, + $device, + CarbonInterval::seconds(self::DEVICE_STATE_TTL), + ); + + $this->cache->set(self::LAST_ACTION_KEY, \time(), CarbonInterval::seconds(self::LAST_ACTION_TTL)); + } + + public function getLastActionTime(): ?int + { + return $this->cache->get(self::LAST_ACTION_KEY) ?? null; + } +} diff --git a/composer.json b/composer.json index 0d33495..421a7a9 100644 --- a/composer.json +++ b/composer.json @@ -11,6 +11,7 @@ "guzzlehttp/guzzle": "^7.0", "internal/dload": "^0.2.2", "llm-agents/agent-site-status-checker": "^1.0", + "llm-agents/agent-smart-home-control": "^1.0", "llm-agents/agents": "^1.0", "llm-agents/cli-chat": "^1.0", "llm-agents/json-schema-mapper": "^1.0",