Forms - v1.3.0
Smart Field Validation Agent
The SmartFieldValidationAgent performs an opt-in semantic plausibility check on a single form field value. It complements format-level validation (required, length, regex) — it never replaces it.
- Class:
ArtisanPackUI\Forms\Ai\Agents\SmartFieldValidationAgent - Feature key:
forms.smart_validation - Default model:
claude-haiku-4-5 - Livewire trigger:
forms::ai-smart-field-validator
When to Use It
Format validation catches "not an email" and "too short." Semantic validation catches:
- Company name =
"asdfasdf"or profanity - Address =
"123 Fake St"or obvious jokes - Full name =
"TEST"or a URL - Phone =
555-555-5555or sequential digits - Email that's format-valid but points at
test@test.test
Wire it into an admin verification workflow, or into the form renderer as an on-blur check for high-signal fields.
Input
[
'field_label' => 'Company', // required — human-readable label
'field_kind' => 'company_name', // required — semantic kind: address, email, phone, etc.
'value' => 'Anthropic', // required — submitted value
'context' => [ // optional — sibling fields for cross-checks
'website' => 'https://anthropic.com',
],
]
field_kind values the shipped prompt recognizes:
| Kind | What the agent looks for |
|---|---|
address |
Real street pattern, real city/state where obvious; rejects "123 Fake St". |
company_name |
Real business name; rejects random strings, profanity. |
full_name |
Plausible human name in any language; rejects "asdfasdf", URLs, "TEST". |
email |
Real-looking address even when format-valid; flags test@test.test. |
phone |
Rejects obvious fakes (555-555-5555, 000-000-0000, sequential digits). |
Custom kinds are supported — the model interprets the field label + kind in context. Keep the kind short and descriptive.
Output
[
'plausible' => true, // bool
'confidence' => 0.9, // float 0-1
'reason' => 'recognizable single-word brand name', // <= 200 chars
'suggestion' => 'ask the user to re-enter the address', // OPTIONAL, only when plausible=false
]
The agent's normalizePlausible() handles the model returning the boolean as a string — "false" / "0" / "no" / "off" all map to false, so a tool-bridge coercion of the JSON enum can't silently flip the verdict.
Usage — Livewire
<livewire:forms::ai-smart-field-validator
field-name="address"
field-label="Business Address"
field-kind="address"
:value="$address"
:context="[
'city' => $city,
'state' => $state,
]"
/>
Emits forms-ai-field-verdict with camelCase payload { fieldName, plausible, confidence, reason }:
#[On('forms-ai-field-verdict')]
public function onFieldVerdict(
string $fieldName,
bool $plausible,
float $confidence,
string $reason,
): void {
if (! $plausible && $confidence > 0.7) {
// High-confidence rejection — surface a warning to the user.
}
}
The component holds $value and $context as #[Locked]. Multi-tenant admins should scope inputs to the current viewer.
Usage — Direct Call
use ArtisanPackUI\Forms\Ai\Agents\SmartFieldValidationAgent;
$result = SmartFieldValidationAgent::for([
'field_label' => 'Business Address',
'field_kind' => 'address',
'value' => $submission->data['address'],
'context' => [
'city' => $submission->data['city'],
'state' => $submission->data['state'],
],
])->run();
if (! $result['plausible']) {
$submission->update([
'address_verified' => false,
'address_reason' => $result['reason'],
]);
}
Behavior Invariants
The agent's validateOutput() enforces:
plausiblenormalized to strict bool vianormalizePlausible()— string forms are handled explicitly.confidenceclamped to[0.0, 1.0].reasontrimmed and capped at 200 characters.suggestionis only kept whenplausible=false. Any suggestion the model emits for a plausible value is stripped.
normalizeInput() requires field_label, field_kind, and value to all be non-empty strings — use SmartFieldValidationAgent only on fields that already passed format validation.
Related
- Spam Detection - Whole-submission spam score
- AI Configuration - Credentials, per-feature overrides, cache
- Feature Toggles - Turn the agent on / off