Protokoll #3116

ID3116
Zeitstempel2025-12-22 01:59:54.223280
Clientroot
IP145.224.96.190
Modellclaude-sonnet-4-20250514
Statuscompleted
Tokens6,025 (Input: 1,132, Output: 4,893)
Dauer98 ms
Request-Zeit2025-12-22 01:59:54.223280
Response-Zeit2025-12-22 01:59:54.321107

Request

{
    "event": "PreToolUse",
    "tool_name": "Edit",
    "tool_input": {
        "file_path": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
        "old_string": "    \/**\n     * Render chat response HTML\n     *\/\n    private function renderResponse(string $question, array $result, string $model): void\n    {\n        $answer = $result['answer'] ?? '';\n        $sources = $result['sources'] ?? [];\n        $usage = $result['usage'] ?? null;\n        $modelLabel = str_starts_with($model, 'ollama:') ? substr($model, 7) : $model;\n\n        \/\/ Convert markdown-style formatting to HTML\n        $answer = $this->formatAnswer($answer);\n\n        echo '<div class=\"chat-message chat-message--user\">';\n        echo '<div class=\"message-content\">' . htmlspecialchars($question) . '<\/div>';\n        echo '<\/div>';\n\n        echo '<div class=\"chat-message chat-message--assistant\">';\n        echo '<div class=\"message-content\">' . $answer . '<\/div>';\n\n        if (count($sources) > 0) {\n            $sourceCount = count($sources);\n            $uniqueId = uniqid('sources-');\n            echo '<div class=\"chat-sources chat-sources--collapsed\" id=\"' . $uniqueId . '\">';\n            echo '<button type=\"button\" class=\"chat-sources__toggle\" onclick=\"toggleSources(\\'' . $uniqueId . '\\')\">';\n            echo '<span class=\"chat-sources__count\">' . $sourceCount . ' Quelle' . ($sourceCount > 1 ? 'n' : '') . '<\/span>';\n            echo '<span class=\"chat-sources__arrow\">&#9660;<\/span>';\n            echo '<\/button>';\n            echo '<div class=\"chat-sources__list\">';\n            foreach ($sources as $source) {\n                $title = htmlspecialchars($source['title'] ?? 'Unbekannt');\n                $score = round(($source['score'] ?? 0) * 100);\n                $content = isset($source['content']) ? htmlspecialchars(mb_substr($source['content'], 0, 200)) : '';\n                echo '<div class=\"source-item\">';\n                echo '<div class=\"source-item__header\">';\n                echo '<span class=\"source-item__title\">' . $title . '<\/span>';\n                echo '<span class=\"source-item__score\">' . $score . '%<\/span>';\n                echo '<\/div>';\n                if ($content !== '') {\n                    echo '<div class=\"source-item__content\">\"' . $content . (mb_strlen($source['content'] ?? '') > 200 ? '...' : '') . '\"<\/div>';\n                }\n                echo '<\/div>';\n            }\n            echo '<\/div>';\n            echo $this->renderMessageMeta($modelLabel, $usage, $model);\n            echo '<\/div>';\n        } else {\n            echo $this->renderMessageMeta($modelLabel, $usage, $model);\n        }\n\n        echo '<\/div>';\n    }\n\n    \/**\n     * Render message meta (model, tokens, cost)\n     *\/\n    private function renderMessageMeta(string $modelLabel, ?array $usage, string $model): string\n    {\n        $html = '<div class=\"message-meta\">';\n        $html .= '<span class=\"model-info\">Modell: ' . htmlspecialchars($modelLabel) . '<\/span>';\n\n        if (str_starts_with($model, 'claude-') && $usage !== null) {\n            $inputTokens = $usage['input_tokens'] ?? 0;\n            $outputTokens = $usage['output_tokens'] ?? 0;\n            $cost = $this->calculateCost($inputTokens, $outputTokens);\n\n            $html .= '<span class=\"tokens-info\">';\n            $html .= '<span class=\"tokens-input\" title=\"Input-Tokens\">↓' . number_format($inputTokens) . '<\/span> ';\n            $html .= '<span class=\"tokens-output\" title=\"Output-Tokens\">↑' . number_format($outputTokens) . '<\/span>';\n            $html .= '<\/span>';\n            $html .= '<span class=\"cost-info\" title=\"Geschätzte Kosten\">~$' . number_format($cost, 4) . '<\/span>';\n        } elseif (str_starts_with($model, 'ollama:')) {\n            $html .= '<span class=\"tokens-info local\">lokal<\/span>';\n        }\n\n        $html .= '<\/div>';\n\n        return $html;\n    }",
        "new_string": "    \/**\n     * Render chat response HTML using view partial\n     *\/\n    private function renderResponse(string $question, array $result, string $model): void\n    {\n        \/\/ Convert markdown-style formatting to HTML\n        $formattedAnswer = $this->formatAnswer($result['answer'] ?? '');\n\n        $this->view('chat.partials.response', [\n            'question' => $question,\n            'result' => $result,\n            'model' => $model,\n            'formattedAnswer' => $formattedAnswer,\n        ]);\n    }"
    }
}

