requireAdminHtml(); $message = ''; $error = ''; $base64ChunkConfig = load_base64_chunk_config(); $localTimezone = new DateTimeZone('Europe/Amsterdam'); function h($s) { return htmlspecialchars((string)$s, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } function t($key, $fallback = null) { global $languageStore, $language; return $languageStore->translate($key, $language, $fallback); } function post_value($name, $default = '') { return $_POST[$name] ?? $default; } function resolve_user_language($userSettings, $userId, $allowedLanguages) { $language = isset($_GET['lang']) ? (string)$_GET['lang'] : (string)$userSettings->get($userId, 'language', 'en'); if (!in_array($language, $allowedLanguages, true)) { $language = 'en'; } $userSettings->set($userId, 'language', $language); return $language; } function base64_binary_chunk_bytes_for_kib($kib) { return racket_zip_binary_chunk_bytes_for_base64_kib($kib); } function format_token_time($timestamp) { global $localTimezone; $time = (new DateTimeImmutable('@' . (int)$timestamp))->setTimezone($localTimezone); return $time->format('Y-m-d H:i:s T'); } function token_status_class($token) { return time() <= (int)($token['expires_at'] ?? 0) ? 'token-valid' : 'token-expired'; } $language = resolve_user_language( $userSettings, $currentUser->id(), $languageStore->supportedLanguages() ); $languageStore->seedDefaults(array( 'app.title' => array('en' => 'Racket sandbox', 'nl' => 'Racket sandbox'), 'app.manage_prompts' => array('en' => 'Manage prompts', 'nl' => 'Prompts beheren'), 'app.user_management' => array('en' => 'User management', 'nl' => 'Gebruikersbeheer'), 'app.configuration' => array('en' => 'Configuration', 'nl' => 'Configuratie'), 'app.logout' => array('en' => 'Logout', 'nl' => 'Uitloggen'), 'app.language' => array('en' => 'Language', 'nl' => 'Taal'), 'app.logged_in_as' => array('en' => 'Logged in as:', 'nl' => 'Ingelogd als:'), 'app.admin' => array('en' => 'Admin', 'nl' => 'Admin'), 'app.back_to_sandbox' => array('en' => 'Back to Racket sandbox', 'nl' => 'Terug naar Racket sandbox'), 'app.download_settings' => array('en' => 'Download settings', 'nl' => 'Downloadinstellingen'), 'app.maintenance' => array('en' => 'Maintenance', 'nl' => 'Onderhoud'), 'app.next_tokens' => array('en' => 'Next tokens', 'nl' => 'Next-tokens'), 'app.current_next_tokens' => array('en' => 'Next tokens', 'nl' => 'Next-tokens'), 'app.token' => array('en' => 'Token', 'nl' => 'Token'), 'app.created_at' => array('en' => 'Created at', 'nl' => 'Aangemaakt op'), 'app.expires_at' => array('en' => 'Expires at', 'nl' => 'Verloopt op'), 'app.no_current_next_tokens' => array('en' => 'No next tokens.', 'nl' => 'Geen next-tokens.'), 'app.remove_expired_tokens' => array('en' => 'Remove expired next tokens', 'nl' => 'Verlopen next-tokens verwijderen'), 'app.racket_zip_chunk_kb' => array('en' => 'Racket installation max base64 chunk size (KiB)', 'nl' => 'Maximale base64-chunkgrootte Racket-installatie (KiB)'), 'app.package_zip_chunk_kb' => array('en' => 'Package/module max base64 chunk size (KiB)', 'nl' => 'Maximale base64-chunkgrootte packages/modules (KiB)'), 'app.save_configuration' => array('en' => 'Save configuration', 'nl' => 'Configuratie opslaan'), 'app.configuration_saved' => array('en' => 'Configuration saved.', 'nl' => 'Configuratie opgeslagen.'), 'app.racket_parts_regenerated' => array('en' => 'Racket installation parts regenerated:', 'nl' => 'Racket-installatie parts opnieuw gemaakt:'), 'app.chunk_size_hint_v2' => array( 'en' => 'Values are maximum base64 payload sizes in KiB. A 6144 KiB binary chunk becomes 8192 KiB base64. Racket installation parts are regenerated when this configuration is saved.', 'nl' => 'Waarden zijn maximale base64-payloadgroottes in KiB. Een binaire chunk van 6144 KiB wordt 8192 KiB base64. Racket-installatie parts worden opnieuw gemaakt wanneer deze configuratie wordt opgeslagen.', ), 'app.effective_binary_chunk' => array('en' => 'Effective binary chunk', 'nl' => 'Effectieve binaire chunk'), 'app.racket_zip_source' => array('en' => 'Racket installation source', 'nl' => 'Bronbestand Racket-installatie'), 'app.racket_parts' => array('en' => 'Racket installation parts', 'nl' => 'Racket-installatie parts'), 'app.racket_parts_current' => array('en' => 'current', 'nl' => 'actueel'), 'app.racket_parts_missing' => array('en' => 'missing or outdated; save configuration to regenerate', 'nl' => 'ontbreken of verouderd; sla configuratie op om opnieuw te maken'), 'app.expired_tokens_removed' => array('en' => 'Expired next tokens removed:', 'nl' => 'Verlopen next-tokens verwijderd:'), 'app.cleanup_help' => array( 'en' => 'Expired links should return an outdated information message to the AI agent. Cleanup only removes old token rows from SQLite.', 'nl' => 'Verlopen links moeten een melding over verouderde informatie aan de AI-agent teruggeven. Opruimen verwijdert alleen oude tokenrijen uit SQLite.' ), )); if ($_SERVER['REQUEST_METHOD'] === 'POST') { $action = post_value('action'); try { if ($action === 'logout') { $auth->logout(); header('Location: /login.php'); exit; } elseif ($action === 'update_config') { save_base64_chunk_config(array( 'racket_zip_max_base64_kb' => post_value('racket_zip_max_base64_kb'), 'package_zip_max_base64_kb' => post_value('package_zip_max_base64_kb'), )); $base64ChunkConfig = load_base64_chunk_config(); $manifest = split_racket_zip_parts($base64ChunkConfig['racket_zip_max_base64_kb']); $message = t('app.configuration_saved', 'Configuration saved.') . ' ' . t('app.racket_parts_regenerated', 'Racket installation parts regenerated:') . ' ' . (int)$manifest['part_count']; } elseif ($action === 'cleanup_tokens') { $deleted = $tokens->cleanup(); $message = t('app.expired_tokens_removed', 'Expired next tokens removed:') . ' ' . $deleted; } } catch (Throwable $e) { $error = $e->getMessage(); } } $racketPartsManifest = null; $racketPartsCurrent = false; try { $racketPartsManifest = load_racket_zip_parts_manifest(); $racketPartsCurrent = racket_zip_parts_current( $racketPartsManifest, $base64ChunkConfig['racket_zip_max_base64_kb'] ); } catch (Throwable $e) { $racketPartsManifest = null; $racketPartsCurrent = false; } if (!$racketPartsCurrent && is_file(RACKET_ZIP_FILE) && is_readable(RACKET_ZIP_FILE)) { try { $racketPartsManifest = split_racket_zip_parts($base64ChunkConfig['racket_zip_max_base64_kb']); $racketPartsCurrent = true; if ($message === '') { $message = t('app.racket_parts_regenerated', 'Racket installation parts regenerated:') . ' ' . (int)$racketPartsManifest['part_count']; } } catch (Throwable $e) { if ($error === '') { $error = $e->getMessage(); } } } $headerLanguages = array(); $currentNextTokens = array(); try { $currentNextTokens = $tokens->tokens(); } catch (Throwable $e) { if ($error === '') { $error = $e->getMessage(); } } foreach ($languageStore->supportedLanguages() as $lang) { $headerLanguages[$lang] = $languageStore->languageLabel($lang); } $styleVersion = @filemtime(__DIR__ . '/styles.css') ?: time(); header('Content-Type: text/html; charset=utf-8'); ?> <?= h(t('app.configuration', 'Configuration')) ?>
t('app.configuration', 'Configuration'), 'nav_items' => array( array('label' => t('app.back_to_sandbox', 'Back to Racket sandbox'), 'url' => '/?lang=' . rawurlencode($language)), array( 'label' => t('app.manage_prompts', 'Manage prompts'), 'url' => '/prompts?lang=' . rawurlencode($language), 'separator_before' => true, ), array( 'label' => t('app.user_management', 'User management'), 'url' => '/users?lang=' . rawurlencode($language), 'separator_before' => true, ), array( 'label' => t('app.configuration', 'Configuration'), 'url' => '/admin-config?lang=' . rawurlencode($language), 'active' => true, 'separator_before' => true, ), ), 'user' => $currentUser, 'user_prefix' => t('app.logged_in_as', 'Logged in as:'), 'admin_label' => t('app.admin', 'Admin'), 'language_label' => t('app.language', 'Language'), 'language' => $language, 'languages' => $headerLanguages, 'language_action' => '/admin-config', 'logout_action' => '/admin-config?lang=' . rawurlencode($language), 'logout_label' => t('app.logout', 'Logout'), 'message' => $message, 'error' => $error, )); ?>

KiB : bytes
KiB : bytes
config/racket.zip bytes
,

0): ?>