onQueue('ai'); } public function handle( AgenticManager $ai, ContentProcessingService $processor, EntitlementService $entitlements ): void { $this->task->markProcessing(); $prompt = $this->task->prompt; if (! $prompt) { $this->task->markFailed('Prompt not found'); return; } // Check AI credits entitlement $workspace = $this->task->workspace; if ($workspace) { $result = $entitlements->can($workspace, 'ai.credits'); if ($result->isDenied()) { $this->task->markFailed("Entitlement denied: {$result->message}"); return; } } $provider = $ai->provider($prompt->model); if (! $provider->isAvailable()) { $this->task->markFailed("AI provider '{$prompt->model}' is not configured"); return; } // Interpolate variables into the user template $userPrompt = $this->interpolateVariables( $prompt->user_template, $this->task->input_data ?? [] ); $response = $provider->generate( $prompt->system_prompt, $userPrompt, $prompt->model_config ?? [] ); $this->task->markCompleted($response->content, [ 'tokens_input' => $response->inputTokens, 'tokens_output' => $response->outputTokens, 'model' => $response->model, 'duration_ms' => $response->durationMs, 'estimated_cost' => $response->estimateCost(), ]); // Record AI usage if ($workspace) { $entitlements->recordUsage( $workspace, 'ai.credits', quantity: 1, metadata: [ 'task_id' => $this->task->id, 'prompt_id' => $prompt->id, 'model' => $response->model, 'tokens_input' => $response->inputTokens, 'tokens_output' => $response->outputTokens, 'estimated_cost' => $response->estimateCost(), ] ); } // If this task has a target, process the output if ($this->task->target_type && $this->task->target_id) { $this->processOutput($response->content, $processor); } } public function failed(Throwable $exception): void { $this->task->markFailed($exception->getMessage()); } /** * Interpolate template variables. */ private function interpolateVariables(string $template, array $data): string { foreach ($data as $key => $value) { if (is_string($value)) { $template = str_replace("{{{$key}}}", $value, $template); } elseif (is_array($value)) { $template = str_replace("{{{$key}}}", json_encode($value), $template); } } return $template; } /** * Process the AI output based on target type. */ private function processOutput(string $content, ContentProcessingService $processor): void { $target = $this->task->target; if (! $target) { return; } // Handle different target types // This can be extended for different content types // For now, just log that processing occurred } }