Read Afia AI credentials from platform admin settings.
Deploy Ladill Link / deploy (push) Successful in 58s

Link Afia now resolves provider, model, and API keys from ladilldb.platform_settings like the monolith, with .env fallbacks for local dev.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-06-27 14:34:43 +00:00
co-authored by Cursor
parent 5a3631cd2e
commit 29993040bd
7 changed files with 159 additions and 5 deletions
+6 -4
View File
@@ -10,9 +10,11 @@ use RuntimeException;
*/
class AfiaService
{
public function __construct(private PlatformAiConfig $ai) {}
public function enabled(): bool
{
return (bool) config('afia.enabled', true) && (string) config('afia.api_key', '') !== '';
return $this->ai->enabled();
}
/**
@@ -25,9 +27,9 @@ class AfiaService
throw new RuntimeException('Afia is not configured.');
}
$provider = (string) config('afia.provider', 'openai');
$model = (string) config('afia.model', 'gpt-4o-mini');
$apiKey = (string) config('afia.api_key');
$provider = $this->ai->provider();
$model = $this->ai->model();
$apiKey = $this->ai->apiKey();
$messages = [['role' => 'system', 'content' => $this->systemPrompt($context)]];
foreach (array_slice($history, -8) as $turn) {
+90
View File
@@ -0,0 +1,90 @@
<?php
namespace App\Services\Afia;
use App\Models\PlatformSetting;
use Illuminate\Support\Facades\Schema;
/**
* Resolves AI credentials from ladilldb.platform_settings (admin Platform settings)
* with .env fallbacks for local/dev.
*/
class PlatformAiConfig
{
/** @var array<string, mixed> */
private array $cache = [];
public function enabled(): bool
{
$platformFlag = $this->setting('ai_enabled');
if ($platformFlag !== null && ! filter_var($platformFlag, FILTER_VALIDATE_BOOLEAN)) {
return false;
}
if (! (bool) config('afia.enabled', true)) {
return false;
}
return $this->apiKey() !== '';
}
public function provider(): string
{
$provider = strtolower(trim((string) ($this->setting('ai_provider') ?? config('afia.provider', 'openai'))));
return in_array($provider, ['openai', 'anthropic'], true) ? $provider : 'openai';
}
public function model(): string
{
$configured = trim((string) ($this->setting('ai_model') ?? config('afia.model', '')));
if ($configured !== '') {
return $configured;
}
return $this->provider() === 'anthropic' ? 'claude-3-5-haiku-latest' : 'gpt-4o-mini';
}
public function apiKey(): string
{
$provider = $this->provider();
$providerKey = match ($provider) {
'anthropic' => trim((string) ($this->setting('ai_anthropic_api_key') ?? '')),
default => trim((string) ($this->setting('ai_openai_api_key') ?? '')),
};
if ($providerKey !== '') {
return $providerKey;
}
$shared = trim((string) ($this->setting('ai_api_key') ?? ''));
if ($shared !== '') {
return $shared;
}
return trim((string) config('afia.api_key', ''));
}
private function setting(string $key): mixed
{
if (array_key_exists($key, $this->cache)) {
return $this->cache[$key];
}
try {
if (! Schema::connection('platform')->hasTable('platform_settings')) {
return $this->cache[$key] = null;
}
$setting = PlatformSetting::query()
->where('key', $key)
->where('is_active', true)
->first();
return $this->cache[$key] = $setting ? ($setting->value['value'] ?? null) : null;
} catch (\Throwable) {
return $this->cache[$key] = null;
}
}
}
+1 -1
View File
@@ -71,7 +71,7 @@ class PaystackService
protected function settingValue(string $key, mixed $fallback = null): mixed
{
try {
if (!Schema::hasTable('platform_settings')) {
if (! Schema::connection('platform')->hasTable('platform_settings')) {
return $fallback;
}