diff --git a/examples/chat-system-prompt.php b/examples/chat-system-prompt.php new file mode 100755 index 0000000..81b71ec --- /dev/null +++ b/examples/chat-system-prompt.php @@ -0,0 +1,28 @@ +loadEnv(dirname(__DIR__).'/.env'); + +if (empty($_ENV['OPENAI_API_KEY'])) { + echo 'Please set the OPENAI_API_KEY environment variable.'.PHP_EOL; + exit(1); +} + +$platform = PlatformFactory::create($_ENV['OPENAI_API_KEY']); +$llm = new GPT(GPT::GPT_4O_MINI); + +$processor = new SystemPromptInputProcessor('You are Yoda and write like he speaks. But short.'); + +$chain = new Chain($platform, $llm, [$processor]); +$messages = new MessageBag(Message::ofUser('What is the meaning of life?')); +$response = $chain->call($messages); + +echo $response->getContent().PHP_EOL; diff --git a/src/Chain/LlmOverrideInputProcessor.php b/src/Chain/InputProcessor/LlmOverrideInputProcessor.php similarity index 83% rename from src/Chain/LlmOverrideInputProcessor.php rename to src/Chain/InputProcessor/LlmOverrideInputProcessor.php index 83241e3..0d50957 100644 --- a/src/Chain/LlmOverrideInputProcessor.php +++ b/src/Chain/InputProcessor/LlmOverrideInputProcessor.php @@ -2,8 +2,10 @@ declare(strict_types=1); -namespace PhpLlm\LlmChain\Chain; +namespace PhpLlm\LlmChain\Chain\InputProcessor; +use PhpLlm\LlmChain\Chain\Input; +use PhpLlm\LlmChain\Chain\InputProcessor; use PhpLlm\LlmChain\Exception\InvalidArgumentException; use PhpLlm\LlmChain\Model\LanguageModel; diff --git a/src/Chain/InputProcessor/SystemPromptInputProcessor.php b/src/Chain/InputProcessor/SystemPromptInputProcessor.php new file mode 100644 index 0000000..1d0058d --- /dev/null +++ b/src/Chain/InputProcessor/SystemPromptInputProcessor.php @@ -0,0 +1,33 @@ +messages; + + if (null !== $messages->getSystemMessage()) { + $this->logger->debug('Skipping system prompt injection since MessageBag already contains a system message.'); + + return; + } + + $input->messages = $messages->prepend(Message::forSystem($this->systemPrompt)); + } +} diff --git a/src/Exception/ToolBoxException.php b/src/Exception/ToolBoxException.php index 5bcbba7..0c87561 100644 --- a/src/Exception/ToolBoxException.php +++ b/src/Exception/ToolBoxException.php @@ -8,7 +8,7 @@ final class ToolBoxException extends RuntimeException { - public ?ToolCall $toolCall; + public ?ToolCall $toolCall = null; public static function notFoundForToolCall(ToolCall $toolCall): self { diff --git a/tests/Chain/LlmOverrideInputProcessorTest.php b/tests/Chain/InputProcessor/LlmOverrideInputProcessorTest.php similarity index 93% rename from tests/Chain/LlmOverrideInputProcessorTest.php rename to tests/Chain/InputProcessor/LlmOverrideInputProcessorTest.php index 84476cb..6ea0991 100644 --- a/tests/Chain/LlmOverrideInputProcessorTest.php +++ b/tests/Chain/InputProcessor/LlmOverrideInputProcessorTest.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace PhpLlm\LlmChain\Tests\Chain; +namespace PhpLlm\LlmChain\Tests\Chain\InputProcessor; use PhpLlm\LlmChain\Bridge\Anthropic\Claude; use PhpLlm\LlmChain\Bridge\OpenAI\Embeddings; use PhpLlm\LlmChain\Bridge\OpenAI\GPT; use PhpLlm\LlmChain\Chain\Input; -use PhpLlm\LlmChain\Chain\LlmOverrideInputProcessor; +use PhpLlm\LlmChain\Chain\InputProcessor\LlmOverrideInputProcessor; use PhpLlm\LlmChain\Exception\InvalidArgumentException; use PhpLlm\LlmChain\Model\Message\MessageBag; use PHPUnit\Framework\Attributes\CoversClass; diff --git a/tests/Chain/InputProcessor/SystemPromptInputProcessorTest.php b/tests/Chain/InputProcessor/SystemPromptInputProcessorTest.php new file mode 100644 index 0000000..ce6b589 --- /dev/null +++ b/tests/Chain/InputProcessor/SystemPromptInputProcessorTest.php @@ -0,0 +1,60 @@ +processInput($input); + + $messages = $input->messages->getMessages(); + self::assertCount(2, $messages); + self::assertInstanceOf(SystemMessage::class, $messages[0]); + self::assertInstanceOf(UserMessage::class, $messages[1]); + self::assertSame('This is a system prompt', $messages[0]->content); + } + + #[Test] + public function processInputDoesNotAddSystemMessageWhenOneExists(): void + { + $processor = new SystemPromptInputProcessor('This is a system prompt'); + + $messages = new MessageBag( + Message::forSystem('This is already a system prompt'), + Message::ofUser('This is a user message'), + ); + $input = new Input(new GPT(), $messages, []); + $processor->processInput($input); + + $messages = $input->messages->getMessages(); + self::assertCount(2, $messages); + self::assertInstanceOf(SystemMessage::class, $messages[0]); + self::assertInstanceOf(UserMessage::class, $messages[1]); + self::assertSame('This is already a system prompt', $messages[0]->content); + } +}