Added configuration settings for file uploads, that allow administrators to specify allowed file types and maximum file sizes, enhancing security and control over user uploads. See the environment variables documentation for more details.
Improved accessiblity of the frontend by adding ARIA attributes and improving keyboard navigation, making it easier for users with disabilities to use the application. Thanks to Thomas Orgeldinger for the tremendous help!
Extended supported file formats for attachments: documents (PPTX, XLSX, HTML, Markdown, AsciiDoc, CSV, WebVTT) and additional image formats (SVG, TIFF, PSD, EPS, AI, BMP, ICO) are now handled via an image pre-processing pipeline using rsvg-convert and ImageMagick — auto-detected from $PATH when available. Note: PostScript-based formats (EPS, AI, PS) require ghostscript to be installed alongside ImageMagick. See the optional dependencies documentation for installation instructions.
Added support for the Kreuzberg open-source document extraction API as a new file converter option. Configure via KREUZBERG_FILE_CONVERTER_API_URL in the .env file. No API key is required.
All file access (attachments and avatars) is now securely proxied through the application via a dedicated storage proxy controller, with proper access control enforced for all file types and storage backends. Direct storage URLs are no longer exposed to clients.
Drag-and-drop file upload now provides real-time visual feedback: files are classified as valid or invalid against the server-configured allowed MIME types before the upload begins, and the file picker's accept attribute is automatically populated to match.
We now have an official Contribution guide that provides detailed instructions and guidelines for contributing to the project, including coding standards, testing procedures, and how to submit pull requests. This should make it easier for new contributors to get started and ensure a consistent codebase.
Introduced the External App (ExtApp) system, enabling third-party applications to integrate with HAWKI via an OAuth-like connection flow with cryptographic keypairs. Includes app user management, feature-level access control (e.g. AI in group chats), and a user-facing confirmation page. Manage apps via artisan commands: ext-app:create, ext-app:list, ext-app:remove. See config/external_access.php for feature toggle configuration.
Added the SyncLog system for real-time synchronization of server-side state changes. Supports both incremental and full sync strategies with entity-specific handlers (rooms, messages, users, members, invitations, AI models, etc.). Provides a REST API endpoint and broadcasts events via WebSocket, enabling clients to stay in sync efficiently.
Added User Keychain — a secure per-user storage system for cryptographic key material and configuration data. Supports symmetric, asymmetric, and hybrid crypto value types with dedicated Eloquent casts. Includes REST endpoints for managing keychain values.
Added message threading support. Messages can now belong to threads via thread_id and has_thread columns. Thread parent tracking is handled automatically via event listeners. Existing messages are backfilled via migrations.
Added System Prompt management via SystemPromptRepository. Supports multiple prompt types (DEFAULT, SUMMARY, IMPROVEMENT, NAME) with locale-aware resolution.
Added locale-aware AI model descriptions: administrators can now provide human-readable descriptions for each AI model in multiple languages. Users see descriptions in their preferred locale automatically via the new /api/v1/ai-model-descriptions endpoint.
Added AI model flags: models can now be tagged with status flags (e.g. experimental, deprecated) that carry a label, description, and color code for display in the frontend. Flags are managed server-side and exposed via /api/v1/ai-model-flags.
Introduced the Frontend Migrations system — a structured mechanism for managing schema and data migrations on the client side. Applied migrations are tracked per user in the database, ensuring each migration runs exactly once across deployments. Exposed via /api/v1/migrations.
HAWKI now ships a full JSON:API v1 REST API at /api/hawki/v1. The API covers 20+ resource types — AI infrastructure (providers, models, tools, capabilities, MCP servers, model flags, model descriptions, system models, system prompts), collaborative chat (rooms, messages, members, attachments), user data (profiles, keychain values, frontend migrations), and external app integrations. All resources follow the JSON:API specification with relationship includes, pagination, and attribute-level authorization. A single connection bootstrap endpoint (GET /connections/hawki) provides the entire frontend initialization payload in one request: user identity, locale, WebSocket config, encryption salts, and any pending frontend migrations — eliminating the previous scatter of individual initialization requests.
Introduced the new Svelte-based chat composer UI — a fully rewritten message composition interface built with Svelte 5. It features a unified composer panel combining message input, model selector, tool menu, file attachments, sampling parameter controls, and a system prompt editor. The composer supports four interaction modes: default chat, threaded reply, message edit, and AI response regeneration. Each mode independently manages its own state snapshot, allowing seamless and reversible transitions between contexts.
AI model responses can now render inline citations — sources are displayed as numbered chips in the message text, each linking to a source tile below the message with the favicon, domain, and title of the referenced page. Clicking a citation scrolls and highlights the corresponding tile.
The message renderer now supports LaTeX math (inline $...$ and block ```math ```), Mermaid diagrams (flowcharts, sequence diagrams, state machines, and more), and Monaco-powered syntax-highlighted code blocks, all rendered via worker threads to keep the UI responsive. Messages stream in with a typewriter effect while the AI is generating. External links show a URL preview tooltip with favicon and page title on hover.
Added support for four new AI provider types: Anthropic, AWS Bedrock, Deepseek, and OpenRouter. Administrators can configure any of these via the provider adapter system.
The model picker now shows a real-time demand indicator (three-bar load meter: low / medium / high) and an online/offline status dot per model, giving users a clear picture of model availability and current load before sending a request.
Models can now carry well-known flags visible in the model picker: descriptive tags such as open weights, eco-friendly, self-hosted, multi-modal, and strength indicators (creative writing, code generation, math, reasoning), as well as feature flags (prompt caching, response schema, streaming, sampling parameters, and reasoning level). This helps users choose the right model for their task at a glance.
Introduced the Announcements system — administrators can post announcements that appear in the application UI. Announcements support flexible targeting (all users or a specific list), scheduled display windows (start and expiry dates), and a forced-display mode for critical notices. Whether a user has seen or accepted each announcement is tracked individually.
Added an "Improve Message" feature: a Sparkles button in the composer sends the current draft to the AI for suggestions before sending, letting users refine their message without starting a new conversation.
Chats can now be exported in four formats: PDF, Word (DOCX), CSV, and JSON. The export menu is accessible from the chat header.
AI Model errors will now be logged to the log file in addition to being printed to the screen, making it easier to debug issues in production.
The VITE_REVERB_* environment variables have been removed, as they are no longer used in the frontend. This simplifies the configuration and reduces potential confusion for users. The information about the connection will now be negotiated automatically.
Attachment file icons are now dynamically generated SVGs with per-extension colors, replacing the previous static PNG icons for PDF and DOCX. Any file type now shows a proper labeled icon.
Cryptographic salts are now delivered via the frontend connection payload instead of individual network requests, reducing initial page load latency.
The frontend translation system has been rewritten. Translations are now available via a unified __() helper function, consistent with Laravel's backend translation API.
HAWKI's locale and settings panel are now also available on the login and gateway pages, enabling translated UI before a user is authenticated.
Development workflow improvements: new phpunit, phpstan, prettier, and php-cs-fixer tools are now integrated to make testing and code formatting easier. Run bin/env test all for tests and static analysis, or bin/env style php / bin/env style js for code formatting.
CSRF tokens are now automatically included in response headers (X-HAWKI-CSRF-TOKEN), allowing frontend applications to retrieve tokens without additional requests.
API responses now include sync log entries in a _hawki_sync_log field automatically, enabling reactive frontends to process state changes immediately without waiting for WebSocket messages.
AI model metadata (capabilities, pricing tiers, context limits, documentation links) is now automatically enriched from the LiteLLM API catalog on a 24-hour cache cycle, with a bundled static data store as a reliable fallback when the API is unavailable. Model information stays accurate without manual maintenance.
Added health check infrastructure: quick checks (database connectivity) and deep checks (database, cache, Redis, storage) are now available for load balancer probes and monitoring integrations.
New artisan commands for administrators and operators: php artisan ai:check-status updates online/offline status for all models and MCP servers in one pass; php artisan ai:models:list lists all configured models; php artisan filestorage:converter:types:list prints the MIME types and extensions your active file converter accepts — useful for diagnosing upload rejections.
The sampling parameter panel now includes three quick presets — Creative, Balanced, and Precise — that set temperature and top_p in one click, with per-model defaults preserved when switching models.
The composer textarea auto-sizes as you type, expanding up to 250 px before scrolling, so short messages don't feel lost in a large input box.
bin/env dev now no longer dies after 300 seconds, allowing for longer-running development sessions without interruption.
The last selected AI model is now automatically re-selected when the model list reloads, preserving the user's choice across page refreshes and model list updates.
Fixed stream chunk processing to correctly handle partial data from AI providers, preventing garbled or truncated responses.
php artisan ai:tools:mcp:add now uses the correct api key to fetch server information, removing the hardcoded api key for the HAWKI dev environment. Thanks to Raphael Fetzer for pointing out this issue!
The external API endpoint to HAWKI no longer throws an error if the stream parameter is missing, improving the robustness of the API and allowing for more flexible usage. Thanks to willirath for pointing this out and providing a fix.
Fixed a typo in the session expiry message: "Your accound has been suspended." → "Your account has been suspended."
Fixed a fatal error in the PreventBackHistory middleware when processing streaming responses that do not support HTTP headers.
Removed the /req/crypto/getServerSalt server endpoint, which inadvertently exposed server-side environment variables. Cryptographic salts are now embedded in the frontend connection payload and never returned via a dedicated HTTP request.
Refactoring of the "file converter" logic, improving the handling of file conversions and reducing potential errors. Also implemented a lot of logging in this area to make it easier to debug issues related to file conversions.
Refactoring and code cleanup of the tool calling logic, improving readability and maintainability. The ToolCallingClient now properly validates that incoming requests contain a model; requests without a model are logged with a warning and passed through to the underlying client without tool calling support.
Inherited a lot of code from the external-chat branch, as preparation for V3 merge and to avoid merge conflicts later on. This also allows us to use the new "connection" logic to pass backend information to the frontend.
It is now possible to implement "custom file converters" using the "file_converter.converters" array in the configuration. This allows for more flexibility and extensibility in handling file conversions, as users can now easily add their own custom converters without modifying the core codebase. A new "class" property has been added to the converter configuration, which specifies the class that should be used for the converter. This class must implement the FileConverterInterface and can be autoloaded using Composer's PSR-4 autoloading.
The FileConverterFactory has been removed, to retrieve the converter simply ask for the FileConverterInterface, which will always provide you the currently configured converter. To determine if the converter is active (e.g. configured or not) check the isAvailable() method on the converter instance.
Complete overhaul of the storage layer with a new value-object-driven architecture. Key new types: StoredFile, FileReference, StoredFileIdentifier, StoredFileCategory, FileCollection, FileType, PlainTextLanguageType. All storage service method signatures have changed — any custom code calling FileStorageService or AvatarStorageService directly must be updated.
Every stored file now has a .meta.json sidecar written alongside it, capturing original filename, MIME type, extracted content references, and creation timestamp. Files without a sidecar (pre-existing uploads) have their metadata generated retroactively on first access.
Attachment formatting for AI providers has been extracted into dedicated per-provider classes (GoogleAttachmentFormatter, GwdgAttachmentFormatter, OllamaAttachmentFormatter, OpenAiAttachmentFormatter), replacing duplicated inline logic in each request converter.
The AttachmentService and AttachmentFactory have been replaced by a leaner AttachmentRepository service. Stored file cleanup on attachment deletion is now handled automatically via the new AttachmentDeleting model event and a dedicated event listener.
The MessageHandlerFactory has been removed. Message handlers (PrivateMessageHandler, GroupMessageHandler) are now resolved via Laravel's service container.
Six new JsonResource classes under Http/Resources/Legacy/ standardize JSON serialization for existing API endpoints, replacing manual inline array construction scattered across models and services.
A new TranslationServiceProvider overrides Laravel's built-in translation loader to merge HAWKI's own JSON language files on top of any Laravel fallback translations. Translation labels are now embedded in the frontend connection payload.
Added RecursiveMerger utility (app/Utils/Arrays/) with configurable deep merge behaviour, including support for unsetting keys. Exposed as Arr::mergeRecursive() macro.
AiErrorResponse now captures a stack trace at construction time and exposes it in toArray() when app.debug is enabled, making AI provider errors significantly easier to trace during development.
Event listeners in app/Services/*/Listeners are now auto-discovered via a glob registered in bootstrap/app.php.
ext-fileinfo is now declared as a required PHP extension in composer.json.
Introduced AbstractCastableObject (App\Utils\Casts) — a foundational reflection-based utility for hydrating and serializing typed PHP objects from/to string arrays. Supports built-in type casting (int, float, bool, string, array), enums, dates, encrypted values, and custom casters via #[CastedValue] annotations. Serves as the base for the upcoming database-backed configuration layer (AbstractConfig).
Added phpstan for static analysis which should help catch potential bugs and improve code quality. Run composer run stan to execute the static analysis checks. Currently NOT in the pipeline, because there are still some issues to fix, but we will get there eventually.
Refactored the AiModel data layer to use structured value objects (ModelCapabilities, ModelIoMethods, ModelParameters, ModelSettings, OnlineStatus, ModelDemand), replacing flat array structures. Model attributes input, output, parameters, status, demand, capabilities, and settings are now cast to typed PHP objects.
AI tools and MCP servers are now database-backed Eloquent models (AiTool, AiToolCapability, McpServer) with full JSON:API endpoints and authorization policies, replacing the previous static configuration approach. Use php artisan ai:tools:sync to populate from config.
Refactored the frontend bootstrap into a six-stage pipeline (preparation → migration → early → main → late → finalization). Each stage supports pre/post hooks; within a stage, up to five tasks run concurrently via ParallelAsyncWorkflow. The connection resource is fetched once at the preparation stage and shared as the authoritative source for locale, user info, and pending migrations for all subsequent stages.
Added php artisan dev:ai:update-lite-llm-static-data command to refresh static LiteLLM model provider data from the upstream API. Available in local environments only.
Achieved 100% test coverage for App\Utils module with comprehensive PHPUnit tests for utility classes like Assert, Arrays, and Casts helpers.
The model config files of config/model_providers.php and config/model_lists are now automatically copied to _docker_production when a new release branch is created.
The jquery library has been removed from the frontend dependencies, as it is not used in the codebase. This reduces the overall bundle size and improves performance.
Update of all major frontend dependencies.
Add prettier and php-cs-fixer configurations to enforce consistent code formatting across the codebase. Run bin/env style php or bin/env style js to automatically format the code according to the defined standards.
Added phpunit and phpstan to run tests and static analysis of the main application. Run bin/env test unit to execute the unit tests and bin/env test stan to run static analysis. Run all tests and checks with bin/env test all.
Comprehensive domain event system with abstract base classes for all major entities (AbstractRoomEvent, AbstractMessageEvent, AbstractUserEvent, AbstractMemberEvent, AbstractInvitationEvent, AbstractExtAppEvent, etc.). Events are dispatched automatically on model lifecycle changes and power the SyncLog broadcasting.
Added ApiRequestMigrator for version-based API request format translation (v2 to legacy), supporting field mapping and ID conversion for backwards compatibility.
Added Eloquent casts for cryptographic types: AsAsymmetricPublicKeyCast, AsHybridCryptoValueCast, AsSymmetricCryptoValueCast — enabling transparent encryption/decryption of model attributes.
Added AiModelIdMap model and ModelIdMapDb service for database-backed mapping between internal numeric IDs and external AI model identifiers.
Added CastableObjectCaster to AbstractCastableObject, enabling nested castable objects as typed properties.
Storage value objects have been moved from Value/ to Values/ namespace (App\Services\Storage\Values).
The ExternalCommunicationCheck middleware has been replaced by the new ExternalAccessMiddleware and AppAccessMiddleware with fine-grained feature flag control.
New Svelte component library with 20+ accessible UI primitives, all styled with scoped CSS and bits-ui (no Tailwind): Badge, BorderBeam, Button, ButtonWithTooltip, Citation/CitationList/CitationRoot, ConfirmDialog/Dialog/InfoDialog, DropdownMenu (with checkbox, radio, switch, detail view variants), InfoPopover/Popover, RadialProgress, RadioCard/RadioCardGroup, SingleSelect, Separator, BottomSheet, Slider, StatusDot, Switch, Tabs, Textarea, Toaster, Tooltip/UrlPreviewTooltip, and Txt.
Introduced a CSS cascade layers architecture: styles are ordered strictly as reset → tokens → base → components → utilities. A custom Svelte preprocessor (ComponentCssLayerProcessor) automatically wraps all component <style> blocks in @layer components {}, preventing specificity conflicts without any manual intervention in component code.
Icon system migrated from custom icons to Hugeicons (@hugeicons/core-free-icons). A custom Vite plugin generates Svelte icon components from the library at build time, with version-based caching to avoid unnecessary rebuilds.
Composer state is split into composable "aspect" classes (ModelAspect, ToolAspect, AttachmentAspect, ModelParameterAspect, ModelUsageAspect, GuardAspect) — each independently manages a self-contained slice of state using Svelte 5 reactivity. Derived aspects are purely computed from others and carry no mutable state of their own.
Added a composer mode system (ChatDefaultMode, ChatEditMode, ChatInThreadMode, ChatRegenMode). Mode transitions use a ContextCheckpointer to snapshot and restore all aspect state, making every transition fully reversible without each mode managing its own copies of shared data.
Added OldUiBridge — a Svelte-to-legacy compatibility layer that forwards message sends, passkey UI, and message history interactions from the new Svelte composer to the existing Blade/JS UI. This enables incremental migration to the new frontend without a big-bang replacement.
Added a Svelte snippet loader (<svelte-snippet> custom HTML element): Blade templates can mount Vite-chunked Svelte components by name without any manual JS glue. The element resolves the component from a registry, hydrates it with props passed via data attributes, and destroys it on disconnect — enabling Svelte islands inside server-rendered pages.
The frontend data layer is built around a typed JSON:API client backed by Zod schemas. getResourceCollectionFromApi() and getResourceFromApi() deserialize JSON:API envelopes, validate against declared schemas, and return flat typed objects. A resource schema registry using TypeScript declaration merging lets any file contribute its schema and have it automatically inferred at call sites without central registration.
End-to-end encryption uses a three-tier cryptographic system: symmetric (AES-256-GCM with random 12-byte IVs) for bulk data and room messages; asymmetric (RSA-OAEP-4096) for encrypting and distributing symmetric keys per recipient; and hybrid (random AES key + asymmetric wrapping) for large data that only the server should decrypt. All keys are stored encrypted at rest in the User Keychain, protected by a passkey-derived key.
Existing passkey keys stored in the legacy JWK format are automatically migrated to the new base64 format on first login via a frontend migration. The migration is non-destructive — the old room key format is preserved until all room keys are re-wrapped in the new structure.
New pluggable provider adapter system (ProviderAdapterRegistry) with first-party adapters for: Anthropic, AWS Bedrock, Azure OpenAI, Cohere, Deepseek, Gemini, GWDG, Mistral, Ollama, OpenAI, OpenAI-compatible, and OpenRouter. Custom adapters can be registered by implementing ProviderAdapterInterface.
Added the model information enrichment pipeline (AiModelInfoEnrichmentPipeline) — an ordered chain of injectable enrichers that populate AiModel records with capabilities, limits, flags, pricing, and documentation URLs. Includes a LiteLLM API enricher, a static GWDG enricher, and a documentation URL enricher. 100+ provider data files are bundled in resources/static_llm_data/lite_llm/ as a static fallback.
Added well-known registries for model capabilities, flags, limits, and pricing — each extensible via PHP registries. Predefined constants in WellKnownCapabilities (web search, web fetch, code execution, knowledge base, tool calling) and WellKnownModelFlags (20+ flags covering model character, strengths, and supported features) ship out of the box.
Introduced the contextual scopes system (HasContextualScopesTrait): Eloquent models can now register conditional global scopes that activate based on request context. Built-in scopes include LocaleAwareScope, UsageTypeFilterScope, ActiveFilterScope, BelongsToUserScope, and ActiveFilterOnRelationScope.
Added UsageContext singleton tracking whether the current request originates from the main application or an external integration — used to filter model availability and evaluate feature flags. UserContext tracks user state across the request lifecycle (guest, registered, registering, external app user).
Added ConfigFileSyncer — orchestrates all registered config syncers with built-in change detection, only re-running a syncer when its source data has actually changed. Powers the php artisan ai:config:sync artisan command (--force flag available to bypass change detection).
Introduced ChatAgent — a structured agent abstraction over the AI service layer. Replaces ad-hoc controller logic for AI conversations with a clean request/response lifecycle supporting context, instructions, message history, and tool resolution.
Three custom LaravelAI driver extensions ship with this release. GeminiExtended adds configuration hoisting (fixing nested generationConfig/safetySettings extraction) and citation streaming. OpenAiCompatibleGateway bridges GWDG and similar OpenAI-compatible endpoints pending upstream support in the Laravel AI library. Both drivers emit Citation events during streaming so the frontend can inject inline source chips as the response arrives.
Added AnnouncementService and Announcement model backing the new announcements feature. Supports global and targeted delivery, scheduling windows, forced-display mode, and per-user seen/accepted tracking.
Added asset cache busting via AssetCacheBustingUrlGenerator: non-Vite assets get a content-hash query parameter appended automatically. Vite build outputs are exempted because their filenames are already content-hashed, which would break ES module URL matching.
The bin/_env system has been refactored into an addon-based architecture: project-specific commands (artisan, queue, websocket, dev, setup-models, clear-cache) live in project.addon.ts and are executed inside Docker containers. Test infrastructure lives in test.addon.ts. This makes it straightforward to add new CLI commands without touching core env logic.
Added three new config files for administrators and contributors: config/external_access.php controls which external API features are enabled (ALLOW_EXTERNAL_COMMUNICATION, ALLOW_USER_TOKEN_CREATION, ALLOW_EXTERNAL_APPS, ALLOW_EXTERNAL_APPS_GROUPS_AI); config/tools.php registers function-calling tools and MCP servers; config/encryption.php centralizes the five application-level encryption salts (USERDATA, INVITATION, AI_CRYPTO, PASSKEY, BACKUP) with auto-generation fallback via SaltProvider.
Docker production deployments now require five pre-configured encryption salts in _docker_production/.env (APP_ENCRYPTION_SALT_*). These replace the previous approach of deriving salts at runtime and must be set before the first migration run. See the upgrade guide for details.
Added make:frontend-migration artisan command for contributors: generates a paired PHP backend migration and TypeScript client migration with a selectable run-type (after_login, after_passkey, or a custom value), pre-wired to the frontend migration system.
PHP upgraded to 8.3 (minimum requirement raised from 8.2) and Laravel upgraded to 13 (from 12). The composer.json now also explicitly declares all required PHP extensions: curl, dom, fileinfo, libxml, openssl, zip, and gd.
Major new PHP packages: laravel-json-api/laravel (^5.2, powers the JSON:API layer), laravel/ai (Laravel's first-party AI abstraction), logiscape/mcp-sdk-php (^1.7, MCP protocol client), opis/json-schema (^2.6, tool input schema validation), phpseclib (^3.0, cryptographic operations).
The Docker base image moves to neunerlei/php-nginx:8.3 and the Dockerfile now installs ghostscript, imagemagick, and librsvg2-bin as system packages, so all file pre-processing features work in Docker without any additional steps.
WebSocket broadcast channels restructured: a private User.{id} channel per user and a semi-public AllUsers channel replace the previous approach. Client-side channel subscriptions are negotiated via the connection payload.
Added AgentRegistry with WellKnownAgents constants — a central registry for named agent types. ChatAgent is the first registered agent; new agent types can be added by registering them with AgentRegistry::register().
Added AlternatingMessageHistory — enforces the user/assistant alternating message pattern required by most LLM APIs, merging consecutive same-role messages automatically so malformed histories never reach the provider.
Tool input and output schemas are now validated with JsonSchemaValidator (backed by opis/json-schema) before tool calls are dispatched, catching schema violations before they reach the provider.
FunctionToolSyncer discovers PHP function tools via the #[Tag(ToolInterface::class)] attribute and syncs them to the database automatically, removing the need for manual tool registration.
SyncActionDetector adds hash-based change detection to ConfigFileSyncer: each syncer records a hash of its source data after running, and is skipped on subsequent calls unless the data has changed.
Added BeforeCallingMcpToolFilterEvent — a filterable event dispatched before any MCP tool call. Listeners can short-circuit the call and inject a synthetic result, which is essential for integration tests that need to mock external MCP servers.
ApiDataScopeContextSettingMiddleware lets API clients opt out of specific contextual scopes per request via the ?no_scope[resource]=* query parameter, providing escape hatches for admin queries that need unfiltered data.
The AiService facade has been expanded with: getAgent(name), tryToGetAgent(name), getMcpClient(server), getSystemPrompts(), getSystemModels() — making it the single entry point for all AI-related service resolution.
Background queue workers now run with --timeout=0 (no per-job timeout), preventing long-running AI streaming jobs from being killed mid-response.
The Clock service has been renamed to CarbonClock and a new CarbonClockInterface (extending Psr\Clock\ClockInterface) has been introduced. The interface guarantees CarbonImmutable as the return type of now(), improving type safety across all time-dependent services. Both ClockInterface and CarbonClockInterface resolve to the same singleton in the service container. All internal services (caching, crypto, URL signing, file converters, frontend migrations) now use constructor injection of this clock, making time-dependent logic fully testable.
LanguageController::getTranslation() and getAvailableLanguages() are deprecated and will be removed in a future version. Use LocaleService and the frontend connection payload instead.
The /req/profile/validatePasskey and /api/link-preview routes are deprecated. Replacements are available via the JSON:API v1 endpoints.
OpenAI requests that still run against the "/chats/completions" endpoint now trigger a warning log, to help understand why the requests are failing.