Fluent API & Execution
v1.0.0Learn how to assemble decision pipelines using DecisionRequest, state context data, and handle typed DecisionResponse outputs in Laravel.
Fluent API & Execution
The Obelaw SystemOne fluent API provides an expressive, chainable interface for composing AI decision requests. Rather than orchestrating multiple HTTP calls or crafting fragile prompt strings, you define application state once and query multiple primitives simultaneously.
The SystemOne Facade
The primary entry point is the SystemOne facade (Obelaw\SystemOne\Facades\SystemOne):
use Obelaw\SystemOne\Facades\SystemOne;
// Initialize request with state
$request = SystemOne::state($context);
// Or initialize an empty request builder
$request = SystemOne::request();
Behind the facade is the SystemOneManager, which handles driver resolution, extensions, and lifecycle management.
Assembling a DecisionRequest
A DecisionRequest contains three core components:
- State: The context data evaluated by the decision engine.
- Questions: One or more registered decision primitives.
- Execution Options: Optional driver and model overrides.
flowchart TD
subgraph Request["DecisionRequest Builder"]
State["1. State Context<br/>String | Array | Eloquent Model (Arrayable)"]
Questions["2. Questions Registry<br/>->ask('key', Noul | Choice | Score)"]
Options["3. Driver & Model Overrides<br/>->driver('...') | ->model('...')"]
end
Request --> Run["->run() / ->decide()"]
Run --> Manager["SystemOneManager<br/>Driver Resolution"]
Manager --> Response["DecisionResponse<br/>Helper methods: value(), confidence(), isPositive()"]
1. Setting State Context
State can be provided as a string, an associative array, or any object implementing Laravel’s Arrayable contract (including Eloquent models):
String Context
SystemOne::state('User IP changed from US to DE within 4 minutes. Failed password twice.')
Array Context
SystemOne::state([
'user_id' => 8421,
'account_age_days' => 2,
'order_total' => 1450.00,
'shipping_country' => 'NG',
'billing_country' => 'US',
'card_country' => 'US',
'ip_proxy_detected' => true,
])
Eloquent Model Context
$ticket = SupportTicket::with('messages', 'customer')->findOrFail($id);
// Automatically serialized via Arrayable::toArray()
SystemOne::state($ticket)
2. Adding Decision Questions
You can chain questions sequentially with ask() or provide them in bulk:
use Obelaw\SystemOne\Primitives\Noul;
use Obelaw\SystemOne\Primitives\Choice;
use Obelaw\SystemOne\Primitives\Score;
$request = SystemOne::state($order)
->ask('is_fraudulent', Noul::make('Is this order fraudulent?'))
->ask('risk_tier', Choice::make('Assign risk category', [
'low' => 'Normal consumer order',
'medium' => 'Suspicious mismatch requiring review',
'high' => 'High certainty fraud, block payment',
]))
->ask('chargeback_risk', Score::range('Estimated chargeback probability 0-100', 0, 100));
Bulk Questions Registration
$request->questions([
'is_urgent' => Noul::make('Is this ticket urgent?'),
'topic' => Choice::make('Topic', ['billing', 'shipping', 'returns']),
]);
3. Model & Driver Selection
By default, SystemOne uses the driver configured in config/clef.php. You can override the driver or model dynamically per request:
// Use faster flash model for low-latency triage
$response = SystemOne::state($alert)
->model('clef-flash')
->ask('ping_ok', Noul::make('Is service alive?'))
->run();
// Explicitly target a specific driver
$response = SystemOne::state($payload)
->driver('cloudflare')
->ask('result', Choice::make('Action', ['retry', 'abort']))
->run();
Working with DecisionResponse
Calling ->run() (or its alias ->decide()) executes the request and returns an implementation of Obelaw\SystemOne\Contracts\DecisionResponseInterface.
sequenceDiagram
autonumber
actor App as Laravel Application
participant Builder as DecisionRequest
participant Manager as SystemOneManager
participant Driver as ClefDriver / CustomDriver
participant Edge as Workers AI (Edge)
participant Response as DecisionResponse
App->>Builder: SystemOne::state($context)->ask(...)->run()
Builder->>Manager: Resolve configured driver
Manager->>Driver: decide(DecisionRequest)
Driver->>Edge: HTTPS POST with serialized payload
Edge-->>Driver: JSON response with evaluated answers
Driver->>Response: instantiate DecisionResponse(answers, raw)
Response-->>App: DecisionResponse instance
App->>Response: ->value(), ->confidence(), ->isPositive()
Key Response Methods
| Method | Description | Return Type |
|---|---|---|
value(string $question) | Gets the resolved primitive value (boolean probability, selected choice key, or score number). | mixed |
confidence(string $question) | Returns the driver’s confidence score for the selected answer. | ?float |
probabilities(string $question) | Returns the complete probability distribution across all categories for Choice primitives. | array<string, float> |
isPositive(string $question, float $threshold = 0.5) | Checks if a binary or likelihood value strictly exceeds the given threshold. | bool |
isNegative(string $question, float $threshold = 0.5) | Checks if a binary or likelihood value is below or equal to the given threshold. | bool |
answer(string $question) | Returns the raw structured array representation for a single question. | mixed |
answers() | Returns all parsed answers keyed by question identifier. | array<string, mixed> |
raw() | Returns the complete unmodified response payload from the underlying AI driver. | array<string, mixed> |
toArray() | Converts the response into an array for logging or JSON serialization. | array |
Code Example: Consuming Response
$response = SystemOne::state($customerFeedback)
->ask('sentiment', Choice::make('Customer sentiment', ['positive', 'neutral', 'negative']))
->ask('churn_risk', Noul::make('Is customer expressing cancellation intent?'))
->ask('satisfaction_score', Score::range('Satisfaction rating 1 to 10', 1, 10))
->run();
// 1. Reading Choice
$sentiment = $response->value('sentiment'); // "negative"
$sentimentConfidence = $response->confidence('sentiment'); // 0.94
$allSentimentProbs = $response->probabilities('sentiment');
// ['positive' => 0.02, 'neutral' => 0.04, 'negative' => 0.94]
// 2. Reading Noul
if ($response->isPositive('churn_risk', threshold: 0.70)) {
Notification::route('slack', '#customer-success')
->notify(new ChurnAlert($customer, $response->value('churn_risk')));
}
// 3. Reading Score
$score = $response->value('satisfaction_score'); // 2.3
Real-World Case Study: Automated RMA Authorization
Here is a full example illustrating an automated warranty and return evaluation in an e-commerce store:
flowchart TD
RMA["ReturnRequest (RMA)<br/>Product info, delivery age, customer return history"] --> Context["Construct State Array Context"]
Context --> Engine["SystemOne Multi-Question Request<br/>1. eligible_policy (Noul)<br/>2. decision (Choice: auto_approve | manual_review | auto_reject)<br/>3. fraud_score (Score: 1-100)"]
Engine --> Run["->run() Edge Evaluation"]
Run --> Check{"eligible_policy > 0.5 &&<br/>decision == 'auto_approve'?"}
Check -- Yes --> Approve["rma->approve()<br/>Generate Prepaid Return Shipping Label"]
Check -- No --> Review["rma->escalateToAgent()<br/>Route to Human Specialist with Decision & Fraud Score"]
namespace App\Services;
use App\Models\ReturnRequest;
use Obelaw\SystemOne\Facades\SystemOne;
use Obelaw\SystemOne\Primitives\Choice;
use Obelaw\SystemOne\Primitives\Noul;
use Obelaw\SystemOne\Primitives\Score;
class ReturnAuthorizationService
{
public function evaluate(ReturnRequest $rma): void
{
$context = [
'item_title' => $rma->orderItem->product->title,
'days_since_delivery' => $rma->order->delivered_at->diffInDays(now()),
'customer_return_count_past_year' => $rma->customer->returns()->where('created_at', '>=', now()->subYear())->count(),
'customer_reason' => $rma->reason_description,
'image_labels' => $rma->photo_analysis_labels, // from vision analyzer
];
$decision = SystemOne::state($context)
->ask('eligible_policy', Noul::make('Does this item qualify within standard 30-day return policy?'))
->ask('decision', Choice::make('RMA disposition action', [
'auto_approve' => 'Approve instantly and issue return shipping label',
'manual_review' => 'Flag for warehouse technician manual review',
'auto_reject' => 'Decline request based on policy violation',
]))
->ask('fraud_score', Score::range('Abuse and warranty fraud risk 1-100', 1, 100))
->run();
$rma->update([
'ai_evaluation' => $decision->toArray(),
'fraud_risk_score' => $decision->value('fraud_score'),
]);
if ($decision->isPositive('eligible_policy') && $decision->value('decision') === 'auto_approve') {
$rma->approve();
$rma->generatePrepaidLabel();
} else {
$rma->escalateToAgent(reason: "SystemOne Disposition: {$decision->value('decision')}");
}
}
}
Next Steps
- Configure edge inference using the Cloudflare Clef Driver.
- Write automated tests with zero API costs in Testing & Mocking.