diff --git a/app/src/Agents/Calculator/CalculatorAgent.php b/app/src/Agents/Calculator/CalculatorAgent.php new file mode 100644 index 0000000..7a5d302 --- /dev/null +++ b/app/src/Agents/Calculator/CalculatorAgent.php @@ -0,0 +1,79 @@ +addMetadata( + new SolutionMetadata( + type: MetadataType::Memory, + key: 'operation_mapping', + content: "Map user requests to the correct operation: 'add' for addition, 'subtract' for subtraction, 'multiply' for multiplication, 'divide' for division, 'average' for averaging, and 'sqrt' for square root.", + ), + new SolutionMetadata( + type: MetadataType::Memory, + key: 'number_formatting', + content: 'Ensure that numbers are correctly formatted as a Python list when passing them to the tool.', + ), + new SolutionMetadata( + type: MetadataType::Memory, + key: 'error_handling', + content: 'Be aware of potential errors like division by zero or invalid operations, and explain these to the user if the generated code might raise such errors.', + ), + new SolutionMetadata( + type: MetadataType::Prompt, + key: 'example_addition', + content: 'Add 5, 10, and 15', + ), + new SolutionMetadata( + type: MetadataType::Prompt, + key: 'example_division', + content: 'Divide 100 by 5 and then by 2', + ), + new SolutionMetadata( + type: MetadataType::Prompt, + key: 'example_square_root', + content: 'Calculate the square root of 16', + ), + ); + + $model = new Model(model: OpenAIModel::Gpt4oMini->value); + $aggregate->addAssociation($model); + + $aggregate->addAssociation(new ToolLink(name: PythonCalculatorTool::NAME)); + + return $aggregate; + } +} diff --git a/app/src/Agents/Calculator/PythonCalculatorInput.php b/app/src/Agents/Calculator/PythonCalculatorInput.php new file mode 100644 index 0000000..b56ec90 --- /dev/null +++ b/app/src/Agents/Calculator/PythonCalculatorInput.php @@ -0,0 +1,21 @@ + + */ + #[Field(title: 'Numbers', description: 'An array of numbers to perform the operation on')] + public array $numbers, + ) {} +} diff --git a/app/src/Agents/Calculator/PythonCalculatorTool.php b/app/src/Agents/Calculator/PythonCalculatorTool.php new file mode 100644 index 0000000..d843fee --- /dev/null +++ b/app/src/Agents/Calculator/PythonCalculatorTool.php @@ -0,0 +1,55 @@ +executor instanceof ExecutorInterface) { + throw new \RuntimeException('Executor is not set for the tool'); + } + + return $this->executor->execute( + \sprintf(self::CODE, \json_encode($input)), + $input, + ); + } + + public function setExecutor(ExecutorInterface $executor): static + { + $this->executor = $executor; + + return $this; + } +} diff --git a/app/src/Application/Bootloader/AgentsBootloader.php b/app/src/Application/Bootloader/AgentsBootloader.php index d93902a..120e319 100644 --- a/app/src/Application/Bootloader/AgentsBootloader.php +++ b/app/src/Application/Bootloader/AgentsBootloader.php @@ -5,6 +5,7 @@ namespace App\Application\Bootloader; use App\Application\AgentsLocator; +use App\Application\PythonExecutor; use App\Application\ToolsLocator; use App\Domain\Chat\ChatHistoryRepositoryInterface; use App\Domain\Chat\ChatServiceInterface; @@ -21,6 +22,8 @@ use LLM\Agents\OpenAI\Client\ContextFactory; use LLM\Agents\OpenAI\Client\OptionsFactory; use LLM\Agents\Tool\SchemaMapperInterface; +use LLM\Agents\Tool\ToolExecutor; +use LLM\Agents\Tool\ToolLanguage; use LLM\Agents\Tool\ToolRegistry; use LLM\Agents\Tool\ToolRegistryInterface; use LLM\Agents\Tool\ToolRepositoryInterface; @@ -37,6 +40,8 @@ public function defineSingletons(): array ToolRegistryInterface::class => ToolRegistry::class, ToolRepositoryInterface::class => ToolRegistry::class, + ToolExecutor::class => ToolExecutor::class, + AgentRegistry::class => AgentRegistry::class, AgentRegistryInterface::class => AgentRegistry::class, AgentRepositoryInterface::class => AgentRegistry::class, @@ -62,7 +67,11 @@ public function init( TokenizerListenerRegistryInterface $listenerRegistry, ToolsLocator $toolsLocator, AgentsLocator $agentsLocator, + ToolExecutor $toolExecutor, + PythonExecutor $pythonExecutor, ): void { + $toolExecutor->register(ToolLanguage::Python, $pythonExecutor); + $listenerRegistry->addListener($agentsLocator); $listenerRegistry->addListener($toolsLocator); } diff --git a/app/src/Application/PythonExecutor.php b/app/src/Application/PythonExecutor.php new file mode 100644 index 0000000..a96f820 --- /dev/null +++ b/app/src/Application/PythonExecutor.php @@ -0,0 +1,38 @@ +files->ensureDirectory($dir = $this->dirs->get('runtime') . 'python'); + + $dir = \realpath($dir); + $file = $dir . '/' . md5(\microtime()) . '.py'; + + $this->files->write($file, $code); + + try { + $output = \shell_exec(\sprintf('%s %s', $this->pythonPath, $file)); + } finally { + $this->files->delete($file); + } + + return \trim($output); + } +}