Protokoll #4667

ID4667
Zeitstempel2025-12-22 10:36:08.492163
Clientroot
IP145.224.96.190
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens13,371 (Input: 1,717, Output: 11,654)
Dauer92 ms
Request-Zeit2025-12-22 10:36:08.492163
Response-Zeit2025-12-22 10:36:08.584211

Request

{
    "event": "PreToolUse",
    "tool_name": "Write",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
        "content": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Formatting\\ChatMessageFormatter;\nuse UseCases\\Chat\\ManageChatSessionsUseCase;\nuse UseCases\\Chat\\SendChatMessageUseCase;\n\nclass ChatController extends Controller\n{\n    private ManageChatSessionsUseCase $sessionsUseCase;\n    private SendChatMessageUseCase $messageUseCase;\n    private ChatMessageFormatter $formatter;\n\n    public function __construct(\n        ?ManageChatSessionsUseCase $sessionsUseCase = null,\n        ?SendChatMessageUseCase $messageUseCase = null,\n        ?ChatMessageFormatter $formatter = null\n    ) {\n        $this->sessionsUseCase = $sessionsUseCase ?? new ManageChatSessionsUseCase();\n        $this->messageUseCase = $messageUseCase ?? new SendChatMessageUseCase();\n        $this->formatter = $formatter ?? new ChatMessageFormatter();\n    }\n\n    public function index(): void\n    {\n        $uuid = $this->sessionsUseCase->createSession();\n        header('Location: \/chat\/' . $uuid);\n        exit;\n    }\n\n    public function show(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            header('Location: \/chat');\n            exit;\n        }\n\n        $this->view('chat.index', [\n            'title' => $session['title'] ?? 'KI-Chat',\n            'session' => $session,\n            'messages' => $this->sessionsUseCase->getMessages($session['id']),\n            'sessions' => $this->sessionsUseCase->getAllSessions(),\n            'authorProfiles' => $this->sessionsUseCase->getAuthorProfiles(),\n            'systemPrompts' => $this->sessionsUseCase->getSystemPrompts(),\n            'collections' => $this->sessionsUseCase->getAvailableCollections(),\n            'models' => ModelConfig::getAll(),\n            'defaultModel' => ModelConfig::DEFAULT_MODEL,\n        ]);\n    }\n\n    public function sessionList(): void\n    {\n        $this->view('chat.partials.session-list', [\n            'sessions' => $this->sessionsUseCase->getAllSessions(),\n            'currentUuid' => $this->getString('current') ?: null,\n        ]);\n    }\n\n    public function message(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->view('chat.partials.error', ['error' => 'Session nicht gefunden.']);\n\n            return;\n        }\n\n        $question = trim($_POST['message'] ?? '');\n        $model = ModelConfig::validate($_POST['model'] ?? $session['model']);\n        $sessionCollections = $this->decodeJson($session['collections'] ?? null) ?: ['documents'];\n        $collections = $_POST['collections'] ?? $sessionCollections;\n        $contextLimit = (int) ($_POST['context_limit'] ?? $session['context_limit'] ?? 5);\n        $authorProfileId = (int) ($_POST['author_profile_id'] ?? $session['author_profile_id'] ?? 0);\n        $systemPromptId = (int) ($_POST['system_prompt_id'] ?? $session['system_prompt_id'] ?? 1);\n        $temperature = (float) ($_POST['temperature'] ?? $session['temperature'] ?? 0.7);\n        $maxTokens = (int) ($_POST['max_tokens'] ?? $session['max_tokens'] ?? 4096);\n\n        if ($this->sessionsUseCase->settingsHaveChanged($session, $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens)) {\n            $this->sessionsUseCase->updateSettings($session['id'], $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens);\n        }\n\n        if ($question === '') {\n            $this->view('chat.partials.error', ['error' => 'Bitte gib eine Frage ein.']);\n\n            return;\n        }\n\n        if (!empty($collections)) {\n            $compatibility = $this->sessionsUseCase->validateCollectionCompatibility($collections);\n            if (!$compatibility['valid']) {\n                $this->view('chat.partials.error', [\n                    'error' => 'Collection-Fehler: ' . $compatibility['error'],\n                    'details' => 'Bitte wähle nur Collections mit gleichem Embedding-Modell.',\n                ]);\n\n                return;\n            }\n        }\n\n        $response = $this->messageUseCase->execute(\n            sessionUuid: $uuid,\n            message: $question,\n            model: $model,\n            collections: $collections,\n            contextLimit: $contextLimit,\n            authorProfileId: $authorProfileId,\n            systemPromptId: $systemPromptId,\n            temperature: $temperature,\n            maxTokens: $maxTokens\n        );\n\n        if ($response->hasError()) {\n            $this->view('chat.partials.error', ['error' => $response->getError()]);\n\n            return;\n        }\n\n        $result = $response->toArray();\n        $this->view('chat.partials.response', [\n            'question' => $question,\n            'result' => $result,\n            'model' => $model,\n            'formattedAnswer' => $this->formatter->formatAnswer($result['answer'] ?? ''),\n        ]);\n    }\n\n    public function updateTitle(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $title = $this->sessionsUseCase->updateTitle($session['id'], $_POST['title'] ?? '');\n        echo htmlspecialchars($title);\n    }\n\n    public function systemPrompt(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $result = $this->sessionsUseCase->updateSystemPrompt($session['id'], $_POST['system_prompt'] ?? '');\n        $this->view('chat.partials.success', ['message' => $result->message]);\n    }\n\n    public function getSystemPrompt(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $this->view('chat.partials.system-prompt-modal', [\n            'session' => $session,\n            'currentPrompt' => $session['system_prompt'] ?? '',\n            'defaultPrompt' => $this->sessionsUseCase->getDefaultSystemPrompt(),\n        ]);\n    }\n\n    public function delete(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session !== null) {\n            $this->sessionsUseCase->deleteSession($session['id']);\n        }\n\n        header('HX-Redirect: \/chat');\n        echo 'OK';\n    }\n}\n"
    }
}

Response

