Download the PHP package noah-medra/prompt-builder without Composer
On this page you can find all versions of the php package noah-medra/prompt-builder. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download noah-medra/prompt-builder
More information about noah-medra/prompt-builder
Files in noah-medra/prompt-builder
Package prompt-builder
Short Description Compose and execute structured AI prompts in PHP with a fluent, framework-agnostic API (Laravel-friendly).
License MIT
Rated 1.00 based on 1 reviews
Informations about the package prompt-builder
PromptBuilder
PromptBuilder composes structured AI prompts with a fluent, query-builder-style API and executes them against an LLM (Ollama today). Its defining idea is a clean split between three concerns, so you can build a prompt once and render it however your target model prefers, in whatever language you want, and send it through whichever driver you like:
- ๐งฉ Composable โ persona, context, instructions (
must/mustNot), few-shot examples, nested sub-instructions,{param}interpolation, conditionals. - ๐จ๏ธ Multi-format rendering โ plain text, chat messages, or XML from the same spec.
- ๐ Localizable โ section labels in 6 languages (English default), pluggable.
- ๐ง Conversation memory โ pluggable history stores (in-memory or Laravel cache).
- ๐ Driver-based execution โ framework-agnostic (Guzzle) or Laravel-native.
- ๐งช Framework-free core โ compose and render with zero Laravel required; the Laravel bits (facade, cache history, translator bridge) are strictly opt-in.
Contents
- Quick start
- Architecture
- Language (i18n)
- Conversation history
- Testing
Requirements
- PHP 8.1+
guzzlehttp/guzzle^7(installed automatically) for the standalone driver- Laravel is optional. When used inside an app,
illuminate/support^10 | ^11 | ^12is supported โ needed only for the facade, the Laravel driver, the cache history store and the translator bridge.
Installation
This is a library:
composer.lockandvendor/are intentionally not shipped with the source. Your application resolves the dependency against its own lock.
Quick start
toPrompt() above prints:
A runnable, network-free demo lives in examples/basic-usage.php.
Architecture
Each layer has one job and never reaches into the next. That's what lets you unit test composition in isolation, render the same prompt differently per model, and swap execution backends.
| Layer | Classes | Responsibility |
|---|---|---|
| Compose | PromptBuilder โ PromptSpec, Instructions\Instruction, Examples\Example |
Build the prompt as plain data. Pure, no I/O, no framework. |
| Render | Rendering\RendererInterface โ TextRenderer, ChatMessagesRenderer, XmlRenderer |
Turn a PromptSpec into a string or chat-message array. Pure and localizable. |
| Execute | Drivers\PromptDriverInterface โ Drivers\OllamaDriver, Drivers\Laravel\OllamaDriver |
Render the spec and send it to a model. The only layer that does I/O. |
PromptSpec is the hand-off: the builder fills it, a renderer reads it, a driver
sends it. You can grab it directly with getSpec() for full control.
Composition
Every method below only mutates the internal PromptSpec โ no I/O, no driver.
| Method | Purpose |
|---|---|
persona(string) |
Who the model should act as |
context(string) |
Background information |
instruction(string, ?Closure) |
A neutral instruction (optionally with nested sub-instructions) |
must(string, ?Closure) |
A positive constraint, rendered with a [Required] marker |
mustNot(string, ?Closure) |
A negative constraint, rendered with a [Forbidden] marker |
example(string $input, string $output) |
A few-shot input/output pair |
expectResponseFormat(string $json) |
Ask for a specific JSON output shape (throws if the sample isn't valid JSON) |
withParams(array) / setParams(array) |
Values for {placeholder} interpolation |
language(string) / locale(string) |
Language of the rendered labels (default English) |
ask(string) |
The actual question |
when(bool, Closure $ifTrue, ?Closure $ifFalse) |
Conditional composition |
getSpec() |
Escape hatch to the raw PromptSpec |
Nested instructions
instruction(), must() and mustNot() accept a closure to add nested
sub-instructions. Each ->add() appends a sibling at the same depth; pass a
closure to add() to go one level deeper.
Parameter interpolation
Any text you pass supports {key} and {nested.key} placeholders, resolved from
withParams(). Unknown placeholders are left untouched (not silently emptied)
so typos are easy to spot.
Conditionals
Structured JSON output
Adds an explicit "answer only with valid JSON matching this shape" instruction to the rendered prompt, and validates that the sample you pass is itself valid JSON (throwing otherwise).
Rendering
toPrompt() renders the composed prompt so you can iterate on quality for free.
It defaults to TextRenderer; pass any renderer to get a different shape.
| Renderer | Output | Use for |
|---|---|---|
TextRenderer |
Single string with # Role, # Context, โฆ sections |
Completion-style APIs, previews |
ChatMessagesRenderer |
{role, content} message array (system + history + question) |
Chat APIs (Ollama /api/chat, OpenAI, Anthropic) |
XmlRenderer |
Well-formed, escaped XML with explicit tags | Models that follow XML-delimited structure better |
Write your own by implementing Rendering\RendererInterface โ it receives a
PromptSpec and returns a string or a {role, content} array.
Language (i18n)
The section labels the renderer emits (# Role, [Required], Example n:, the
JSON-output instruction, โฆ) are localized. English is the default; pick another
language per builder:
Bundled locales: en (default), es, fr, de, zh, ar. An unknown
locale, or a key missing in a locale, falls back to English. Only the labels are
translated โ your persona/context/instruction text is emitted verbatim, and
XmlRenderer tag names stay English on purpose (they're structural).
Translation goes through a framework-free Translation\TranslatorInterface. The
default Translation\ArrayTranslator reads bundled PHP language files with no
framework. Point it at your own directory, or implement the interface for full
control:
Using Laravel's translator
Inside Laravel, the service provider registers the bundled strings under the
promptbuilder translation namespace. Publish them to customize:
Then render through Laravel's translator (which follows the app locale and any
overrides you published) with Translation\Laravel\LaravelTranslator:
Execution
If you call process() without setting a driver, the standalone
Drivers\OllamaDriver is used by default.
BuilderOutput decodes JSON responses and lets you pluck values with dotted
paths, or grab the raw body:
Choosing an Ollama driver
Two interchangeable implementations ship with the package:
| Driver | Built on | Use when |
|---|---|---|
Drivers\OllamaDriver |
Guzzle directly | You want a framework-agnostic driver that works in any PHP script, no booted Laravel app. This is the default. Accepts an injectable Guzzle client for testing. |
Drivers\Laravel\OllamaDriver |
Laravel Http facade |
You're already in a Laravel app and want Http::fake() in your tests. Requires a booted application. |
Both accept model, endpoint, a renderer, and a timeoutSeconds:
Writing a custom driver
Implement Drivers\PromptDriverInterface. A driver receives a PromptSpec
directly (never a pre-rendered string) and picks its own renderer:
Conversation history
Call useHistory() to enable multi-turn memory. Prior turns are loaded into the
prompt, and process() appends this turn's question and the model's reply back
into the store โ so the next builder using the same store sees the full exchange.
| Store | Persistence | Notes |
|---|---|---|
History\InMemoryHistoryStore |
Process lifetime | Default, framework-free |
History\Laravel\CacheHistoryStore |
Across requests, via the Laravel cache | Pass a conversation id: new CacheHistoryStore('conv-42') |
Implement History\HistoryStoreInterface (all(), push(), clear()) for a
custom backend. You can also seed turns manually with
setHistory([['role' => 'user', 'content' => 'โฆ']]).
Laravel integration
Everything above works without Laravel. When you are in a Laravel app, these
opt-in conveniences light up automatically via package auto-discovery
(PromptBuilderServiceProvider):
- Facade โ
'promptbuilder'is bound in the container; eachPromptBuilder::make()returns a fresh, isolated builder. - Translations โ bundled strings are registered under the
promptbuildernamespace and publishable (--tag=promptbuilder-lang). - Laravel-native pieces โ
Drivers\Laravel\OllamaDriver,History\Laravel\CacheHistoryStore,Translation\Laravel\LaravelTranslator.
Testing
The Unit suite covers the framework-free core (composition, every renderer,
translation, history) with plain PHPUnit. The Feature suite uses Orchestra
Testbench to boot a real Laravel app for the facade, the Laravel driver (via
Http::fake()), the cache history store and the translator bridge. The
framework-agnostic Ollama driver is tested with a Guzzle MockHandler, asserting
the composed prompt is really what gets sent.
License
Released under the MIT License โ see LICENCE.txt.
All versions of prompt-builder with dependencies
illuminate/support Version ^10.0 || ^11.0 || ^12.0
guzzlehttp/guzzle Version ^7.0