mirror of
https://github.com/InvoiceShelf/InvoiceShelf.git
synced 2026-07-17 06:15:20 +00:00
refactor(ai): move chat + text-gen prompts into resources/ai/prompts/
Extracts the two inline LLM prompts (AiAssistantService's chat system
prompt and AiTextGenerationService's writing preamble) out of PHP
heredocs and into plain-markdown template files under resources/ai/
prompts/. Each file can now be edited without opening a service
class, without wrestling with PHP string interpolation, and with
proper markdown syntax highlighting in editors.
A tiny PromptLoader helper at app/Support/Ai/PromptLoader.php reads
the file and does {{placeholder}} substitution via strtr() — no
Blade, because Blade's {{ $var }} HTML-escapes ampersands and quotes,
which is wrong for LLM prompts (a company called "Smith & Co" would
be sent as "Smith & Co"). Missing templates throw RuntimeException
so they fail loud during development.
Pure refactor: no prompt wording changes. Existing AI feature tests
(AiChatFlowTest, AiGenerationTest) pass unchanged — they assert on
message structure via ScriptedAiDriver, not on prompt content. Three
new unit tests in PromptLoaderTest lock the helper's contract:
placeholder substitution, no-var loading, missing-file error.
This commit is contained in:
36
tests/Unit/PromptLoaderTest.php
Normal file
36
tests/Unit/PromptLoaderTest.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
use App\Support\Ai\PromptLoader;
|
||||
|
||||
test('load substitutes placeholders in the chat-system template', function () {
|
||||
$prompt = PromptLoader::load('chat-system', [
|
||||
'user_name' => 'Jane Doe',
|
||||
'company_name' => 'Acme Corp',
|
||||
'today' => '2026-04-11',
|
||||
]);
|
||||
|
||||
// Substituted values present
|
||||
expect($prompt)->toContain('Jane Doe');
|
||||
expect($prompt)->toContain('Acme Corp');
|
||||
expect($prompt)->toContain('2026-04-11');
|
||||
|
||||
// Raw placeholders are gone
|
||||
expect($prompt)->not->toContain('{{user_name}}');
|
||||
expect($prompt)->not->toContain('{{company_name}}');
|
||||
expect($prompt)->not->toContain('{{today}}');
|
||||
});
|
||||
|
||||
test('load returns a trimmed template when no placeholders are provided', function () {
|
||||
$prompt = PromptLoader::load('text-generation');
|
||||
|
||||
expect($prompt)->not->toBe('');
|
||||
// No leading/trailing whitespace — trim() stripped the trailing newline.
|
||||
expect($prompt)->toBe(trim($prompt));
|
||||
// Sanity-check a word known to appear in the preamble.
|
||||
expect($prompt)->toContain('writing assistant');
|
||||
});
|
||||
|
||||
test('load throws when the template file is missing', function () {
|
||||
expect(fn () => PromptLoader::load('definitely-not-a-real-prompt'))
|
||||
->toThrow(RuntimeException::class, 'Missing AI prompt template: definitely-not-a-real-prompt');
|
||||
});
|
||||
Reference in New Issue
Block a user