diff --git a/.idea/neoban.iml b/.idea/neoban.iml
index 511bbe3..0bca37a 100644
--- a/.idea/neoban.iml
+++ b/.idea/neoban.iml
@@ -6,6 +6,10 @@
+
+
+
+
@@ -27,6 +31,7 @@
+
@@ -43,6 +48,7 @@
+
@@ -102,6 +108,7 @@
+
diff --git a/.idea/php.xml b/.idea/php.xml
index 7e3d2f7..294e22d 100644
--- a/.idea/php.xml
+++ b/.idea/php.xml
@@ -136,6 +136,11 @@
+
+
+
+
+
@@ -144,6 +149,11 @@
+
+
+
+
+
diff --git a/.idea/phpunit.xml b/.idea/phpunit.xml
new file mode 100644
index 0000000..dbd4856
--- /dev/null
+++ b/.idea/phpunit.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/backend/.env.example b/backend/.env.example
index c0660ea..60309a7 100644
--- a/backend/.env.example
+++ b/backend/.env.example
@@ -63,3 +63,18 @@ AWS_BUCKET=
AWS_USE_PATH_STYLE_ENDPOINT=false
VITE_APP_NAME="${APP_NAME}"
+
+ANTHROPIC_API_KEY=
+AZURE_OPENAI_API_KEY=
+COHERE_API_KEY=
+DEEPSEEK_API_KEY=
+ELEVENLABS_API_KEY=
+GEMINI_API_KEY=
+GROQ_API_KEY=
+MISTRAL_API_KEY=
+OLLAMA_API_KEY=
+OPENAI_API_KEY=
+OPENROUTER_API_KEY=
+JINA_API_KEY=
+VOYAGEAI_API_KEY=
+XAI_API_KEY=
diff --git a/backend/composer.json b/backend/composer.json
index 4683afa..699e102 100644
--- a/backend/composer.json
+++ b/backend/composer.json
@@ -10,6 +10,7 @@
"license": "MIT",
"require": {
"php": "^8.3",
+ "laravel/ai": "^0.6.3",
"laravel/framework": "^13.0",
"laravel/sanctum": "^4.0",
"laravel/tinker": "^3.0"
diff --git a/backend/composer.lock b/backend/composer.lock
index d281dde..9c7fe5c 100644
--- a/backend/composer.lock
+++ b/backend/composer.lock
@@ -4,8 +4,159 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "e9b9fcbae4973df88c2a8fcae09e716f",
+ "content-hash": "31337405f959f523455e59893a55ca54",
"packages": [
+ {
+ "name": "aws/aws-crt-php",
+ "version": "v1.2.7",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/awslabs/aws-crt-php.git",
+ "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/awslabs/aws-crt-php/zipball/d71d9906c7bb63a28295447ba12e74723bd3730e",
+ "reference": "d71d9906c7bb63a28295447ba12e74723bd3730e",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=5.5"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^4.8.35||^5.6.3||^9.5",
+ "yoast/phpunit-polyfills": "^1.0"
+ },
+ "suggest": {
+ "ext-awscrt": "Make sure you install awscrt native extension to use any of the functionality."
+ },
+ "type": "library",
+ "autoload": {
+ "classmap": [
+ "src/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "AWS SDK Common Runtime Team",
+ "email": "aws-sdk-common-runtime@amazon.com"
+ }
+ ],
+ "description": "AWS Common Runtime for PHP",
+ "homepage": "https://github.com/awslabs/aws-crt-php",
+ "keywords": [
+ "amazon",
+ "aws",
+ "crt",
+ "sdk"
+ ],
+ "support": {
+ "issues": "https://github.com/awslabs/aws-crt-php/issues",
+ "source": "https://github.com/awslabs/aws-crt-php/tree/v1.2.7"
+ },
+ "time": "2024-10-18T22:15:13+00:00"
+ },
+ {
+ "name": "aws/aws-sdk-php",
+ "version": "3.379.6",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/aws/aws-sdk-php.git",
+ "reference": "587f0bafd28a7dc3395b0c55f93f2474657767e2"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/587f0bafd28a7dc3395b0c55f93f2474657767e2",
+ "reference": "587f0bafd28a7dc3395b0c55f93f2474657767e2",
+ "shasum": ""
+ },
+ "require": {
+ "aws/aws-crt-php": "^1.2.3",
+ "ext-json": "*",
+ "ext-pcre": "*",
+ "ext-simplexml": "*",
+ "guzzlehttp/guzzle": "^7.4.5",
+ "guzzlehttp/promises": "^2.0",
+ "guzzlehttp/psr7": "^2.4.5",
+ "mtdowling/jmespath.php": "^2.8.0",
+ "php": ">=8.1",
+ "psr/http-message": "^1.0 || ^2.0",
+ "symfony/filesystem": "^v5.4.45 || ^v6.4.3 || ^v7.1.0 || ^v8.0.0"
+ },
+ "require-dev": {
+ "andrewsville/php-token-reflection": "^1.4",
+ "aws/aws-php-sns-message-validator": "~1.0",
+ "behat/behat": "~3.0",
+ "composer/composer": "^2.7.8",
+ "dms/phpunit-arraysubset-asserts": "^v0.5.0",
+ "doctrine/cache": "~1.4",
+ "ext-dom": "*",
+ "ext-openssl": "*",
+ "ext-sockets": "*",
+ "phpunit/phpunit": "^10.0",
+ "psr/cache": "^2.0 || ^3.0",
+ "psr/simple-cache": "^2.0 || ^3.0",
+ "sebastian/comparator": "^1.2.3 || ^4.0 || ^5.0",
+ "yoast/phpunit-polyfills": "^2.0"
+ },
+ "suggest": {
+ "aws/aws-php-sns-message-validator": "To validate incoming SNS notifications",
+ "doctrine/cache": "To use the DoctrineCacheAdapter",
+ "ext-curl": "To send requests using cURL",
+ "ext-openssl": "Allows working with CloudFront private distributions and verifying received SNS messages",
+ "ext-pcntl": "To use client-side monitoring",
+ "ext-sockets": "To use client-side monitoring"
+ },
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "3.0-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/functions.php"
+ ],
+ "psr-4": {
+ "Aws\\": "src/"
+ },
+ "exclude-from-classmap": [
+ "src/data/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "Apache-2.0"
+ ],
+ "authors": [
+ {
+ "name": "Amazon Web Services",
+ "homepage": "https://aws.amazon.com"
+ }
+ ],
+ "description": "AWS SDK for PHP - Use Amazon Web Services in your PHP project",
+ "homepage": "https://aws.amazon.com/sdk-for-php",
+ "keywords": [
+ "amazon",
+ "aws",
+ "cloud",
+ "dynamodb",
+ "ec2",
+ "glacier",
+ "s3",
+ "sdk"
+ ],
+ "support": {
+ "forum": "https://github.com/aws/aws-sdk-php/discussions",
+ "issues": "https://github.com/aws/aws-sdk-php/issues",
+ "source": "https://github.com/aws/aws-sdk-php/tree/3.379.6"
+ },
+ "time": "2026-04-23T18:11:11+00:00"
+ },
{
"name": "brick/math",
"version": "0.14.8",
@@ -1053,6 +1204,74 @@
],
"time": "2025-08-22T14:27:06+00:00"
},
+ {
+ "name": "laravel/ai",
+ "version": "v0.6.3",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/laravel/ai.git",
+ "reference": "42cefc32ae2762b6fd1ec0b3c9272e894623b717"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/laravel/ai/zipball/42cefc32ae2762b6fd1ec0b3c9272e894623b717",
+ "reference": "42cefc32ae2762b6fd1ec0b3c9272e894623b717",
+ "shasum": ""
+ },
+ "require": {
+ "aws/aws-sdk-php": "^3.339",
+ "illuminate/console": "^12.0|^13.0",
+ "illuminate/container": "^12.0|^13.0",
+ "illuminate/contracts": "^12.0|^13.0",
+ "illuminate/filesystem": "^12.0|^13.0",
+ "illuminate/json-schema": "^12.0|^13.0",
+ "illuminate/support": "^12.0|^13.0",
+ "laravel/prompts": "^0.3.6",
+ "laravel/serializable-closure": "^2.0",
+ "php": "^8.3"
+ },
+ "require-dev": {
+ "laravel/pint": "^1.26",
+ "mockery/mockery": "^1.6.12",
+ "orchestra/testbench": "^10.6|^11.0",
+ "pestphp/pest": "^3.0|^4.0",
+ "pestphp/pest-plugin-laravel": "^3.0|^4.0"
+ },
+ "type": "library",
+ "extra": {
+ "laravel": {
+ "providers": [
+ "Laravel\\Ai\\AiServiceProvider"
+ ]
+ },
+ "branch-alias": {
+ "dev-master": "1.x-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "functions.php"
+ ],
+ "psr-4": {
+ "Laravel\\Ai\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "description": "The official AI SDK for Laravel.",
+ "homepage": "https://github.com/laravel/ai",
+ "keywords": [
+ "ai",
+ "laravel"
+ ],
+ "support": {
+ "issues": "https://github.com/laravel/ai/issues",
+ "source": "https://github.com/laravel/ai"
+ },
+ "time": "2026-04-22T21:16:19+00:00"
+ },
{
"name": "laravel/framework",
"version": "v13.6.0",
@@ -2190,6 +2409,72 @@
],
"time": "2026-01-02T08:56:05+00:00"
},
+ {
+ "name": "mtdowling/jmespath.php",
+ "version": "2.8.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/jmespath/jmespath.php.git",
+ "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
+ "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc",
+ "shasum": ""
+ },
+ "require": {
+ "php": "^7.2.5 || ^8.0",
+ "symfony/polyfill-mbstring": "^1.17"
+ },
+ "require-dev": {
+ "composer/xdebug-handler": "^3.0.3",
+ "phpunit/phpunit": "^8.5.33"
+ },
+ "bin": [
+ "bin/jp.php"
+ ],
+ "type": "library",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "2.8-dev"
+ }
+ },
+ "autoload": {
+ "files": [
+ "src/JmesPath.php"
+ ],
+ "psr-4": {
+ "JmesPath\\": "src/"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Graham Campbell",
+ "email": "hello@gjcampbell.co.uk",
+ "homepage": "https://github.com/GrahamCampbell"
+ },
+ {
+ "name": "Michael Dowling",
+ "email": "mtdowling@gmail.com",
+ "homepage": "https://github.com/mtdowling"
+ }
+ ],
+ "description": "Declaratively specify how to extract elements from a JSON document",
+ "keywords": [
+ "json",
+ "jsonpath"
+ ],
+ "support": {
+ "issues": "https://github.com/jmespath/jmespath.php/issues",
+ "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0"
+ },
+ "time": "2024-09-04T18:46:31+00:00"
+ },
{
"name": "nesbot/carbon",
"version": "3.11.4",
@@ -3907,6 +4192,76 @@
],
"time": "2024-09-25T14:21:43+00:00"
},
+ {
+ "name": "symfony/filesystem",
+ "version": "v8.0.8",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/symfony/filesystem.git",
+ "reference": "66b769ae743ce2d13e435528fbef4af03d623e5a"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/symfony/filesystem/zipball/66b769ae743ce2d13e435528fbef4af03d623e5a",
+ "reference": "66b769ae743ce2d13e435528fbef4af03d623e5a",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=8.4",
+ "symfony/polyfill-ctype": "~1.8",
+ "symfony/polyfill-mbstring": "~1.8"
+ },
+ "require-dev": {
+ "symfony/process": "^7.4|^8.0"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "Symfony\\Component\\Filesystem\\": ""
+ },
+ "exclude-from-classmap": [
+ "/Tests/"
+ ]
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Fabien Potencier",
+ "email": "fabien@symfony.com"
+ },
+ {
+ "name": "Symfony Community",
+ "homepage": "https://symfony.com/contributors"
+ }
+ ],
+ "description": "Provides basic utilities for the filesystem",
+ "homepage": "https://symfony.com",
+ "support": {
+ "source": "https://github.com/symfony/filesystem/tree/v8.0.8"
+ },
+ "funding": [
+ {
+ "url": "https://symfony.com/sponsor",
+ "type": "custom"
+ },
+ {
+ "url": "https://github.com/fabpot",
+ "type": "github"
+ },
+ {
+ "url": "https://github.com/nicolas-grekas",
+ "type": "github"
+ },
+ {
+ "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
+ "type": "tidelift"
+ }
+ ],
+ "time": "2026-03-30T15:14:47+00:00"
+ },
{
"name": "symfony/finder",
"version": "v8.0.8",
diff --git a/backend/config/ai.php b/backend/config/ai.php
new file mode 100644
index 0000000..8d2443b
--- /dev/null
+++ b/backend/config/ai.php
@@ -0,0 +1,147 @@
+ 'openai',
+ 'default_for_images' => 'gemini',
+ 'default_for_audio' => 'openai',
+ 'default_for_transcription' => 'openai',
+ 'default_for_embeddings' => 'openai',
+ 'default_for_reranking' => 'cohere',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Caching
+ |--------------------------------------------------------------------------
+ |
+ | Below you may configure caching strategies for AI related operations
+ | such as embedding generation. You are free to adjust these values
+ | based on your application's available caching stores and needs.
+ |
+ */
+
+ 'caching' => [
+ 'embeddings' => [
+ 'cache' => false,
+ 'store' => env('CACHE_STORE', 'database'),
+ ],
+ ],
+
+ /*
+ |--------------------------------------------------------------------------
+ | AI Providers
+ |--------------------------------------------------------------------------
+ |
+ | Below are each of your AI providers defined for this application. Each
+ | represents an AI provider and API key combination which can be used
+ | to perform tasks like text, image, and audio creation via agents.
+ |
+ */
+
+ 'providers' => [
+ 'anthropic' => [
+ 'driver' => 'anthropic',
+ 'key' => env('ANTHROPIC_API_KEY'),
+ 'url' => env('ANTHROPIC_URL', 'https://api.anthropic.com/v1'),
+ ],
+
+ 'azure' => [
+ 'driver' => 'azure',
+ 'key' => env('AZURE_OPENAI_API_KEY'),
+ 'url' => env('AZURE_OPENAI_URL'),
+ 'api_version' => env('AZURE_OPENAI_API_VERSION', '2025-04-01-preview'),
+ 'deployment' => env('AZURE_OPENAI_DEPLOYMENT', 'gpt-4o'),
+ 'embedding_deployment' => env('AZURE_OPENAI_EMBEDDING_DEPLOYMENT', 'text-embedding-3-small'),
+ ],
+
+ 'bedrock' => [
+ 'driver' => 'bedrock',
+ 'region' => env('AWS_BEDROCK_REGION', 'us-east-1'),
+ 'key' => env('AWS_BEARER_TOKEN_BEDROCK'),
+ 'access_key_id' => env('AWS_ACCESS_KEY_ID'),
+ 'secret_access_key' => env('AWS_SECRET_ACCESS_KEY'),
+ 'session_token' => env('AWS_SESSION_TOKEN'),
+ 'use_default_credential_provider' => env('AWS_USE_DEFAULT_CREDENTIALS', true),
+ ],
+
+ 'cohere' => [
+ 'driver' => 'cohere',
+ 'key' => env('COHERE_API_KEY'),
+ ],
+
+ 'deepseek' => [
+ 'driver' => 'deepseek',
+ 'key' => env('DEEPSEEK_API_KEY'),
+ 'url' => env('DEEPSEEK_URL', 'https://api.deepseek.com'),
+ ],
+
+ 'eleven' => [
+ 'driver' => 'eleven',
+ 'key' => env('ELEVENLABS_API_KEY'),
+ ],
+
+ 'gemini' => [
+ 'driver' => 'gemini',
+ 'key' => env('GEMINI_API_KEY'),
+ ],
+
+ 'groq' => [
+ 'driver' => 'groq',
+ 'key' => env('GROQ_API_KEY'),
+ 'url' => env('GROQ_URL', 'https://api.groq.com/openai/v1'),
+ ],
+
+ 'jina' => [
+ 'driver' => 'jina',
+ 'key' => env('JINA_API_KEY'),
+ ],
+
+ 'mistral' => [
+ 'driver' => 'mistral',
+ 'key' => env('MISTRAL_API_KEY'),
+ 'url' => env('MISTRAL_URL', 'https://api.mistral.ai/v1'),
+ ],
+
+ 'ollama' => [
+ 'driver' => 'ollama',
+ 'key' => env('OLLAMA_API_KEY', ''),
+ 'url' => env('OLLAMA_URL', 'http://localhost:11434'),
+ ],
+
+ 'openai' => [
+ 'driver' => 'openai',
+ 'key' => env('OPENAI_API_KEY'),
+ 'url' => env('OPENAI_URL', 'https://api.openai.com/v1'),
+ ],
+
+ 'openrouter' => [
+ 'driver' => 'openrouter',
+ 'key' => env('OPENROUTER_API_KEY'),
+ 'url' => env('OPENROUTER_URL', 'https://openrouter.ai/api/v1'),
+ ],
+
+ 'voyageai' => [
+ 'driver' => 'voyageai',
+ 'key' => env('VOYAGEAI_API_KEY'),
+ 'url' => env('VOYAGEAI_URL', 'https://api.voyageai.com/v1'),
+ ],
+
+ 'xai' => [
+ 'driver' => 'xai',
+ 'key' => env('XAI_API_KEY'),
+ 'url' => env('XAI_URL', 'https://api.x.ai/v1'),
+ ],
+ ],
+
+];
diff --git a/backend/database/migrations/2026_04_24_062452_create_agent_conversations_table.php b/backend/database/migrations/2026_04_24_062452_create_agent_conversations_table.php
new file mode 100644
index 0000000..e1f2d63
--- /dev/null
+++ b/backend/database/migrations/2026_04_24_062452_create_agent_conversations_table.php
@@ -0,0 +1,50 @@
+string('id', 36)->primary();
+ $table->foreignId('user_id')->nullable();
+ $table->string('title');
+ $table->timestamps();
+
+ $table->index(['user_id', 'updated_at']);
+ });
+
+ Schema::create('agent_conversation_messages', function (Blueprint $table) {
+ $table->string('id', 36)->primary();
+ $table->string('conversation_id', 36)->index();
+ $table->foreignId('user_id')->nullable();
+ $table->string('agent');
+ $table->string('role', 25);
+ $table->text('content');
+ $table->text('attachments');
+ $table->text('tool_calls');
+ $table->text('tool_results');
+ $table->text('usage');
+ $table->text('meta');
+ $table->timestamps();
+
+ $table->index(['conversation_id', 'user_id', 'updated_at'], 'conversation_index');
+ $table->index(['user_id']);
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::dropIfExists('agent_conversations');
+ Schema::dropIfExists('agent_conversation_messages');
+ }
+};
diff --git a/backend/routes/api.php b/backend/routes/api.php
index ccc387f..65390bd 100644
--- a/backend/routes/api.php
+++ b/backend/routes/api.php
@@ -6,3 +6,4 @@
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:sanctum');
+
diff --git a/backend/stubs/agent-middleware.stub b/backend/stubs/agent-middleware.stub
new file mode 100644
index 0000000..c1a50f4
--- /dev/null
+++ b/backend/stubs/agent-middleware.stub
@@ -0,0 +1,20 @@
+then(function (AgentResponse $response) {
+ // ...
+ });
+ }
+}
diff --git a/backend/stubs/agent.stub b/backend/stubs/agent.stub
new file mode 100644
index 0000000..06471d5
--- /dev/null
+++ b/backend/stubs/agent.stub
@@ -0,0 +1,44 @@
+ $schema->string()->required(),
+ ];
+ }
+}
diff --git a/backend/stubs/tool.stub b/backend/stubs/tool.stub
new file mode 100644
index 0000000..e096021
--- /dev/null
+++ b/backend/stubs/tool.stub
@@ -0,0 +1,37 @@
+ $schema->string()->required(),
+ ];
+ }
+}