Response

{
    "tool_response": {
        "filePath": "\/var\/www\/dev.campus.systemische-tools.de\/src\/Controller\/ChatController.php",
        "oldString": "    \/**\n     * Render chat response HTML\n     *\/\n    private function renderResponse(string $question, array $result, string $model): void\n    {\n        $answer = $result['answer'] ?? '';\n        $sources = $result['sources'] ?? [];\n        $usage = $result['usage'] ?? null;\n        $modelLabel = str_starts_with($model, 'ollama:') ? substr($model, 7) : $model;\n\n        \/\/ Convert markdown-style formatting to HTML\n        $answer = $this->formatAnswer($answer);\n\n        echo '<div class=\"chat-message chat-message--user\">';\n        echo '<div class=\"message-content\">' . htmlspecialchars($question) . '<\/div>';\n        echo '<\/div>';\n\n        echo '<div class=\"chat-message chat-message--assistant\">';\n        echo '<div class=\"message-content\">' . $answer . '<\/div>';\n\n        if (count($sources) > 0) {\n            $sourceCount = count($sources);\n            $uniqueId = uniqid('sources-');\n            echo '<div class=\"chat-sources chat-sources--collapsed\" id=\"' . $uniqueId . '\">';\n            echo '<button type=\"button\" class=\"chat-sources__toggle\" onclick=\"toggleSources(\\'' . $uniqueId . '\\')\">';\n            echo '<span class=\"chat-sources__count\">' . $sourceCount . ' Quelle' . ($sourceCount > 1 ? 'n' : '') . '<\/span>';\n            echo '<span class=\"chat-sources__arrow\">&#9660;<\/span>';\n            echo '<\/button>';\n            echo '<div class=\"chat-sources__list\">';\n            foreach ($sources as $source) {\n                $title = htmlspecialchars($source['title'] ?? 'Unbekannt');\n                $score = round(($source['score'] ?? 0) * 100);\n                $content = isset($source['content']) ? htmlspecialchars(mb_substr($source['content'], 0, 200)) : '';\n                echo '<div class=\"source-item\">';\n                echo '<div class=\"source-item__header\">';\n                echo '<span class=\"source-item__title\">' . $title . '<\/span>';\n                echo '<span class=\"source-item__score\">' . $score . '%<\/span>';\n                echo '<\/div>';\n                if ($content !== '') {\n                    echo '<div class=\"source-item__content\">\"' . $content . (mb_strlen($source['content'] ?? '') > 200 ? '...' : '') . '\"<\/div>';\n                }\n                echo '<\/div>';\n            }\n            echo '<\/div>';\n            echo $this->renderMessageMeta($modelLabel, $usage, $model);\n            echo '<\/div>';\n        } else {\n            echo $this->renderMessageMeta($modelLabel, $usage, $model);\n        }\n\n        echo '<\/div>';\n    }\n\n    \/**\n     * Render message meta (model, tokens, cost)\n     *\/\n    private function renderMessageMeta(string $modelLabel, ?array $usage, string $model): string\n    {\n        $html = '<div class=\"message-meta\">';\n        $html .= '<span class=\"model-info\">Modell: ' . htmlspecialchars($modelLabel) . '<\/span>';\n\n        if (str_starts_with($model, 'claude-') && $usage !== null) {\n            $inputTokens = $usage['input_tokens'] ?? 0;\n            $outputTokens = $usage['output_tokens'] ?? 0;\n            $cost = $this->calculateCost($inputTokens, $outputTokens);\n\n            $html .= '<span class=\"tokens-info\">';\n            $html .= '<span class=\"tokens-input\" title=\"Input-Tokens\">↓' . number_format($inputTokens) . '<\/span> ';\n            $html .= '<span class=\"tokens-output\" title=\"Output-Tokens\">↑' . number_format($outputTokens) . '<\/span>';\n            $html .= '<\/span>';\n            $html .= '<span class=\"cost-info\" title=\"Geschätzte Kosten\">~$' . number_format($cost, 4) . '<\/span>';\n        } elseif (str_starts_with($model, 'ollama:')) {\n            $html .= '<span class=\"tokens-info local\">lokal<\/span>';\n        }\n\n        $html .= '<\/div>';\n\n        return $html;\n    }",
        "newString": "    \/**\n     * Render chat response HTML using view partial\n     *\/\n    private function renderResponse(string $question, array $result, string $model): void\n    {\n        \/\/ Convert markdown-style formatting to HTML\n        $formattedAnswer = $this->formatAnswer($result['answer'] ?? '');\n\n        $this->view('chat.partials.response', [\n            'question' => $question,\n            'result' => $result,\n            'model' => $model,\n            'formattedAnswer' => $formattedAnswer,\n        ]);\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\\Validation\\CollectionValidator;\n\nclass ChatController extends Controller\n{\n    private ChatService $chatService;\n    private CollectionRepository $collectionRepository;\n    private CollectionValidator $collectionValidator;\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->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        try {\n            \/\/ Save user message\n            $this->saveMessage($session['id'], 'user', $question, $model);\n\n            \/\/ Auto-set title from first message\n            if ($session['title'] === null) {\n                $title = mb_substr($question, 0, 50) . (mb_strlen($question) > 50 ? '...' : '');\n                $this->updateSessionTitle($session['id'], $title);\n            }\n\n            \/\/ Get style prompt from author profile\n            $stylePrompt = $this->getStylePromptFromProfile($authorProfileId);\n\n            \/\/ Get system prompt from content_config\n            $systemPromptData = $this->getSystemPromptById($systemPromptId);\n            $customSystemPrompt = $this->extractPromptText($systemPromptData);\n\n            \/\/ Track timing\n            $startMicrotime = microtime(true);\n\n            \/\/ Get response from AI\n            $result = $this->askChat(\n                $question,\n                $model,\n                $collections,\n                $contextLimit,\n                $stylePrompt,\n                $customSystemPrompt,\n                $temperature,\n                $maxTokens\n            );\n\n            $endMicrotime = microtime(true);\n\n            if (isset($result['error'])) {\n                $this->view('chat.partials.error', ['error' => $result['error']]);\n\n                return;\n            }\n\n            \/\/ Save assistant message with full tracking\n            $tokensInput = $result['usage']['input_tokens'] ?? null;\n            $tokensOutput = $result['usage']['output_tokens'] ?? null;\n            $sources = $result['sources'] ?? [];\n\n            $this->saveMessage(\n                $session['id'],\n                'assistant',\n                $result['answer'],\n                $model,\n                $tokensInput,\n                $tokensOutput,\n                $sources,\n                $startMicrotime,\n                $endMicrotime,\n                $authorProfileId > 0 ? $authorProfileId : null,\n                $systemPromptId > 0 ? $systemPromptId : null,\n                $collectionsJson,\n                $contextLimit\n            );\n\n            $this->renderResponse($question, $result, $model);\n        } catch (\\Exception $e) {\n            $this->view('chat.partials.error', ['error' => 'Fehler: ' . $e->getMessage()]);\n        }\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-... [TRUNCATED-f5386d48d086b377]",
        "structuredPatch": [
            {
                "oldStart": 789,
                "oldLines": 86,
                "newStart": 789,
                "newLines": 22,
                "lines": [
                    "     }",
                    " ",
                    "     \/**",
                    "-     * Render chat response HTML",
                    "+     * Render chat response HTML using view partial",
                    "      *\/",
                    "     private function renderResponse(string $question, array $result, string $model): void",
                    "     {",
                    "-        $answer = $result['answer'] ?? '';",
                    "-        $sources = $result['sources'] ?? [];",
                    "-        $usage = $result['usage'] ?? null;",
                    "-        $modelLabel = str_starts_with($model, 'ollama:') ? substr($model, 7) : $model;",
                    "-",
                    "         \/\/ Convert markdown-style formatting to HTML",
                    "-        $answer = $this->formatAnswer($answer);",
                    "+        $formattedAnswer = $this->formatAnswer($result['answer'] ?? '');",
                    " ",
                    "-        echo '<div class=\"chat-message chat-message--user\">';",
                    "-        echo '<div class=\"message-content\">' . htmlspecialchars($question) . '<\/div>';",
                    "-        echo '<\/div>';",
                    "-",
                    "-        echo '<div class=\"chat-message chat-message--assistant\">';",
                    "-        echo '<div class=\"message-content\">' . $answer . '<\/div>';",
                    "-",
                    "-        if (count($sources) > 0) {",
                    "-            $sourceCount = count($sources);",
                    "-            $uniqueId = uniqid('sources-');",
                    "-            echo '<div class=\"chat-sources chat-sources--collapsed\" id=\"' . $uniqueId . '\">';",
                    "-            echo '<button type=\"button\" class=\"chat-sources__toggle\" onclick=\"toggleSources(\\'' . $uniqueId . '\\')\">';",
                    "-            echo '<span class=\"chat-sources__count\">' . $sourceCount . ' Quelle' . ($sourceCount > 1 ? 'n' : '') . '<\/span>';",
                    "-            echo '<span class=\"chat-sources__arrow\">&#9660;<\/span>';",
                    "-            echo '<\/button>';",
                    "-            echo '<div class=\"chat-sources__list\">';",
                    "-            foreach ($sources as $source) {",
                    "-                $title = htmlspecialchars($source['title'] ?? 'Unbekannt');",
                    "-                $score = round(($source['score'] ?? 0) * 100);",
                    "-                $content = isset($source['content']) ? htmlspecialchars(mb_substr($source['content'], 0, 200)) : '';",
                    "-                echo '<div class=\"source-item\">';",
                    "-                echo '<div class=\"source-item__header\">';",
                    "-                echo '<span class=\"source-item__title\">' . $title . '<\/span>';",
                    "-                echo '<span class=\"source-item__score\">' . $score . '%<\/span>';",
                    "-                echo '<\/div>';",
                    "-                if ($content !== '') {",
                    "-                    echo '<div class=\"source-item__content\">\"' . $content . (mb_strlen($source['content'] ?? '') > 200 ? '...' : '') . '\"<\/div>';",
                    "-                }",
                    "-                echo '<\/div>';",
                    "-            }",
                    "-            echo '<\/div>';",
                    "-            echo $this->renderMessageMeta($modelLabel, $usage, $model);",
                    "-            echo '<\/div>';",
                    "-        } else {",
                    "-            echo $this->renderMessageMeta($modelLabel, $usage, $model);",
                    "-        }",
                    "-",
                    "-        echo '<\/div>';",
                    "+        $this->view('chat.partials.response', [",
                    "+            'question' => $question,",
                    "+            'result' => $result,",
                    "+            'model' => $model,",
                    "+            'formattedAnswer' => $formattedAnswer,",
                    "+        ]);",
                    "     }",
                    " ",
                    "     \/**",
                    "-     * Render message meta (model, tokens, cost)",
                    "-     *\/",
                    "-    private function renderMessageMeta(string $modelLabel, ?array $usage, string $model): string",
                    "-    {",
                    "-        $html = '<div class=\"message-meta\">';",
                    "-        $html .= '<span class=\"model-info\">Modell: ' . htmlspecialchars($modelLabel) . '<\/span>';",
                    "-",
                    "-        if (str_starts_with($model, 'claude-') && $usage !== null) {",
                    "-            $inputTokens = $usage['input_tokens'] ?? 0;",
                    "-            $outputTokens = $usage['output_tokens'] ?? 0;",
                    "-            $cost = $this->calculateCost($inputTokens, $outputTokens);",
                    "-",
                    "-            $html .= '<span class=\"tokens-info\">';",
                    "-            $html .= '<span class=\"tokens-input\" title=\"Input-Tokens\">↓' . number_format($inputTokens) . '<\/span> ';",
                    "-            $html .= '<span class=\"tokens-output\" title=\"Output-Tokens\">↑' . number_format($outputTokens) . '<\/span>';",
                    "-            $html .= '<\/span>';",
                    "-            $html .= '<span class=\"cost-info\" title=\"Geschätzte Kosten\">~$' . number_format($cost, 4) . '<\/span>';",
                    "-        } elseif (str_starts_with($model, 'ollama:')) {",
                    "-            $html .= '<span class=\"tokens-info local\">lokal<\/span>';",
                    "-        }",
                    "-",
                    "-        $html .= '<\/div>';",
                    "-",
                    "-        return $html;",
                    "-    }",
                    "-",
                    "-    \/**",
                    "      * Calculate cost for Claude API usage",
                    "      * Opus 4.5 Pricing: $15 per 1M input, $75 per 1M output",
                    "      *\/"
                ]
            }
        ],
        "userModified": false,
        "replaceAll": false
    }
}
← Vorheriger Zur Liste Nächster →