sessionRepo->updateTitle($sessionId, $title); return $title; } public function updateSettings( int $sessionId, string $model, array $collections, int $contextLimit, int $authorProfileId, float $temperature, int $maxTokens ): void { $model = $this->modelRegistry->isValid($model) ? $model : $this->modelRegistry->getDefaultChatModel(); $collections = $this->validateCollections($collections); $contextLimit = $this->validateContextLimit($contextLimit); $authorProfileId = $this->validateAuthorProfileId($authorProfileId); $temperature = $this->validateTemperature($temperature); $maxTokens = $this->validateMaxTokens($maxTokens); $this->sessionRepo->updateSettings( $sessionId, $model, $collections, $contextLimit, $authorProfileId > 0 ? $authorProfileId : null, $temperature, $maxTokens ); } public function updateSystemPrompt(int $sessionId, string $systemPrompt): ChatSessionResult { $maxLength = 2000; $wasTruncated = mb_strlen($systemPrompt) > $maxLength; $systemPrompt = trim(mb_substr($systemPrompt, 0, $maxLength)); $this->logSystemPromptChange($systemPrompt, $wasTruncated); $this->sessionRepo->updateSystemPrompt($sessionId, $systemPrompt); return ChatSessionResult::success('System-Prompt gespeichert.'); } public function settingsHaveChanged( ChatSession $session, string $model, array $collections, int $contextLimit, int $authorProfileId, float $temperature, int $maxTokens ): bool { return $model !== $session->getModel() || $collections !== $session->getCollections() || $contextLimit !== $session->getContextLimit() || $authorProfileId !== ($session->getAuthorProfileId() ?? 0) || $temperature !== $session->getTemperature() || $maxTokens !== $session->getMaxTokens(); } public 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(), ]; } private function validateCollections(array|string $collections): array { $availableIds = array_column($this->collectionRepo->getSearchable(), 'collection_id'); if (is_string($collections)) { $collections = [$collections]; } $valid = array_filter($collections, fn ($c) => in_array($c, $availableIds, true)); return array_values($valid); } private function validateContextLimit(int $limit): int { $allowedLimits = [3, 5, 10, 15]; return in_array($limit, $allowedLimits, true) ? $limit : 5; } private function validateAuthorProfileId(int $profileId): int { if ($profileId === 0) { return 0; } $profile = $this->configRepo->getAuthorProfile($profileId); return $profile !== null ? $profileId : 0; } private function validateTemperature(float $temperature): float { return max(0.0, min(1.0, $temperature)); } private function validateMaxTokens(int $maxTokens): int { $allowedValues = [1024, 2048, 4096, 8192]; return in_array($maxTokens, $allowedValues, true) ? $maxTokens : 4096; } private function logSystemPromptChange(string $prompt, bool $wasTruncated): void { $logData = [ 'prompt_length' => mb_strlen($prompt), 'truncated' => $wasTruncated, 'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown', 'timestamp' => date('c'), ]; try { $stmt = $this->pdoDev->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 } } }