{
"tool_response": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
"oldString": " return in_array($maxTokens, $allowedValues, true) ? $maxTokens : 4096;\n }\n\n \/**\n * Generate style prompt from author profile config\n *\/\n private function getStylePromptFromProfile(int $profileId): ?string\n {\n if ($profileId === 0) {\n return null;\n }\n\n $profile = $this->getAuthorProfile($profileId);\n if ($profile === null) {\n return null;\n }\n\n $config = json_decode($profile['config'], true);\n if ($config === null) {\n return null;\n }\n\n $parts = [];\n\n \/\/ Build style instructions from config\n if (isset($config['stimme']['ton'])) {\n $parts[] = 'Ton: ' . $config['stimme']['ton'];\n }\n if (isset($config['stimme']['perspektive'])) {\n $parts[] = 'Perspektive: ' . $config['stimme']['perspektive'];\n }\n if (isset($config['stil']['fachsprache']) && $config['stil']['fachsprache']) {\n $parts[] = 'Verwende Fachsprache';\n }\n if (isset($config['stil']['beispiele']) && $config['stil']['beispiele'] === 'häufig') {\n $parts[] = 'Nutze häufig Beispiele';\n }\n if (isset($config['stil']['listen']) && $config['stil']['listen'] === 'bevorzugt') {\n $parts[] = 'Bevorzuge Listen und Bullet-Points';\n }\n if (isset($config['tabus']) && is_array($config['tabus'])) {\n $parts[] = 'Vermeide: ' . implode(', ', $config['tabus']);\n }\n\n if ($parts === []) {\n return null;\n }\n\n return 'Schreibstil (' . $profile['name'] . '): ' . implode('. ', $parts) . '.';\n }\n\n \/**\n * Update session model, collections, context limit, author profile, temperature and max_tokens settings",
"newString": " return in_array($maxTokens, $allowedValues, true) ? $maxTokens : 4096;\n }\n\n \/**\n * Update session model, collections, context limit, author profile, temperature and max_tokens settings",
"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\\Persistence\\ContentConfigRepository;\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 ContentConfigRepository $configRepository;\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->configRepository = new ContentConfigRepository();\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' => $_GET['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 = json_decode($session['collections'] ?? '[\"documents\"]', true) ?: ['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 (SEL... [TRUNCATED-52b4fec1a809d106]",
"structuredPatch": [
{
"oldStart": 536,
"oldLines": 54,
"newStart": 536,
"newLines": 6,
"lines": [
" }",
" ",
" \/**",
"- * Generate style prompt from author profile config",
"- *\/",
"- private function getStylePromptFromProfile(int $profileId): ?string",
"- {",
"- if ($profileId === 0) {",
"- return null;",
"- }",
"-",
"- $profile = $this->getAuthorProfile($profileId);",
"- if ($profile === null) {",
"- return null;",
"- }",
"-",
"- $config = json_decode($profile['config'], true);",
"- if ($config === null) {",
"- return null;",
"- }",
"-",
"- $parts = [];",
"-",
"- \/\/ Build style instructions from config",
"- if (isset($config['stimme']['ton'])) {",
"- $parts[] = 'Ton: ' . $config['stimme']['ton'];",
"- }",
"- if (isset($config['stimme']['perspektive'])) {",
"- $parts[] = 'Perspektive: ' . $config['stimme']['perspektive'];",
"- }",
"- if (isset($config['stil']['fachsprache']) && $config['stil']['fachsprache']) {",
"- $parts[] = 'Verwende Fachsprache';",
"- }",
"- if (isset($config['stil']['beispiele']) && $config['stil']['beispiele'] === 'häufig') {",
"- $parts[] = 'Nutze häufig Beispiele';",
"- }",
"- if (isset($config['stil']['listen']) && $config['stil']['listen'] === 'bevorzugt') {",
"- $parts[] = 'Bevorzuge Listen und Bullet-Points';",
"- }",
"- if (isset($config['tabus']) && is_array($config['tabus'])) {",
"- $parts[] = 'Vermeide: ' . implode(', ', $config['tabus']);",
"- }",
"-",
"- if ($parts === []) {",
"- return null;",
"- }",
"-",
"- return 'Schreibstil (' . $profile['name'] . '): ' . implode('. ', $parts) . '.';",
"- }",
"-",
"- \/**",
" * Update session model, collections, context limit, author profile, temperature and max_tokens settings",
" *",
" * @param array<string> $collections Array of collection names"
]
}
],
"userModified": false,
"replaceAll": false
}
}