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(), + ]; + } +}