From 1d1ad76620155948a46175526aa6f34f95153880 Mon Sep 17 00:00:00 2001 From: "Ronald A. Richardson" Date: Thu, 2 Jul 2026 14:18:18 +0800 Subject: [PATCH] Release AI runtime availability fix --- addon/components/ai-header-tray-button.js | 2 +- addon/services/ai.js | 13 ++++ package.json | 4 +- pnpm-lock.yaml | 68 +++++++++---------- .../Internal/AiConfigController.php | 10 +++ .../Controllers/Internal/AiTaskController.php | 12 ++++ server/src/routes.php | 1 + 7 files changed, 73 insertions(+), 37 deletions(-) diff --git a/addon/components/ai-header-tray-button.js b/addon/components/ai-header-tray-button.js index f3ce50a..3bc49c1 100644 --- a/addon/components/ai-header-tray-button.js +++ b/addon/components/ai-header-tray-button.js @@ -8,7 +8,7 @@ export default class AiHeaderTrayButtonComponent extends Component { constructor() { super(...arguments); - this.ai.loadConfig.perform(); + this.ai.loadStatus.perform(); } @action togglePrompt() { diff --git a/addon/services/ai.js b/addon/services/ai.js index 88b499f..2001e81 100644 --- a/addon/services/ai.js +++ b/addon/services/ai.js @@ -69,6 +69,19 @@ export default class AiService extends Service { } } + @task *loadStatus() { + try { + const response = yield this.fetch.get('status', {}, { namespace: 'ai/int/v1' }); + this.applyConfig({ enabled: response.enabled === true }); + + return this.config; + } catch (error) { + this.applyConfig({ enabled: false }); + + return this.config; + } + } + @task *submit(prompt, attachments = []) { if (!this.isEnabled) { return null; diff --git a/package.json b/package.json index 55491e0..63c5ca3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@fleetbase/ai-engine", - "version": "0.0.1", + "version": "0.0.2", "description": "Fleetbase AI operations copilot and task automation module", "keywords": [ "fleetbase-extension", @@ -44,7 +44,7 @@ "dependencies": { "@babel/core": "^7.23.2", "@fleetbase/ember-core": "^0.3.24", - "@fleetbase/ember-ui": "^0.3.39", + "@fleetbase/ember-ui": "^0.3.41", "@fortawesome/ember-fontawesome": "^2.0.0", "@fortawesome/fontawesome-svg-core": "6.4.0", "@fortawesome/free-brands-svg-icons": "6.4.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d69bc41..a3407ee 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: ^0.3.24 version: 0.3.24(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(eslint@8.57.1)(webpack@5.105.4) '@fleetbase/ember-ui': - specifier: ^0.3.39 - version: 0.3.39(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(postcss@8.5.8)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.4) + specifier: ^0.3.41 + version: 0.3.41(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(postcss@8.5.8)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.4) '@fortawesome/ember-fontawesome': specifier: ^2.0.0 version: 2.0.0(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(rollup@2.80.0)(webpack@5.105.4) @@ -1292,8 +1292,8 @@ packages: resolution: {integrity: sha512-WG32JlX4S75ofa34RQEMxFEqc20fTv2Qn3A5+NlqXtL0lfnCthdO+a1DrGqIIierthHl3mVTxhe+z63f8sM6EA==} engines: {node: '>= 18'} - '@fleetbase/ember-ui@0.3.39': - resolution: {integrity: sha512-qb8sCq4bfAMq8UGWVlUiXWvRoInmCPqeFu3XDWxUdwJUYR4kGL0lvyO1q2Ej7GcxtiDEnZ4JX+Qp2Tj+TvG3yw==} + '@fleetbase/ember-ui@0.3.41': + resolution: {integrity: sha512-xWWrqHnVj2YW1dfEGC5woLrpPEGx8Z6dstxVZygjt9apf8Vu3goyNnLSdkIdbJS2ACMlg+QuAUV5tPySQuO+3w==} engines: {node: '>= 18'} '@floating-ui/core@1.7.5': @@ -9873,9 +9873,9 @@ snapshots: ember-rfc176-data: 0.3.18 fs-extra: 9.1.0 js-string-escape: 1.0.1 - lodash: 4.17.23 + lodash: 4.18.1 resolve-package-path: 4.0.3 - semver: 7.7.4 + semver: 7.8.5 typescript-memoize: 1.1.1 '@embroider/shared-internals@2.9.2': @@ -10017,7 +10017,7 @@ snapshots: - utf-8-validate - webpack - '@fleetbase/ember-ui@0.3.39(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(postcss@8.5.8)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.4)': + '@fleetbase/ember-ui@0.3.41(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-resolver@11.0.1(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(postcss@8.5.8)(rollup@2.80.0)(tracked-built-ins@3.4.0(@babel/core@7.29.0))(webpack@5.105.4)': dependencies: '@babel/core': 7.29.0 '@ember/render-modifiers': 2.1.0(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)) @@ -10841,7 +10841,7 @@ snapshots: '@types/eslint@9.6.1': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 '@types/json-schema': 7.0.15 '@types/estree@1.0.8': {} @@ -10902,7 +10902,7 @@ snapshots: '@types/minimatch@6.0.0': dependencies: - minimatch: 7.4.9 + minimatch: 10.2.4 '@types/minimist@1.2.5': {} @@ -11410,7 +11410,7 @@ snapshots: convert-source-map: 1.9.0 debug: 2.6.9 json5: 0.5.1 - lodash: 4.17.23 + lodash: 4.18.1 minimatch: 3.1.5 path-is-absolute: 1.0.1 private: 0.1.8 @@ -11426,7 +11426,7 @@ snapshots: babel-types: 6.26.0 detect-indent: 4.0.0 jsesc: 1.3.0 - lodash: 4.17.23 + lodash: 4.18.1 source-map: 0.5.7 trim-right: 1.0.1 @@ -11563,7 +11563,7 @@ snapshots: babel-runtime: 6.26.0 core-js: 2.6.12 home-or-tmp: 2.0.0 - lodash: 4.17.23 + lodash: 4.18.1 mkdirp: 0.5.6 source-map-support: 0.4.18 transitivePeerDependencies: @@ -11580,7 +11580,7 @@ snapshots: babel-traverse: 6.26.0 babel-types: 6.26.0 babylon: 6.18.0 - lodash: 4.17.23 + lodash: 4.18.1 transitivePeerDependencies: - supports-color @@ -11594,7 +11594,7 @@ snapshots: debug: 2.6.9 globals: 9.18.0 invariant: 2.2.4 - lodash: 4.17.23 + lodash: 4.18.1 transitivePeerDependencies: - supports-color @@ -11602,7 +11602,7 @@ snapshots: dependencies: babel-runtime: 6.26.0 esutils: 2.0.3 - lodash: 4.17.23 + lodash: 4.18.1 to-fast-properties: 1.0.3 babel6-plugin-strip-class-callcheck@6.0.0: {} @@ -13097,7 +13097,7 @@ snapshots: ember-animated@1.1.4(@babel/core@7.29.0)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)): dependencies: - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 '@embroider/macros': 1.20.2(@babel/core@7.29.0) '@embroider/util': 1.13.5(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)) assert-never: 1.4.0 @@ -13131,7 +13131,7 @@ snapshots: ember-assign-helper@0.5.1: dependencies: - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 transitivePeerDependencies: - supports-color @@ -13159,11 +13159,11 @@ snapshots: fs-tree-diff: 2.0.1 handlebars: 4.7.9 js-string-escape: 1.0.1 - lodash: 4.17.23 + lodash: 4.18.1 mkdirp: 0.5.6 resolve-package-path: 3.1.0 rimraf: 2.7.1 - semver: 7.7.4 + semver: 7.8.5 symlink-or-copy: 1.3.1 typescript-memoize: 1.1.1 walk-sync: 0.3.4 @@ -13221,12 +13221,12 @@ snapshots: dependencies: '@babel/core': 7.29.0 '@ember/test-helpers': 3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4) - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 '@embroider/macros': 1.20.2(@babel/core@7.29.0) '@embroider/util': 1.13.5(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)) '@glimmer/component': 1.1.2(@babel/core@7.29.0) '@glimmer/tracking': 1.1.2 - decorator-transforms: 2.3.1(@babel/core@7.29.0) + decorator-transforms: 2.4.0(@babel/core@7.29.0) ember-element-helper: 0.8.8 ember-lifeline: 7.0.0(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4)) ember-modifier: 4.3.0(@babel/core@7.29.0) @@ -13965,7 +13965,7 @@ snapshots: ember-element-helper@0.8.8: dependencies: - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 transitivePeerDependencies: - supports-color @@ -14013,8 +14013,8 @@ snapshots: ember-focus-trap@1.2.0(@babel/core@7.29.0): dependencies: - '@embroider/addon-shim': 1.10.2 - decorator-transforms: 2.3.1(@babel/core@7.29.0) + '@embroider/addon-shim': 1.10.3 + decorator-transforms: 2.4.0(@babel/core@7.29.0) focus-trap: 7.8.0 transitivePeerDependencies: - '@babel/core' @@ -14120,7 +14120,7 @@ snapshots: ember-lifeline@7.0.0(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4)): dependencies: - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 optionalDependencies: '@ember/test-helpers': 3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4) transitivePeerDependencies: @@ -14190,8 +14190,8 @@ snapshots: ember-modifier@4.3.0(@babel/core@7.29.0): dependencies: - '@embroider/addon-shim': 1.10.2 - decorator-transforms: 2.3.1(@babel/core@7.29.0) + '@embroider/addon-shim': 1.10.3 + decorator-transforms: 2.4.0(@babel/core@7.29.0) transitivePeerDependencies: - '@babel/core' - supports-color @@ -14230,11 +14230,11 @@ snapshots: ember-power-select@8.6.2(@babel/core@7.29.0)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-basic-dropdown@8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)))(ember-concurrency@4.0.6(@babel/core@7.29.0))(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)): dependencies: '@ember/test-helpers': 3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4) - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 '@embroider/util': 1.13.5(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)) '@glimmer/component': 1.1.2(@babel/core@7.29.0) '@glimmer/tracking': 1.1.2 - decorator-transforms: 2.3.1(@babel/core@7.29.0) + decorator-transforms: 2.4.0(@babel/core@7.29.0) ember-assign-helper: 0.5.1 ember-basic-dropdown: 8.4.0(@ember/string@3.1.1)(@ember/test-helpers@3.3.1(@babel/core@7.29.0)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4))(webpack@5.105.4))(@glimmer/component@1.1.2(@babel/core@7.29.0))(@glimmer/tracking@1.1.2)(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)) ember-concurrency: 4.0.6(@babel/core@7.29.0) @@ -14408,9 +14408,9 @@ snapshots: ember-style-modifier@4.5.1(@babel/core@7.29.0)(@ember/string@3.1.1): dependencies: '@ember/string': 3.1.1 - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 csstype: 3.2.3 - decorator-transforms: 2.3.1(@babel/core@7.29.0) + decorator-transforms: 2.4.0(@babel/core@7.29.0) ember-modifier: 4.3.0(@babel/core@7.29.0) transitivePeerDependencies: - '@babel/core' @@ -14498,7 +14498,7 @@ snapshots: ember-truth-helpers@4.0.3(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)): dependencies: - '@embroider/addon-shim': 1.10.2 + '@embroider/addon-shim': 1.10.3 ember-functions-as-helper-polyfill: 2.1.3(ember-source@5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4)) ember-source: 5.4.1(@babel/core@7.29.0)(@glimmer/component@1.1.2(@babel/core@7.29.0))(rsvp@4.8.5)(webpack@5.105.4) transitivePeerDependencies: @@ -16574,7 +16574,7 @@ snapshots: md5.js@1.3.5: dependencies: - hash-base: 3.0.5 + hash-base: 3.1.2 inherits: 2.0.4 safe-buffer: 5.2.1 @@ -18915,7 +18915,7 @@ snapshots: terser@4.8.1: dependencies: - acorn: 8.16.0 + acorn: 8.17.0 commander: 2.20.3 source-map: 0.6.1 source-map-support: 0.5.21 diff --git a/server/src/Http/Controllers/Internal/AiConfigController.php b/server/src/Http/Controllers/Internal/AiConfigController.php index d453d1e..a9d1eaa 100644 --- a/server/src/Http/Controllers/Internal/AiConfigController.php +++ b/server/src/Http/Controllers/Internal/AiConfigController.php @@ -7,9 +7,19 @@ use Fleetbase\Http\Controllers\Controller; use Fleetbase\Http\Requests\AdminRequest; use Fleetbase\Models\Setting; +use Illuminate\Http\Request; class AiConfigController extends Controller { + public function status(Request $request, AiProviderManager $providers) + { + $config = $providers->normalizeConfig(Setting::system('ai', $providers->defaultConfig())); + + return response()->json([ + 'enabled' => (bool) data_get($config, 'enabled', false), + ]); + } + public function show(AdminRequest $request, AiProviderManager $providers) { $config = $providers->normalizeConfig(Setting::system('ai', $providers->defaultConfig())); diff --git a/server/src/Http/Controllers/Internal/AiTaskController.php b/server/src/Http/Controllers/Internal/AiTaskController.php index cac6fd2..799fdf2 100644 --- a/server/src/Http/Controllers/Internal/AiTaskController.php +++ b/server/src/Http/Controllers/Internal/AiTaskController.php @@ -5,6 +5,7 @@ use Fleetbase\Ai\Models\AiTask; use Fleetbase\Ai\Services\AiTaskService; use Fleetbase\Http\Controllers\Controller; +use Fleetbase\Models\Setting; use Illuminate\Http\Request; class AiTaskController extends Controller @@ -22,6 +23,8 @@ public function index(Request $request) public function store(Request $request, AiTaskService $tasks) { + $this->abortIfAiDisabled(); + $request->validate([ 'prompt' => ['required', 'string', 'max:12000'], 'session_uuid' => ['nullable', 'string'], @@ -39,6 +42,8 @@ public function show(string $id) public function preview(string $id, Request $request, AiTaskService $tasks) { + $this->abortIfAiDisabled(); + $task = $this->findTask($id); return response()->json(['task' => $tasks->refreshPreview($task, $request->input('action_key'), $request->input('input', []))->load('session')]); @@ -46,6 +51,8 @@ public function preview(string $id, Request $request, AiTaskService $tasks) public function apply(string $id, Request $request, AiTaskService $tasks) { + $this->abortIfAiDisabled(); + $task = $this->findTask($id); return response()->json(['task' => $tasks->apply($task, $request->input('action_key'), $request->input('input', []))->load('session')]); @@ -87,4 +94,9 @@ protected function findTask(string $id): AiTask }) ->firstOrFail(); } + + protected function abortIfAiDisabled(): void + { + abort_unless((bool) data_get(Setting::system('ai', []), 'enabled', false), 403, 'Fleetbase AI is disabled.'); + } } diff --git a/server/src/routes.php b/server/src/routes.php index 4da22ef..c91b248 100644 --- a/server/src/routes.php +++ b/server/src/routes.php @@ -27,6 +27,7 @@ function ($router) { $router->group( ['prefix' => 'v1', 'middleware' => ['fleetbase.protected']], function ($router) { + $router->get('status', 'Internal\AiConfigController@status'); $router->get('config', 'Internal\AiConfigController@show'); $router->post('config', 'Internal\AiConfigController@store'); $router->post('test-provider', 'Internal\AiConfigController@testProvider');