{
"event": "PreToolUse",
"tool_name": "Edit",
"tool_input": {
"file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
"old_string": " return $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n }\n\n \/**\n * Save a message to the database\n *\/\n private function saveMessage(\n int $sessionId,\n string $role,\n string $content,\n string $model,\n ?int $tokensInput = null,\n ?int $tokensOutput = null,\n array $sources = [],\n ?float $startMicrotime = null,\n ?float $endMicrotime = null,\n ?int $authorProfileId = null,\n ?int $systemPromptId = null,\n ?string $collectionsJson = null,\n ?int $contextLimit = null\n ): void {\n $stmt = $this->db->prepare(\n 'INSERT INTO chat_messages\n (session_id, role, content, model, tokens_input, tokens_output, sources,\n start_microtime, end_microtime, author_profile_id, system_prompt_id, collections, context_limit)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n );\n $stmt->execute([\n $sessionId,\n $role,\n $content,\n $model,\n $tokensInput,\n $tokensOutput,\n $sources !== [] ? json_encode($sources) : null,\n $startMicrotime,\n $endMicrotime,\n $authorProfileId,\n $systemPromptId,\n $collectionsJson,\n $contextLimit,\n ]);\n\n \/\/ Update session timestamp\n $this->db->prepare('UPDATE chat_sessions SET updated_at = NOW() WHERE id = ?')\n ->execute([$sessionId]);\n }\n\n \/**\n * Update session title\n *\/",
"new_string": " return $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n }\n\n \/**\n * Update session title\n *\/"
}
}
{
"tool_response": {
"filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
"oldString": " return $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n }\n\n \/**\n * Save a message to the database\n *\/\n private function saveMessage(\n int $sessionId,\n string $role,\n string $content,\n string $model,\n ?int $tokensInput = null,\n ?int $tokensOutput = null,\n array $sources = [],\n ?float $startMicrotime = null,\n ?float $endMicrotime = null,\n ?int $authorProfileId = null,\n ?int $systemPromptId = null,\n ?string $collectionsJson = null,\n ?int $contextLimit = null\n ): void {\n $stmt = $this->db->prepare(\n 'INSERT INTO chat_messages\n (session_id, role, content, model, tokens_input, tokens_output, sources,\n start_microtime, end_microtime, author_profile_id, system_prompt_id, collections, context_limit)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'\n );\n $stmt->execute([\n $sessionId,\n $role,\n $content,\n $model,\n $tokensInput,\n $tokensOutput,\n $sources !== [] ? json_encode($sources) : null,\n $startMicrotime,\n $endMicrotime,\n $authorProfileId,\n $systemPromptId,\n $collectionsJson,\n $contextLimit,\n ]);\n\n \/\/ Update session timestamp\n $this->db->prepare('UPDATE chat_sessions SET updated_at = NOW() WHERE id = ?')\n ->execute([$sessionId]);\n }\n\n \/**\n * Update session title\n *\/",
"newString": " return $stmt->fetchAll(\\PDO::FETCH_ASSOC);\n }\n\n \/**\n * Update session title\n *\/",
"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-1579be49f483bf56]",
"structuredPatch": [
{
"oldStart": 394,
"oldLines": 51,
"newStart": 394,
"newLines": 6,
"lines": [
" }",
" ",
" \/**",
"- * Save a message to the database",
"- *\/",
"- private function saveMessage(",
"- int $sessionId,",
"- string $role,",
"- string $content,",
"- string $model,",
"- ?int $tokensInput = null,",
"- ?int $tokensOutput = null,",
"- array $sources = [],",
"- ?float $startMicrotime = null,",
"- ?float $endMicrotime = null,",
"- ?int $authorProfileId = null,",
"- ?int $systemPromptId = null,",
"- ?string $collectionsJson = null,",
"- ?int $contextLimit = null",
"- ): void {",
"- $stmt = $this->db->prepare(",
"- 'INSERT INTO chat_messages",
"- (session_id, role, content, model, tokens_input, tokens_output, sources,",
"- start_microtime, end_microtime, author_profile_id, system_prompt_id, collections, context_limit)",
"- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)'",
"- );",
"- $stmt->execute([",
"- $sessionId,",
"- $role,",
"- $content,",
"- $model,",
"- $tokensInput,",
"- $tokensOutput,",
"- $sources !== [] ? json_encode($sources) : null,",
"- $startMicrotime,",
"- $endMicrotime,",
"- $authorProfileId,",
"- $systemPromptId,",
"- $collectionsJson,",
"- $contextLimit,",
"- ]);",
"-",
"- \/\/ Update session timestamp",
"- $this->db->prepare('UPDATE chat_sessions SET updated_at = NOW() WHERE id = ?')",
"- ->execute([$sessionId]);",
"- }",
"-",
"- \/**",
" * Update session title",
" *\/",
" private function updateSessionTitle(int $sessionId, string $title): void"
]
}
],
"userModified": false,
"replaceAll": false
}
}