{
    "tool_response": {
        "type": "update",
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
        "content": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Formatting\\ChatMessageFormatter;\nuse UseCases\\Chat\\ManageChatSessionsUseCase;\nuse UseCases\\Chat\\SendChatMessageUseCase;\n\nclass ChatController extends Controller\n{\n    private ManageChatSessionsUseCase $sessionsUseCase;\n    private SendChatMessageUseCase $messageUseCase;\n    private ChatMessageFormatter $formatter;\n\n    public function __construct(\n        ?ManageChatSessionsUseCase $sessionsUseCase = null,\n        ?SendChatMessageUseCase $messageUseCase = null,\n        ?ChatMessageFormatter $formatter = null\n    ) {\n        $this->sessionsUseCase = $sessionsUseCase ?? new ManageChatSessionsUseCase();\n        $this->messageUseCase = $messageUseCase ?? new SendChatMessageUseCase();\n        $this->formatter = $formatter ?? new ChatMessageFormatter();\n    }\n\n    public function index(): void\n    {\n        $uuid = $this->sessionsUseCase->createSession();\n        header('Location: \/chat\/' . $uuid);\n        exit;\n    }\n\n    public function show(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            header('Location: \/chat');\n            exit;\n        }\n\n        $this->view('chat.index', [\n            'title' => $session['title'] ?? 'KI-Chat',\n            'session' => $session,\n            'messages' => $this->sessionsUseCase->getMessages($session['id']),\n            'sessions' => $this->sessionsUseCase->getAllSessions(),\n            'authorProfiles' => $this->sessionsUseCase->getAuthorProfiles(),\n            'systemPrompts' => $this->sessionsUseCase->getSystemPrompts(),\n            'collections' => $this->sessionsUseCase->getAvailableCollections(),\n            'models' => ModelConfig::getAll(),\n            'defaultModel' => ModelConfig::DEFAULT_MODEL,\n        ]);\n    }\n\n    public function sessionList(): void\n    {\n        $this->view('chat.partials.session-list', [\n            'sessions' => $this->sessionsUseCase->getAllSessions(),\n            'currentUuid' => $this->getString('current') ?: null,\n        ]);\n    }\n\n    public function message(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->view('chat.partials.error', ['error' => 'Session nicht gefunden.']);\n\n            return;\n        }\n\n        $question = trim($_POST['message'] ?? '');\n        $model = ModelConfig::validate($_POST['model'] ?? $session['model']);\n        $sessionCollections = $this->decodeJson($session['collections'] ?? null) ?: ['documents'];\n        $collections = $_POST['collections'] ?? $sessionCollections;\n        $contextLimit = (int) ($_POST['context_limit'] ?? $session['context_limit'] ?? 5);\n        $authorProfileId = (int) ($_POST['author_profile_id'] ?? $session['author_profile_id'] ?? 0);\n        $systemPromptId = (int) ($_POST['system_prompt_id'] ?? $session['system_prompt_id'] ?? 1);\n        $temperature = (float) ($_POST['temperature'] ?? $session['temperature'] ?? 0.7);\n        $maxTokens = (int) ($_POST['max_tokens'] ?? $session['max_tokens'] ?? 4096);\n\n        if ($this->sessionsUseCase->settingsHaveChanged($session, $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens)) {\n            $this->sessionsUseCase->updateSettings($session['id'], $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens);\n        }\n\n        if ($question === '') {\n            $this->view('chat.partials.error', ['error' => 'Bitte gib eine Frage ein.']);\n\n            return;\n        }\n\n        if (!empty($collections)) {\n            $compatibility = $this->sessionsUseCase->validateCollectionCompatibility($collections);\n            if (!$compatibility['valid']) {\n                $this->view('chat.partials.error', [\n                    'error' => 'Collection-Fehler: ' . $compatibility['error'],\n                    'details' => 'Bitte wähle nur Collections mit gleichem Embedding-Modell.',\n                ]);\n\n                return;\n            }\n        }\n\n        $response = $this->messageUseCase->execute(\n            sessionUuid: $uuid,\n            message: $question,\n            model: $model,\n            collections: $collections,\n            contextLimit: $contextLimit,\n            authorProfileId: $authorProfileId,\n            systemPromptId: $systemPromptId,\n            temperature: $temperature,\n            maxTokens: $maxTokens\n        );\n\n        if ($response->hasError()) {\n            $this->view('chat.partials.error', ['error' => $response->getError()]);\n\n            return;\n        }\n\n        $result = $response->toArray();\n        $this->view('chat.partials.response', [\n            'question' => $question,\n            'result' => $result,\n            'model' => $model,\n            'formattedAnswer' => $this->formatter->formatAnswer($result['answer'] ?? ''),\n        ]);\n    }\n\n    public function updateTitle(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $title = $this->sessionsUseCase->updateTitle($session['id'], $_POST['title'] ?? '');\n        echo htmlspecialchars($title);\n    }\n\n    public function systemPrompt(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $result = $this->sessionsUseCase->updateSystemPrompt($session['id'], $_POST['system_prompt'] ?? '');\n        $this->view('chat.partials.success', ['message' => $result->message]);\n    }\n\n    public function getSystemPrompt(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $this->view('chat.partials.system-prompt-modal', [\n            'session' => $session,\n            'currentPrompt' => $session['system_prompt'] ?? '',\n            'defaultPrompt' => $this->sessionsUseCase->getDefaultSystemPrompt(),\n        ]);\n    }\n\n    public function delete(string $uuid): void\n    {\n        $session = $this->sessionsUseCase->getSession($uuid);\n\n        if ($session !== null) {\n            $this->sessionsUseCase->deleteSession($session['id']);\n        }\n\n        header('HX-Redirect: \/chat');\n        echo 'OK';\n    }\n}\n",
        "structuredPatch": [
            {
                "oldStart": 3,
                "oldLines": 100,
                "newStart": 3,
                "newLines": 67,
                "lines": [
                    " namespace Controller;",
                    " ",
                    " use Framework\\Controller;",
                    "-use Infrastructure\\AI\\AIConfig;",
                    "-use Infrastructure\\AI\\ChatService;",
                    " use Infrastructure\\AI\\ModelConfig;",
                    "-use Infrastructure\\Persistence\\CollectionRepository;",
                    "-use Infrastructure\\Validation\\CollectionValidator;",
                    "+use Infrastructure\\Formatting\\ChatMessageFormatter;",
                    "+use UseCases\\Chat\\ManageChatSessionsUseCase;",
                    " use UseCases\\Chat\\SendChatMessageUseCase;",
                    " ",
                    " class ChatController extends Controller",
                    " {",
                    "-    private ChatService $chatService;",
                    "-    private CollectionRepository $collectionRepository;",
                    "-    private CollectionValidator $collectionValidator;",
                    "-    private SendChatMessageUseCase $sendMessageUseCase;",
                    "-    private \\PDO $db;",
                    "+    private ManageChatSessionsUseCase $sessionsUseCase;",
                    "+    private SendChatMessageUseCase $messageUseCase;",
                    "+    private ChatMessageFormatter $formatter;",
                    " ",
                    "-    \/** @var array<array<string,mixed>>|null Cached collections list *\/",
                    "-    private ?array $collectionsCache = null;",
                    "-",
                    "-    public function __construct()",
                    "-    {",
                    "-        $config = AIConfig::fromCredentialsFile();",
                    "-        $this->chatService = $config->createChatService();",
                    "-        $this->collectionRepository = new CollectionRepository();",
                    "-        $this->collectionValidator = new CollectionValidator($this->collectionRepository);",
                    "-        $this->sendMessageUseCase = new SendChatMessageUseCase($this->chatService);",
                    "-        $this->db = $this->initializeDatabase();",
                    "+    public function __construct(",
                    "+        ?ManageChatSessionsUseCase $sessionsUseCase = null,",
                    "+        ?SendChatMessageUseCase $messageUseCase = null,",
                    "+        ?ChatMessageFormatter $formatter = null",
                    "+    ) {",
                    "+        $this->sessionsUseCase = $sessionsUseCase ?? new ManageChatSessionsUseCase();",
                    "+        $this->messageUseCase = $messageUseCase ?? new SendChatMessageUseCase();",
                    "+        $this->formatter = $formatter ?? new ChatMessageFormatter();",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/chat",
                    "-     * Show chat interface with session list, create new session if none",
                    "-     *\/",
                    "     public function index(): void",
                    "     {",
                    "-        $sessions = $this->getSessions();",
                    "-",
                    "-        \/\/ Create new session and redirect",
                    "-        $uuid = $this->createSession();",
                    "+        $uuid = $this->sessionsUseCase->createSession();",
                    "         header('Location: \/chat\/' . $uuid);",
                    "         exit;",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/chat\/{uuid}",
                    "-     * Show specific chat session",
                    "-     *\/",
                    "     public function show(string $uuid): void",
                    "     {",
                    "-        $session = $this->getSession($uuid);",
                    "+        $session = $this->sessionsUseCase->getSession($uuid);",
                    " ",
                    "         if ($session === null) {",
                    "             header('Location: \/chat');",
                    "             exit;",
                    "         }",
                    " ",
                    "-        $messages = $this->getMessages($session['id']);",
                    "-        $sessions = $this->getSessions();",
                    "-        $authorProfiles = $this->getAuthorProfiles();",
                    "-        $systemPrompts = $this->getSystemPrompts();",
                    "-        $collections = $this->getAvailableCollections();",
                    "-",
                    "         $this->view('chat.index', [",
                    "             'title' => $session['title'] ?? 'KI-Chat',",
                    "             'session' => $session,",
                    "-            'messages' => $messages,",
                    "-            'sessions' => $sessions,",
                    "-            'authorProfiles' => $authorProfiles,",
                    "-            'systemPrompts' => $systemPrompts,",
                    "-            'collections' => $collections,",
                    "+            'messages' => $this->sessionsUseCase->getMessages($session['id']),",
                    "+            'sessions' => $this->sessionsUseCase->getAllSessions(),",
                    "+            'authorProfiles' => $this->sessionsUseCase->getAuthorProfiles(),",
                    "+            'systemPrompts' => $this->sessionsUseCase->getSystemPrompts(),",
                    "+            'collections' => $this->sessionsUseCase->getAvailableCollections(),",
                    "             'models' => ModelConfig::getAll(),",
                    "             'defaultModel' => ModelConfig::DEFAULT_MODEL,",
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/chat\/sessions (HTMX partial)",
                    "-     * Return session list HTML",
                    "-     *\/",
                    "     public function sessionList(): void",
                    "     {",
                    "-        $sessions = $this->getSessions();",
                    "         $this->view('chat.partials.session-list', [",
                    "-            'sessions' => $sessions,",
                    "+            'sessions' => $this->sessionsUseCase->getAllSessions(),",
                    "             'currentUuid' => $this->getString('current') ?: null,",
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * POST \/chat\/{uuid}\/message (HTMX)",
                    "-     * Process message and return HTML response",
                    "-     *\/",
                    "     public function message(string $uuid): void",
                    "     {",
                    "-        $session = $this->getSession($uuid);",
                    "+        $session = $this->sessionsUseCase->getSession($uuid);",
                    " ",
                    "         if ($session === null) {",
                    "             $this->view('chat.partials.error', ['error' => 'Session nicht gefunden.']);"
                ]
            },
            {
                "oldStart": 105,
                "oldLines": 23,
                "newStart": 72,
                "newLines": 17,
                "lines": [
                    "         }",
                    " ",
                    "         $question = trim($_POST['message'] ?? '');",
                    "-        $model = $this->validateModel($_POST['model'] ?? $session['model']);",
                    "+        $model = ModelConfig::validate($_POST['model'] ?? $session['model']);",
                    "         $sessionCollections = $this->decodeJson($session['collections'] ?? null) ?: ['documents'];",
                    "-        $collections = $this->validateCollections($_POST['collections'] ?? $sessionCollections);",
                    "-        $contextLimit = $this->validateContextLimit((int) ($_POST['context_limit'] ?? $session['context_limit'] ?? 5));",
                    "-        $authorProfileId = $this->validateAuthorProfileId((int) ($_POST['author_profile_id'] ?? $session['author_profile_id'] ?? 0));",
                    "+        $collections = $_POST['collections'] ?? $sessionCollections;",
                    "+        $contextLimit = (int) ($_POST['context_limit'] ?? $session['context_limit'] ?? 5);",
                    "+        $authorProfileId = (int) ($_POST['author_profile_id'] ?? $session['author_profile_id'] ?? 0);",
                    "         $systemPromptId = (int) ($_POST['system_prompt_id'] ?? $session['system_prompt_id'] ?? 1);",
                    "-        $temperature = $this->validateTemperature((float) ($_POST['temperature'] ?? $session['temperature'] ?? 0.7));",
                    "-        $maxTokens = $this->validateMaxTokens((int) ($_POST['max_tokens'] ?? $session['max_tokens'] ?? 4096));",
                    "+        $temperature = (float) ($_POST['temperature'] ?? $session['temperature'] ?? 0.7);",
                    "+        $maxTokens = (int) ($_POST['max_tokens'] ?? $session['max_tokens'] ?? 4096);",
                    " ",
                    "-        \/\/ Update session if settings changed",
                    "-        $currentLimit = (int) ($session['context_limit'] ?? 5);",
                    "-        $currentProfileId = (int) ($session['author_profile_id'] ?? 0);",
                    "-        $currentTemperature = (float) ($session['temperature'] ?? 0.7);",
                    "-        $currentMaxTokens = (int) ($session['max_tokens'] ?? 4096);",
                    "-        $collectionsJson = json_encode($collections);",
                    "-        if ($model !== $session['model'] || $collectionsJson !== ($session['collections'] ?? '[\"documents\"]') || $contextLimit !== $currentLimit || $authorProfileId !== $currentProfileId || $temperature !== $currentTemperature || $maxTokens !== $currentMaxTokens) {",
                    "-            $this->updateSessionSettings($session['id'], $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens);",
                    "+        if ($this->sessionsUseCase->settingsHaveChanged($session, $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens)) {",
                    "+            $this->sessionsUseCase->updateSettings($session['id'], $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens);",
                    "         }",
                    " ",
                    "         if ($question === '') {"
                ]
            },
            {
                "oldStart": 130,
                "oldLines": 9,
                "newStart": 91,
                "newLines": 8,
                "lines": [
                    "             return;",
                    "         }",
                    " ",
                    "-        \/\/ Validate collection compatibility (vector dimensions)",
                    "         if (!empty($collections)) {",
                    "-            $compatibility = $this->validateCollectionCompatibility($collections);",
                    "+            $compatibility = $this->sessionsUseCase->validateCollectionCompatibility($collections);",
                    "             if (!$compatibility['valid']) {",
                    "                 $this->view('chat.partials.error', [",
                    "                     'error' => 'Collection-Fehler: ' . $compatibility['error'],"
                ]
            },
            {
                "oldStart": 143,
                "oldLines": 8,
                "newStart": 103,
                "newLines": 7,
                "lines": [
                    "             }",
                    "         }",
                    " ",
                    "-        \/\/ Execute UseCase",
                    "-        $response = $this->sendMessageUseCase->execute(",
                    "+        $response = $this->messageUseCase->execute(",
                    "             sessionUuid: $uuid,",
                    "             message: $question,",
                    "             model: $model,"
                ]
            },
            {
                "oldStart": 162,
                "oldLines": 550,
                "newStart": 121,
                "newLines": 63,
                "lines": [
                    "             return;",
                    "         }",
                    " ",
                    "-        $this->renderResponse($question, $response->toArray(), $model);",
                    "+        $result = $response->toArray();",
                    "+        $this->view('chat.partials.response', [",
                    "+            'question' => $question,",
                    "+            'result' => $result,",
                    "+            'model' => $model,",
                    "+            'formattedAnswer' => $this->formatter->formatAnswer($result['answer'] ?? ''),",
                    "+        ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * POST \/chat\/{uuid}\/title (HTMX)",
                    "-     * Update session title",
                    "-     *\/",
                    "     public function updateTitle(string $uuid): void",
                    "     {",
                    "-        $session = $this->getSession($uuid);",
                    "+        $session = $this->sessionsUseCase->getSession($uuid);",
                    " ",
                    "         if ($session === null) {",
                    "             $this->notFound('Session nicht gefunden');",
                    "         }",
                    " ",
                    "-        $title = trim($_POST['title'] ?? '');",
                    "-",
                    "-        \/\/ Validate title",
                    "-        if ($title === '') {",
                    "-            $title = 'Neuer Chat';",
                    "-        }",
                    "-",
                    "-        \/\/ Max 100 characters",
                    "-        $title = mb_substr($title, 0, 100);",
                    "-",
                    "-        \/\/ Save to database",
                    "-        $this->updateSessionTitle($session['id'], $title);",
                    "-",
                    "-        \/\/ Return updated title HTML",
                    "+        $title = $this->sessionsUseCase->updateTitle($session['id'], $_POST['title'] ?? '');",
                    "         echo htmlspecialchars($title);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * POST \/chat\/{uuid}\/system-prompt (HTMX)",
                    "-     * Update session system prompt",
                    "-     *\/",
                    "     public function systemPrompt(string $uuid): void",
                    "     {",
                    "-        $session = $this->getSession($uuid);",
                    "+        $session = $this->sessionsUseCase->getSession($uuid);",
                    " ",
                    "         if ($session === null) {",
                    "             $this->notFound('Session nicht gefunden');",
                    "         }",
                    " ",
                    "-        $systemPrompt = trim($_POST['system_prompt'] ?? '');",
                    "-",
                    "-        \/\/ Validate and sanitize system prompt",
                    "-        $systemPrompt = $this->validateSystemPrompt($systemPrompt);",
                    "-",
                    "-        \/\/ Save to database",
                    "-        $this->updateSystemPrompt($session['id'], $systemPrompt);",
                    "-",
                    "-        \/\/ Return success message",
                    "-        $this->view('chat.partials.success', ['message' => 'System-Prompt gespeichert.']);",
                    "+        $result = $this->sessionsUseCase->updateSystemPrompt($session['id'], $_POST['system_prompt'] ?? '');",
                    "+        $this->view('chat.partials.success', ['message' => $result->message]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * GET \/chat\/{uuid}\/system-prompt (HTMX)",
                    "-     * Get system prompt form",
                    "-     *\/",
                    "     public function getSystemPrompt(string $uuid): void",
                    "     {",
                    "-        $session = $this->getSession($uuid);",
                    "+        $session = $this->sessionsUseCase->getSession($uuid);",
                    " ",
                    "         if ($session === null) {",
                    "             $this->notFound('Session nicht gefunden');",
                    "         }",
                    " ",
                    "-        $defaultPrompt = $this->getDefaultSystemPrompt();",
                    "-        $currentPrompt = $session['system_prompt'] ?? '';",
                    "-",
                    "         $this->view('chat.partials.system-prompt-modal', [",
                    "             'session' => $session,",
                    "-            'currentPrompt' => $currentPrompt,",
                    "-            'defaultPrompt' => $defaultPrompt,",
                    "+            'currentPrompt' => $session['system_prompt'] ?? '',",
                    "+            'defaultPrompt' => $this->sessionsUseCase->getDefaultSystemPrompt(),",
                    "         ]);",
                    "     }",
                    " ",
                    "-    \/**",
                    "-     * DELETE \/chat\/{uuid}",
                    "-     * Delete a session",
                    "-     *\/",
                    "     public function delete(string $uuid): void",
                    "     {",
                    "-        $session = $this->getSession($uuid);",
                    "+        $session = $this->sessionsUseCase->getSession($uuid);",
                    " ",
                    "         if ($session !== null) {",
                    "-            $stmt = $this->db->prepare('DELETE FROM chat_sessions WHERE id = ?');",
                    "-            $stmt->execute([$session['id']]);",
                    "+            $this->sessionsUseCase->deleteSession($session['id']);",
                    "         }",
                    " ",
                    "-        \/\/ Return success for HTMX",
                    "         header('HX-Redirect: \/chat');",
                    "         echo 'OK';",
                    "     }",
                    "-",
                    "-    \/\/ ========== Private Helper Methods ==========",
                    "-",
                    "-    \/**",
                    "-     * Initialize database connection",
                    "-     *\/",
                    "-    private function initializeDatabase(): \\PDO",
                    "-    {",
                    "-        return \\Infrastructure\\Config\\DatabaseFactory::content();",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Create a new chat session",
                    "-     *\/",
                    "-    private function createSession(): string",
                    "-    {",
                    "-        $uuid = $this->generateUuid();",
                    "-",
                    "-        $stmt = $this->db->prepare(",
                    "-            'INSERT INTO chat_sessions (uuid, model, collections, context_limit) VALUES (?, ?, ?, ?)'",
                    "-        );",
                    "-        $stmt->execute([$uuid, 'claude-opus-4-5-20251101', '[\"documents\"]', 5]);",
                    "-",
                    "-        return $uuid;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get session by UUID",
                    "-     *\/",
                    "-    private function getSession(string $uuid): ?array",
                    "-    {",
                    "-        $stmt = $this->db->prepare('SELECT * FROM chat_sessions WHERE uuid = ?');",
                    "-        $stmt->execute([$uuid]);",
                    "-        $result = $stmt->fetch(\\PDO::FETCH_ASSOC);",
                    "-",
                    "-        return $result !== false ? $result : null;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get all sessions ordered by most recent",
                    "-     *\/",
                    "-    private function getSessions(): array",
                    "-    {",
                    "-        $stmt = $this->db->query(",
                    "-            'SELECT s.*,",
                    "-                    (SELECT COUNT(*) FROM chat_messages WHERE session_id = s.id) as message_count,",
                    "-                    (SELECT COALESCE(SUM(tokens_input), 0) FROM chat_messages WHERE session_id = s.id) as total_input_tokens,",
                    "-                    (SELECT COALESCE(SUM(tokens_output), 0) FROM chat_messages WHERE session_id = s.id) as total_output_tokens,",
                    "-                    (SELECT COALESCE(SUM(end_microtime - start_microtime), 0) FROM chat_messages WHERE session_id = s.id AND start_microtime IS NOT NULL) as total_duration,",
                    "-                    (SELECT model FROM chat_messages WHERE session_id = s.id AND role = \"assistant\" ORDER BY id DESC LIMIT 1) as last_model",
                    "-             FROM chat_sessions s",
                    "-             ORDER BY s.last_activity DESC",
                    "-             LIMIT 50'",
                    "-        );",
                    "-",
                    "-        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get author profiles from content_config table",
                    "-     *\/",
                    "-    private function getAuthorProfiles(): array",
                    "-    {",
                    "-        $stmt = $this->db->query(",
                    "-            \"SELECT id, name, slug, content as config",
                    "-             FROM content_config",
                    "-             WHERE type = 'author_profile' AND status = 'active'",
                    "-             ORDER BY name\"",
                    "-        );",
                    "-",
                    "-        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get author profile by ID",
                    "-     *\/",
                    "-    private function getAuthorProfile(int $profileId): ?array",
                    "-    {",
                    "-        $stmt = $this->db->prepare(",
                    "-            \"SELECT id, name, slug, content as config",
                    "-             FROM content_config",
                    "-             WHERE id = ? AND type = 'author_profile' AND status = 'active'\"",
                    "-        );",
                    "-        $stmt->execute([$profileId]);",
                    "-        $result = $stmt->fetch(\\PDO::FETCH_ASSOC);",
                    "-",
                    "-        return $result !== false ? $result : null;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get system prompts from content_config table",
                    "-     *\/",
                    "-    private function getSystemPrompts(): array",
                    "-    {",
                    "-        $stmt = $this->db->query(",
                    "-            \"SELECT id, name, slug, content",
                    "-             FROM content_config",
                    "-             WHERE type = 'system_prompt' AND status = 'active'",
                    "-             ORDER BY name\"",
                    "-        );",
                    "-",
                    "-        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get messages for a session",
                    "-     *\/",
                    "-    private function getMessages(int $sessionId): array",
                    "-    {",
                    "-        $stmt = $this->db->prepare(",
                    "-            'SELECT * FROM chat_messages WHERE session_id = ? ORDER BY created_at ASC'",
                    "-        );",
                    "-        $stmt->execute([$sessionId]);",
                    "-",
                    "-        return $stmt->fetchAll(\\PDO::FETCH_ASSOC);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Update session title",
                    "-     *\/",
                    "-    private function updateSessionTitle(int $sessionId, string $title): void",
                    "-    {",
                    "-        $stmt = $this->db->prepare('UPDATE chat_sessions SET title = ? WHERE id = ?');",
                    "-        $stmt->execute([$title, $sessionId]);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Generate UUID v4",
                    "-     *\/",
                    "-    private function generateUuid(): string",
                    "-    {",
                    "-        $data = random_bytes(16);",
                    "-        $data[6] = chr(ord($data[6]) & 0x0f | 0x40);",
                    "-        $data[8] = chr(ord($data[8]) & 0x3f | 0x80);",
                    "-",
                    "-        return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate model parameter",
                    "-     *\/",
                    "-    private function validateModel(string $model): string",
                    "-    {",
                    "-        return ModelConfig::validate($model);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get available collections from database (cached per request)",
                    "-     *",
                    "-     * @return array<int, array<string,mixed>> List of collection data",
                    "-     *\/",
                    "-    private function getAvailableCollections(): array",
                    "-    {",
                    "-        if ($this->collectionsCache === null) {",
                    "-            $this->collectionsCache = $this->collectionRepository->getSearchable();",
                    "-",
                    "-            \/\/ Fallback if database is empty",
                    "-            if ($this->collectionsCache === []) {",
                    "-                $this->collectionsCache = [",
                    "-                    ['collection_id' => 'documents', 'display_name' => 'Dokumente', 'points_count' => 0, 'vector_size' => 1024],",
                    "-                ];",
                    "-            }",
                    "-        }",
                    "-",
                    "-        return $this->collectionsCache;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get collection IDs only (for backwards compatibility)",
                    "-     *",
                    "-     * @return array<string>",
                    "-     *\/",
                    "-    private function getAvailableCollectionIds(): array",
                    "-    {",
                    "-        return array_column($this->getAvailableCollections(), 'collection_id');",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate collections array against available collections",
                    "-     *",
                    "-     * @param array<string>|string $collections Collections to validate (array or single string)",
                    "-     * @return array<string> Validated collections array (may be empty for no RAG)",
                    "-     *\/",
                    "-    private function validateCollections(array|string $collections): array",
                    "-    {",
                    "-        $availableIds = $this->getAvailableCollectionIds();",
                    "-",
                    "-        \/\/ Handle string input (backwards compatibility)",
                    "-        if (is_string($collections)) {",
                    "-            $collections = [$collections];",
                    "-        }",
                    "-",
                    "-        \/\/ Filter to only valid collections",
                    "-        $valid = array_filter($collections, fn ($c) => in_array($c, $availableIds, true));",
                    "-",
                    "-        return array_values($valid);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate collection compatibility (vector dimensions)",
                    "-     *",
                    "-     * @param array<string> $collectionIds",
                    "-     * @return array{valid: bool, error: string|null}",
                    "-     *\/",
                    "-    private function validateCollectionCompatibility(array $collectionIds): array",
                    "-    {",
                    "-        if (empty($collectionIds)) {",
                    "-            return ['valid' => true, 'error' => null];",
                    "-        }",
                    "-",
                    "-        $result = $this->collectionValidator->validateSelection($collectionIds);",
                    "-",
                    "-        return [",
                    "-            'valid' => $result->isValid(),",
                    "-            'error' => $result->getError(),",
                    "-        ];",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate context limit parameter against allowed values",
                    "-     *\/",
                    "-    private function validateContextLimit(int $limit): int",
                    "-    {",
                    "-        $allowedLimits = [3, 5, 10, 15];",
                    "-",
                    "-        return in_array($limit, $allowedLimits, true) ? $limit : 5;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate author profile ID (0 = no profile)",
                    "-     *\/",
                    "-    private function validateAuthorProfileId(int $profileId): int",
                    "-    {",
                    "-        if ($profileId === 0) {",
                    "-            return 0;",
                    "-        }",
                    "-        $profile = $this->getAuthorProfile($profileId);",
                    "-",
                    "-        return $profile !== null ? $profileId : 0;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate temperature parameter (0.0 - 1.0)",
                    "-     *\/",
                    "-    private function validateTemperature(float $temperature): float",
                    "-    {",
                    "-        return max(0.0, min(1.0, $temperature));",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate max_tokens parameter against allowed values",
                    "-     *\/",
                    "-    private function validateMaxTokens(int $maxTokens): int",
                    "-    {",
                    "-        $allowedValues = [1024, 2048, 4096, 8192];",
                    "-",
                    "-        return in_array($maxTokens, $allowedValues, true) ? $maxTokens : 4096;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Update session model, collections, context limit, author profile, temperature and max_tokens settings",
                    "-     *",
                    "-     * @param array<string> $collections Array of collection names",
                    "-     *\/",
                    "-    private function updateSessionSettings(int $sessionId, string $model, array $collections, int $contextLimit = 5, int $authorProfileId = 0, float $temperature = 0.7, int $maxTokens = 4096): void",
                    "-    {",
                    "-        $collectionsJson = json_encode($collections);",
                    "-        $stmt = $this->db->prepare('UPDATE chat_sessions SET model = ?, collections = ?, context_limit = ?, author_profile_id = ?, temperature = ?, max_tokens = ? WHERE id = ?');",
                    "-        $stmt->execute([$model, $collectionsJson, $contextLimit, $authorProfileId > 0 ? $authorProfileId : null, $temperature, $maxTokens, $sessionId]);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Validate system prompt input.",
                    "-     *",
                    "-     * NOTE: Pattern-based prompt injection filtering was intentionally removed.",
                    "-     * Such filtering provides false security since attackers can easily rephrase",
                    "-     * malicious instructions. LLM prompt injection cannot be reliably prevented",
                    "-     * through input sanitization alone.",
                    "-     *",
                    "-     * Instead, we apply:",
                    "-     * - Length limits (to prevent resource abuse)",
                    "-     * - Logging (for monitoring and incident response)",
                    "-     *",
                    "-     * True prompt injection mitigation requires architectural measures like",
                    "-     * sandboxing LLM outputs and limiting LLM capabilities.",
                    "-     *\/",
                    "-    private function validateSystemPrompt(string $prompt): string",
                    "-    {",
                    "-        \/\/ Length limit: prevent resource abuse",
                    "-        $maxLength = 2000;",
                    "-        $wasTruncated = mb_strlen($prompt) > $maxLength;",
                    "-        $prompt = mb_substr($prompt, 0, $maxLength);",
                    "-",
                    "-        \/\/ Log custom system prompts for monitoring",
                    "-        $this->logSystemPromptChange($prompt, $wasTruncated);",
                    "-",
                    "-        return trim($prompt);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Log system prompt changes for security monitoring.",
                    "-     *\/",
                    "-    private function logSystemPromptChange(string $prompt, bool $wasTruncated): void",
                    "-    {",
                    "-        $logData = [",
                    "-            'prompt_length' => mb_strlen($prompt),",
                    "-            'truncated' => $wasTruncated,",
                    "-            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',",
                    "-            'timestamp' => date('c'),",
                    "-        ];",
                    "-",
                    "-        \/\/ Log to database via ki_dev.mcp_log",
                    "-        try {",
                    "-            $devDb = \\Infrastructure\\Config\\DatabaseFactory::dev();",
                    "-            $stmt = $devDb->prepare(",
                    "-                \"INSERT INTO mcp_log (tool, operation, parameters, result, logged_at)",
                    "-                 VALUES ('chat', 'system_prompt_change', :params, 'logged', NOW())\"",
                    "-            );",
                    "-            $stmt->execute(['params' => json_encode($logData)]);",
                    "-        } catch (\\Exception $e) {",
                    "-            \/\/ Silently fail - logging should not break functionality",
                    "-        }",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Update session system prompt",
                    "-     *\/",
                    "-    private function updateSystemPrompt(int $sessionId, string $systemPrompt): void",
                    "-    {",
                    "-        $stmt = $this->db->prepare('UPDATE chat_sessions SET system_prompt = ? WHERE id = ?');",
                    "-        $stmt->execute([$systemPrompt !== '' ? $systemPrompt : null, $sessionId]);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Get default system prompt from ClaudeService",
                    "-     *\/",
                    "-    private function getDefaultSystemPrompt(): string",
                    "-    {",
                    "-        return <<<'PROMPT'",
                    "-            Du bist ein hilfreicher Assistent für Fragen zu systemischem Teamcoaching und Teamentwicklung.",
                    "-",
                    "-            Beantworte die Frage des Nutzers basierend auf dem bereitgestellten Kontext.",
                    "-            - Antworte auf Deutsch",
                    "-            - Sei präzise und hilfreich",
                    "-            - Wenn der Kontext die Frage nicht beantwortet, sage das ehrlich",
                    "-            - Verweise auf die Quellen wenn passend",
                    "-            PROMPT;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Render chat response HTML using view partial",
                    "-     *\/",
                    "-    private function renderResponse(string $question, array $result, string $model): void",
                    "-    {",
                    "-        \/\/ Convert markdown-style formatting to HTML",
                    "-        $formattedAnswer = $this->formatAnswer($result['answer'] ?? '');",
                    "-",
                    "-        $this->view('chat.partials.response', [",
                    "-            'question' => $question,",
                    "-            'result' => $result,",
                    "-            'model' => $model,",
                    "-            'formattedAnswer' => $formattedAnswer,",
                    "-        ]);",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Format markdown-like answer to HTML.",
                    "-     *",
                    "-     * Converts basic markdown syntax to HTML. Uses line-based processing",
                    "-     * to correctly handle list blocks mixed with regular text.",
                    "-     *\/",
                    "-    private function formatAnswer(string $text): string",
                    "-    {",
                    "-        \/\/ Escape HTML first",
                    "-        $text = htmlspecialchars($text);",
                    "-",
                    "-        \/\/ Headers",
                    "-        $text = preg_replace('\/^### (.+)$\/m', '<h4>$1<\/h4>', $text);",
                    "-        $text = preg_replace('\/^## (.+)$\/m', '<h3>$1<\/h3>', $text);",
                    "-        $text = preg_replace('\/^# (.+)$\/m', '<h3>$1<\/h3>', $text);",
                    "-",
                    "-        \/\/ Bold",
                    "-        $text = preg_replace('\/\\*\\*(.+?)\\*\\*\/', '<strong>$1<\/strong>', $text);",
                    "-",
                    "-        \/\/ Italic",
                    "-        $text = preg_replace('\/\\*(.+?)\\*\/', '<em>$1<\/em>', $text);",
                    "-",
                    "-        \/\/ Code",
                    "-        $text = preg_replace('\/`(.+?)`\/', '<code>$1<\/code>', $text);",
                    "-",
                    "-        \/\/ Blockquotes",
                    "-        $text = preg_replace('\/^&gt; (.+)$\/m', '<blockquote>$1<\/blockquote>', $text);",
                    "-",
                    "-        \/\/ Lists: Process line by line to correctly wrap consecutive list items",
                    "-        $text = $this->formatLists($text);",
                    "-",
                    "-        \/\/ Line breaks",
                    "-        $text = nl2br($text);",
                    "-",
                    "-        \/\/ Clean up multiple <br> tags",
                    "-        $text = preg_replace('\/(<br\\s*\\\/?>\\s*){3,}\/', '<br><br>', $text);",
                    "-",
                    "-        return $text;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "-     * Format list items and wrap consecutive items in <ul> tags.",
                    "-     *",
                    "-     * Processes text line by line to correctly handle:",
                    "-     * - Multiple separate lists with text between them",
                    "-     * - Mixed content (text + list + text + list)",
                    "-     * - Numbered lists (converted to unordered for simplicity)",
                    "-     *\/",
                    "-    private function formatLists(string $text): string",
                    "-    {",
                    "-        $lines = explode(\"\\n\", $text);",
                    "-        $result = [];",
                    "-        $inList = false;",
                    "-",
                    "-        foreach ($lines as $line) {",
                    "-            \/\/ Check if line is a list item (- or * or numbered)",
                    "-            if (preg_match('\/^[-*] (.+)$\/', $line, $matches)) {",
                    "-                if (!$inList) {",
                    "-                    $result[] = '<ul>';",
                    "-                    $inList = true;",
                    "-                }",
                    "-                $result[] = '<li>' . $matches[1] . '<\/li>';",
                    "-            } elseif (preg_match('\/^\\d+\\. (.+)$\/', $line, $matches)) {",
                    "-                \/\/ Numbered list item",
                    "-                if (!$inList) {",
                    "-                    $result[] = '<ul>';",
                    "-                    $inList = true;",
                    "-                }",
                    "-                $result[] = '<li>' . $matches[1] . '<\/li>';",
                    "-            } else {",
                    "-                \/\/ Not a list item",
                    "-                if ($inList) {",
                    "-                    $result[] = '<\/ul>';",
                    "-                    $inList = false;",
                    "-                }",
                    "-                $result[] = $line;",
                    "-            }",
                    "-        }",
                    "-",
                    "-        \/\/ Close any open list",
                    "-        if ($inList) {",
                    "-            $result[] = '<\/ul>';",
                    "-        }",
                    "-",
                    "-        return implode(\"\\n\", $result);",
                    "-    }",
                    " }"
                ]
            }
        ],
        "originalFile": "<?php\n\nnamespace Controller;\n\nuse Framework\\Controller;\nuse Infrastructure\\AI\\AIConfig;\nuse Infrastructure\\AI\\ChatService;\nuse Infrastructure\\AI\\ModelConfig;\nuse Infrastructure\\Persistence\\CollectionRepository;\nuse Infrastructure\\Validation\\CollectionValidator;\nuse UseCases\\Chat\\SendChatMessageUseCase;\n\nclass ChatController extends Controller\n{\n    private ChatService $chatService;\n    private CollectionRepository $collectionRepository;\n    private CollectionValidator $collectionValidator;\n    private SendChatMessageUseCase $sendMessageUseCase;\n    private \\PDO $db;\n\n    \/** @var array<array<string,mixed>>|null Cached collections list *\/\n    private ?array $collectionsCache = null;\n\n    public function __construct()\n    {\n        $config = AIConfig::fromCredentialsFile();\n        $this->chatService = $config->createChatService();\n        $this->collectionRepository = new CollectionRepository();\n        $this->collectionValidator = new CollectionValidator($this->collectionRepository);\n        $this->sendMessageUseCase = new SendChatMessageUseCase($this->chatService);\n        $this->db = $this->initializeDatabase();\n    }\n\n    \/**\n     * GET \/chat\n     * Show chat interface with session list, create new session if none\n     *\/\n    public function index(): void\n    {\n        $sessions = $this->getSessions();\n\n        \/\/ Create new session and redirect\n        $uuid = $this->createSession();\n        header('Location: \/chat\/' . $uuid);\n        exit;\n    }\n\n    \/**\n     * GET \/chat\/{uuid}\n     * Show specific chat session\n     *\/\n    public function show(string $uuid): void\n    {\n        $session = $this->getSession($uuid);\n\n        if ($session === null) {\n            header('Location: \/chat');\n            exit;\n        }\n\n        $messages = $this->getMessages($session['id']);\n        $sessions = $this->getSessions();\n        $authorProfiles = $this->getAuthorProfiles();\n        $systemPrompts = $this->getSystemPrompts();\n        $collections = $this->getAvailableCollections();\n\n        $this->view('chat.index', [\n            'title' => $session['title'] ?? 'KI-Chat',\n            'session' => $session,\n            'messages' => $messages,\n            'sessions' => $sessions,\n            'authorProfiles' => $authorProfiles,\n            'systemPrompts' => $systemPrompts,\n            'collections' => $collections,\n            'models' => ModelConfig::getAll(),\n            'defaultModel' => ModelConfig::DEFAULT_MODEL,\n        ]);\n    }\n\n    \/**\n     * GET \/chat\/sessions (HTMX partial)\n     * Return session list HTML\n     *\/\n    public function sessionList(): void\n    {\n        $sessions = $this->getSessions();\n        $this->view('chat.partials.session-list', [\n            'sessions' => $sessions,\n            'currentUuid' => $this->getString('current') ?: null,\n        ]);\n    }\n\n    \/**\n     * POST \/chat\/{uuid}\/message (HTMX)\n     * Process message and return HTML response\n     *\/\n    public function message(string $uuid): void\n    {\n        $session = $this->getSession($uuid);\n\n        if ($session === null) {\n            $this->view('chat.partials.error', ['error' => 'Session nicht gefunden.']);\n\n            return;\n        }\n\n        $question = trim($_POST['message'] ?? '');\n        $model = $this->validateModel($_POST['model'] ?? $session['model']);\n        $sessionCollections = $this->decodeJson($session['collections'] ?? null) ?: ['documents'];\n        $collections = $this->validateCollections($_POST['collections'] ?? $sessionCollections);\n        $contextLimit = $this->validateContextLimit((int) ($_POST['context_limit'] ?? $session['context_limit'] ?? 5));\n        $authorProfileId = $this->validateAuthorProfileId((int) ($_POST['author_profile_id'] ?? $session['author_profile_id'] ?? 0));\n        $systemPromptId = (int) ($_POST['system_prompt_id'] ?? $session['system_prompt_id'] ?? 1);\n        $temperature = $this->validateTemperature((float) ($_POST['temperature'] ?? $session['temperature'] ?? 0.7));\n        $maxTokens = $this->validateMaxTokens((int) ($_POST['max_tokens'] ?? $session['max_tokens'] ?? 4096));\n\n        \/\/ Update session if settings changed\n        $currentLimit = (int) ($session['context_limit'] ?? 5);\n        $currentProfileId = (int) ($session['author_profile_id'] ?? 0);\n        $currentTemperature = (float) ($session['temperature'] ?? 0.7);\n        $currentMaxTokens = (int) ($session['max_tokens'] ?? 4096);\n        $collectionsJson = json_encode($collections);\n        if ($model !== $session['model'] || $collectionsJson !== ($session['collections'] ?? '[\"documents\"]') || $contextLimit !== $currentLimit || $authorProfileId !== $currentProfileId || $temperature !== $currentTemperature || $maxTokens !== $currentMaxTokens) {\n            $this->updateSessionSettings($session['id'], $model, $collections, $contextLimit, $authorProfileId, $temperature, $maxTokens);\n        }\n\n        if ($question === '') {\n            $this->view('chat.partials.error', ['error' => 'Bitte gib eine Frage ein.']);\n\n            return;\n        }\n\n        \/\/ Validate collection compatibility (vector dimensions)\n        if (!empty($collections)) {\n            $compatibility = $this->validateCollectionCompatibility($collections);\n            if (!$compatibility['valid']) {\n                $this->view('chat.partials.error', [\n                    'error' => 'Collection-Fehler: ' . $compatibility['error'],\n                    'details' => 'Bitte wähle nur Collections mit gleichem Embedding-Modell.',\n                ]);\n\n                return;\n            }\n        }\n\n        \/\/ Execute UseCase\n        $response = $this->sendMessageUseCase->execute(\n            sessionUuid: $uuid,\n            message: $question,\n            model: $model,\n            collections: $collections,\n            contextLimit: $contextLimit,\n            authorProfileId: $authorProfileId,\n            systemPromptId: $systemPromptId,\n            temperature: $temperature,\n            maxTokens: $maxTokens\n        );\n\n        if ($response->hasError()) {\n            $this->view('chat.partials.error', ['error' => $response->getError()]);\n\n            return;\n        }\n\n        $this->renderResponse($question, $response->toArray(), $model);\n    }\n\n    \/**\n     * POST \/chat\/{uuid}\/title (HTMX)\n     * Update session title\n     *\/\n    public function updateTitle(string $uuid): void\n    {\n        $session = $this->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $title = trim($_POST['title'] ?? '');\n\n        \/\/ Validate title\n        if ($title === '') {\n            $title = 'Neuer Chat';\n        }\n\n        \/\/ Max 100 characters\n        $title = mb_substr($title, 0, 100);\n\n        \/\/ Save to database\n        $this->updateSessionTitle($session['id'], $title);\n\n        \/\/ Return updated title HTML\n        echo htmlspecialchars($title);\n    }\n\n    \/**\n     * POST \/chat\/{uuid}\/system-prompt (HTMX)\n     * Update session system prompt\n     *\/\n    public function systemPrompt(string $uuid): void\n    {\n        $session = $this->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $systemPrompt = trim($_POST['system_prompt'] ?? '');\n\n        \/\/ Validate and sanitize system prompt\n        $systemPrompt = $this->validateSystemPrompt($systemPrompt);\n\n        \/\/ Save to database\n        $this->updateSystemPrompt($session['id'], $systemPrompt);\n\n        \/\/ Return success message\n        $this->view('chat.partials.success', ['message' => 'System-Prompt gespeichert.']);\n    }\n\n    \/**\n     * GET \/chat\/{uuid}\/system-prompt (HTMX)\n     * Get system prompt form\n     *\/\n    public function getSystemPrompt(string $uuid): void\n    {\n        $session = $this->getSession($uuid);\n\n        if ($session === null) {\n            $this->notFound('Session nicht gefunden');\n        }\n\n        $defaultPrompt = $this->getDefaultSystemPrompt();\n        $currentPrompt = $session['system_prompt'] ?? '';\n\n        $this->view('chat.partials.system-prompt-modal', [\n            'session' => $session,\n            'currentPrompt' => $currentPrompt,\n            'defaultPrompt' => $defaultPrompt,\n        ]);\n    }\n\n    \/**\n     * DELETE \/chat\/{uuid}\n     * Delete a session\n     *\/\n    public function delete(string $uuid): void\n    {\n        $session = $this->getSession($uuid);\n\n        if ($session !== null) {\n            $stmt = $this->db->prepare('DELETE FROM chat_sessions WHERE id = ?');\n            $stmt->execute([$session['id']]);\n        }\n\n        \/\/ Return success for HTMX\n        header('HX-Redirect: \/chat');\n        echo 'OK';\n    }\n\n    \/\/ ========== Private Helper Methods ==========\n\n    \/**\n     * Initialize database connection\n     *\/\n    private function initializeDatabase(): \\PDO\n    {\n        return \\Infrastructure\\Config\\DatabaseFactory::content();\n    }\n\n    \/**\n     * Create a new chat session\n     *\/\n    private function createSession(): string\n    {\n        $uuid = $this->generateUuid();\n\n        $stmt = $this->db->prepare(\n            'INSERT INTO chat_sessions (uuid, model, collections, context_limit) VALUES (?, ?, ?, ?)'\n        );\n        $stmt->execute([$uuid, 'claude-opus-4-5-20251101', '[\"documents\"]', 5]);\n\n        return $uuid;\n    }\n\n    \/**\n     * Get session by UUID\n     *\/\n    private function getSession(string $uuid): ?array\n    {\n        $stmt = $this->db->prepare('SELECT * FROM chat_sessions WHERE uuid = ?');\n        $stmt->execute([$uuid]);\n        $result = $stmt->fetch(\\PDO::FETCH_ASSOC);\n\n        return $result !== false ? $result : null;\n    }\n\n    \/**\n     * Get all sessions ordered by most recent\n     *\/\n    private function getSessions(): array\n    {\n        $stmt = $this->db->query(\n            'SELECT s.*,\n                    (SELECT COUNT(*) FROM chat_messages WHERE session_id = s.id) as message_count,\n                    (SELECT COALESCE(SUM(tokens_input), 0) FROM chat_messages WHERE session_id = s.id... [TRUNCATED-e64f2bf35a1c435f]"
    }
}
← Vorheriger Zur Liste Nächster →