From ad83825f9336f8ff51be527ea05bff83c8c24250 Mon Sep 17 00:00:00 2001 From: Snider Date: Tue, 27 Jan 2026 16:12:58 +0000 Subject: [PATCH] refactor: rename namespace Core\Agentic to Core\Mod\Agentic Updates all classes to use the new modular namespace convention. Adds Service/ layer with Core\Service\Agentic for service definition. Co-Authored-By: Claude Opus 4.5 --- Boot.php | 4 +- Configs/AIConfig.php | 4 +- Console/Commands/GenerateCommand.php | 4 +- Console/Commands/PlanCommand.php | 6 +- Console/Commands/TaskCommand.php | 4 +- Controllers/ForAgentsController.php | 2 +- Facades/Agentic.php | 14 +- Jobs/BatchContentGeneration.php | 2 +- Jobs/ProcessContentTask.php | 4 +- Mcp/Prompts/AnalysePerformancePrompt.php | 2 +- Mcp/Prompts/ConfigureNotificationsPrompt.php | 2 +- Mcp/Prompts/SetupQrCampaignPrompt.php | 2 +- Mcp/Servers/HostHub.php | 10 +- Mcp/Servers/Marketing.php | 2 +- Mcp/Tools/Agent/AgentTool.php | 4 +- .../Agent/Content/ContentBatchGenerate.php | 4 +- .../Agent/Content/ContentBriefCreate.php | 6 +- Mcp/Tools/Agent/Content/ContentBriefGet.php | 4 +- Mcp/Tools/Agent/Content/ContentBriefList.php | 4 +- Mcp/Tools/Agent/Content/ContentFromPlan.php | 6 +- Mcp/Tools/Agent/Content/ContentGenerate.php | 4 +- Mcp/Tools/Agent/Content/ContentStatus.php | 4 +- Mcp/Tools/Agent/Content/ContentUsageStats.php | 4 +- .../Agent/Contracts/AgentToolInterface.php | 2 +- Mcp/Tools/Agent/Phase/PhaseAddCheckpoint.php | 8 +- Mcp/Tools/Agent/Phase/PhaseGet.php | 8 +- Mcp/Tools/Agent/Phase/PhaseUpdateStatus.php | 8 +- Mcp/Tools/Agent/Plan/PlanArchive.php | 6 +- Mcp/Tools/Agent/Plan/PlanCreate.php | 8 +- Mcp/Tools/Agent/Plan/PlanGet.php | 6 +- Mcp/Tools/Agent/Plan/PlanList.php | 6 +- Mcp/Tools/Agent/Plan/PlanUpdateStatus.php | 6 +- Mcp/Tools/Agent/Session/SessionArtifact.php | 6 +- Mcp/Tools/Agent/Session/SessionContinue.php | 6 +- Mcp/Tools/Agent/Session/SessionEnd.php | 6 +- Mcp/Tools/Agent/Session/SessionHandoff.php | 6 +- Mcp/Tools/Agent/Session/SessionList.php | 8 +- Mcp/Tools/Agent/Session/SessionLog.php | 6 +- Mcp/Tools/Agent/Session/SessionReplay.php | 6 +- Mcp/Tools/Agent/Session/SessionResume.php | 6 +- Mcp/Tools/Agent/Session/SessionStart.php | 8 +- Mcp/Tools/Agent/State/StateGet.php | 6 +- Mcp/Tools/Agent/State/StateList.php | 6 +- Mcp/Tools/Agent/State/StateSet.php | 8 +- Mcp/Tools/Agent/Task/TaskToggle.php | 8 +- Mcp/Tools/Agent/Task/TaskUpdate.php | 8 +- .../Agent/Template/TemplateCreatePlan.php | 6 +- Mcp/Tools/Agent/Template/TemplateList.php | 6 +- Mcp/Tools/Agent/Template/TemplatePreview.php | 6 +- Middleware/AgentApiAuth.php | 6 +- Models/AgentApiKey.php | 2 +- Models/AgentPhase.php | 4 +- Models/AgentPlan.php | 4 +- Models/AgentSession.php | 4 +- Models/AgentWorkspaceState.php | 2 +- Models/Prompt.php | 2 +- Models/PromptVersion.php | 2 +- Models/Task.php | 2 +- Models/WorkspaceState.php | 2 +- Service/Boot.php | 120 + Services/AgentApiKeyService.php | 4 +- Services/AgentDetection.php | 6 +- Services/AgentSessionService.php | 6 +- Services/AgentToolRegistry.php | 4 +- Services/AgenticManager.php | 2 +- Services/AgenticProviderInterface.php | 2 +- Services/AgenticResponse.php | 2 +- Services/ClaudeService.php | 6 +- Services/Concerns/HasRetry.php | 2 +- Services/Concerns/HasStreamParsing.php | 2 +- Services/ContentService.php | 2 +- Services/GeminiService.php | 6 +- Services/IpRestrictionService.php | 4 +- Services/OpenAIService.php | 6 +- Services/PlanTemplateService.php | 6 +- Support/AgentIdentity.php | 2 +- View/Blade/admin/templates.blade.php | 2 +- View/Modal/Admin/ApiKeyManager.php | 2 +- View/Modal/Admin/ApiKeys.php | 6 +- View/Modal/Admin/Dashboard.php | 6 +- View/Modal/Admin/PlanDetail.php | 6 +- View/Modal/Admin/Plans.php | 4 +- View/Modal/Admin/Playground.php | 2 +- View/Modal/Admin/RequestLog.php | 2 +- View/Modal/Admin/SessionDetail.php | 4 +- View/Modal/Admin/Sessions.php | 6 +- View/Modal/Admin/Templates.php | 4 +- View/Modal/Admin/ToolAnalytics.php | 2 +- View/Modal/Admin/ToolCalls.php | 2 +- changelog/2026/jan/PORTING_PLAN.md | 313 +++ .../2026/jan/TASK-006-agent-plans-admin-ui.md | 2214 +++++++++++++++++ changelog/2026/jan/agentic-tasks-readme.md | 186 ++ changelog/2026/jan/code-review.md | 107 + changelog/2026/jan/features.md | 72 + composer.json | 95 +- routes/admin.php | 18 +- tests/Feature/AgentPhaseTest.php | 6 +- tests/Feature/AgentPlanTest.php | 6 +- tests/Feature/AgentSessionTest.php | 6 +- tests/Feature/ContentServiceTest.php | 6 +- tests/UseCase/AdminPanelBasic.php | 4 +- 101 files changed, 3289 insertions(+), 276 deletions(-) create mode 100644 Service/Boot.php create mode 100644 changelog/2026/jan/PORTING_PLAN.md create mode 100644 changelog/2026/jan/TASK-006-agent-plans-admin-ui.md create mode 100644 changelog/2026/jan/agentic-tasks-readme.md create mode 100644 changelog/2026/jan/code-review.md create mode 100644 changelog/2026/jan/features.md diff --git a/Boot.php b/Boot.php index 765b8b2..575cd41 100644 --- a/Boot.php +++ b/Boot.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic; +namespace Core\Mod\Agentic; use Core\Events\AdminPanelBooting; use Core\Events\ConsoleBooting; @@ -53,7 +53,7 @@ class Boot extends ServiceProvider 'mcp' ); - $this->app->singleton(\Core\Agentic\Services\AgenticManager::class); + $this->app->singleton(\Core\Mod\Agentic\Services\AgenticManager::class); } // ------------------------------------------------------------------------- diff --git a/Configs/AIConfig.php b/Configs/AIConfig.php index a3a6e03..4224250 100644 --- a/Configs/AIConfig.php +++ b/Configs/AIConfig.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Configs; +namespace Core\Mod\Agentic\Configs; use Core\Config\Config; -use Core\Agentic\Services\AgenticManager; +use Core\Mod\Agentic\Services\AgenticManager; use Illuminate\Validation\Rule; /** diff --git a/Console/Commands/GenerateCommand.php b/Console/Commands/GenerateCommand.php index 63f6f7d..46ac499 100644 --- a/Console/Commands/GenerateCommand.php +++ b/Console/Commands/GenerateCommand.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Console\Commands; +namespace Core\Mod\Agentic\Console\Commands; use Illuminate\Console\Command; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentPlan; use Mod\Content\Jobs\GenerateContentJob; use Mod\Content\Models\ContentBrief; use Mod\Content\Services\AIGatewayService; diff --git a/Console/Commands/PlanCommand.php b/Console/Commands/PlanCommand.php index f89e7aa..e40200c 100644 --- a/Console/Commands/PlanCommand.php +++ b/Console/Commands/PlanCommand.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Agentic\Console\Commands; +namespace Core\Mod\Agentic\Console\Commands; use Illuminate\Console\Command; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Services\PlanTemplateService; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Services\PlanTemplateService; class PlanCommand extends Command { diff --git a/Console/Commands/TaskCommand.php b/Console/Commands/TaskCommand.php index 10c2ed4..8d5f283 100644 --- a/Console/Commands/TaskCommand.php +++ b/Console/Commands/TaskCommand.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Console\Commands; +namespace Core\Mod\Agentic\Console\Commands; use Illuminate\Console\Command; -use Core\Agentic\Models\Task; +use Core\Mod\Agentic\Models\Task; class TaskCommand extends Command { diff --git a/Controllers/ForAgentsController.php b/Controllers/ForAgentsController.php index 17f214a..467c524 100644 --- a/Controllers/ForAgentsController.php +++ b/Controllers/ForAgentsController.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Controllers; +namespace Core\Mod\Agentic\Controllers; use Core\Front\Controller; use Illuminate\Http\JsonResponse; diff --git a/Facades/Agentic.php b/Facades/Agentic.php index 0fedc01..be43cf2 100644 --- a/Facades/Agentic.php +++ b/Facades/Agentic.php @@ -2,21 +2,21 @@ declare(strict_types=1); -namespace Core\Agentic\Facades; +namespace Core\Mod\Agentic\Facades; -use Core\Agentic\Services\AgenticManager; +use Core\Mod\Agentic\Services\AgenticManager; use Illuminate\Support\Facades\Facade; /** - * @method static \Core\Agentic\Services\AgenticProviderInterface provider(string $name = null) - * @method static \Core\Agentic\Services\ClaudeService claude() - * @method static \Core\Agentic\Services\GeminiService gemini() - * @method static \Core\Agentic\Services\OpenAIService openai() + * @method static \Core\Mod\Agentic\Services\AgenticProviderInterface provider(string $name = null) + * @method static \Core\Mod\Agentic\Services\ClaudeService claude() + * @method static \Core\Mod\Agentic\Services\GeminiService gemini() + * @method static \Core\Mod\Agentic\Services\OpenAIService openai() * @method static array availableProviders() * @method static bool isAvailable(string $name) * @method static void setDefault(string $name) * - * @see \Core\Agentic\Services\AgenticManager + * @see \Core\Mod\Agentic\Services\AgenticManager */ class Agentic extends Facade { diff --git a/Jobs/BatchContentGeneration.php b/Jobs/BatchContentGeneration.php index bf33020..359e45e 100644 --- a/Jobs/BatchContentGeneration.php +++ b/Jobs/BatchContentGeneration.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Jobs; +namespace Core\Mod\Agentic\Jobs; use Mod\Content\Models\ContentTask; use Illuminate\Bus\Queueable; diff --git a/Jobs/ProcessContentTask.php b/Jobs/ProcessContentTask.php index 0a37531..dd0495e 100644 --- a/Jobs/ProcessContentTask.php +++ b/Jobs/ProcessContentTask.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Core\Agentic\Jobs; +namespace Core\Mod\Agentic\Jobs; -use Core\Agentic\Services\AgenticManager; +use Core\Mod\Agentic\Services\AgenticManager; use Mod\Content\Models\ContentTask; use Mod\Content\Services\ContentProcessingService; use Core\Mod\Tenant\Services\EntitlementService; diff --git a/Mcp/Prompts/AnalysePerformancePrompt.php b/Mcp/Prompts/AnalysePerformancePrompt.php index 6792c55..e657fa3 100644 --- a/Mcp/Prompts/AnalysePerformancePrompt.php +++ b/Mcp/Prompts/AnalysePerformancePrompt.php @@ -1,6 +1,6 @@ getActiveSessions($context['workspace_id'] ?? null); } else { // Query with filters - $query = \Core\Agentic\Models\AgentSession::query() + $query = \Core\Mod\Agentic\Models\AgentSession::query() ->orderBy('last_active_at', 'desc'); // Apply workspace filter if provided diff --git a/Mcp/Tools/Agent/Session/SessionLog.php b/Mcp/Tools/Agent/Session/SessionLog.php index 87980ff..68ea543 100644 --- a/Mcp/Tools/Agent/Session/SessionLog.php +++ b/Mcp/Tools/Agent/Session/SessionLog.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Session; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session; use Core\Mod\Mcp\Dependencies\ToolDependency; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentSession; /** * Log an entry in the current session. diff --git a/Mcp/Tools/Agent/Session/SessionReplay.php b/Mcp/Tools/Agent/Session/SessionReplay.php index 28fd340..fe0f46b 100644 --- a/Mcp/Tools/Agent/Session/SessionReplay.php +++ b/Mcp/Tools/Agent/Session/SessionReplay.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Session; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; -use Core\Agentic\Services\AgentSessionService; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Services\AgentSessionService; /** * Replay a session by creating a new session with the original's context. diff --git a/Mcp/Tools/Agent/Session/SessionResume.php b/Mcp/Tools/Agent/Session/SessionResume.php index fdc2bde..ee051ed 100644 --- a/Mcp/Tools/Agent/Session/SessionResume.php +++ b/Mcp/Tools/Agent/Session/SessionResume.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Session; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session; -use Core\Agentic\Services\AgentSessionService; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Services\AgentSessionService; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * Resume a paused or handed-off session. diff --git a/Mcp/Tools/Agent/Session/SessionStart.php b/Mcp/Tools/Agent/Session/SessionStart.php index e16550f..e89c3e4 100644 --- a/Mcp/Tools/Agent/Session/SessionStart.php +++ b/Mcp/Tools/Agent/Session/SessionStart.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Session; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Session; use Core\Mod\Mcp\Dependencies\ToolDependency; use Illuminate\Support\Str; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentSession; /** * Start a new agent session for a plan. diff --git a/Mcp/Tools/Agent/State/StateGet.php b/Mcp/Tools/Agent/State/StateGet.php index 1bbddf4..e01974f 100644 --- a/Mcp/Tools/Agent/State/StateGet.php +++ b/Mcp/Tools/Agent/State/StateGet.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\State; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\State; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * Get a workspace state value. diff --git a/Mcp/Tools/Agent/State/StateList.php b/Mcp/Tools/Agent/State/StateList.php index 1ece720..d4ff589 100644 --- a/Mcp/Tools/Agent/State/StateList.php +++ b/Mcp/Tools/Agent/State/StateList.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\State; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\State; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * List all state values for a plan. diff --git a/Mcp/Tools/Agent/State/StateSet.php b/Mcp/Tools/Agent/State/StateSet.php index bb5a2f0..b231545 100644 --- a/Mcp/Tools/Agent/State/StateSet.php +++ b/Mcp/Tools/Agent/State/StateSet.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\State; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\State; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Models\AgentWorkspaceState; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentWorkspaceState; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * Set a workspace state value. diff --git a/Mcp/Tools/Agent/Task/TaskToggle.php b/Mcp/Tools/Agent/Task/TaskToggle.php index 2f4bef0..d7ec51d 100644 --- a/Mcp/Tools/Agent/Task/TaskToggle.php +++ b/Mcp/Tools/Agent/Task/TaskToggle.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Task; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Task; use Core\Mod\Mcp\Dependencies\ToolDependency; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; -use Core\Agentic\Models\AgentPhase; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentPhase; +use Core\Mod\Agentic\Models\AgentPlan; /** * Toggle a task completion status. diff --git a/Mcp/Tools/Agent/Task/TaskUpdate.php b/Mcp/Tools/Agent/Task/TaskUpdate.php index dc2eba4..3a14534 100644 --- a/Mcp/Tools/Agent/Task/TaskUpdate.php +++ b/Mcp/Tools/Agent/Task/TaskUpdate.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Task; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Task; use Core\Mod\Mcp\Dependencies\ToolDependency; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; -use Core\Agentic\Models\AgentPhase; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Models\AgentPhase; +use Core\Mod\Agentic\Models\AgentPlan; /** * Update task details (status, notes). diff --git a/Mcp/Tools/Agent/Template/TemplateCreatePlan.php b/Mcp/Tools/Agent/Template/TemplateCreatePlan.php index 2d48576..ab5f009 100644 --- a/Mcp/Tools/Agent/Template/TemplateCreatePlan.php +++ b/Mcp/Tools/Agent/Template/TemplateCreatePlan.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Template; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Template; -use Core\Agentic\Services\PlanTemplateService; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Services\PlanTemplateService; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * Create a new plan from a template. diff --git a/Mcp/Tools/Agent/Template/TemplateList.php b/Mcp/Tools/Agent/Template/TemplateList.php index 9fc296c..429b9eb 100644 --- a/Mcp/Tools/Agent/Template/TemplateList.php +++ b/Mcp/Tools/Agent/Template/TemplateList.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Template; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Template; -use Core\Agentic\Services\PlanTemplateService; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Services\PlanTemplateService; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * List available plan templates. diff --git a/Mcp/Tools/Agent/Template/TemplatePreview.php b/Mcp/Tools/Agent/Template/TemplatePreview.php index a0423c5..606566a 100644 --- a/Mcp/Tools/Agent/Template/TemplatePreview.php +++ b/Mcp/Tools/Agent/Template/TemplatePreview.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Mcp\Tools\Agent\Template; +namespace Core\Mod\Agentic\Mcp\Tools\Agent\Template; -use Core\Agentic\Services\PlanTemplateService; -use Core\Agentic\Mcp\Tools\Agent\AgentTool; +use Core\Mod\Agentic\Services\PlanTemplateService; +use Core\Mod\Agentic\Mcp\Tools\Agent\AgentTool; /** * Preview a template with variables. diff --git a/Middleware/AgentApiAuth.php b/Middleware/AgentApiAuth.php index 2fdfd20..9bb39f1 100644 --- a/Middleware/AgentApiAuth.php +++ b/Middleware/AgentApiAuth.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Agentic\Middleware; +namespace Core\Mod\Agentic\Middleware; use Closure; use Illuminate\Http\Request; -use Core\Agentic\Models\AgentApiKey; -use Core\Agentic\Services\AgentApiKeyService; +use Core\Mod\Agentic\Models\AgentApiKey; +use Core\Mod\Agentic\Services\AgentApiKeyService; use Symfony\Component\HttpFoundation\Response; /** diff --git a/Models/AgentApiKey.php b/Models/AgentApiKey.php index 92a1541..ec072f0 100644 --- a/Models/AgentApiKey.php +++ b/Models/AgentApiKey.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Database\Eloquent\Model; diff --git a/Models/AgentPhase.php b/Models/AgentPhase.php index fd61d7b..b52b66a 100644 --- a/Models/AgentPhase.php +++ b/Models/AgentPhase.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Support\Facades\DB; -use Core\Agentic\Database\Factories\AgentPhaseFactory; +use Core\Mod\Agentic\Database\Factories\AgentPhaseFactory; /** * Agent Phase - individual phase within a plan. diff --git a/Models/AgentPlan.php b/Models/AgentPlan.php index 506ba19..fb13046 100644 --- a/Models/AgentPlan.php +++ b/Models/AgentPlan.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Str; -use Core\Agentic\Database\Factories\AgentPlanFactory; +use Core\Mod\Agentic\Database\Factories\AgentPlanFactory; use Core\Mod\Tenant\Concerns\BelongsToWorkspace; use Core\Mod\Tenant\Models\Workspace; use Spatie\Activitylog\LogOptions; diff --git a/Models/AgentSession.php b/Models/AgentSession.php index e49453f..8ce68f5 100644 --- a/Models/AgentSession.php +++ b/Models/AgentSession.php @@ -2,14 +2,14 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Core\Mod\Tenant\Concerns\BelongsToWorkspace; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Core\Agentic\Database\Factories\AgentSessionFactory; +use Core\Mod\Agentic\Database\Factories\AgentSessionFactory; use Ramsey\Uuid\Uuid; /** diff --git a/Models/AgentWorkspaceState.php b/Models/AgentWorkspaceState.php index 5ec4008..ba6bebe 100644 --- a/Models/AgentWorkspaceState.php +++ b/Models/AgentWorkspaceState.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; diff --git a/Models/Prompt.php b/Models/Prompt.php index ee776f9..453168b 100644 --- a/Models/Prompt.php +++ b/Models/Prompt.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Mod\Content\Models\ContentTask; use Illuminate\Database\Eloquent\Factories\HasFactory; diff --git a/Models/PromptVersion.php b/Models/PromptVersion.php index 11d6a9d..b9be986 100644 --- a/Models/PromptVersion.php +++ b/Models/PromptVersion.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Core\Mod\Tenant\Models\User; use Illuminate\Database\Eloquent\Model; diff --git a/Models/Task.php b/Models/Task.php index f02cd53..7aa829c 100644 --- a/Models/Task.php +++ b/Models/Task.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Illuminate\Database\Eloquent\Model; use Core\Mod\Tenant\Concerns\BelongsToWorkspace; diff --git a/Models/WorkspaceState.php b/Models/WorkspaceState.php index 3ba5318..c3f7267 100644 --- a/Models/WorkspaceState.php +++ b/Models/WorkspaceState.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Models; +namespace Core\Mod\Agentic\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; diff --git a/Service/Boot.php b/Service/Boot.php new file mode 100644 index 0000000..12fae90 --- /dev/null +++ b/Service/Boot.php @@ -0,0 +1,120 @@ + + */ + public static array $listens = [ + AdminPanelBooting::class => 'onAdminPanel', + ]; + + /** + * Bootstrap the service. + */ + public function boot(): void + { + app(AdminMenuRegistry::class)->register($this); + } + + /** + * Get the service definition for seeding platform_services. + */ + public static function definition(): array + { + return [ + 'code' => 'agentic', + 'module' => 'Agentic', + 'name' => 'Agentic', + 'tagline' => 'AI agent orchestration', + 'description' => 'Build and deploy AI agents with planning, tool use, and conversation capabilities.', + 'icon' => 'robot', + 'color' => 'violet', + 'marketing_domain' => null, // API service, no marketing site yet + 'website_class' => null, + 'entitlement_code' => 'core.srv.agentic', + 'sort_order' => 60, + ]; + } + + /** + * Admin menu items for this service. + * + * Agentic is positioned in the dashboard group (not services) + * as it's a cross-cutting AI capability, not a standalone product. + */ + public function adminMenuItems(): array + { + return [ + [ + 'group' => 'dashboard', + 'priority' => 5, + 'entitlement' => 'core.srv.agentic', + 'item' => fn () => [ + 'label' => 'Agentic', + 'icon' => 'robot', + 'color' => 'violet', + 'active' => request()->routeIs('hub.agents.*'), + 'children' => [ + ['label' => 'Dashboard', 'icon' => 'gauge', 'href' => route('hub.agents.index'), 'active' => request()->routeIs('hub.agents.index')], + ['label' => 'Plans', 'icon' => 'list-check', 'href' => route('hub.agents.plans'), 'active' => request()->routeIs('hub.agents.plans*')], + ['label' => 'Sessions', 'icon' => 'messages', 'href' => route('hub.agents.sessions'), 'active' => request()->routeIs('hub.agents.sessions*')], + ['label' => 'Tool Analytics', 'icon' => 'chart-bar', 'href' => route('hub.agents.tools'), 'active' => request()->routeIs('hub.agents.tools*')], + ['label' => 'API Keys', 'icon' => 'key', 'href' => route('hub.agents.api-keys'), 'active' => request()->routeIs('hub.agents.api-keys*')], + ['label' => 'Templates', 'icon' => 'copy', 'href' => route('hub.agents.templates'), 'active' => request()->routeIs('hub.agents.templates*')], + ], + ], + ], + ]; + } + + /** + * Register admin panel components. + */ + public function onAdminPanel(AdminPanelBooting $event): void + { + // Service-specific admin routes could go here + // Components are registered by Core\Agentic + } + + public function menuPermissions(): array + { + return []; + } + + public function canViewMenu(?object $user, ?object $workspace): bool + { + return $user !== null; + } + + public static function version(): ServiceVersion + { + return new ServiceVersion(1, 0, 0); + } + + /** + * Service dependencies. + */ + public static function dependencies(): array + { + return []; + } +} diff --git a/Services/AgentApiKeyService.php b/Services/AgentApiKeyService.php index ddd6492..e58b70d 100644 --- a/Services/AgentApiKeyService.php +++ b/Services/AgentApiKeyService.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Log; -use Core\Agentic\Models\AgentApiKey; +use Core\Mod\Agentic\Models\AgentApiKey; /** * Agent API Key Service. diff --git a/Services/AgentDetection.php b/Services/AgentDetection.php index fc19446..6c82a45 100644 --- a/Services/AgentDetection.php +++ b/Services/AgentDetection.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; -use Core\Agentic\Models\AgentApiKey; -use Core\Agentic\Support\AgentIdentity; +use Core\Mod\Agentic\Models\AgentApiKey; +use Core\Mod\Agentic\Support\AgentIdentity; use Illuminate\Http\Request; /** diff --git a/Services/AgentSessionService.php b/Services/AgentSessionService.php index 2e29688..1d4db30 100644 --- a/Services/AgentSessionService.php +++ b/Services/AgentSessionService.php @@ -2,12 +2,12 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Illuminate\Support\Collection; use Illuminate\Support\Facades\Cache; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentSession; /** * Agent Session Service - manages session persistence for agent continuity. diff --git a/Services/AgentToolRegistry.php b/Services/AgentToolRegistry.php index c3e64c9..252ae86 100644 --- a/Services/AgentToolRegistry.php +++ b/Services/AgentToolRegistry.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Core\Mod\Api\Models\ApiKey; use Core\Mod\Mcp\Dependencies\HasDependencies; use Core\Mod\Mcp\Services\ToolDependencyService; use Illuminate\Support\Collection; -use Core\Agentic\Mcp\Tools\Agent\Contracts\AgentToolInterface; +use Core\Mod\Agentic\Mcp\Tools\Agent\Contracts\AgentToolInterface; /** * Registry for MCP Agent Server tools. diff --git a/Services/AgenticManager.php b/Services/AgenticManager.php index caa1059..7130fd9 100644 --- a/Services/AgenticManager.php +++ b/Services/AgenticManager.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use InvalidArgumentException; diff --git a/Services/AgenticProviderInterface.php b/Services/AgenticProviderInterface.php index bda87a1..3fe2590 100644 --- a/Services/AgenticProviderInterface.php +++ b/Services/AgenticProviderInterface.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; interface AgenticProviderInterface { diff --git a/Services/AgenticResponse.php b/Services/AgenticResponse.php index d6534cc..06ef4bc 100644 --- a/Services/AgenticResponse.php +++ b/Services/AgenticResponse.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; class AgenticResponse { diff --git a/Services/ClaudeService.php b/Services/ClaudeService.php index 83aaa8a..b852d02 100644 --- a/Services/ClaudeService.php +++ b/Services/ClaudeService.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Generator; use Illuminate\Http\Client\PendingRequest; use Illuminate\Support\Facades\Http; -use Core\Agentic\Services\Concerns\HasRetry; -use Core\Agentic\Services\Concerns\HasStreamParsing; +use Core\Mod\Agentic\Services\Concerns\HasRetry; +use Core\Mod\Agentic\Services\Concerns\HasStreamParsing; use RuntimeException; class ClaudeService implements AgenticProviderInterface diff --git a/Services/Concerns/HasRetry.php b/Services/Concerns/HasRetry.php index 287e587..83d024f 100644 --- a/Services/Concerns/HasRetry.php +++ b/Services/Concerns/HasRetry.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Services\Concerns; +namespace Core\Mod\Agentic\Services\Concerns; use Illuminate\Http\Client\ConnectionException; use Illuminate\Http\Client\RequestException; diff --git a/Services/Concerns/HasStreamParsing.php b/Services/Concerns/HasStreamParsing.php index c8d60e7..da5bbf5 100644 --- a/Services/Concerns/HasStreamParsing.php +++ b/Services/Concerns/HasStreamParsing.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Services\Concerns; +namespace Core\Mod\Agentic\Services\Concerns; use Generator; use Psr\Http\Message\StreamInterface; diff --git a/Services/ContentService.php b/Services/ContentService.php index 6bf92a4..8d022b7 100644 --- a/Services/ContentService.php +++ b/Services/ContentService.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Mod\Content\Models\ContentItem; use Illuminate\Support\Facades\File; diff --git a/Services/GeminiService.php b/Services/GeminiService.php index 792c922..321445d 100644 --- a/Services/GeminiService.php +++ b/Services/GeminiService.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Generator; use Illuminate\Http\Client\PendingRequest; use Illuminate\Support\Facades\Http; -use Core\Agentic\Services\Concerns\HasRetry; -use Core\Agentic\Services\Concerns\HasStreamParsing; +use Core\Mod\Agentic\Services\Concerns\HasRetry; +use Core\Mod\Agentic\Services\Concerns\HasStreamParsing; use RuntimeException; class GeminiService implements AgenticProviderInterface diff --git a/Services/IpRestrictionService.php b/Services/IpRestrictionService.php index 2032bfc..4409f4f 100644 --- a/Services/IpRestrictionService.php +++ b/Services/IpRestrictionService.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; -use Core\Agentic\Models\AgentApiKey; +use Core\Mod\Agentic\Models\AgentApiKey; /** * IP Restriction Service. diff --git a/Services/OpenAIService.php b/Services/OpenAIService.php index de2d65f..1c5151d 100644 --- a/Services/OpenAIService.php +++ b/Services/OpenAIService.php @@ -2,13 +2,13 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; use Generator; use Illuminate\Http\Client\PendingRequest; use Illuminate\Support\Facades\Http; -use Core\Agentic\Services\Concerns\HasRetry; -use Core\Agentic\Services\Concerns\HasStreamParsing; +use Core\Mod\Agentic\Services\Concerns\HasRetry; +use Core\Mod\Agentic\Services\Concerns\HasStreamParsing; use RuntimeException; class OpenAIService implements AgenticProviderInterface diff --git a/Services/PlanTemplateService.php b/Services/PlanTemplateService.php index 87cb37a..7a7158c 100644 --- a/Services/PlanTemplateService.php +++ b/Services/PlanTemplateService.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\Services; +namespace Core\Mod\Agentic\Services; -use Core\Agentic\Models\AgentPhase; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentPhase; +use Core\Mod\Agentic\Models\AgentPlan; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Support\Collection; use Illuminate\Support\Facades\File; diff --git a/Support/AgentIdentity.php b/Support/AgentIdentity.php index 0d4e7ce..9d134c1 100644 --- a/Support/AgentIdentity.php +++ b/Support/AgentIdentity.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\Support; +namespace Core\Mod\Agentic\Support; /** * Represents the identity of an AI agent making a request. diff --git a/View/Blade/admin/templates.blade.php b/View/Blade/admin/templates.blade.php index ae10250..56887e4 100644 --- a/View/Blade/admin/templates.blade.php +++ b/View/Blade/admin/templates.blade.php @@ -240,7 +240,7 @@ {{-- Variables --}} @php - $template = app(\Core\Agentic\Services\PlanTemplateService::class)->get($previewSlug); + $template = app(\Core\Mod\Agentic\Services\PlanTemplateService::class)->get($previewSlug); $variables = $template['variables'] ?? []; @endphp @if(!empty($variables)) diff --git a/View/Modal/Admin/ApiKeyManager.php b/View/Modal/Admin/ApiKeyManager.php index e76347c..a5ea272 100644 --- a/View/Modal/Admin/ApiKeyManager.php +++ b/View/Modal/Admin/ApiKeyManager.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Core\Mod\Api\Models\ApiKey; use Core\Mod\Tenant\Models\Workspace; diff --git a/View/Modal/Admin/ApiKeys.php b/View/Modal/Admin/ApiKeys.php index 35f72dc..f446eb4 100644 --- a/View/Modal/Admin/ApiKeys.php +++ b/View/Modal/Admin/ApiKeys.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Contracts\View\View; @@ -13,8 +13,8 @@ use Livewire\Attributes\Title; use Livewire\Attributes\Url; use Livewire\Component; use Livewire\WithPagination; -use Core\Agentic\Models\AgentApiKey; -use Core\Agentic\Services\AgentApiKeyService; +use Core\Mod\Agentic\Models\AgentApiKey; +use Core\Mod\Agentic\Services\AgentApiKeyService; use Symfony\Component\HttpFoundation\StreamedResponse; #[Title('API Keys')] diff --git a/View/Modal/Admin/Dashboard.php b/View/Modal/Admin/Dashboard.php index e6438ff..fdc0f6e 100644 --- a/View/Modal/Admin/Dashboard.php +++ b/View/Modal/Admin/Dashboard.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentSession; use Core\Mod\Mcp\Models\McpToolCallStat; use Illuminate\Contracts\View\View; use Illuminate\Support\Facades\Cache; diff --git a/View/Modal/Admin/PlanDetail.php b/View/Modal/Admin/PlanDetail.php index ccc2d65..5a690df 100644 --- a/View/Modal/Admin/PlanDetail.php +++ b/View/Modal/Admin/PlanDetail.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; -use Core\Agentic\Models\AgentPhase; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentPhase; +use Core\Mod\Agentic\Models\AgentPlan; use Illuminate\Contracts\View\View; use Livewire\Attributes\Computed; use Livewire\Attributes\Layout; diff --git a/View/Modal/Admin/Plans.php b/View/Modal/Admin/Plans.php index aefc156..cc96fd5 100644 --- a/View/Modal/Admin/Plans.php +++ b/View/Modal/Admin/Plans.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentPlan; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Contracts\View\View; use Illuminate\Pagination\LengthAwarePaginator; diff --git a/View/Modal/Admin/Playground.php b/View/Modal/Admin/Playground.php index d6aba3a..72687e4 100644 --- a/View/Modal/Admin/Playground.php +++ b/View/Modal/Admin/Playground.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Core\Mod\Api\Models\ApiKey; use Illuminate\Support\Facades\Http; diff --git a/View/Modal/Admin/RequestLog.php b/View/Modal/Admin/RequestLog.php index b9722b6..d298ec9 100644 --- a/View/Modal/Admin/RequestLog.php +++ b/View/Modal/Admin/RequestLog.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Core\Mod\Mcp\Models\McpApiRequest; use Livewire\Attributes\Layout; diff --git a/View/Modal/Admin/SessionDetail.php b/View/Modal/Admin/SessionDetail.php index af375bb..71c0b83 100644 --- a/View/Modal/Admin/SessionDetail.php +++ b/View/Modal/Admin/SessionDetail.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Collection; @@ -10,7 +10,7 @@ use Livewire\Attributes\Computed; use Livewire\Attributes\Layout; use Livewire\Attributes\Title; use Livewire\Component; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Models\AgentSession; #[Title('Session Detail')] #[Layout('hub::admin.layouts.app')] diff --git a/View/Modal/Admin/Sessions.php b/View/Modal/Admin/Sessions.php index 776d910..0901e3c 100644 --- a/View/Modal/Admin/Sessions.php +++ b/View/Modal/Admin/Sessions.php @@ -2,10 +2,10 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentSession; use Core\Mod\Tenant\Models\Workspace; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Contracts\View\View; diff --git a/View/Modal/Admin/Templates.php b/View/Modal/Admin/Templates.php index e17a751..f93f3d4 100644 --- a/View/Modal/Admin/Templates.php +++ b/View/Modal/Admin/Templates.php @@ -2,9 +2,9 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; -use Core\Agentic\Services\PlanTemplateService; +use Core\Mod\Agentic\Services\PlanTemplateService; use Core\Mod\Tenant\Models\Workspace; use Flux\Flux; use Illuminate\Contracts\View\View; diff --git a/View/Modal/Admin/ToolAnalytics.php b/View/Modal/Admin/ToolAnalytics.php index 176ee93..0a9ca63 100644 --- a/View/Modal/Admin/ToolAnalytics.php +++ b/View/Modal/Admin/ToolAnalytics.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Core\Mod\Tenant\Models\Workspace; use Core\Mod\Mcp\Models\McpToolCall; diff --git a/View/Modal/Admin/ToolCalls.php b/View/Modal/Admin/ToolCalls.php index 793cbbf..069574f 100644 --- a/View/Modal/Admin/ToolCalls.php +++ b/View/Modal/Admin/ToolCalls.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace Core\Agentic\View\Modal\Admin; +namespace Core\Mod\Agentic\View\Modal\Admin; use Core\Mod\Tenant\Models\Workspace; use Core\Mod\Mcp\Models\McpToolCall; diff --git a/changelog/2026/jan/PORTING_PLAN.md b/changelog/2026/jan/PORTING_PLAN.md new file mode 100644 index 0000000..a5e38ef --- /dev/null +++ b/changelog/2026/jan/PORTING_PLAN.md @@ -0,0 +1,313 @@ +# Agentic Task System - Porting Plan + +MCP-powered workspace for persistent work plans that survive context limits and enable multi-agent collaboration. + +## Why this exists + +- **Context persistence** - Work plans persist across Claude sessions, surviving context window limits +- **Multi-agent collaboration** - Handoff support between different agents (Opus, Sonnet, Haiku) +- **Checkpoint verification** - Phase gates ensure work is complete before progressing +- **Workspace state** - Shared key-value storage for agents to communicate findings + +## Source Location + +``` +/Users/snider/Code/lab/upstream/ +├── app/Models/ +│ ├── AgentPlan.php (6.1KB, ~200 lines) +│ ├── AgentPhase.php (7.9KB, ~260 lines) +│ ├── AgentSession.php (7.5KB, ~250 lines) +│ └── WorkspaceState.php (2.1KB, ~70 lines) +├── app/Console/Commands/ +│ ├── McpAgentServerCommand.php (42KB, ~1200 lines) +│ ├── PlanCreateCommand.php (8.5KB) +│ ├── PlanListCommand.php (1.8KB) +│ ├── PlanShowCommand.php (4.0KB) +│ ├── PlanStatusCommand.php (3.7KB) +│ ├── PlanCheckCommand.php (5.7KB) +│ └── PlanPhaseCommand.php (5.8KB) +└── database/migrations/ + └── 2025_12_31_000001_create_agent_tables.php +``` + +## Target Location + +``` +/Users/snider/Code/lab/host.uk.com/ +├── app/Models/Agent/ # New subdirectory +│ ├── AgentPlan.php +│ ├── AgentPhase.php +│ ├── AgentSession.php +│ └── WorkspaceState.php +├── app/Console/Commands/Agent/ # New subdirectory +│ ├── McpAgentServerCommand.php +│ ├── PlanCreateCommand.php +│ ├── PlanListCommand.php +│ ├── PlanShowCommand.php +│ ├── PlanStatusCommand.php +│ ├── PlanCheckCommand.php +│ └── PlanPhaseCommand.php +├── database/migrations/ +│ └── 2025_12_31_100000_create_agent_tables.php +└── tests/Feature/Agent/ # New subdirectory + ├── AgentPlanTest.php + ├── AgentPhaseTest.php + └── PlanCommandsTest.php +``` + +--- + +## Phase 1: Database Migration + +Create the migration file with all four tables. + +### Tasks + +- [ ] Create migration `2025_12_31_100000_create_agent_tables.php` +- [ ] Tables: `agent_plans`, `agent_phases`, `agent_sessions`, `workspace_states` +- [ ] Run migration and verify schema + +### Source File + +Copy from: `upstream/database/migrations/2025_12_31_000001_create_agent_tables.php` + +### Schema Summary + +| Table | Purpose | Key Columns | +|-------|---------|-------------| +| `agent_plans` | Work plans with phases | slug, title, status, current_phase | +| `agent_phases` | Individual phases | order, name, tasks (JSON), status, dependencies | +| `agent_sessions` | Agent work sessions | session_id, agent_type, work_log, handoff_notes | +| `workspace_states` | Shared key-value state | key, value (JSON), type | + +--- + +## Phase 2: Eloquent Models + +Port all four models with namespace adjustment. + +### Tasks + +- [ ] Create `app/Models/Agent/` directory +- [ ] Port `AgentPlan.php` - update namespace to `App\Models\Agent` +- [ ] Port `AgentPhase.php` - update namespace and relationships +- [ ] Port `AgentSession.php` - update namespace +- [ ] Port `WorkspaceState.php` - update namespace + +### Namespace Changes + +```php +// From (upstream) +namespace App\Models; + +// To (host.uk.com) +namespace App\Models\Agent; +``` + +### Relationship Updates + +Update all `use` statements: + +```php +use Mod\Agentic\Models\AgentPlan; +use Mod\Agentic\Models\AgentPhase; +use Mod\Agentic\Models\AgentSession; +use Mod\Agentic\Models\WorkspaceState; +``` + +### Key Methods to Verify + +**AgentPlan:** +- `getCurrentPhase()` - proper orWhere scoping with closure +- `generateSlug()` - race-condition safe unique slug generation +- `checkAllPhasesComplete()` - completion verification + +**AgentPhase:** +- `complete()` - wrapped in DB::transaction +- `canStart()` - dependency checking +- `isPending()`, `isCompleted()`, `isBlocked()` + +--- + +## Phase 3: CLI Commands + +Port all plan management commands. + +### Tasks + +- [ ] Create `app/Console/Commands/Agent/` directory +- [ ] Port `PlanCreateCommand.php` - markdown import support +- [ ] Port `PlanListCommand.php` - list all plans with stats +- [ ] Port `PlanShowCommand.php` - detailed plan view +- [ ] Port `PlanStatusCommand.php` - status management +- [ ] Port `PlanCheckCommand.php` - checkpoint verification +- [ ] Port `PlanPhaseCommand.php` - phase management + +### Namespace Changes + +```php +// From +namespace App\Console\Commands; + +// To +namespace App\Console\Commands\Agent; +``` + +### Command Signatures + +| Command | Signature | Purpose | +|---------|-----------|---------| +| `plan:create` | `plan:create {slug} {--title=} {--import=} {--activate}` | Create new plan | +| `plan:list` | `plan:list {--status=}` | List all plans | +| `plan:show` | `plan:show {slug} {--markdown}` | Show plan details | +| `plan:status` | `plan:status {slug} {--set=}` | Get/set plan status | +| `plan:check` | `plan:check {slug} {phase?}` | Verify phase completion | +| `plan:phase` | `plan:phase {slug} {phase} {--status=} {--add-task=} {--complete-task=}` | Manage phases | + +--- + +## Phase 4: MCP Agent Server + +Port the MCP server command with all tools and resources. + +### Tasks + +- [ ] Port `McpAgentServerCommand.php` (~1200 lines) +- [ ] Update all model imports to use `Mod\Agentic\Models\*` +- [ ] Register command in `Kernel.php` or auto-discovery +- [ ] Test JSON-RPC protocol over stdio + +### MCP Tools (18 total) + +| Tool | Purpose | +|------|---------| +| `plan_create` | Create new plan with phases | +| `plan_get` | Get plan by slug with all phases | +| `plan_list` | List plans (optionally filtered) | +| `plan_update` | Update plan status/metadata | +| `phase_update` | Update phase status | +| `phase_check` | **Checkpoint** - verify phase completion | +| `task_add` | Add task to a phase | +| `task_complete` | Mark task done | +| `session_start` | Begin agent session | +| `session_log` | Log action to session | +| `session_artifact` | Log file artifact | +| `session_handoff` | Prepare for agent handoff | +| `session_resume` | Resume from previous session | +| `session_complete` | Mark session completed | +| `state_set` | Store workspace state | +| `state_get` | Retrieve workspace state | +| `state_list` | List all state keys | +| `state_delete` | Delete state key | + +### MCP Resources (5 total) + +| Resource URI | Purpose | +|--------------|---------| +| `hosthub://plans` | List of all work plans | +| `hosthub://plans/{slug}` | Full plan as markdown | +| `hosthub://plans/{slug}/phase/{n}` | Phase tasks as checklist | +| `hosthub://state/{plan}/{key}` | Specific state value | +| `hosthub://sessions/{id}` | Session handoff context | + +--- + +## Phase 5: Tests ✅ + +Port and adapt tests for host.uk.com conventions. + +### Tasks + +- [x] Create `app/Mod/Agentic/Tests/Feature/` directory +- [x] Create `AgentPlanTest.php` with factory support +- [x] Create `AgentPhaseTest.php` with factory support +- [x] Create `AgentSessionTest.php` with factory support +- [x] Create model factories (`AgentPlanFactory`, `AgentPhaseFactory`, `AgentSessionFactory`) +- [x] Run full test suite - 67 tests passing + +### Test Coverage + +- Model CRUD operations +- Relationship integrity +- Status transitions +- Phase dependency checking +- Command input/output +- MCP protocol compliance (optional E2E) + +--- + +## Phase 6: Documentation and Integration + +Finalise integration with host.uk.com. + +### Tasks + +- [ ] Add MCP server config to `mcp.json` example +- [ ] Update `CLAUDE.md` with agentic task commands +- [ ] Create feature documentation following `_TEMPLATE.md` +- [ ] Add to route/command discovery if needed + +### MCP Configuration + +```json +{ + "mcpServers": { + "hosthub-agent": { + "command": "php", + "args": ["artisan", "mcp:agent-server"], + "cwd": "/Users/snider/Code/lab/host.uk.com" + } + } +} +``` + +--- + +## Verification Checklist + +After each phase, verify: + +- [ ] No syntax errors (`php artisan list` works) +- [ ] Migrations run cleanly +- [ ] Models can be instantiated +- [ ] Commands appear in `php artisan list` +- [ ] Tests pass (`php artisan test --filter=Agent`) + +--- + +## Files to Copy (Summary) + +| Source | Target | Changes Required | +|--------|--------|------------------| +| `upstream/database/migrations/2025_12_31_000001_create_agent_tables.php` | `host.uk.com/database/migrations/2025_12_31_100000_create_agent_tables.php` | Rename only | +| `upstream/app/Models/AgentPlan.php` | `host.uk.com/app/Models/Agent/AgentPlan.php` | Namespace | +| `upstream/app/Models/AgentPhase.php` | `host.uk.com/app/Models/Agent/AgentPhase.php` | Namespace | +| `upstream/app/Models/AgentSession.php` | `host.uk.com/app/Models/Agent/AgentSession.php` | Namespace | +| `upstream/app/Models/WorkspaceState.php` | `host.uk.com/app/Models/Agent/WorkspaceState.php` | Namespace | +| `upstream/app/Console/Commands/McpAgentServerCommand.php` | `host.uk.com/app/Console/Commands/Agent/McpAgentServerCommand.php` | Namespace + imports | +| `upstream/app/Console/Commands/Plan*.php` (6 files) | `host.uk.com/app/Console/Commands/Agent/Plan*.php` | Namespace + imports | +| `upstream/tests/Feature/Agent*.php` | `host.uk.com/tests/Feature/Agent/*.php` | Namespace | +| `upstream/tests/Feature/PlanCommandsTest.php` | `host.uk.com/tests/Feature/Agent/PlanCommandsTest.php` | Namespace | + +--- + +## Estimated Effort + +| Phase | Complexity | Notes | +|-------|------------|-------| +| 1. Migration | Low | Direct copy | +| 2. Models | Low | Namespace changes only | +| 3. CLI Commands | Medium | 7 files, namespace + import updates | +| 4. MCP Server | Medium | Large file, many import updates | +| 5. Tests | Low | Namespace changes | +| 6. Documentation | Low | Config and docs | + +--- + +## Related Services + +- `ContentProcessingService` - May benefit from agent tracking +- `EntitlementService` - No direct relation +- Existing `Task` model - Different purpose (simple tasks vs agent plans) + +See also: `/Users/snider/Code/lab/upstream/CLAUDE.md` for original implementation details. diff --git a/changelog/2026/jan/TASK-006-agent-plans-admin-ui.md b/changelog/2026/jan/TASK-006-agent-plans-admin-ui.md new file mode 100644 index 0000000..1826ace --- /dev/null +++ b/changelog/2026/jan/TASK-006-agent-plans-admin-ui.md @@ -0,0 +1,2214 @@ +# TASK-006: Agent Plans Admin UI + +**Status:** all_phases_verified (Ready for human approval) +**Created:** 2026-01-02 +**Last Updated:** 2026-01-02 23:45 by Claude Opus 4.5 (Verification Agent) +**Assignee:** Claude Opus 4.5 (Implementation Agent) +**Verifier:** Claude Opus 4.5 (Verification Agent) + +--- + +## Critical Context (READ FIRST) + +**The agent infrastructure exists. Now we need visibility.** + +### What Already Exists + +The codebase has sophisticated agent workflow infrastructure: + +| Component | Location | Purpose | +|-----------|----------|---------| +| AgentPlan | `app/Models/Agent/AgentPlan.php` | Multi-phase work plans | +| AgentPhase | `app/Models/Agent/AgentPhase.php` | Individual phases with tasks | +| AgentSession | `app/Models/Agent/AgentSession.php` | Work sessions with handoff | +| AgentWorkspaceState | `app/Models/Agent/AgentWorkspaceState.php` | Shared state storage | +| McpToolCall | `app/Models/Mcp/McpToolCall.php` | Tool invocation logs | +| McpToolCallStat | `app/Models/Mcp/McpToolCallStat.php` | Daily aggregates | +| PlanTemplateService | `app/Services/Agent/PlanTemplateService.php` | Template-based plan creation | +| MCP Registry | `routes/mcp.php` | Agent discovery endpoints | + +**What's Missing:** Admin UI to view, manage, and monitor all of this. + +### The Vision + +A Hades admin section that provides: +1. **Plan Dashboard** — See all active plans across workspaces +2. **Phase Tracking** — Visual progress through plan phases +3. **Session Monitor** — Watch agent sessions in real-time +4. **Tool Analytics** — MCP tool usage and performance +5. **API Key Management** — Enable external agent access +6. **Plan Templates** — Browse and create from templates + +This becomes the control tower for AI-stabilised hosting — where humans supervise agent work. + +--- + +## Objective + +Build a comprehensive Agent Plans admin UI in the Hades section that surfaces all existing agent infrastructure. Enable operators to monitor, manage, and guide agent work across the platform. + +**"Done" looks like:** +- Hades users can see all agent plans and their progress +- Real-time session monitoring shows active agent work +- MCP tool analytics reveal usage patterns +- API keys allow external agents to create/update plans +- Plan templates can be browsed and instantiated + +--- + +## Acceptance Criteria + +### Phase 1: Plan Dashboard ✅ + +- [x] AC1: Route `hub.agents.plans` shows all AgentPlans (filterable by workspace, status) +- [x] AC2: Plan list shows: title, workspace, status, phase progress, last activity +- [x] AC3: Plan detail view shows all phases with task checklists +- [x] AC4: Phase progress displayed as visual percentage bar +- [x] AC5: Can manually update plan status (activate, complete, archive) +- [x] AC6: Can manually update phase status (start, complete, block, skip) + +### Phase 2: Session Monitor ✅ + +- [x] AC7: Route `hub.agents.sessions` shows all AgentSessions +- [x] AC8: Active sessions show real-time activity (polling or WebSocket) +- [x] AC9: Session detail shows: work log, artifacts, handoff notes +- [x] AC10: Can view session context summary and final summary +- [x] AC11: Timeline view shows session sequence within a plan +- [x] AC12: Can pause/resume/fail active sessions manually + +### Phase 3: Tool Analytics ✅ + +- [x] AC13: Route `hub.agents.tools` shows MCP tool usage dashboard +- [x] AC14: Top 10 tools by usage displayed +- [x] AC15: Daily trend chart (calls per day, 30-day window) +- [x] AC16: Server breakdown shows usage by MCP server +- [x] AC17: Error rate and average duration displayed per tool +- [x] AC18: Can drill down to individual tool calls with full params + +### Phase 4: API Key Management ✅ + +- [x] AC19: Route `hub.agents.api-keys` manages agent API access +- [x] AC20: Can create API keys scoped to workspace +- [x] AC21: Keys have configurable permissions (read plans, write plans, execute tools) +- [x] AC22: Key usage tracking (last used, call count) +- [x] AC23: Can revoke keys immediately +- [x] AC24: Rate limiting configuration per key + +### Phase 5: Plan Templates ✅ + +- [x] AC25: Route `hub.agents.templates` lists available plan templates +- [x] AC26: Template preview shows phases and variables +- [x] AC27: Can create new plan from template with variable input +- [x] AC28: Template categories displayed for organisation +- [x] AC29: Can import custom templates (YAML upload) + +--- + +## Implementation Checklist + +### Routes (`routes/web.php`) + +Add after line 164 (after Commerce routes), inside the hub group: + +```php +// Agent Operations (Hades only) +Route::prefix('agents')->name('agents.')->group(function () { + Route::get('/', \App\Livewire\Admin\Agent\Dashboard::class)->name('index'); + Route::get('/plans', \App\Livewire\Admin\Agent\Plans::class)->name('plans'); + Route::get('/plans/{slug}', \App\Livewire\Admin\Agent\PlanDetail::class)->name('plans.show'); + Route::get('/sessions', \App\Livewire\Admin\Agent\Sessions::class)->name('sessions'); + Route::get('/sessions/{id}', \App\Livewire\Admin\Agent\SessionDetail::class)->name('sessions.show'); + Route::get('/tools', \App\Livewire\Admin\Agent\ToolAnalytics::class)->name('tools'); + Route::get('/tools/calls', \App\Livewire\Admin\Agent\ToolCalls::class)->name('tools.calls'); + Route::get('/api-keys', \App\Livewire\Admin\Agent\ApiKeys::class)->name('api-keys'); + Route::get('/templates', \App\Livewire\Admin\Agent\Templates::class)->name('templates'); +}); +``` + +- [x] Add route group `hub/agents` +- [x] Route `hub.agents.index` → Dashboard (overview) +- [x] Route `hub.agents.plans` → Plans (list) +- [x] Route `hub.agents.plans.show` → PlanDetail (single plan by slug) +- [x] Route `hub.agents.sessions` → Sessions (list) *(Phase 2)* ✅ +- [x] Route `hub.agents.sessions.show` → SessionDetail (single session) *(Phase 2)* ✅ +- [x] Route `hub.agents.tools` → ToolAnalytics (MCP stats) *(Phase 3)* ✅ +- [x] Route `hub.agents.tools.calls` → ToolCalls (detailed logs) *(Phase 3)* ✅ +- [x] Route `hub.agents.api-keys` → ApiKeys (key management) *(Phase 4)* ✅ +- [x] Route `hub.agents.templates` → Templates (template browser) *(Phase 5)* ✅ + +### Livewire Components (`app/Livewire/Admin/Agent/`) + +**Create directory:** `mkdir -p app/Livewire/Admin/Agent` + +Each component should check `$this->authorize()` or `auth()->user()->isHades()` in mount(). + +- [x] Create `Dashboard.php` — Overview with key metrics ✅ + - Query: `AgentPlan::where('status', 'active')->count()` + - Query: `AgentSession::where('status', 'active')->count()` + - Query: `McpToolCallStat::getTopTools()` + - Query: `McpToolCallStat::getDailyTrend()` + +- [x] Create `Plans.php` — Plan list with filters ✅ + - Properties: `$status`, `$workspace`, `$search`, `$perPage` + - Query: `AgentPlan::with(['workspace', 'agentPhases'])->filter()->paginate()` + - Methods: `activate()`, `archive()`, `delete()` + +- [x] Create `PlanDetail.php` — Single plan with phases ✅ + - Property: `AgentPlan $plan` (route model binding via slug) + - Relationships: `$plan->agentPhases`, `$plan->sessions`, `$plan->states` + - Methods: `updatePhaseStatus()`, `completeTask()`, `addTask()` + +- [x] Create `Sessions.php` — Session list ✅ + - Properties: `$status`, `$agentType`, `$planSlug`, `$workspace`, `$search` + - Query: `AgentSession::with(['plan', 'workspace'])->filter()->paginate()` + - Methods: `pause()`, `resume()`, `complete()`, `fail()`, `clearFilters()` + +- [x] Create `SessionDetail.php` — Single session with logs ✅ + - Property: `AgentSession $session` + - Display: `$session->work_log`, `$session->artifacts`, `$session->handoff_notes` + - Methods: `pauseSession()`, `resumeSession()`, `completeSession()`, `failSession()`, `poll()` + - Polling: 5-second interval for active sessions (disabled when ended) + +- [x] Create `ToolAnalytics.php` — MCP usage charts ✅ + - Query: `McpToolCallStat::getTopTools()`, `getDailyTrend()`, `getServerStats()` + - Chart data for Chart.js with daily trend visualization + - Filters: days (7/14/30), workspace, server + +- [x] Create `ToolCalls.php` — Tool call log browser ✅ + - Properties: `$search`, `$server`, `$tool`, `$status`, `$workspace`, `$agentType` + - Query: `McpToolCall::with(['workspace'])->filter()->paginate()` + - Modal detail view for individual tool calls (AC18) + +- [x] Create `ApiKeys.php` — Key CRUD *(Phase 4)* ✅ + - Methods: `createKey()`, `updateKey()`, `revokeKey()` + - Display plaintext key ONCE on creation + - Filters: workspace, status (active/revoked/expired) + - Edit modal for permissions and rate limit updates + +- [x] Create `Templates.php` — Template browser and instantiation *(Phase 5)* ✅ + - Uses: `PlanTemplateService::list()`, `get()`, `createPlan()`, `previewTemplate()` + - Modal for variable input before instantiation + - YAML import with validation and preview + - Category filtering and search + - Template preview with phases and variables + +### Views (`resources/views/admin/livewire/agent/`) + +- [x] Create `dashboard.blade.php` ✅ +- [x] Create `plans.blade.php` ✅ +- [x] Create `plan-detail.blade.php` ✅ +- [x] Create `sessions.blade.php` *(Phase 2)* ✅ +- [x] Create `session-detail.blade.php` *(Phase 2)* ✅ +- [x] Create `tool-analytics.blade.php` *(Phase 3)* ✅ +- [x] Create `tool-calls.blade.php` *(Phase 3)* ✅ +- [x] Create `api-keys.blade.php` *(Phase 4)* ✅ +- [x] Create `templates.blade.php` *(Phase 5)* ✅ + +### API Endpoints (`routes/api.php`) + +- [ ] Add API route group `api/v1/agents` with API key auth +- [ ] `GET /api/v1/agents/plans` — List plans for workspace +- [ ] `POST /api/v1/agents/plans` — Create plan (from template or raw) +- [ ] `GET /api/v1/agents/plans/{slug}` — Get plan detail +- [ ] `PATCH /api/v1/agents/plans/{slug}` — Update plan status +- [ ] `POST /api/v1/agents/plans/{slug}/phases/{id}/tasks` — Add task to phase +- [ ] `PATCH /api/v1/agents/plans/{slug}/phases/{id}/tasks/{name}` — Complete task +- [ ] `POST /api/v1/agents/sessions` — Start new session +- [ ] `PATCH /api/v1/agents/sessions/{id}` — Update session (log, artifacts, handoff) +- [ ] `POST /api/v1/agents/sessions/{id}/complete` — End session with summary +- [ ] `GET /api/v1/agents/templates` — List available templates +- [ ] `POST /api/v1/agents/templates/{slug}/instantiate` — Create plan from template + +### Models & Migrations + +- [x] Create `AgentApiKey` model with: *(Phase 4)* ✅ + - workspace_id, name, key (hashed), permissions (JSON) + - last_used_at, call_count, rate_limit + - expires_at, revoked_at + - Key methods: `generate()`, `findByKey()`, `hasPermission()`, `revoke()`, `recordUsage()` +- [x] Migration for `agent_api_keys` table *(Phase 4)* ✅ +- [x] Add `api_key_id` to `agent_sessions` table (track which key started session) *(Phase 4)* ✅ +- [x] Add `api_key_id` to `mcp_tool_calls` table (track which key made call) *(Phase 4)* ✅ + +### Services + +- [x] Create `AgentApiKeyService.php`: *(Phase 4)* ✅ + - `create()`, `revoke()`, `validate()` + - `checkPermission()`, `checkPermissions()`, `recordUsage()` + - `isRateLimited()`, `getRateLimitStatus()` + - `authenticate()` — Full auth flow with rate limiting + - `updatePermissions()`, `updateRateLimit()` +- [x] `PlanTemplateService.php` already has all needed methods *(Phase 5)* ✅ + - `list()`, `get()`, `createPlan()`, `previewTemplate()` + - `getCategories()`, `getByCategory()`, `validateVariables()` + - YAML import handled directly in Livewire component + +### Sidebar Integration + +- [x] Add "Agents" group to Hades sidebar: ✅ + ``` + Agents + ├── Dashboard → hub.agents.index ✅ + ├── Plans → hub.agents.plans ✅ + ├── Sessions → hub.agents.sessions ✅ (Phase 2) + ├── Tool Analytics → hub.agents.tools ✅ (Phase 3) + ├── API Keys → hub.agents.api-keys (Phase 4) + └── Templates → hub.agents.templates (Phase 5) + ``` +- [x] Sessions link added to sidebar *(Phase 2)* ✅ +- [x] Sessions quick link activated in dashboard *(Phase 2)* ✅ +- [x] Add badge for plans needing attention (blocked phases) ✅ +- [x] Tool Analytics link added to sidebar *(Phase 3)* ✅ +- [x] Tool Analytics quick link activated in dashboard *(Phase 3)* ✅ +- [x] API Keys link added to sidebar *(Phase 4)* ✅ +- [x] Templates link added to sidebar *(Phase 5)* ✅ +- [x] Templates quick link activated in dashboard *(Phase 5)* ✅ + +### Testing + +- [ ] Feature test: Plan list filters work +- [ ] Feature test: Plan status transitions work +- [ ] Feature test: Session creation and update work +- [ ] Feature test: API key authentication works +- [ ] Feature test: API key permissions enforced +- [ ] Feature test: Rate limiting works +- [ ] Feature test: Template instantiation works +- [ ] Browser test: Dashboard loads with charts +- [ ] Browser test: Real-time session updates work + +--- + +## UI Specifications + +### Agent Dashboard (Overview) + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Agent Operations [Refresh] │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 12 │ │ 3 │ │ 847 │ │ 98.2% │ │ +│ │ Active │ │ Sessions │ │ Tool │ │ Success │ │ +│ │ Plans │ │ Today │ │ Calls │ │ Rate │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +│ │ +│ Recent Activity Tool Usage (7 days) │ +│ ┌─────────────────────────┐ ┌─────────────────────┐ │ +│ │ • Plan "content-gen" │ │ ▓▓▓▓▓▓▓▓░░ 80% │ │ +│ │ Phase 2 completed │ │ content_create │ │ +│ │ 2 minutes ago │ │ │ │ +│ │ │ │ ▓▓▓▓▓░░░░░ 50% │ │ +│ │ • Session opus-abc123 │ │ content_read │ │ +│ │ Started work on plan │ │ │ │ +│ │ 5 minutes ago │ │ ▓▓▓░░░░░░░ 30% │ │ +│ └─────────────────────────┘ │ search_docs │ │ +│ └─────────────────────┘ │ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Plan Detail View + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Plan: Content Migration Status: Active│ +│ Workspace: main │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Progress: ████████████░░░░░░░░ 60% │ +│ │ +│ Phases: │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ ✓ Phase 1: Audit Existing Content [Completed] ││ +│ │ └─ 5/5 tasks complete ││ +│ ├─────────────────────────────────────────────────────────────┤│ +│ │ ● Phase 2: Migrate Blog Posts [In Progress] ││ +│ │ ├─ ✓ Export WordPress posts ││ +│ │ ├─ ✓ Transform to native format ││ +│ │ ├─ ○ Import to ContentItem ││ +│ │ └─ ○ Verify all posts render ││ +│ │ Progress: ██████░░░░ 50% ││ +│ ├─────────────────────────────────────────────────────────────┤│ +│ │ ○ Phase 3: Migrate Help Articles [Pending] ││ +│ │ └─ Waiting for Phase 2 ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +│ Sessions: │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ sess_abc123 │ opus │ Active │ Started 10m ago │ [View] ││ +│ │ sess_xyz789 │ sonnet │ Completed │ 2h duration │ [View] ││ +│ └─────────────────────────────────────────────────────────────┘│ +└─────────────────────────────────────────────────────────────────┘ +``` + +### Session Detail View + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Session: sess_abc123 Agent: opus │ +│ Plan: Content Migration Status: Active │ +├─────────────────────────────────────────────────────────────────┤ +│ │ +│ Duration: 10m 23s Last Active: 30s ago │ +│ │ +│ Work Log: │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ 15:30:00 [info] Starting phase 2 execution ││ +│ │ 15:30:15 [success] Exported 47 WordPress posts ││ +│ │ 15:32:00 [info] Transforming post format... ││ +│ │ 15:35:22 [checkpoint] 25/47 posts transformed ││ +│ │ 15:38:45 [success] All posts transformed ││ +│ │ 15:39:00 [info] Beginning import to ContentItem... ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +│ Artifacts: │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ storage/exports/wp-posts.json │ created │ 15:30:15 ││ +│ │ app/Services/ContentImporter.php │ modified │ 15:35:22 ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +│ Handoff Notes: │ +│ ┌─────────────────────────────────────────────────────────────┐│ +│ │ Summary: Completed export and transformation phases. ││ +│ │ Next: Import remaining 22 posts, verify rendering. ││ +│ │ Blockers: None currently. ││ +│ └─────────────────────────────────────────────────────────────┘│ +│ │ +│ [Pause Session] [Complete Session] [Fail Session] │ +└─────────────────────────────────────────────────────────────────┘ +``` + +--- + +## API Authentication + +### Key Generation + +```php +// Create key +$key = AgentApiKey::create([ + 'workspace_id' => $workspace->id, + 'name' => 'Claude Code Integration', + 'permissions' => ['plans.read', 'plans.write', 'sessions.write'], + 'rate_limit' => 100, // per minute + 'expires_at' => now()->addYear(), +]); + +// Returns unhashed key ONCE for user to copy +return $key->plainTextKey; // ak_live_xxxxxxxxxxxx +``` + +### Key Usage + +```bash +# External agent creates a plan +curl -X POST https://host.uk.com/api/v1/agents/plans \ + -H "Authorization: Bearer ak_live_xxxxxxxxxxxx" \ + -H "Content-Type: application/json" \ + -d '{ + "template": "content-migration", + "variables": { + "source": "wordpress", + "workspace": "main" + } + }' + +# Agent logs work to session +curl -X PATCH https://host.uk.com/api/v1/agents/sessions/sess_abc123 \ + -H "Authorization: Bearer ak_live_xxxxxxxxxxxx" \ + -d '{ + "work_log": { + "type": "checkpoint", + "message": "Completed 25/47 posts" + } + }' +``` + +### Permissions + +| Permission | Allows | +|------------|--------| +| `plans.read` | List and view plans | +| `plans.write` | Create, update, archive plans | +| `phases.write` | Update phase status, add/complete tasks | +| `sessions.read` | List and view sessions | +| `sessions.write` | Start, update, complete sessions | +| `tools.read` | View tool analytics | +| `templates.read` | List and view templates | +| `templates.instantiate` | Create plans from templates | + +--- + +## Dependencies + +- Flux UI components (cards, tables, charts) +- Chart library for analytics (ApexCharts or Chart.js via Livewire) +- Real-time updates (Livewire polling or Laravel Echo) +- Existing agent models (AgentPlan, AgentPhase, AgentSession) +- Existing MCP models (McpToolCall, McpToolCallStat) + +--- + +## Integration with Existing Infrastructure + +### MCP Registry + +The existing MCP registry at `mcp.host.uk.com` provides agent discovery. The new API endpoints extend this with: +- Plan management (create, track, complete) +- Session logging (work log, artifacts, handoff) +- State persistence (shared workspace state) + +### Entitlement Gating + +Future: Add entitlement features for agent access: +- `agents.plans.create` — Can create agent plans +- `agents.sessions.concurrent` — Max concurrent sessions +- `agents.tools.calls` — Monthly tool call limit +- `agents.api_keys` — Max API keys per workspace + +### External Agent Flow + +``` +External Agent (Claude Code, Cursor, etc.) + │ + ├─ Discovers Host Hub via mcp.host.uk.com + │ + ├─ Authenticates with API key + │ + ├─ Creates plan from template + │ POST /api/v1/agents/plans + │ + ├─ Starts session + │ POST /api/v1/agents/sessions + │ + ├─ Logs work progress + │ PATCH /api/v1/agents/sessions/{id} + │ + ├─ Completes tasks + │ PATCH /api/v1/agents/plans/{slug}/phases/{id}/tasks/{name} + │ + └─ Completes session with handoff notes + POST /api/v1/agents/sessions/{id}/complete +``` + +--- + +## Notes + +### Why API Keys (Not OAuth) + +For agent-to-agent communication: +- OAuth is designed for human authorization flows +- API keys are simpler for programmatic access +- Keys can be scoped per workspace and permission +- Rate limiting is straightforward +- Revocation is immediate + +### Real-Time Considerations + +For session monitoring: +- Start with Livewire polling (every 5 seconds) +- Upgrade to WebSocket (Laravel Echo) if needed +- Consider SSE for one-way updates (server → browser) + +### Multi-System Cooperation + +The API enables: +1. **Claude Code** creates plan for Host Hub work +2. **Cursor** picks up session for code changes +3. **Host Hub AI** generates content as directed +4. **Human** reviews in admin UI, approves or redirects + +Each system maintains its own context but shares state via the plan. + +--- + +## Verification Results + +### Phase 1 Verification (2026-01-02 19:30) + +**Verification Agent:** Claude Opus 4.5 +**Verdict:** ✅ PASS - All Phase 1 acceptance criteria met + +#### AC1: Route `hub.agents.plans` shows all AgentPlans (filterable by workspace, status) ✅ + +**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/Plans.php` + +**Evidence - Routes (lines 180-185):** +```php +Route::prefix('agents')->name('agents.')->group(function () { + Route::get('/', \App\Livewire\Admin\Agent\Dashboard::class)->name('index'); + Route::get('/plans', \App\Livewire\Admin\Agent\Plans::class)->name('plans'); + Route::get('/plans/{slug}', \App\Livewire\Admin\Agent\PlanDetail::class)->name('plans.show'); +}); +``` + +**Evidence - Plans.php (lines 39-61):** +```php +public function plans(): LengthAwarePaginator +{ + $query = AgentPlan::with(['workspace', 'agentPhases']) + ->withCount('sessions'); + + if ($this->search) { ... } + if ($this->status) { $query->where('status', $this->status); } + if ($this->workspace) { $query->where('workspace_id', $this->workspace); } + + return $query->latest('updated_at')->paginate($this->perPage); +} +``` + +**Filters confirmed:** Search (title/slug/description), Status (draft/active/completed/archived), Workspace ✅ + +#### AC2: Plan list shows: title, workspace, status, phase progress, last activity ✅ + +**Method:** Code inspection of `resources/views/admin/livewire/agent/plans.blade.php` + +**Evidence - Table headers (lines 44-53):** +```blade +Plan +Workspace +Status +Progress +Sessions +Last Activity +``` + +**All required columns present:** ✅ +- Title (line 64): `{{ $plan->title }}` +- Workspace (line 69): `{{ $plan->workspace?->name ?? 'N/A' }}` +- Status (lines 71-86): Coloured badge with ucfirst status +- Progress (lines 88-96): Visual bar + percentage + phases count +- Last Activity (lines 100-102): `{{ $plan->updated_at->diffForHumans() }}` + +#### AC3: Plan detail view shows all phases with task checklists ✅ + +**Method:** Code inspection of `resources/views/admin/livewire/agent/plan-detail.blade.php` + +**Evidence - Phases section (lines 66-183):** +```blade + + Phases + @foreach($this->phases as $phase) + + @if($phase->tasks && count($phase->tasks) > 0) +
+ @foreach($phase->tasks as $index => $task) + + @endforeach +
+ @endif + @endforeach +
+``` + +**Task checklist features:** +- Checkbox toggle for completing tasks (line 143-156) +- Completed tasks show strikethrough (line 158) +- Optional task notes displayed (lines 159-161) +- "Add Task" modal (lines 248-274) ✅ + +#### AC4: Phase progress displayed as visual percentage bar ✅ + +**Method:** Code inspection of views + +**Evidence - Plan-level progress (lines 29-56):** +```blade +
+
+
+``` + +**Evidence - Phase-level progress (lines 96-102):** +```blade +@if($taskProgress['total'] > 0) +
+
+
+ {{ $taskProgress['completed'] }}/{{ $taskProgress['total'] }} +@endif +``` + +**Progress bars present at:** +- Plan list (each row has progress bar + percentage) +- Plan detail (overview card with large progress bar) +- Each phase (task completion progress) ✅ + +#### AC5: Can manually update plan status (activate, complete, archive) ✅ + +**Method:** Code inspection of `Plans.php` and `PlanDetail.php` + +**Evidence - Plans.php (lines 103-122):** +```php +public function activate(int $planId): void { + $plan = AgentPlan::findOrFail($planId); + $plan->activate(); +} + +public function complete(int $planId): void { + $plan = AgentPlan::findOrFail($planId); + $plan->complete(); +} + +public function archive(int $planId): void { + $plan = AgentPlan::findOrFail($planId); + $plan->archive('Archived via admin UI'); +} +``` + +**Evidence - PlanDetail.php (lines 55-72):** +```php +public function activatePlan(): void { $this->plan->activate(); } +public function completePlan(): void { $this->plan->complete(); } +public function archivePlan(): void { $this->plan->archive('Archived via admin UI'); } +``` + +**UI buttons confirmed:** +- Plans list: Dropdown menu with Activate/Complete/Archive/Delete (lines 108-122) +- Plan detail: Header buttons for Activate/Complete/Archive (lines 17-26) ✅ + +#### AC6: Can manually update phase status (start, complete, block, skip) ✅ + +**Method:** Code inspection of `PlanDetail.php` + +**Evidence - Phase actions (lines 75-120):** +```php +public function startPhase(int $phaseId): void { + $phase = AgentPhase::findOrFail($phaseId); + if (! $phase->canStart()) { return; } + $phase->start(); +} + +public function completePhase(int $phaseId): void { + $phase = AgentPhase::findOrFail($phaseId); + $phase->complete(); +} + +public function blockPhase(int $phaseId): void { + $phase = AgentPhase::findOrFail($phaseId); + $phase->block('Blocked via admin UI'); +} + +public function skipPhase(int $phaseId): void { + $phase = AgentPhase::findOrFail($phaseId); + $phase->skip('Skipped via admin UI'); +} + +public function resetPhase(int $phaseId): void { + $phase = AgentPhase::findOrFail($phaseId); + $phase->reset(); +} +``` + +**Evidence - View dropdown (lines 106-128):** +```blade + + @if($phase->isPending()) + Start Phase + @endif + @if($phase->isInProgress()) + Complete Phase + Block Phase + @endif + @if($phase->isBlocked()) + Unblock (Reset) + @endif + @if(!$phase->isCompleted() && !$phase->isSkipped()) + Skip Phase + @endif + @if($phase->isCompleted() || $phase->isSkipped()) + Reset to Pending + @endif + +``` + +**All phase status actions available:** Start, Complete, Block, Skip, Reset ✅ + +### Phase 1 Summary + +| AC | Description | Evidence | Status | +|----|-------------|----------|--------| +| AC1 | Route exists with filters | `routes/web.php:184`, `Plans.php` query builder | ✅ PASS | +| AC2 | Plan list columns | `plans.blade.php` table with all 6 columns | ✅ PASS | +| AC3 | Phases with task checklists | `plan-detail.blade.php:132-165` task list with checkboxes | ✅ PASS | +| AC4 | Visual progress bars | Plan list + detail + per-phase progress | ✅ PASS | +| AC5 | Plan status updates | `activate()`, `complete()`, `archive()` methods | ✅ PASS | +| AC6 | Phase status updates | `startPhase()`, `completePhase()`, `blockPhase()`, `skipPhase()`, `resetPhase()` | ✅ PASS | + +**Additional Implementation Verified:** +- Hades access control in all components (`checkHadesAccess()` in mount) +- Sidebar integration (lines 520-576 in sidebar.blade.php) +- Dashboard with stats and recent activity (`Dashboard.php`) +- Task management (add task modal, complete task) +- Session list in plan detail view + +**Phase 1 Status:** ✅ VERIFIED — Ready for human approval + +--- + +### Phase 2 Verification (2026-01-02 20:00) + +**Verification Agent:** Claude Opus 4.5 +**Verdict:** ✅ PASS - All Phase 2 acceptance criteria met + +#### AC7: Route `hub.agents.sessions` shows all AgentSessions ✅ + +**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/Sessions.php` + +**Evidence - Routes (lines 187-188):** +```php +Route::get('/sessions', \App\Livewire\Admin\Agent\Sessions::class)->name('sessions'); +Route::get('/sessions/{id}', \App\Livewire\Admin\Agent\SessionDetail::class)->name('sessions.show'); +``` + +**Evidence - Sessions.php (lines 46-76):** +```php +public function sessions(): LengthAwarePaginator +{ + $query = AgentSession::with(['workspace', 'plan']); + + if ($this->search) { ... } + if ($this->status) { $query->where('status', $this->status); } + if ($this->agentType) { $query->where('agent_type', $this->agentType); } + if ($this->workspace) { $query->where('workspace_id', $this->workspace); } + if ($this->planSlug) { $query->whereHas('plan', ...); } + + return $query->latest('last_active_at')->paginate($this->perPage); +} +``` + +**Filters confirmed:** Search, Status, Agent Type, Workspace, Plan ✅ + +#### AC8: Active sessions show real-time activity (polling or WebSocket) ✅ + +**Method:** Code inspection of `SessionDetail.php` and `session-detail.blade.php` + +**Evidence - Polling implementation (SessionDetail.php lines 27-41, 104-114):** +```php +public int $pollingInterval = 5000; + +public function mount(int $id): void +{ + // Disable polling for completed/failed sessions + if ($this->session->isEnded()) { + $this->pollingInterval = 0; + } +} + +public function poll(): void +{ + $this->session->refresh(); + if ($this->session->isEnded()) { + $this->pollingInterval = 0; + } +} +``` + +**Evidence - View polling directive (session-detail.blade.php line 1):** +```blade +
+``` + +**Polling behaviour:** +- 5-second interval for active sessions +- Automatically disabled when session ends +- Refreshes session data on each poll ✅ + +#### AC9: Session detail shows: work log, artifacts, handoff notes ✅ + +**Method:** Code inspection of `session-detail.blade.php` + +**Evidence - Work Log (lines 143-188):** +```blade + +
+ Work Log +
+ @foreach($this->recentWorkLog as $entry) + + @endforeach +
+``` + +**Evidence - Artifacts (lines 228-257):** +```blade + + Artifacts + @foreach($this->artifacts as $artifact) + + @endforeach + +``` + +**Evidence - Handoff Notes (lines 259-296):** +```blade + + Handoff Notes + + +``` + +**All three sections present with proper data display** ✅ + +#### AC10: Can view session context summary and final summary ✅ + +**Method:** Code inspection of `SessionDetail.php` and `session-detail.blade.php` + +**Evidence - Context Summary computed property (lines 69-73):** +```php +#[Computed] +public function contextSummary(): ?array +{ + return $this->session->context_summary; +} +``` + +**Evidence - Context Summary view (lines 110-141):** +```blade +@if($this->contextSummary) + + Context Summary + + +@endif +``` + +**Evidence - Final Summary view (lines 190-200):** +```blade +@if($session->final_summary) + + Final Summary + {{ $session->final_summary }} + +@endif +``` + +**Both summary types displayed when present** ✅ + +#### AC11: Timeline view shows session sequence within a plan ✅ + +**Method:** Code inspection of `SessionDetail.php` and `session-detail.blade.php` + +**Evidence - Plan Sessions computed property (lines 75-85):** +```php +#[Computed] +public function planSessions(): Collection +{ + if (! $this->session->agent_plan_id) { + return collect(); + } + return AgentSession::where('agent_plan_id', $this->session->agent_plan_id) + ->orderBy('started_at') + ->get(); +} +``` + +**Evidence - Session Index (lines 87-102):** +```php +#[Computed] +public function sessionIndex(): int +{ + // Returns 1-based index of current session in plan +} +``` + +**Evidence - Timeline view (lines 71-105):** +```blade +@if($session->agent_plan_id && $this->planSessions->count() > 1) + + Plan Timeline (Session {{ $this->sessionIndex }} of {{ $this->planSessions->count() }}) +
+ @foreach($this->planSessions as $index => $planSession) + + + @endforeach +
+
+@endif +``` + +**Timeline shows:** +- Session number in sequence (1 of N) +- All sessions ordered by start time +- Current session highlighted +- Click to navigate to other sessions +- Status indicators (active pulse, completed/failed colours) ✅ + +#### AC12: Can pause/resume/fail active sessions manually ✅ + +**Method:** Code inspection of `Sessions.php`, `SessionDetail.php`, and views + +**Evidence - Sessions.php list actions (lines 127-153):** +```php +public function pause(int $sessionId): void { $session->pause(); } +public function resume(int $sessionId): void { $session->resume(); } +public function complete(int $sessionId): void { $session->complete('...'); } +public function fail(int $sessionId): void { $session->fail('...'); } +``` + +**Evidence - SessionDetail.php actions (lines 117-156):** +```php +public function pauseSession(): void { $this->session->pause(); } +public function resumeSession(): void { $this->session->resume(); } +public function completeSession(): void { $this->session->complete($this->completeSummary); } +public function failSession(): void { $this->session->fail($this->failReason); } +``` + +**Evidence - Sessions list dropdown (sessions.blade.php lines 143-157):** +```blade + + @if($session->isActive()) + Pause + @endif + @if($session->isPaused()) + Resume + @endif + Complete + Fail + +``` + +**Evidence - Session detail buttons (session-detail.blade.php lines 28-39):** +```blade +@if($session->isActive()) + Pause +@elseif($session->isPaused()) + Resume +@endif +@if(!$session->isEnded()) + Complete + Fail +@endif +``` + +**Complete/Fail modals (lines 300-324):** +- Complete modal with optional summary +- Fail modal with reason input ✅ + +### Phase 2 Summary + +| AC | Description | Evidence | Status | +|----|-------------|----------|--------| +| AC7 | Sessions route with filters | `routes/web.php:187-188`, `Sessions.php` query builder | ✅ PASS | +| AC8 | Real-time polling | `wire:poll.5000ms`, disabled when session ends | ✅ PASS | +| AC9 | Work log, artifacts, handoff notes | Three dedicated sections in `session-detail.blade.php` | ✅ PASS | +| AC10 | Context and final summary | Computed properties + conditional display | ✅ PASS | +| AC11 | Timeline view | Horizontal timeline with session sequence navigation | ✅ PASS | +| AC12 | Manual session controls | Pause/Resume/Complete/Fail with modals | ✅ PASS | + +**Additional Implementation Verified:** +- Hades access control in both components +- Sidebar link at line 558 (`hub.agents.sessions`) +- Dashboard quick link at line 160 +- Active session count indicator with animated pulse +- Agent type badges (Opus/Sonnet/Haiku) +- Status colour coding + +**Phase 2 Status:** ✅ VERIFIED — Ready for human approval + +--- + +### Phase 3 Verification (2026-01-02 21:45) + +**Verification Agent:** Claude Opus 4.5 +**Verdict:** ✅ PASS - All Phase 3 acceptance criteria met + +#### AC13: Route `hub.agents.tools` shows MCP tool usage dashboard ✅ + +**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/ToolAnalytics.php` + +**Evidence - Routes (lines 189-191):** +```php +/ Phase 3: Tool Analytics +Route::get('/tools', \App\Livewire\Admin\Agent\ToolAnalytics::class)->name('tools'); +Route::get('/tools/calls', \App\Livewire\Admin\Agent\ToolCalls::class)->name('tools.calls'); +``` + +**Evidence - ToolAnalytics.php (lines 17-18, 29-32):** +```php +#[Title('Tool Analytics')] +class ToolAnalytics extends Component +{ + public function mount(): void + { + $this->checkHadesAccess(); + } +} +``` + +**Dashboard features:** +- Stats cards: Total calls, Successful, Errors, Success rate, Unique tools (lines 51-111 in view) +- Filters: Days (7/14/30/90), Workspace, Server (lines 15-48 in view) +- Hades access control enforced ✅ + +#### AC14: Top 10 tools by usage displayed ✅ + +**Method:** Code inspection of `ToolAnalytics.php` and `tool-analytics.blade.php` + +**Evidence - ToolAnalytics.php (lines 77-88):** +```php +#[Computed] +public function topTools(): Collection +{ + $workspaceId = $this->workspace ? (int) $this->workspace : null; + $tools = McpToolCallStat::getTopTools($this->days, 10, $workspaceId); + + if ($this->server) { + $tools = $tools->filter(fn ($t) => $t->server_id === $this->server)->values(); + } + + return $tools->take(10); +} +``` + +**Evidence - View (lines 168-236):** +```blade +Top 10 Tools + + + + + + @foreach($this->topTools as $tool) + + @endforeach + +
ToolServerCallsSuccess RateErrorsAvg Duration
+``` + +**Top 10 tools displayed with:** +- Tool name, Server ID +- Total calls count +- Success rate (colour-coded) +- Error count +- Average duration +- Drill-down button ✅ + +#### AC15: Daily trend chart (calls per day, 30-day window) ✅ + +**Method:** Code inspection of `ToolAnalytics.php` and `tool-analytics.blade.php` + +**Evidence - ToolAnalytics.php (lines 90-96, 131-142):** +```php +#[Computed] +public function dailyTrend(): Collection +{ + $workspaceId = $this->workspace ? (int) $this->workspace : null; + return McpToolCallStat::getDailyTrend($this->days, $workspaceId); +} + +#[Computed] +public function chartData(): array +{ + $trend = $this->dailyTrend; + return [ + 'labels' => $trend->pluck('date')->map(fn ($d) => $d->format('M j'))->toArray(), + 'calls' => $trend->pluck('total_calls')->toArray(), + 'errors' => $trend->pluck('total_errors')->toArray(), + 'success_rates' => $trend->pluck('success_rate')->toArray(), + ]; +} +``` + +**Evidence - Chart.js integration (lines 272-346):** +```blade + + +``` + +**Chart features:** +- Line chart with Chart.js +- Configurable window: 7/14/30/90 days (view line 19-24) +- Shows Total Calls (violet) and Errors (red) +- Dark mode support +- Responsive design ✅ + +#### AC16: Server breakdown shows usage by MCP server ✅ + +**Method:** Code inspection of `ToolAnalytics.php` and `tool-analytics.blade.php` + +**Evidence - ToolAnalytics.php (lines 98-109):** +```php +#[Computed] +public function serverStats(): Collection +{ + $workspaceId = $this->workspace ? (int) $this->workspace : null; + $stats = McpToolCallStat::getServerStats($this->days, $workspaceId); + + if ($this->server) { + $stats = $stats->filter(fn ($s) => $s->server_id === $this->server)->values(); + } + + return $stats; +} +``` + +**Evidence - View (lines 132-165):** +```blade +Server Breakdown +@foreach($this->serverStats as $serverStat) +
+ {{ $serverStat->server_id }} + {{ number_format($serverStat->total_calls) }} calls +
+
+
+ {{ $serverStat->unique_tools }} tools + {{ $serverStat->success_rate }}% success +
+@endforeach +``` + +**Server breakdown shows:** +- Server ID +- Total call count +- Visual progress bar (relative to max) +- Unique tools count +- Success rate (colour-coded) ✅ + +#### AC17: Error rate and average duration displayed per tool ✅ + +**Method:** Code inspection of `tool-analytics.blade.php` + +**Evidence - Top Tools table columns (lines 183-218):** +```blade +Success Rate +Errors +Avg Duration +... + + {{ $tool->success_rate }}% + + + @if($tool->total_errors > 0) + {{ number_format($tool->total_errors) }} + @else + 0 + @endif + + + @if($tool->avg_duration) + {{ round($tool->avg_duration) < 1000 ? round($tool->avg_duration) . 'ms' : round($tool->avg_duration / 1000, 2) . 's' }} + @endif + +``` + +**Error/duration display features:** +- Success rate with colour coding (green ≥95%, amber ≥80%, red <80%) +- Error count highlighted in red when >0 +- Duration formatted as ms or seconds +- Recent Errors section (lines 238-269) shows last 10 failures ✅ + +#### AC18: Can drill down to individual tool calls with full params ✅ + +**Method:** Code inspection of `ToolCalls.php` and `tool-calls.blade.php` + +**Evidence - ToolCalls.php (lines 133-151):** +```php +#[Computed] +public function selectedCall(): ?McpToolCall +{ + if (! $this->selectedCallId) { + return null; + } + return McpToolCall::with('workspace')->find($this->selectedCallId); +} + +public function viewCall(int $id): void +{ + $this->selectedCallId = $id; +} + +public function closeCallDetail(): void +{ + $this->selectedCallId = null; +} +``` + +**Evidence - View modal (lines 155-244):** +```blade +@if($selectedCall) + + {{ $selectedCall->tool_name }} + + + + + {{-- Input Parameters --}} + @if($selectedCall->input_params && count($selectedCall->input_params) > 0) +
+
{{ json_encode($selectedCall->input_params, JSON_PRETTY_PRINT) }}
+
+ @endif + + {{-- Error Details --}} + @if(!$selectedCall->success) +
+ Code: {{ $selectedCall->error_code }} + {{ $selectedCall->error_message }} +
+ @endif + + {{-- Result Summary --}} + @if($selectedCall->result_summary && count($selectedCall->result_summary) > 0) +
{{ json_encode($selectedCall->result_summary, JSON_PRETTY_PRINT) }}
+ @endif +
+@endif +``` + +**Drill-down features:** +- Modal with full tool call details +- Input parameters (JSON pretty-printed) +- Result summary (JSON pretty-printed) +- Error details (code + message) for failed calls +- Metadata: duration, agent type, workspace, timestamp +- Session and Plan links for traceability +- Filters: server, tool, status, workspace, agent type +- Pagination with 25 per page ✅ + +### Phase 3 Summary + +| AC | Description | Evidence | Status | +|----|-------------|----------|--------| +| AC13 | Tool usage dashboard route | `routes/web.php:190`, `ToolAnalytics.php` with Hades auth | ✅ PASS | +| AC14 | Top 10 tools by usage | `topTools()` computed, table with 6 columns | ✅ PASS | +| AC15 | Daily trend chart | Chart.js line chart, configurable 7-90 days | ✅ PASS | +| AC16 | Server breakdown | `serverStats()` computed, progress bars, success rates | ✅ PASS | +| AC17 | Error rate and duration | Table columns + colour-coded success rate | ✅ PASS | +| AC18 | Drill-down to tool calls | Modal with input_params, result_summary, error_details | ✅ PASS | + +**Additional Implementation Verified:** +- Hades access control in both components +- Sidebar link at `hub.agents.tools` +- Dashboard quick link to Tool Analytics +- Drill-down links from Top Tools table +- Recent Errors section in dashboard +- Comprehensive filtering in ToolCalls +- Pagination with proper links + +**Phase 3 Status:** ✅ VERIFIED — Ready for human approval + +--- + +### Phase 3 Implementation Notes (2026-01-02 21:30) + +**Implementation Agent:** Claude Opus 4.5 + +**Routes Added (`routes/web.php`):** +- `hub.agents.tools` → ToolAnalytics dashboard +- `hub.agents.tools.calls` → ToolCalls drill-down list + +**Livewire Components Created:** +- `app/Livewire/Admin/Agent/ToolAnalytics.php` - Dashboard with stats, charts, filters +- `app/Livewire/Admin/Agent/ToolCalls.php` - Paginated call list with modal detail + +**Views Created:** +- `resources/views/admin/livewire/agent/tool-analytics.blade.php` +- `resources/views/admin/livewire/agent/tool-calls.blade.php` + +**Phase 5:** Not yet implemented (commented out in routes) + +--- + +### Phase 4 Implementation Notes (2026-01-02 22:30) + +**Implementation Agent:** Claude Opus 4.5 + +**Route Added (`routes/web.php`):** +- `hub.agents.api-keys` → ApiKeys management + +**Model Created:** +- `app/Models/Agent/AgentApiKey.php` + - Key generation with `ak_` prefix + 32 random chars + - SHA-256 hashing for storage + - Permission constants: `PERM_PLANS_READ`, `PERM_PLANS_WRITE`, `PERM_PHASES_WRITE`, `PERM_SESSIONS_READ`, `PERM_SESSIONS_WRITE`, `PERM_TOOLS_READ`, `PERM_TEMPLATES_READ`, `PERM_TEMPLATES_INSTANTIATE` + - Status helpers: `isActive()`, `isRevoked()`, `isExpired()` + - Scopes: `active()`, `revoked()`, `expired()`, `forWorkspace()` + +**Migration Created:** +- `database/migrations/2026_01_02_220000_create_agent_api_keys_table.php` + - Creates `agent_api_keys` table with key, permissions (JSON), rate_limit, call_count, timestamps + - Adds `agent_api_key_id` foreign key to `agent_sessions` and `mcp_tool_calls` + +**Service Created:** +- `app/Services/Agent/AgentApiKeyService.php` + - `create()` — Generate new key with permissions and rate limit + - `validate()` — Validate plaintext key and return model + - `checkPermission()`, `checkPermissions()` — Verify access + - `recordUsage()` — Increment call count and cache for rate limiting + - `isRateLimited()`, `getRateLimitStatus()` — Rate limiting helpers + - `authenticate()` — Full auth flow returning structured result + - `revoke()`, `updatePermissions()`, `updateRateLimit()` + +**Livewire Component Created:** +- `app/Livewire/Admin/Agent/ApiKeys.php` + - Stats: total, active, revoked, total calls + - Filters: workspace, status + - Create modal: name, workspace, permissions, rate limit, expiry + - Created key modal: shows plaintext key ONCE + - Edit modal: update permissions and rate limit + - Revoke action with immediate effect + +**View Created:** +- `resources/views/admin/livewire/agent/api-keys.blade.php` + +**Sidebar Updated:** +- Added API Keys link to Agents submenu + +**Phase 4 Status:** ✅ COMPLETE — Ready for verification + +--- + +### Phase 4 Verification (2026-01-02 23:15) + +**Verification Agent:** Claude Opus 4.5 +**Verdict:** ✅ PASS - All Phase 4 acceptance criteria met + +#### AC19: Route `hub.agents.api-keys` manages agent API access ✅ + +**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/ApiKeys.php` + +**Evidence - Route (routes/web.php line 193):** +```php +Route::get('/api-keys', \App\Livewire\Admin\Agent\ApiKeys::class)->name('api-keys'); +``` + +**Evidence - Sidebar link (sidebar.blade.php line 568):** +```blade +API Keys +``` + +**Evidence - Hades access control (ApiKeys.php lines 49-55):** +```php +public function mount(): void +{ + $this->checkHadesAccess(); +} + +private function checkHadesAccess(): void +{ + if (! auth()->user()?->isHades()) { + abort(403, 'Hades access required'); + } +} +``` + +**Route exists and is accessible only to Hades users** ✅ + +#### AC20: Can create API keys scoped to workspace ✅ + +**Method:** Code inspection of `ApiKeys.php` and `api-keys.blade.php` + +**Evidence - ApiKeys.php createKey() (lines 89-116):** +```php +public function createKey(): void +{ + $this->validate([ + 'newKeyName' => 'required|string|max:255', + 'newKeyWorkspace' => 'required|exists:workspaces,id', + 'newKeyPermissions' => 'array', + 'newKeyRateLimit' => 'required|integer|min:1|max:10000', + ]); + + $key = $this->apiKeyService->create( + workspace: (int) $this->newKeyWorkspace, + name: $this->newKeyName, + permissions: $this->newKeyPermissions, + rateLimit: $this->newKeyRateLimit, + expiresAt: $this->newKeyExpiry ? Carbon::parse($this->newKeyExpiry) : null + ); + + $this->createdKey = $key->plainTextKey; + // ... +} +``` + +**Evidence - View workspace dropdown (api-keys.blade.php lines 211-221):** +```blade + + Select workspace... + @foreach($this->workspaces as $ws) + {{ $ws->name }} + @endforeach + +``` + +**Evidence - AgentApiKey model (lines 113-118):** +```php +public function scopeForWorkspace($query, Workspace|int $workspace) +{ + $workspaceId = $workspace instanceof Workspace ? $workspace->id : $workspace; + return $query->where('workspace_id', $workspaceId); +} +``` + +**Keys are scoped to workspace via foreign key and workspace selector** ✅ + +#### AC21: Keys have configurable permissions (read plans, write plans, execute tools) ✅ + +**Method:** Code inspection of `AgentApiKey.php` and view + +**Evidence - Permission constants (AgentApiKey.php lines 63-78):** +```php +public const PERM_PLANS_READ = 'plans.read'; +public const PERM_PLANS_WRITE = 'plans.write'; +public const PERM_PHASES_WRITE = 'phases.write'; +public const PERM_SESSIONS_READ = 'sessions.read'; +public const PERM_SESSIONS_WRITE = 'sessions.write'; +public const PERM_TOOLS_READ = 'tools.read'; +public const PERM_TEMPLATES_READ = 'templates.read'; +public const PERM_TEMPLATES_INSTANTIATE = 'templates.instantiate'; +``` + +**Evidence - availablePermissions() (lines 83-95):** +```php +public static function availablePermissions(): array +{ + return [ + self::PERM_PLANS_READ => 'List and view plans', + self::PERM_PLANS_WRITE => 'Create, update, archive plans', + self::PERM_PHASES_WRITE => 'Update phase status, add/complete tasks', + self::PERM_SESSIONS_READ => 'List and view sessions', + self::PERM_SESSIONS_WRITE => 'Start, update, complete sessions', + self::PERM_TOOLS_READ => 'View tool analytics', + self::PERM_TEMPLATES_READ => 'List and view templates', + self::PERM_TEMPLATES_INSTANTIATE => 'Create plans from templates', + ]; +} +``` + +**Evidence - View permission checkboxes (api-keys.blade.php lines 227-237):** +```blade +
+ @foreach(\Mod\Agentic\Models\AgentApiKey::availablePermissions() as $perm => $description) + + @endforeach +
+``` + +**Evidence - Permission helpers (AgentApiKey.php lines 195-220):** +```php +public function hasPermission(string $permission): bool +public function hasAnyPermission(array $permissions): bool +public function hasAllPermissions(array $permissions): bool +``` + +**8 configurable permissions with checkboxes in create/edit modals** ✅ + +#### AC22: Key usage tracking (last used, call count) ✅ + +**Method:** Code inspection of model, service, and view + +**Evidence - Migration fields (migration lines 24-25):** +```php +$table->unsignedBigInteger('call_count')->default(0); +$table->timestamp('last_used_at')->nullable(); +``` + +**Evidence - AgentApiKey recordUsage() (lines 230-236):** +```php +public function recordUsage(): self +{ + $this->increment('call_count'); + $this->update(['last_used_at' => now()]); + return $this; +} +``` + +**Evidence - AgentApiKeyService recordUsage() (lines 79-91):** +```php +public function recordUsage(AgentApiKey $key): void +{ + $key->recordUsage(); + // Increment rate limit counter in cache + $cacheKey = $this->getRateLimitCacheKey($key); + Cache::increment($cacheKey); + // ... +} +``` + +**Evidence - View table columns (api-keys.blade.php lines 106-118):** +```blade +{{ number_format($key->call_count) }} +{{ $key->getLastUsedForHumans() }} +``` + +**Evidence - Stats card (api-keys.blade.php lines 54-59):** +```blade +{{ number_format($this->stats['total_calls']) }} +Total Calls +``` + +**Usage tracked via call_count + last_used_at, displayed in table and stats** ✅ + +#### AC23: Can revoke keys immediately ✅ + +**Method:** Code inspection of service, model, and Livewire component + +**Evidence - AgentApiKey revoke() (lines 223-228):** +```php +public function revoke(): self +{ + $this->update(['revoked_at' => now()]); + return $this; +} +``` + +**Evidence - AgentApiKeyService revoke() (lines 129-135):** +```php +public function revoke(AgentApiKey $key): void +{ + $key->revoke(); + // Clear rate limit cache + Cache::forget($this->getRateLimitCacheKey($key)); +} +``` + +**Evidence - ApiKeys.php revokeKey() (lines 118-128):** +```php +public function revokeKey(int $keyId): void +{ + $key = AgentApiKey::findOrFail($keyId); + $this->apiKeyService->revoke($key); + Flux::toast( + heading: 'API Key Revoked', + text: "Key '{$key->name}' has been revoked and can no longer be used.", + variant: 'warning', + ); +} +``` + +**Evidence - View revoke button (api-keys.blade.php line 133):** +```blade + + Revoke Key + +``` + +**Evidence - isRevoked helper (AgentApiKey.php lines 184-187):** +```php +public function isRevoked(): bool +{ + return $this->revoked_at !== null; +} +``` + +**Revocation sets revoked_at timestamp, clears cache, shows confirmation** ✅ + +#### AC24: Rate limiting configuration per key ✅ + +**Method:** Code inspection of model, service, and view + +**Evidence - Migration field (line 23):** +```php +$table->integer('rate_limit')->default(100); // Calls per minute +``` + +**Evidence - AgentApiKeyService rate limiting (lines 96-124):** +```php +public function isRateLimited(AgentApiKey $key): bool +{ + $cacheKey = $this->getRateLimitCacheKey($key); + $currentCalls = (int) Cache::get($cacheKey, 0); + return $currentCalls >= $key->rate_limit; +} + +public function getRateLimitStatus(AgentApiKey $key): array +{ + $cacheKey = $this->getRateLimitCacheKey($key); + $currentCalls = (int) Cache::get($cacheKey, 0); + $remaining = max(0, $key->rate_limit - $currentCalls); + // ... + return [ + 'limit' => $key->rate_limit, + 'remaining' => $remaining, + 'reset_in_seconds' => max(0, $ttl), + 'used' => $currentCalls, + ]; +} +``` + +**Evidence - authenticate() rate limiting check (lines 253-262):** +```php +if ($this->isRateLimited($key)) { + $status = $this->getRateLimitStatus($key); + return [ + 'success' => false, + 'error' => 'rate_limited', + 'message' => 'Rate limit exceeded', + 'rate_limit' => $status, + ]; +} +``` + +**Evidence - View rate limit input (api-keys.blade.php lines 239-241):** +```blade + +``` + +**Evidence - Table column (api-keys.blade.php line 102):** +```blade +{{ $key->rate_limit }}/min +``` + +**Evidence - Edit modal rate limit (api-keys.blade.php lines 334-336):** +```blade + +``` + +**Rate limit configurable 1-10000 calls/min, enforced via Cache with 60s window** ✅ + +### Phase 4 Summary + +| AC | Description | Evidence | Status | +|----|-------------|----------|--------| +| AC19 | Route manages API access | `routes/web.php:193`, Hades auth, sidebar link | ✅ PASS | +| AC20 | Keys scoped to workspace | `workspace_id` FK, workspace dropdown in create modal | ✅ PASS | +| AC21 | Configurable permissions | 8 permissions with checkboxes, `hasPermission()` helpers | ✅ PASS | +| AC22 | Usage tracking | `call_count` + `last_used_at` fields, displayed in UI | ✅ PASS | +| AC23 | Immediate revocation | `revoke()` sets timestamp, clears cache, confirmation dialog | ✅ PASS | +| AC24 | Rate limiting per key | Configurable 1-10000/min, Cache-based enforcement | ✅ PASS | + +**Additional Implementation Verified:** +- Hades access control in component +- Sidebar link at line 568 +- Stats cards: total, active, revoked, total calls +- Create modal shows plaintext key ONCE +- Edit modal for permissions and rate limit updates +- Key expiry support (optional) +- Filter by workspace and status (active/revoked/expired) +- Foreign keys added to `agent_sessions` and `mcp_tool_calls` for tracking + +**Phase 4 Status:** ✅ VERIFIED — Ready for human approval + +--- + +### Phase 5 Implementation Notes (2026-01-02 23:45) + +**Implementation Agent:** Claude Opus 4.5 + +**Route Added (`routes/web.php`):** +- `hub.agents.templates` → Templates browser + +**Livewire Component Created:** +- `app/Livewire/Admin/Agent/Templates.php` + - Uses existing `PlanTemplateService` for all template operations + - Template listing with category filter and search + - Preview modal showing phases, tasks, variables, guidelines + - Create plan modal with variable inputs and workspace selection + - YAML import modal with file upload, validation, and preview + - Delete template functionality + +**View Created:** +- `resources/views/admin/livewire/agent/templates.blade.php` + - Stats cards: total templates, categories, total phases, with variables + - Grid layout for template cards + - Category colour coding + - Preview modal with full template details + - Create modal with variable input fields + - Import modal with drag-drop file upload + +**Sidebar Updated:** +- Added Templates link to Agents submenu + +**Dashboard Updated:** +- Templates quick link now active (was "Coming soon") + +**Existing Templates (5):** +- `bug-fix.yaml` - Bug fix workflow +- `code-review.yaml` - Code review process +- `feature-port.yaml` - Feature porting +- `new-feature.yaml` - New feature development +- `refactor.yaml` - Code refactoring + +**Phase 5 Status:** ✅ COMPLETE — Ready for verification + +--- + +### Phase 5 Verification (2026-01-02 23:45) + +**Verification Agent:** Claude Opus 4.5 +**Verdict:** ✅ PASS - All Phase 5 acceptance criteria met + +#### AC25: Route `hub.agents.templates` lists available plan templates ✅ + +**Method:** Code inspection of `routes/web.php` and `app/Livewire/Admin/Agent/Templates.php` + +**Evidence - Route (routes/web.php line 195):** +```php +Route::get('/templates', \App\Livewire\Admin\Agent\Templates::class)->name('templates'); +``` + +**Evidence - Sidebar link (sidebar.blade.php lines 573-574):** +```blade + + Templates +``` + +**Evidence - Templates.php templates() computed property (lines 76-93):** +```php +#[Computed] +public function templates(): Collection +{ + $templates = $this->templateService->list(); + + if ($this->category) { + $templates = $templates->filter(fn ($t) => $t['category'] === $this->category); + } + + if ($this->search) { + $search = strtolower($this->search); + $templates = $templates->filter(fn ($t) => ...); + } + + return $templates->values(); +} +``` + +**Evidence - View grid (templates.blade.php lines 60-149):** +```blade +
+ @foreach($this->templates as $template) + + + + @endforeach +
+``` + +**5 templates available:** bug-fix, code-review, feature-port, new-feature, refactor ✅ + +#### AC26: Template preview shows phases and variables ✅ + +**Method:** Code inspection of `Templates.php` and `templates.blade.php` + +**Evidence - previewTemplate() computed property (Templates.php lines 107-115):** +```php +#[Computed] +public function previewTemplate(): ?array +{ + if (! $this->previewSlug) { + return null; + } + return $this->templateService->previewTemplate($this->previewSlug, []); +} +``` + +**Evidence - Preview modal phases (templates.blade.php lines 207-235):** +```blade +Phases ({{ count($this->previewTemplate['phases']) }}) +
+ @foreach($this->previewTemplate['phases'] as $index => $phase) +
+ {{ $phase['order'] }} + {{ $phase['name'] }} + @if(!empty($phase['tasks'])) +
    + @foreach($phase['tasks'] as $task) +
  • {{ is_array($task) ? $task['name'] : $task }}
  • + @endforeach +
+ @endif +
+ @endforeach +
+``` + +**Evidence - Preview modal variables table (templates.blade.php lines 237-274):** +```blade +@if(!empty($variables)) + Variables + + + + + + @foreach($variables as $name => $config) + + + + + + + @endforeach + +
VariableDescriptionDefaultRequired
{{ $name }}{{ $config['description'] ?? '-' }}{{ $config['default'] ?? '-' }}{{ $config['required'] ? 'Yes' : 'No' }}
+@endif +``` + +**Preview shows:** Phases with order/name/tasks, Variables with name/description/default/required, Guidelines ✅ + +#### AC27: Can create new plan from template with variable input ✅ + +**Method:** Code inspection of `Templates.php` and `templates.blade.php` + +**Evidence - openCreateModal() (Templates.php lines 162-188):** +```php +public function openCreateModal(string $slug): void +{ + $template = $this->templateService->get($slug); + $this->createTemplateSlug = $slug; + $this->createTitle = $template['name']; + $this->createWorkspaceId = $this->workspaces->first()?->id ?? 0; + + // Initialise variables with defaults + $this->createVariables = []; + foreach ($template['variables'] ?? [] as $name => $config) { + $this->createVariables[$name] = $config['default'] ?? ''; + } + $this->showCreateModal = true; +} +``` + +**Evidence - createPlan() (Templates.php lines 198-272):** +```php +public function createPlan(): void +{ + // Validate required variables + $this->validate([ + 'createWorkspaceId' => 'required|exists:workspaces,id', + 'createTitle' => 'required|string|max:255', + ]); + + // Add variable validation + foreach ($template['variables'] ?? [] as $name => $config) { + if ($config['required'] ?? false) { + $rules["createVariables.{$name}"] = 'required|string'; + } + } + + // Create the plan via service + $plan = $this->templateService->createPlan( + $this->createTemplateSlug, + $this->createVariables, + ['title' => $this->createTitle, 'activate' => $this->createActivate], + $workspace + ); + + // Redirect to new plan + $this->redirect(route('hub.agents.plans.show', $plan->slug), navigate: true); +} +``` + +**Evidence - Create modal with variable inputs (templates.blade.php lines 319-341):** +```blade +@if(!empty($this->createTemplate['variables'])) + Template Variables +
+ @foreach($this->createTemplate['variables'] as $name => $config) + + @endforeach +
+@endif +``` + +**Create plan features:** Plan title, Workspace selection, Variable inputs, Activate immediately option, Live preview ✅ + +#### AC28: Template categories displayed for organisation ✅ + +**Method:** Code inspection of `Templates.php`, `PlanTemplateService.php`, and view + +**Evidence - categories() computed property (Templates.php lines 95-99):** +```php +#[Computed] +public function categories(): Collection +{ + return $this->templateService->getCategories(); +} +``` + +**Evidence - PlanTemplateService getCategories() (lines 319-326):** +```php +public function getCategories(): Collection +{ + return $this->list() + ->pluck('category') + ->unique() + ->sort() + ->values(); +} +``` + +**Evidence - Category filter dropdown (templates.blade.php lines 45-50):** +```blade + + All Categories + @foreach($this->categories as $cat) + {{ ucfirst($cat) }} + @endforeach + +``` + +**Evidence - Category badge in template cards (templates.blade.php lines 69-71):** +```blade + + {{ ucfirst($template['category']) }} + +``` + +**Evidence - Category colour coding (Templates.php lines 436-446):** +```php +public function getCategoryColor(string $category): string +{ + return match ($category) { + 'development' => 'bg-blue-100 text-blue-700 ...', + 'maintenance' => 'bg-green-100 text-green-700 ...', + 'review' => 'bg-amber-100 text-amber-700 ...', + 'migration' => 'bg-purple-100 text-purple-700 ...', + 'custom' => 'bg-zinc-100 text-zinc-700 ...', + default => 'bg-violet-100 text-violet-700 ...', + }; +} +``` + +**Category features:** Filter dropdown, Colour-coded badges, Stats showing category count ✅ + +#### AC29: Can import custom templates (YAML upload) ✅ + +**Method:** Code inspection of `Templates.php` and `templates.blade.php` + +**Evidence - Import modal state (Templates.php lines 53-62):** +```php +public bool $showImportModal = false; +public ?UploadedFile $importFile = null; +public string $importFileName = ''; +public ?array $importPreview = null; +public ?string $importError = null; +``` + +**Evidence - updatedImportFile() validation (Templates.php lines 293-351):** +```php +public function updatedImportFile(): void +{ + $content = file_get_contents($this->importFile->getRealPath()); + $parsed = Yaml::parse($content); + + // Validate basic structure + if (! is_array($parsed)) { + $this->importError = 'Invalid YAML format: expected an object.'; + return; + } + if (! isset($parsed['name'])) { + $this->importError = 'Template must have a "name" field.'; + return; + } + if (! isset($parsed['phases']) || ! is_array($parsed['phases'])) { + $this->importError = 'Template must have a "phases" array.'; + return; + } + + // Build preview + $this->importPreview = [ + 'name' => $parsed['name'], + 'description' => $parsed['description'] ?? null, + 'category' => $parsed['category'] ?? 'custom', + 'phases_count' => count($parsed['phases']), + 'variables_count' => count($parsed['variables'] ?? []), + ]; +} +``` + +**Evidence - importTemplate() save (Templates.php lines 353-397):** +```php +public function importTemplate(): void +{ + $this->validate([ + 'importFileName' => 'required|string|regex:/^[a-z0-9-]+$/|max:64', + ]); + + $content = file_get_contents($this->importFile->getRealPath()); + $targetPath = resource_path("plan-templates/{$this->importFileName}.yaml"); + + // Check for existing file + if (File::exists($targetPath)) { + $this->importError = 'A template with this filename already exists.'; + return; + } + + // Save the file + File::put($targetPath, $content); + + Flux::toast(heading: 'Template Imported', ...); +} +``` + +**Evidence - Import modal with file upload (templates.blade.php lines 381-476):** +```blade + + Import Template + + {{-- File Upload --}} +
+ +
+ + {{-- Preview --}} + @if($importPreview) +
+
Name:
{{ $importPreview['name'] }}
+
Category:
{{ $importPreview['category'] }}
+
Phases:
{{ $importPreview['phases_count'] }}
+
Variables:
{{ $importPreview['variables_count'] }}
+
+ + + @endif + + Import Template +
+``` + +**Import features:** YAML file upload, Validation (structure, name, phases), Preview before import, Custom filename, Duplicate detection ✅ + +### Phase 5 Summary + +| AC | Description | Evidence | Status | +|----|-------------|----------|--------| +| AC25 | Route lists templates | `routes/web.php:195`, `templates()` computed, grid layout | ✅ PASS | +| AC26 | Preview shows phases/variables | `previewTemplate()`, modal with phases list + variables table | ✅ PASS | +| AC27 | Create plan with variables | `createPlan()`, variable inputs in modal, validation | ✅ PASS | +| AC28 | Categories displayed | `getCategories()`, filter dropdown, colour-coded badges | ✅ PASS | +| AC29 | YAML import | `importTemplate()`, file upload, validation, preview | ✅ PASS | + +**Additional Implementation Verified:** +- Hades access control in component (`checkHadesAccess()`) +- Sidebar link at line 573 +- Dashboard quick link activated +- Template deletion with confirmation +- 5 templates available: bug-fix, code-review, feature-port, new-feature, refactor +- Stats cards: total templates, categories, phases, with variables +- Search functionality with debounce +- Category colour coding for visual organisation + +**Phase 5 Status:** ✅ VERIFIED — Ready for human approval + +--- + +## Implementation Hints (Added by Planning Agent) + +### Existing Code Reference + +**Agent models already exist** — don't recreate them: + +| Model | Location | Key Methods | +|-------|----------|-------------| +| `AgentPlan` | `app/Models/Agent/AgentPlan.php` | `getProgress()`, `getCurrentPhase()`, `activate()`, `complete()`, `archive()`, `toMcpContext()` | +| `AgentPhase` | `app/Models/Agent/AgentPhase.php` | Status constants: `STATUS_PENDING`, `STATUS_IN_PROGRESS`, `STATUS_COMPLETED`, `STATUS_BLOCKED`, `STATUS_SKIPPED` | +| `AgentSession` | `app/Models/Agent/AgentSession.php` | `start()`, `pause()`, `resume()`, `complete()`, `fail()`, `logAction()`, `prepareHandoff()`, `getDurationFormatted()` | +| `McpToolCallStat` | `app/Models/Mcp/McpToolCallStat.php` | `getTopTools()`, `getDailyTrend()`, `getServerStats()` — these are ready-made for dashboards | + +### Hades Auth Pattern + +Follow existing pattern from other Hades-only components: + +```php +// In mount() method +public function mount(): void +{ + if (!auth()->user()?->isHades()) { + abort(403); + } + // ... rest of mount +} +``` + +See examples: `PackageManager.php:21`, `FeatureManager.php:20`, `Platform.php:36` + +### Sidebar Integration + +Add to `resources/views/admin/components/sidebar.blade.php` **after line 376** (before the closing `` of the Hades section), using the existing pattern: + +```blade +{{-- Agent Operations --}} +
  • + +
    +
    + + Agents +
    +
    + + + +
    +
    +
    + +
  • +``` + +### Admin Layout Pattern + +Use existing admin layout: + +```php +public function render() +{ + return view('admin.admin.agent.dashboard') + ->layout('admin.layouts.app', ['title' => 'Agent Dashboard']); +} +``` + +### View Location + +Views go in `resources/views/admin/livewire/agent/` (matches other admin components) + +### Dashboard Queries (Ready to Use) + +```php +// These methods already exist on McpToolCallStat +$topTools = McpToolCallStat::getTopTools(days: 7, limit: 10); +$dailyTrend = McpToolCallStat::getDailyTrend(days: 7); +$serverStats = McpToolCallStat::getServerStats(days: 7); + +// AgentPlan queries +$activePlans = AgentPlan::active()->with(['workspace', 'agentPhases'])->count(); +$activeSessions = AgentSession::active()->count(); +``` + +### Routes Location + +Add after line 164 in `routes/web.php` (inside the hub group, after Commerce routes): + +```php +// Check existing structure at lines 131-169 for context +``` + +--- + +*This task creates the human interface for supervising AI agent operations.* diff --git a/changelog/2026/jan/agentic-tasks-readme.md b/changelog/2026/jan/agentic-tasks-readme.md new file mode 100644 index 0000000..0797800 --- /dev/null +++ b/changelog/2026/jan/agentic-tasks-readme.md @@ -0,0 +1,186 @@ +# Agentic Task System + +MCP-powered workspace for persistent work plans that survive context limits and enable multi-agent collaboration. + +## Why this exists + +- **Context persistence** - Work plans persist across Claude sessions, surviving context window limits +- **Multi-agent collaboration** - Handoff support between different agents with shared state +- **Checkpoint verification** - Phase gates ensure work is complete before progressing +- **Structured planning** - Break complex tasks into phases with dependencies + +## Location + +``` +app/Models/Agent/AgentPlan.php +app/Models/Agent/AgentPhase.php +app/Models/Agent/AgentSession.php +app/Models/Agent/WorkspaceState.php +app/Console/Commands/Agent/McpAgentServerCommand.php +``` + +## Basic usage + +```bash +# Create a new plan +php artisan plan:create my-feature --title="Implement Feature X" + +# Import from markdown +php artisan plan:create my-plan --import=PLAN.md --activate + +# List all plans +php artisan plan:list +php artisan plan:list --status=active + +# Show plan details +php artisan plan:show my-plan +php artisan plan:show my-plan --markdown + +# Check phase completion (checkpoint) +php artisan plan:check my-plan +php artisan plan:check my-plan 1 # Check specific phase + +# Manage phases +php artisan plan:phase my-plan 1 --status=in_progress +php artisan plan:phase my-plan 1 --add-task="Complete the migration" +php artisan plan:phase my-plan 1 --complete-task=0 +``` + +## Key methods + +### AgentPlan + +```php +use Mod\Agentic\Models\AgentPlan; + +// Create a plan +$plan = AgentPlan::create([ + 'slug' => 'my-feature', + 'title' => 'Implement Feature X', + 'status' => AgentPlan::STATUS_ACTIVE, +]); + +// Get current phase +$phase = $plan->getCurrentPhase(); +// Returns: AgentPhase or null + +// Check completion +$plan->checkAllPhasesComplete(); +// Returns: bool +``` + +### AgentPhase + +```php +use Mod\Agentic\Models\AgentPhase; + +// Start a phase +$phase->start(); +// Returns: self (status changed to in_progress) + +// Complete a phase (with transaction protection) +$phase->complete(); +// Returns: self (status changed to completed, plan auto-completes if all done) + +// Check if phase can start (dependencies met) +$phase->canStart(); +// Returns: bool +``` + +### WorkspaceState + +```php +use Mod\Agentic\Models\WorkspaceState; + +// Store shared state +WorkspaceState::setValue($plan, 'api_findings', ['endpoints' => 12]); + +// Retrieve state +$value = WorkspaceState::getValue($plan, 'api_findings'); +// Returns: array or null +``` + +## Example: Checkpoint pattern + +The checkpoint pattern ensures agents verify previous work before progressing: + +``` +Agent: "Starting Phase 3" + ↓ +MCP: phase_check(plan_slug, phase=2) + ↓ +Returns: { + "complete": false, + "remaining_tasks": ["Task 2.4", "Task 2.5"], + "message": "Phase 2 not complete. 2 tasks remaining." +} + ↓ +Agent: "Completing remaining Phase 2 tasks first..." +``` + +## Configuration + +MCP server configuration for Claude Code: + +```json +{ + "mcpServers": { + "hosthub-agent": { + "command": "php", + "args": ["artisan", "mcp:agent-server"], + "cwd": "/path/to/host.uk.com" + } + } +} +``` + +## How it works + +``` +1. Plan created with phases (via CLI or MCP) +2. Agent starts session and binds to plan +3. Agent works through phases, logging actions +4. Checkpoint verification before phase transitions +5. Workspace state shared between agents +6. Handoff notes preserved for context continuity +``` + +## MCP Tools + +| Tool | Purpose | +|------|---------| +| `plan_create` | Create new plan with phases | +| `plan_get` | Get plan by slug with all phases | +| `plan_list` | List plans (optionally filtered) | +| `plan_update` | Update plan status/metadata | +| `phase_update` | Update phase status | +| `phase_check` | Verify phase completion | +| `task_add` | Add task to a phase | +| `task_complete` | Mark task done | +| `session_start` | Begin agent session | +| `session_log` | Log action to session | +| `session_artifact` | Log file artifact | +| `session_handoff` | Prepare for agent handoff | +| `session_resume` | Resume from previous session | +| `session_complete` | Mark session completed | +| `state_set` | Store workspace state | +| `state_get` | Retrieve workspace state | +| `state_list` | List all state keys | +| `state_delete` | Delete state key | + +## MCP Resources + +| URI | Purpose | +|-----|---------| +| `hosthub://plans` | List of all work plans | +| `hosthub://plans/{slug}` | Full plan as markdown | +| `hosthub://plans/{slug}/phase/{n}` | Phase tasks as checklist | +| `hosthub://state/{plan}/{key}` | Specific state value | +| `hosthub://sessions/{id}` | Session handoff context | + +## Related services + +- `Task` model - Simple task tracking (different purpose) +- `ContentTask` model - Content generation tasks + +See also: `doc/dev-feat-docs/agentic-tasks/PORTING_PLAN.md` for implementation details. diff --git a/changelog/2026/jan/code-review.md b/changelog/2026/jan/code-review.md new file mode 100644 index 0000000..d32795e --- /dev/null +++ b/changelog/2026/jan/code-review.md @@ -0,0 +1,107 @@ +# Agentic Module Review + +**Updated:** 2026-01-21 - OpenAI pricing, MCP token lookup, and Boot.php cleanup verified complete + +## Overview + +The Agentic module provides AI agent infrastructure for Host Hub, including: + +1. **Multi-provider AI abstraction** - Unified interface for Claude, Gemini, and OpenAI APIs +2. **Agent work plans** - Structured task tracking with phases, dependencies, and progress +3. **Session management** - Track agent work sessions for handoff and context recovery +4. **API key management** - Workspace-scoped keys with permissions and rate limiting +5. **Plan templates** - YAML-based reusable plan structures +6. **Content generation pipeline** - Batch content generation with quality validation +7. **Agent detection** - Identify AI agents from HTTP requests (Trees for Agents) +8. **Admin dashboard** - Hades-only admin panel for monitoring agent operations + +## Production Readiness Score: 88/100 (was 85/100 - Additional improvements 2026-01-21) + +The module has solid foundational architecture. Critical issues fixed in Wave 2. All recommended improvements now implemented. OpenAI pricing, MCP token database lookup, and Boot.php cleanup completed. + +## Critical Issues (Must Fix) + +- [x] **Missing `agent_api_keys` table migration** - FIXED: Migration exists at `Migrations/2026_01_15_090000_create_agent_api_keys_table.php`. +- [x] **Missing `tasks` table migration** - FIXED: Migration exists at `Migrations/2026_01_15_090001_create_tasks_table.php`. Task model updated with `BelongsToWorkspace` trait and `workspace_id` in fillable. +- [x] **`AgenticResponse::estimateCost()` missing OpenAI pricing** - FIXED: Pricing array now includes GPT-4o, GPT-4o-mini, GPT-4-turbo, GPT-4, GPT-3.5-turbo, o1, o1-mini, and o1-preview models. +- [x] **`AgentApiKey::getRecentCallCount()` is a stub** - FIXED: Now reads from cache key `agent_api_key_rate:{id}` which is incremented by `AgentApiKeyService::recordUsage()`. +- [x] **`PlanCommand`/`TaskCommand` missing workspace scope** - FIXED: Both commands now require `--workspace=ID` option or authenticated user context. All queries scoped via `forWorkspace()` to prevent data leakage. + +## Recommended Improvements + +- [x] **Add retry logic to AI provider services** - FIXED: HasRetry trait added with exponential backoff for transient failures. +- [x] **Stream parsing is fragile** - FIXED: HasStreamParsing trait added for robust chunked response handling. +- [x] **ContentService uses hardcoded paths** - FIXED: `$batchPath`, `$promptPath`, `$draftsPath` now use config values. +- [x] **AgentApiKeyService rate limit TTL is incorrect** - FIXED: Now uses `Cache::add()` with TTL to prevent race condition. +- [x] **Missing validation on PlanTemplateService variable substitution** - FIXED: JSON escaping added to prevent data corruption from special characters. +- [x] **Dashboard queries not optimised** - FIXED: `cacheWithLock` added to prevent cache stampede. +- [x] **Add middleware for admin routes** - FIXED: RequireHades middleware now applied to `/hub/agents/*` routes. +- [x] **Add request validation to ForAgentsController** - FIXED: Rate limiting and caching added. + +## Missing Features (Future) + +- [x] **MCP tool handlers commented out** - FIXED: `Boot::onMcpTools()` now has clean documentation explaining that agent tools are registered in Mcp module via AgentToolRegistry. +- [x] **MCP token lookup not implemented** - FIXED: `AgentDetection::identifyFromMcpToken()` now supports opaque `ak_` prefix tokens with database lookup via `AgentApiKey::findByKey()`, plus structured `provider:model:secret` format. +- [ ] **No tests for AgentApiKey model** - Unlike other models (AgentPlan, AgentPhase, AgentSession), AgentApiKey has no dedicated test file. +- [ ] **No tests for AI provider services** - ClaudeService, GeminiService, OpenAIService have no unit tests. +- [ ] **No tests for AgentApiKeyService** - Service has complex authentication logic but no tests. +- [ ] **No tests for AgentDetection** - User-Agent pattern matching logic is untested. +- [ ] **No tests for PlanTemplateService** - Variable substitution and plan creation untested. +- [ ] **Missing admin panel tests for all Livewire components** - Only `UseCase/AdminPanelBasic.php` exists but may not execute (uses non-standard test syntax). +- [ ] **GenerateCommand depends on Content module** - Uses `Mod\Content\Models\ContentBrief`, `Mod\Content\Jobs\GenerateContentJob`, etc. Should verify Content module is always loaded. + +## Test Coverage Assessment + +**Current test files:** +- `Tests/Feature/AgentPlanTest.php` - 17 tests, good coverage of plan lifecycle +- `Tests/Feature/AgentPhaseTest.php` - 17 tests, good coverage of phase operations +- `Tests/Feature/AgentSessionTest.php` - 22 tests, thorough session tracking tests +- `Tests/Feature/ContentServiceTest.php` - 4 tests, basic coverage using mocks +- `Tests/UseCase/AdminPanelBasic.php` - UI acceptance tests (may not be functional) + +**Coverage gaps:** +- No unit tests for any of the 11 services +- No tests for 3 console commands +- No tests for AgentApiKey model +- No tests for Task model +- No tests for admin Livewire components +- No integration tests for AI provider APIs + +**Estimated coverage:** ~35% (models well-tested, services untested) + +## Security Concerns + +1. **API key stored as SHA-256 hash only** - No salt used in `AgentApiKey::generate()`. While SHA-256 is acceptable, using `password_hash()` with Argon2 would be more secure for credential storage. + +2. **Rate limiting bypass** - FIXED: `getRecentCallCount()` now reads from cache, making rate limiting functional when `AgentApiKeyService::recordUsage()` is called. + +3. **No input validation on plan/template variables** - `PlanTemplateService::substituteVariables()` uses regex replacement without sanitising input, potentially allowing injection. + +4. **Admin routes lack middleware** - FIXED: RequireHades middleware now applied to admin routes. + +5. **ForAgentsController exposes internal URLs** - Returns hardcoded URLs to MCP registry and documentation that could be enumerated by attackers. + +6. **TaskCommand uses FIELD() with unescaped values** - `orderByRaw("FIELD(priority, 'urgent', 'high', 'normal', 'low')")` - while current usage is safe (status/priority are validated), this pattern is SQL injection prone if extended. + +## Notes + +**Architecture:** Well-structured following the modular monolith pattern. Boot.php properly uses event listeners for lazy loading. Services are appropriately separated. + +**Code quality:** Consistent use of strict types, proper PHPDoc annotations, and Eloquent conventions. Factory pattern for test data is well implemented. + +**Dependencies on other modules:** +- `Mod\Tenant` - Workspace model and BelongsToWorkspace trait +- `Mod\Mcp` - McpToolCallStat for dashboard analytics +- `Mod\Content` - ContentBrief, AIUsage, GenerateContentJob (in GenerateCommand) + +**Files reviewed:** +- `/app/Mod/Agentic/Boot.php` +- `/app/Mod/Agentic/config.php` +- `/app/Mod/Agentic/Migrations/2026_01_15_100000_create_agentic_tables.php` +- All 11 models in `/app/Mod/Agentic/Models/` +- All 9 services in `/app/Mod/Agentic/Services/` +- All 3 console commands in `/app/Mod/Agentic/Console/Commands/` +- `/app/Mod/Agentic/Controllers/ForAgentsController.php` +- `/app/Mod/Agentic/Routes/admin.php` +- All 4 test files in `/app/Mod/Agentic/Tests/` +- `/app/Mod/Agentic/View/Modal/Admin/Dashboard.php` diff --git a/changelog/2026/jan/features.md b/changelog/2026/jan/features.md new file mode 100644 index 0000000..5bdd1b6 --- /dev/null +++ b/changelog/2026/jan/features.md @@ -0,0 +1,72 @@ +# Core-Agentic - January 2026 + +## Features Implemented + +### Agent Plans Admin UI (TASK-006) + +Complete admin interface for managing agent work plans. + +**Components:** +- Plan list with status filters +- Plan editor with phases +- Phase management (add, edit, reorder) +- Progress tracking +- Session viewer + +**Files:** +- `View/Modal/Admin/PlanManager.php` +- `View/Modal/Admin/PlanEditor.php` +- `View/Modal/Admin/PhaseEditor.php` + +--- + +### Session Recovery/Replay + +Resume and replay agent sessions across context windows. + +**Methods:** +- `getReplayContext()` - reconstruct session state +- `createReplaySession()` - spawn continuation session +- Checkpoint and decision tracking + +**MCP Tool:** +- `session_replay` - replay tool for agents + +--- + +### Agent API Keys + +Scoped API keys for agent authentication. + +**Features:** +- Key generation with prefixes +- Scope restrictions +- Usage tracking +- IP restrictions + +**Files:** +- `Models/AgentApiKey.php` +- `Services/AgentApiKeyService.php` +- `Services/IpRestrictionService.php` + +--- + +### MCP Usage Quotas + +Per-workspace usage limits for MCP operations. + +**Files:** +- `Models/McpUsageQuota.php` +- `Services/McpQuotaService.php` +- Quota middleware +- Entitlement feature integration + +--- + +### Plan Templates + +Reusable plan templates for common workflows. + +**Files:** +- `Services/PlanTemplateService.php` +- Template MCP tools diff --git a/composer.json b/composer.json index 89a3dd6..15fe864 100644 --- a/composer.json +++ b/composer.json @@ -1,49 +1,50 @@ { - "name": "host-uk/core-agentic", - "description": "AI agent orchestration and MCP tools for Laravel", - "keywords": [ - "ai", - "agents", - "mcp", - "orchestration" - ], - "license": "EUPL-1.2", - "require": { - "php": "^8.2", - "host-uk/core": "dev-main" - }, - "require-dev": { - "laravel/pint": "^1.18", - "orchestra/testbench": "^9.0|^10.0", - "pestphp/pest": "^3.0" - }, - "autoload": { - "psr-4": { - "Core\\Agentic\\": "" - } - }, - "autoload-dev": { - "psr-4": { - "Core\\Agentic\\Tests\\": "Tests/" - } - }, - "extra": { - "laravel": { - "providers": [ - "Core\\Agentic\\Boot" - ] - } - }, - "scripts": { - "lint": "pint", - "test": "pest" - }, - "config": { - "sort-packages": true, - "allow-plugins": { - "pestphp/pest-plugin": true - } - }, - "minimum-stability": "dev", - "prefer-stable": true + "name": "host-uk/core-agentic", + "description": "AI agent orchestration and MCP tools for Laravel", + "keywords": [ + "ai", + "agents", + "mcp", + "orchestration" + ], + "license": "EUPL-1.2", + "require": { + "php": "^8.2", + "host-uk/core": "dev-main" + }, + "require-dev": { + "laravel/pint": "^1.18", + "orchestra/testbench": "^9.0|^10.0", + "pestphp/pest": "^3.0" + }, + "autoload": { + "psr-4": { + "Core\\Mod\\Agentic\\": "", + "Core\\Service\\Agentic\\": "Service/" + } + }, + "autoload-dev": { + "psr-4": { + "Core\\Mod\\Agentic\\Tests\\": "Tests/" + } + }, + "extra": { + "laravel": { + "providers": [ + "Core\\Mod\\Agentic\\Boot" + ] + } + }, + "scripts": { + "lint": "pint", + "test": "pest" + }, + "config": { + "sort-packages": true, + "allow-plugins": { + "pestphp/pest-plugin": true + } + }, + "minimum-stability": "dev", + "prefer-stable": true } diff --git a/routes/admin.php b/routes/admin.php index 3f7a9f2..9458774 100644 --- a/routes/admin.php +++ b/routes/admin.php @@ -17,19 +17,19 @@ Route::prefix('hub')->name('hub.')->group(function () { ->middleware(['auth', RequireHades::class]) ->group(function () { // Phase 1: Plan Dashboard - Route::get('/', \Core\Agentic\View\Modal\Admin\Dashboard::class)->name('index'); - Route::get('/plans', \Core\Agentic\View\Modal\Admin\Plans::class)->name('plans'); - Route::get('/plans/{slug}', \Core\Agentic\View\Modal\Admin\PlanDetail::class)->name('plans.show'); + Route::get('/', \Core\Mod\Agentic\View\Modal\Admin\Dashboard::class)->name('index'); + Route::get('/plans', \Core\Mod\Agentic\View\Modal\Admin\Plans::class)->name('plans'); + Route::get('/plans/{slug}', \Core\Mod\Agentic\View\Modal\Admin\PlanDetail::class)->name('plans.show'); // Phase 2: Session Monitor - Route::get('/sessions', \Core\Agentic\View\Modal\Admin\Sessions::class)->name('sessions'); - Route::get('/sessions/{id}', \Core\Agentic\View\Modal\Admin\SessionDetail::class)->name('sessions.show'); + Route::get('/sessions', \Core\Mod\Agentic\View\Modal\Admin\Sessions::class)->name('sessions'); + Route::get('/sessions/{id}', \Core\Mod\Agentic\View\Modal\Admin\SessionDetail::class)->name('sessions.show'); // Phase 3: Tool Analytics - Route::get('/tools', \Core\Agentic\View\Modal\Admin\ToolAnalytics::class)->name('tools'); - Route::get('/tools/calls', \Core\Agentic\View\Modal\Admin\ToolCalls::class)->name('tools.calls'); + Route::get('/tools', \Core\Mod\Agentic\View\Modal\Admin\ToolAnalytics::class)->name('tools'); + Route::get('/tools/calls', \Core\Mod\Agentic\View\Modal\Admin\ToolCalls::class)->name('tools.calls'); // Phase 4: API Key Management - Route::get('/api-keys', \Core\Agentic\View\Modal\Admin\ApiKeys::class)->name('api-keys'); + Route::get('/api-keys', \Core\Mod\Agentic\View\Modal\Admin\ApiKeys::class)->name('api-keys'); // Phase 5: Plan Templates - Route::get('/templates', \Core\Agentic\View\Modal\Admin\Templates::class)->name('templates'); + Route::get('/templates', \Core\Mod\Agentic\View\Modal\Admin\Templates::class)->name('templates'); }); }); diff --git a/tests/Feature/AgentPhaseTest.php b/tests/Feature/AgentPhaseTest.php index 70a703e..695fa69 100644 --- a/tests/Feature/AgentPhaseTest.php +++ b/tests/Feature/AgentPhaseTest.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Agentic\Tests\Feature; +namespace Core\Mod\Agentic\Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; -use Core\Agentic\Models\AgentPhase; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentPhase; +use Core\Mod\Agentic\Models\AgentPlan; use Core\Mod\Tenant\Models\Workspace; use Tests\TestCase; diff --git a/tests/Feature/AgentPlanTest.php b/tests/Feature/AgentPlanTest.php index 11f0cb8..e761704 100644 --- a/tests/Feature/AgentPlanTest.php +++ b/tests/Feature/AgentPlanTest.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Agentic\Tests\Feature; +namespace Core\Mod\Agentic\Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; -use Core\Agentic\Models\AgentPhase; -use Core\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentPhase; +use Core\Mod\Agentic\Models\AgentPlan; use Core\Mod\Tenant\Models\Workspace; use Tests\TestCase; diff --git a/tests/Feature/AgentSessionTest.php b/tests/Feature/AgentSessionTest.php index 83034d6..de04589 100644 --- a/tests/Feature/AgentSessionTest.php +++ b/tests/Feature/AgentSessionTest.php @@ -2,11 +2,11 @@ declare(strict_types=1); -namespace Core\Agentic\Tests\Feature; +namespace Core\Mod\Agentic\Tests\Feature; use Illuminate\Foundation\Testing\RefreshDatabase; -use Core\Agentic\Models\AgentPlan; -use Core\Agentic\Models\AgentSession; +use Core\Mod\Agentic\Models\AgentPlan; +use Core\Mod\Agentic\Models\AgentSession; use Core\Mod\Tenant\Models\Workspace; use Tests\TestCase; diff --git a/tests/Feature/ContentServiceTest.php b/tests/Feature/ContentServiceTest.php index b80c027..ee2e572 100644 --- a/tests/Feature/ContentServiceTest.php +++ b/tests/Feature/ContentServiceTest.php @@ -1,8 +1,8 @@