Simple Chat

Release notes 0.261.045 – 0.261.002

Back to release notes index

(v0.261.045)

Bug Fixes

  • Public Workspace Selector Dark Theme Styling
    • Fixed the public workspace selector dropdown so its dark-theme background, border, search area, hover state, and active item styling match the group workspace selector.
    • Added the shared workspace selector row class to the public selector row and extended the existing group dropdown dark-theme rules to the public dropdown.
    • (Ref: public workspace selector, dark theme dropdown styling, public_workspaces.html, styles.css)
  • Revert Premature OneNote Rollout From Development
    • Removed native .one and .onepkg workspace uploads from Development pending Reactv2 testing, correcting the accidental merge of PR #1525.
    • Restored the previous upload formats and container packaging. Existing document formats and the separately adapted Reactv2 OneNote implementation remain unchanged.
    • (Ref: config.py, functions_documents.py, Dockerfile, OneNote Development Rollout Revert)

(v0.261.044)

New Features

  • Admin Defaults For New Chat Model And Reasoning Effort
    • Added Admin Settings controls that let administrators opt in to a default model and default reasoning effort for new non-agent chats.
    • The setting is off by default, preserving each user’s existing last-selected model and per-model reasoning preferences until an admin enables the override.
    • New-chat defaults use the existing multi-endpoint model selector and continue to leave agent model bindings and existing conversation model history intact.
    • (Ref: enable_default_model_for_new_conversations, default_reasoning_effort, Model Endpoints admin settings, chat model selector)

Bug Fixes

  • New Chat Defaults No Longer Leak Across Conversations
    • Fixed new-chat admin model defaults being overwritten by a user’s saved model when a freshly created blank conversation was opened through /chats?conversationId=..., including the left-navigation New Chat flow.
    • Existing conversations now restore their own last-used model from saved message metadata, while blank conversations with no model history apply the admin default model and reasoning effort.
    • Programmatic model selector refreshes no longer save the admin default as the user’s preferred model or prematurely disable the admin default reasoning state.
    • (Ref: chat-conversations.js, chat-model-selector.js, chat-messages.js, chat-reasoning.js)
  • Shared Conversation Prompts Persist After Invite Approval
    • Accepting an invitation now loads the conversation with the authoritative collaborative metadata returned by the approval request, preventing the initial creator prompt from disappearing while the response remains visible.
    • (Ref: chat-collaboration.js, chat-conversations.js)
  • Shared Conversation Delivery Remains Reliable Across Workers
    • Shared event sessions now use a cross-worker Cosmos fallback when Redis is unavailable, preserve Redis event logs during worker attachment, and retry concurrent Cosmos event writes.
    • History supplies an EventSource cursor, so retained events do not replay after history loads and invitees retain the owner’s existing prompts.
    • Accepting an invite while already viewing the conversation now updates membership and composer state in place instead of clearing the rendered history.
    • (Ref: app_settings_cache.py, route_backend_collaboration.py, chat-collaboration.js)
  • Microsoft 365 Enhancements Do Not Interrupt Shared Chat
    • Optional Microsoft 365 action-card projection failures no longer terminate collaboration events.
    • Background action recovery remains silent for ordinary shared conversations, while saved actions retain explicit recovery controls.
    • (Ref: route_backend_collaboration.py, chat-streaming.js, m365-pending-actions.js)

(v0.261.043)

Bug Fixes

  • Add Participants Remains Available Before Sharing
    • Ordinary personal conversations no longer lose the Add participants action when a metadata response omits collaboration-only permission fields.
    • (Ref: chat-conversations.js, chat-sidebar-conversations.js)

(v0.261.042)

Bug Fixes

  • Add Participants Appears After the First Shared Exchange
    • Collaboration metadata updates now refresh the conversation menus after prompt/response completion, so the Add participants action appears without a page refresh.
    • (Ref: chat-collaboration.js, chat-conversations.js, chat-sidebar-conversations.js)

(v0.261.041)

Bug Fixes

  • Shared Conversation State No Longer Leaks Into New Conversations
    • Starting a new conversation now disconnects the previous shared conversation’s event stream and clears its typing state, preventing participant activity and messages from appearing in the new conversation.
    • Conversation metadata updates now refresh the Add participants action immediately, without requiring a page refresh after sharing a conversation.
    • (Ref: chat-conversations.js, chat-collaboration.js, chat-sidebar-conversations.js, Collaboration Shared AI Workflow Fix)

(v0.261.040)

Bug Fixes

  • Collaborative Prompts Now Receive Model Responses
    • Fixed ordinary prompts in conversations shared through Invite Participants being saved as human-only messages without invoking the model.
    • All non-empty collaborative prompts now use the shared AI streaming workflow, while preserving explicit agent, model, workspace, and tool targeting.
    • (Ref: chat-messages.js, chat-collaboration.js, Collaboration Shared AI Workflow Fix)

(v0.261.030)

Bug Fixes

  • Cross-Cloud Account Selection for Access-Denied Users
    • Added a Sign in with another account action for authenticated users whose selected Microsoft Entra identity does not have the required SimpleChat app role.
    • The alternate flow requests the Entra account picker only through the controlled /login?select_account=1 path; ordinary sign-in remains prompt-free, and arbitrary OAuth prompt values are ignored.
    • The access-denied state now identifies the current account using safe session claims while suppressing resource-tenant #EXT# UPNs, helping users distinguish native Azure Government and synchronized commercial identities.
    • Improved the action’s light- and dark-theme contrast without changing tenant authority, app-role authorization, Easy Auth configuration, or login-hint behavior.
    • (Ref: route_frontend_authentication.py, functions_authentication.py, access-denied landing page, cross-cloud Microsoft Entra B2B sign-in)
  • ANSI-Encoded CSV Files Are Now Read Correctly
    • CSV metadata extraction, indexing, citations, row searches, and durable tabular replay now support UTF-8, UTF-8 with BOM, Windows-1252, and Latin-1 files, preserving characters that previously made uploaded content appear unreadable.
    • Tabular analysis retains the broader automatic-invocation budget for complex questions while detecting repeated equivalent failures and routing the next model pass to a different call shape instead of repeating the same error.
    • Repeated tabular tool failures now emit an explicit retry lifecycle thought and server-side diagnostic event, making the failure visible while recovery continues.
    • (Ref: functions_tabular_csv_query.py, functions_documents.py, tabular_processing_plugin.py, route_backend_chats.py, Tabular CSV ANSI Encoding and Retry Fix)
  • Group Chat Uploads Now Recognize Workspace Owners
    • Fixed group-scoped chat uploads incorrectly reporting that no group workspace was available when the signed-in user was the group owner.
    • Chat bootstrap data now includes each group’s resolved user role, allowing owners, admins, and document managers to use the existing group upload permissions while preserving server-side authorization checks.
    • (Ref: route_frontend_chats.py, chat-input-actions.js, Chat Group Upload Owner Role Fix)

(v0.261.028)

Tracking: #1489; implementation: PR #1488.

Bug Fixes

  • Credential-Aware Cosmos Deployment Checks
    • Managed-identity deployments now use the deployment runner’s tenant-scoped Entra credential instead of requiring Cosmos keys. Key-mode deployments report when local authentication is disabled.
    • Authentication and network failures no longer trigger automatic firewall changes or misleading propagation waits. Windows environment lookups and POSIX role operations target the selected deployment explicitly.
    • Deployment requirement: The runner must already have the required data-plane permissions and network access. Post-configuration does not open firewalls, enable key authentication, or create policy exemptions.
    • (Ref: PR #1488, deployers/azure.yaml, deployment_cosmos.py, cosmosDb-postDeployPerms.sh)
  • Safe Post-Deployment Settings Publication
    • Post-configuration uses conflict-checked Cosmos writes and the application’s shared Redis publication protocol, preserving concurrent unrelated settings changes and reporting publication failures instead of claiming success.
    • Consolidated duplicate Redis configuration blocks and preserved external Redis settings when no cache is provisioned. Equivalent connection settings can be normalized; changing an active cache endpoint or authentication mode requires a planned migration.
    • Deployment requirement: When Redis is enabled, the runner needs Redis data-plane access as well as network connectivity. The service restarts only after post-configuration succeeds.
    • (Ref: PR #1488, postconfig.py, deployment_configuration.py, app_settings_store.py)

New Features

  • Automatic Missing Search Index Creation
    • Post-configuration creates missing personal, group, and public Search indexes from the same JSON schemas used by the admin setup controls.
    • Existing indexes and documents are left unchanged. Authorization and service failures stop initialization rather than being treated as missing indexes; concurrent creation is verified before continuing.
    • Included in deployer version 1.0.31. Existing-index schema upgrades remain administrator-managed operations.
    • (Ref: PR #1488, deployment_configuration.py, application/single_app/static/json/ai_search-index-*.json, deployment prerequisites)

(v0.261.027)

Bug Fixes

  • Settings Cache Bootstrap Import Boundaries
    • Removed reverse imports from cache helpers into application configuration, preventing the import cycle identified during review.
    • Web and scheduler startup now configure the cache from the supplied settings object, with storage handles, the Redis factory, and logging callbacks passed separately.
    • Preserves shared settings reads and fail-closed Redis writes without restoring worker-local settings snapshots.
    • Added real-module cold-start probes for normal and optimized Python, moved state-changing test operations outside assertions, and strengthened repository instructions for dependency and startup validation.
    • (Ref: #1477, PR #1478, app_settings_cache.py, functions_settings.py, test_app_settings_import_boundaries.py)

(v0.261.026)

Bug Fixes

  • Redis Explorer Shared Settings Compatibility
    • Fixed key browsing and previews failing after removal of the worker-local settings cache.
    • Explorer now recognizes the current shared settings record and labels leftover settings payload/version keys as legacy, without restoring worker caching.
    • Preserves credential and Cosmos session-token redaction in previews.
    • Added offline coverage for Azure Managed Redis and Azure Cache for Redis, including service-specific ports, key/managed-identity authentication, and app-cache/session clients.
    • (Ref: #1477, functions_redis_monitoring.py, test_cosmos_wave5a3_redis_monitoring.py)

(v0.261.025)

Bug Fixes

  • Delegated Action-Type Policies Now Override Broad Action Access
    • Fixed a governance gap where an explicit delegated item policy for a personal, group, or global action type could still be bypassed by a broader feature-level allow.
    • Action-type governance now treats explicit item policies as authoritative once they exist, so a targeted policy such as personal_action_type = azure_maps can block that action type even when the broader action feature remains enabled.
    • This resolves cases where action types such as Azure Maps continued to appear in action creation flows after admins saved a delegated item policy intended to block them.
    • (Ref: delegated item governance, action-type enforcement, functions_governance.py)
  • Admin Settings Consistency Across Workers
    • Removed worker-local admin settings snapshots so reloads read shared Redis settings, or Cosmos directly when Redis is disabled.
    • Added conflict-checked writes and coordinated cache publication to prevent stale metadata updates, worker startup, and interrupted saves from restoring older settings.
    • Stale admin forms now require a reload. Saves are rejected when configured Redis is unavailable; unconfirmed saves prompt verification rather than reporting success.
    • Reads retain Cosmos fallback without serving an old worker snapshot. Deploy all web workers and the scheduler together; Cosmos fallback remains subject to Session consistency.
    • (Ref: #1477, app_settings_store.py, app_settings_cache.py, functions_settings.py, admin settings form, auxiliary settings writers, docs/admin/scale.md)

(v0.261.023)

New Features

  • XSD Ingestion and Schema-Validated XML Generation
    • Added .xsd ingestion for personal, group, public, chat-upload, generated-artifact promotion, and File Sync paths when Enhanced Citations storage is available.
    • Preserves exact schema bytes in immutable Blob locations and indexes one bounded metadata summary instead of fragmenting the schema as narrative content.
    • Resolves same-workspace includes and imports, tracks schema readiness, and revalidates dependent schemas when current revisions change.
    • Uses an explicitly selected ready XSD as the authoritative contract for XML generated by Chat, Analyze, agents, and Analyze workflows, with whole-document validation before publication.
    • Implements the fail-closed simplechat-xsd10-subset-profile/1; unsupported XSD 1.1 and other excluded constructs are retained with diagnostics but cannot govern generation.
    • (Ref: #1212, XSD ingestion, mixed-source orchestration, schema-bound XML artifacts, functions_xsd_schema.py, functions_documents.py)

Bug Fixes

  • XSD Upload Errors Use Allowlisted Browser Responses
    • Replaced exception-derived chat-upload responses with an explicit allowlist of stable XSD error codes, messages, and HTTP statuses.
    • Unknown XSD ingestion failures now return a generic error without exposing exception details.
    • (Ref: route_frontend_chats.py, XSD upload error handling)

(v0.261.021)

Bug Fixes

  • OAuth2 Token Endpoints Are Now Validated When The Token Is Fetched
    • A Custom endpoint’s OAuth2 token URL was checked when the endpoint was saved, but not when the token was actually requested. Validating only at save time leaves the request itself unguarded, since settings can be written by another path, restored from backup, or changed after validation. Code scanning correctly identified this as a server-side request forgery.
    • The token URL is now revalidated at request time against the same outbound policy as the inference endpoint, and the request runs on the same pinned transport, so its addresses are validated at connection time and redirects are refused.
    • Refusing redirects is safe for this grant: redirects belong to the browser-based authorization-code flow, whereas a client-credentials token endpoint answers a server-to-server POST with a JSON body. The previous code allowed them based on an incorrect assumption.
    • (Ref: functions_model_endpoint_auth.py, #1437)
  • Endpoint URL Version Matching No Longer Backtracks
    • The pattern recognising a version path segment allowed its optional suffix to begin with a digit, making it ambiguous with the preceding digits and quadratic on a long run of them. A 8,000-character segment took roughly 0.19 seconds to reject; it now takes 0.0003 seconds.
    • The suffix must now begin with a letter, which removes the ambiguity while matching exactly the same version segments.
    • (Ref: model_endpoint_clients.py, #1437)

(v0.261.020)

New Features

  • Custom Model Endpoints Support Bearer Tokens, OAuth2, And Client Certificates
    • Custom endpoints accepted one authentication scheme: an API key sent in whichever header the built-in providers happened to use. That covers OpenAI and Anthropic and nothing else, so a gateway expecting x-goog-api-key, a corporate gateway issuing short-lived tokens, and an appliance requiring a client certificate were all unreachable.
    • The API key header name and value prefix are now configurable, so a single scheme covers Authorization: Bearer, Anthropic’s x-api-key, Google’s x-goog-api-key, and any bespoke gateway header.
    • Added static bearer token authentication.
    • Added OAuth2 client credentials, with token caching and refresh ahead of expiry so a token cannot lapse mid-request. The token endpoint is validated against the same outbound policy as the inference endpoint, so it cannot become an unchecked request target, and a failing token response is sanitized before it reaches the browser.
    • Added mTLS client certificates. Certificates are referenced by file path so a private key is mounted into the deployment and never written to the configuration database.
    • (Ref: functions_model_endpoint_auth.py, functions_model_endpoint_providers.py, functions_model_endpoint_validation.py, #1228)

(v0.261.019)

New Features

  • On-Premises Custom Model Endpoints Now Work
    • The administrator gate named “allow private Custom endpoint hosts” did not actually permit the two most common on-premises address forms. An IP address such as https://10.20.30.40/v1 and a short host name such as https://llm-gateway/v1 were both rejected even with the gate enabled, and both were refused with a message claiming the URL was an IP address, which was wrong for the short host name.
    • With the gate enabled, IP addresses, short host names, and hosts resolving to private ranges are now accepted. Loopback, link-local, and cloud metadata addresses remain rejected regardless of any setting, and every address is still revalidated at connection time.
    • Added a CA bundle setting. Custom endpoints trust only public certificate authorities and deliberately ignore ambient environment variables, so an on-premises gateway using an internally issued certificate previously could not be trusted at all. An administrator can now name a PEM bundle. A bundle that cannot be loaded fails loudly rather than silently falling back to weaker trust.
    • Added a separate plaintext HTTP gate for isolated networks where TLS cannot be terminated. It requires the private-hosts gate as well, and is labelled with its consequence: prompts and API keys travel unencrypted.
    • Saving an endpoint no longer requires the host name to resolve from the application tier, so configuration can be seeded or restored from backup ahead of connectivity. Policy violations are still refused at save time, and the connection-time check is unchanged.
    • (Ref: functions_model_endpoint_validation.py, model_endpoint_clients.py, allow_insecure_custom_model_endpoints, custom_model_endpoint_ca_bundle_path, #1228)

(v0.261.018)

Bug Fixes

  • Tool-Calling Responses Now Actually Stream
    • SimpleChat only supports streaming responses, but tool calling cannot stream, because a tool call has to arrive whole. The completed answer was delivered through the streaming interface as a single chunk, so the user saw nothing at all and then the entire response at once, which reads as a hang. Because agents and plugins rely on tool calling, this was a common path rather than an edge case.
    • A completed answer is now split into chunks at word boundaries and delivered progressively, so it reads like a real stream. Chunking is lossless — the reassembled text is byte-for-byte identical.
    • Tool calls still arrive whole, on the final chunk, alongside the finish reason and usage metadata. Emitting metadata once means token usage is no longer at risk of being counted per chunk.
    • Streaming responses can report token usage again. stream_options was stripped from every OpenAI-compatible request, which suppressed usage reporting for all of them. It is now dropped only for surfaces that reject it.
    • (Ref: model_endpoint_clients.py, functions_model_endpoint_providers.py, #1228)

(v0.261.017)

Bug Fixes

  • Custom Endpoint URLs Are No Longer Rewritten Into 404s
    • SimpleChat appended /v1 to every Custom OpenAI-compatible endpoint, even when the configured URL already said where the API lived. A gateway at https://apim.example.com/inference/chat/completions was called at https://apim.example.com/inference/v1/, and any base carrying its own version segment, such as /v1beta or /v2, was broken the same way.
    • /v1 is now appended only when the URL does not already name the API surface. A path whose last segment is a version is left alone, and a full operation URL is treated as stating the base exactly.
    • Added a Use this URL exactly as entered option for gateways that serve the API at a path SimpleChat cannot infer.
    • Test Connection now reports the URL that was actually called. URL normalization rewrites the configured endpoint, and that rewrite was previously invisible, so a misdirected request looked identical to a correct one.
    • (Ref: model_endpoint_clients.py, route_backend_models.py, _multiendpoint_modal.html, admin_model_endpoints.js, workspace_model_endpoints.js, #1228)

(v0.261.016)

Bug Fixes

  • Custom Model Endpoint Failures Are Now Diagnosable
    • Every Custom endpoint failure produced the same sentence — “Custom model request failed.” — with the underlying cause discarded before it reached the log. A wrong path, a wrong API key, a wrong model name, a TLS failure, and a blocked address were indistinguishable, and nothing anywhere explained which had happened.
    • The browser message stays sanitized, because an upstream error body can echo back a URL, a header, or an API key. The real cause is now recorded server-side with the API type, the resolved request URL, the upstream status code, and the upstream error body.
    • Both the message and the log entry now carry a short reference id, so an administrator can join the message a user reports to the log entry that explains it.
    • Credentials are redacted before anything is written to the log, covering API keys, bearer tokens, x-api-key, x-goog-api-key, and key query parameters. A logging failure never replaces the original error.
    • The resolved request URL is included deliberately: URL normalization can rewrite what the administrator typed, and that rewrite was previously invisible.
    • (Ref: functions_model_endpoint_diagnostics.py, model_endpoint_clients.py, functions_model_endpoint_runtime.py, #1228)

(v0.261.015)

New Features

  • Custom Model Endpoints Now Support Google Gemini, Through A Provider Registry
    • Custom endpoints supported exactly three API types, and each one was hard-coded in five separate places: the allowlist, the request-model resolver, the protocol inference chain, the admin template’s option list, and the admin JavaScript. Adding a provider meant editing all five and hoping none were missed.
    • An API type is now a single declarative registry entry that carries its wire protocol, which field names the model, how its URL is built, which authentication types it accepts, and which version field applies. The admin API Type list, the model identifier label, and the version fields all render from that registry.
    • Google Gemini is now selectable as a Custom endpoint API type, reached through its OpenAI-compatible surface so it still runs on SimpleChat’s validated-DNS pinned transport.
    • Fixed URL handling for endpoints that already carry a version segment. SimpleChat appended /v1 unconditionally, which turned Gemini’s …/v1beta/openai base into …/v1beta/openai/v1 and produced a 404. URL construction is now per-provider, so /v1 is appended only where it belongs.
    • The three existing API types are unchanged, and an unregistered API type is still refused.
    • (Ref: functions_model_endpoint_providers.py, functions_model_endpoint_types.py, model_endpoint_clients.py, admin_model_endpoints.js, workspace_model_endpoints.js, _multiendpoint_modal.html, #1228)

(v0.261.014)

New Features

  • Model Capabilities Now Come From The Model Catalog Instead Of The Model’s Name
    • SimpleChat previously worked out what a model could do by pattern-matching its name, so a model the catalog did not know about — an on-premises or customer-supplied model reached through a Custom endpoint — silently received wrong answers for vision, tool calling, streaming, and reasoning. A model named corp-llm-v2 was treated as having no capabilities at all.
    • Capability answers now resolve through a precedence chain: a per-model override, then an endpoint-level override, then the shipped model catalog, then the original name heuristics. Administrators can describe a model the catalog has never heard of without waiting for a catalog update, and models absent from the catalog behave exactly as before.
    • The catalog gained supportsStreaming and reasoning flags for every model, and now covers Google Gemini, which had no entries at all. Claude, Llama 4, and Phi-4 multimodal models are correctly recognised as vision-capable for the first time; the -chat variants of the GPT-5.x families are correctly recognised as not vision-capable.
    • The catalog is now validated against a published JSON schema, so a malformed or incomplete model record fails a test rather than silently degrading capability answers at runtime.
    • (Ref: functions_model_capabilities.py, model_capabilities.json, model_capabilities.schema.json, MODEL_CAPABILITY_CATALOG.md, #1228)

(v0.261.013)

New Features

  • Custom Model Endpoint Provider
    • Added manually configured Custom endpoints for OpenAI API, Azure OpenAI API, and Anthropic chat models across global, personal, and group scopes.
    • Added type-specific model identifiers, API-key authentication, connection testing, response-length controls, and Anthropic Version support without model discovery.
    • Enforced HTTPS, DNS/address safety with connection-time address pinning, runtime URL revalidation, redirect refusal, Key Vault secret handling, and an administrator-controlled private-host policy.
    • (Ref: #1222, Custom model endpoints, functions_model_endpoint_runtime.py, _multiendpoint_modal.html, CUSTOM_MODEL_ENDPOINT_PROVIDER.md)

(v0.261.012)

New Features

  • Yamcs Actions Can Reach Servers Behind An Authenticating Proxy
    • Ground segments commonly publish Yamcs through a reverse proxy, such as Apache, that challenges every request with HTTP Basic authentication against a directory before the request reaches Yamcs. Yamcs behind that proxy often has no authentication of its own. Until now a Yamcs action could not answer that challenge, so such a server was unreachable even when the Yamcs settings were correct.
    • A new Reverse Proxy Authentication option on the Yamcs action sends an HTTP Basic Authorization header on every request. It is off by default, so a Yamcs server reached directly, such as a local simulator, is unaffected.
    • The proxy credential can be typed on the action, with the password stored in Key Vault, or supplied by a reusable username and password identity. Where a directory issues temporary passwords, the identity is rotated once under Workspace → Identities and every action that references it picks up the new password without being edited.
    • The proxy credential has its own identity reference, separate from the Yamcs credential, so one action can use both.
    • Proxy authentication combines with the No Authentication and API Key Yamcs methods. It cannot combine with Username and Password or Access Token, because only one Authorization header can be sent and the Yamcs token request would itself be refused by the proxy. The conflict is reported when saving the action and when running Test Yamcs Connection rather than failing later at run time.
    • Test Yamcs Connection exercises the proxy credential and distinguishes a proxy rejection from a Yamcs rejection.
    • (Ref: functions_yamcs_operations.py, yamcs_plugin.py, functions_workspace_identities.py, plugin_health_checker.py, route_backend_plugins.py, _plugin_modal.html, plugin_modal_stepper.js, test_yamcs_basic_auth.py, Yamcs Action, #1435)

(v0.261.011)

Bug Fixes

  • Redis Connection Test No Longer Returns Credential Errors To The Browser
    • Restored the hardening that a refactor had dropped: when the admin Redis connection test fails while resolving credentials, the details are logged under [REDIS_TEST] and the browser receives a generic message instead of the raw exception, which could carry Key Vault secret names, vault URIs, or token details.
    • Validation problems such as a missing host name or access key are still returned directly, because those messages are generated by SimpleChat and are what the admin needs to fix the form.
    • (Ref: route_backend_settings.py, test_redis_client_factory.py)
  • Deployer Redis Kind Detection Matches The Full Host Name Suffix
    • The postprovision fallback that infers the Redis offering from a host name used a substring check, so a host name that merely contained .redis.azure.net anywhere could be misread as Azure Managed Redis and configured with the wrong port.
    • It now matches the full suffix, consistent with the application’s own detection.
    • (Ref: deployers/bicep/postconfig.py)

(v0.261.010)

New Features

  • Azure Managed Redis Support
    • SimpleChat now connects to Azure Managed Redis as well as Azure Cache for Redis, ahead of the September 30, 2028 retirement of the Azure Cache for Redis Basic, Standard, and Premium tiers.
    • The two services listen on different TLS ports, so SimpleChat resolves the port from the host name suffix: *.<region>.redis.azure.net connects on port 10000 and *.redis.cache.windows.net (plus the Azure Government and 21Vianet equivalents) on port 6380.
    • New Redis Service and Redis Port settings let an administrator state the service explicitly when a custom DNS name or private endpoint hides the Azure suffix. Existing deployments are unaffected: unrecognized host names keep the previous Azure Cache for Redis behavior.
    • The Redis Metrics panel now reports which service and port were resolved, and whether that came from detection or an explicit setting.
    • Both services are supported because Azure Managed Redis is not available in Azure Government or Azure operated by 21Vianet.
    • (Ref: functions_redis_client.py, app_settings_cache.py, app.py, redis-caching.html, Azure Managed Redis Support)
  • Redis Deployment Uses Azure Managed Redis
    • The Bicep deployer now provisions Azure Managed Redis Balanced_B0 with high availability enabled, Microsoft’s documented replacement for the Azure Cache for Redis Standard C0 it previously deployed. That is twice the memory for less cost.
    • A new redisCacheKind parameter still deploys classic Azure Cache for Redis for sovereign clouds where Azure Managed Redis is unavailable.
    • The database is created with the NoCluster clustering policy. The service default is OSSCluster, which requires a cluster-aware Redis client that SimpleChat does not use.
    • Managed identity deployments disable access keys and grant the web app the built-in default access policy on the Azure Managed Redis database.
    • (Ref: deployers/bicep/modules/redisCache.bicep, setPermissions.bicep, setNativeWebAppPermissions.bicep, postconfig.py, deployers/version.txt)

Bug Fixes

  • Redis Managed Identity Tokens Refresh On Open Connections
    • Redis managed identity authentication now uses the redis-entraid streaming credential provider, which renews the Microsoft Entra token in the background and re-issues AUTH on connections that are already open. Previously credentials were supplied only at connect time, so a long-lived pooled connection relied on the server dropping it once the token expired.
    • The shared application cache and Flask session storage each get their own provider instance, because the provider holds a single re-authentication callback slot and sharing one would leave the first client’s connections unrefreshed.
    • The admin “Test Redis Connection” button uses a connect-time-only provider, so repeated clicks no longer accumulate background threads, event loops, and recurring token requests.
    • The package is imported defensively, falling back to the previous in-repo provider if it is missing, so an application updated without reinstalling requirements still starts.
    • (Ref: functions_redis_client.py, requirements.txt, test_redis_entra_token_auth.py)
  • Redis Connection Test Uses The Same Token Scope As The Application
    • The admin Redis connection test acquired its managed identity token from the legacy cache infrastructure endpoint while the running application used the https://redis.azure.com/.default scope, so a passing test did not prove the application could connect.
    • The test now builds its client through the same factory as the application, including service and port resolution.
    • (Ref: route_backend_settings.py)

(v0.261.009)

Bug Fixes

  • Shared Workspace File Approvals Are Visible To Approvers Again
    • Fixed document access index candidate selection for workspace scope projections so pending-approval records are considered alongside already granted records.
    • Shared files staged for approval are intentionally not granted yet, so filtering only on access_granted = true could hide those files from approval experiences even though they were eligible for review.
    • The projection query now includes approval_status = not_approved rows while still requiring current-version projection records.
    • (Ref: functions_document_access_index.py, Workspace Shared File Approval Visibility Fix)
  • Distroless Runtime Copy No Longer Fails On /usr/lib64 Overlay Conflicts
    • Fixed Docker BuildKit failures where COPY --from=builder /odbc-runtime/ / or COPY --from=builder /playwright-runtime/ / could abort with cannot copy to non-directory ... /usr/lib64 when the distroless base exposes /usr/lib64 as a non-directory entry.
    • Updated runtime staging to copy native shared libraries into /odbc-runtime/usr/lib and /playwright-runtime/usr/lib while continuing to source candidates from both /usr/lib64 and /usr/lib in the builder stage.
    • This preserves SQL ODBC and Playwright Chromium runtime packaging while avoiding path-type collisions against evolving base-image filesystem layouts.
    • (Ref: Dockerfile, test_sql_container_odbc_runtime.py, test_deep_research_chromium_build_opt_out.py, Distroless Runtime Overlay Path Fix)

(v0.261.007)

Bug Fixes

  • Markdown Retry Helper Return Contract Clarified
    • Added an explicit defensive exception at the end of the Markdown OrderedDict retry helper so static analysis no longer sees a possible implicit None return.
    • Runtime behavior is unchanged for normal success and retry-exhaustion paths.
    • (Ref: functions_documents.py, Markdown Retry Return Contract Fix)

(v0.261.006)

Bug Fixes

  • Markdown Uploads Retry Transient OrderedDict Parser Failures
    • Markdown document processing now retries the known transient OrderedDict mutated during iteration parser failure before marking a document failed.
    • The retry is limited to this specific Markdown failure signature, so unrelated parsing, validation, or service errors still fail normally with their original error.
    • (Ref: Markdown upload processing, functions_documents.py, test_markdown_processing_batches_search_writes.py, Search Write Gate Upload Contention Fix)

(v0.261.005)

User Interface Enhancements

  • Workspace Upload Progress Now Separates Request Status From Document Processing Status
    • The temporary upload summary no longer labels unconfirmed browser upload requests as final document failures. This avoids misleading summaries such as Uploaded 77/204, Failed: 127 when the document list later shows that most documents were queued and processed successfully.
    • Personal, group, and public workspace uploads now use Queued for confirmed upload requests and direct users to the refreshed document list for final processing status.
    • (Ref: workspace upload progress summary, workspace-documents.js, public_workspace.js, group_workspaces.html, Workspace Upload Status Counter Fix)

(v0.261.004)

Bug Fixes

  • Large Workspace Uploads No Longer Fail On Search Write Gate Contention
    • Fixed partial failures when uploading many small Markdown, JSON, or YAML files to personal, group, or public workspaces at once. Document processing could fail with a message that the Data Management Search write gate changed too often to reserve a write slot.
    • The shared write gate now waits within the existing request timeout budget, briefly backs off after transient Cosmos ETag conflicts, and serializes Search writes inside each worker process. This prevents local upload threads from stampeding the same gate document while preserving the migration freeze protection for Azure AI Search writes.
    • Markdown processing now batches its chunk embeddings and Search upload instead of reserving the gate once per chunk, which reduces contention and avoids the intermittent OrderedDict mutated during iteration failures seen during concurrent Markdown ingestion.
    • Added regression coverage for repeated transient gate conflicts, local worker serialization, and Markdown use of the batch chunk writer.
    • (Ref: functions_data_management_search_write_fence.py, functions_documents.py, test_data_management_search_write_fence.py, test_markdown_processing_batches_search_writes.py, Search Write Gate Upload Contention Fix)

(v0.261.003)

Bug Fixes

  • Broken Documentation Links Repaired
    • Clicking the upgrade guide, Docker customization, or enterprise networking links from the repository README or the deployer READMEs led to a “page not found”. Those pages were reorganized from docs/how-to/<snake_case>.md to docs/guides/<kebab-case>.md, and the site kept redirects, but redirects do not apply when browsing files on GitHub. No documentation was ever lost, only mislinked.
    • Repaired 46 broken relative links in total: 12 in the README and deployer READMEs, and 34 in archived per-version engineering notes. Archived links whose target was never migrated now keep the prose without a dead link, rather than pointing at a file that does not exist.
    • Also corrected the “Return to Main” link in the Azure CLI and Terraform deployer READMEs, which pointed one directory too shallow.
    • (Ref: README.md, deployers/*/README.md, docs/explanation/features/, docs/explanation/fixes/, #1371)
  • Recovered 27 Release Note Sections Missing From The Source File
    • docs/explanation/release_notes.md had been truncated from 46 version sections to 19, dropping every v0.260 entry along with v0.250.229 through v0.250.231. The published site still showed them, because the pages that render release notes are generated from this file and had not been rebuilt since the truncation.
    • That left the repository one routine build_release_notes_pages.py run away from erasing roughly 2,400 lines of release history from the site with no obvious cause. The sections have been restored from history and the pages regenerated, so the source and the site agree again.
    • (Ref: docs/explanation/release_notes.md, scripts/build_release_notes_pages.py, #1371)

Documentation

  • Web Search Documentation Now Describes What Actually Happens
    • The web search guide still described the Bing Web Search API integration that was removed back in v0.229.001. Web search has since run through an Azure AI Foundry agent using the Grounding with Bing Search tool, which is why an admin has to configure a Foundry project and agent ID before the Web control appears.
    • Added a dedicated What leaves SimpleChat section stating the egress boundary plainly: only the message the user just typed is sent to the external search service. Conversation history, workspace documents, attached file contents, system prompts, agent instructions, and workspace or document names are never included. This behavior was hardened in v0.241.022 but was previously mentioned only in passing.
    • Documented the Deep Research nuance: it runs several planned queries instead of one, but every query is still derived from the current message alone, so no conversation history is introduced.
    • Added the Grounding with Bing Search compliance-boundary notice to the user-facing guide, replaced the placeholder text in the admin Web Search settings table with real descriptions, and reused the existing web search flow diagram instead of leaving a “recording planned” video card.
    • (Ref: docs/guides/use-web-search.md, docs/admin/knowledge.md, docs/reference/chat-controls.md, build_web_search_query_text, #1371)
  • Documentation Link Rot Now Fails A Test
    • Added functional_tests/test_docs_link_integrity.py, which fails when any relative markdown link in the README, docs/, or deployers/ points at a missing file, when a Jekyll relative_url page link does not resolve, or when a media include names an unregistered slot. Outstanding screenshots are reported but never fail the run.
    • Added functional_tests/test_docs_web_search_accuracy.py, which ties the published privacy claim to the implementation. If the web search query builder ever starts folding conversation history back into the outbound query, the test fails and forces the documentation to be corrected with it.
    • (Ref: test_docs_link_integrity.py, test_docs_web_search_accuracy.py, #1371)
  • First Batch Of Documentation Screenshots
    • Filled 54 empty screenshot slots, taking documentation screenshot coverage from 18 of 122 to 72 of 122. The Administration group is now fully illustrated.
    • Added the four admin settings overviews (Backup & Recovery, Data Lifecycle, Governance, Workflow), six chat control references (conversation list, conversation header, composer, selectors, grounded search, and advanced conversation search), thirty-three task guide steps, and configuration panes for eleven action types (Azure Maps, Blob Storage, Chart, Cosmos Query, Databricks, Document Search, Log Analytics, MCP, Microsoft Graph, OpenAPI, RocksDB, and SimpleChat).
    • The web search screenshot captures the live data notice, so the guide’s claim that only the current message is sent is now visible rather than only asserted.
    • Action configuration panes were captured without saving any action, so every credential field shows only its placeholder text and no tenant values were recorded. Where an admin settings pane already held real values, those fields were replaced with example values before capture and the page was reloaded without saving.
    • Replaced the generated placeholder alt text on every filled slot with a description of what the reader actually learns from the image.
    • (Ref: docs/images/admin/, docs/images/reference/, docs/images/guides/, #1371)

(v0.261.002)

User Interface Enhancements

  • Inbound MCP Enablement Guidance
    • Added a visible Inbound MCP tab state for deployments where the preview admin UI is disabled by the missing ENABLE_MCP_UI=true App Service application setting.
    • The disabled-state card explains how to enable the preview UI while making clear that the inbound MCP runtime remains off until an admin turns on Enable inbound MCP server after authentication, client allowlist, source, and governance prerequisites are ready.
    • (Ref: admin/_panes/inbound-mcp.html, admin_settings_nav.py, #1364)

Bug Fixes

  • Delegated Governance New Policy Modal Opens On Split Governance Tabs
    • Fixed the delegated item governance New Policy button so it opens the policy editor after Admin Settings governance was split into Feature Governance, Policies, and MCP Governance tabs.
    • Updated governance quick links to target the correct split tab panes instead of the retired aggregate Governance pane.
    • (Ref: admin_governance.js, delegated item policy editor, #1362)
  • Large Markdown Files No Longer Fail To Upload
    • Uploading a Markdown file could fail with Failed processing Markdown file ... and take down the whole document, not just the oversized part of it. Long pages with a big section under a single heading, such as a release notes file, were the usual trigger.
    • Markdown was the only ingestion path with no maximum chunk size. Its splitter divided the file on headings, and the step afterwards only ever merged chunks that were too small — nothing split a chunk that was too large. A heading with no subheading beneath it therefore became one chunk as large as all the text under it, which the embedding model refused.
    • Lowering Markdown (words) in Admin Settings did not work around this, because that value was only ever used as a minimum. It is now a real target, so the setting behaves the way its name implies.
    • Sections are now split to the configured size, a character limit is applied after merging to catch content such as tables and code blocks that take up more of the model’s budget than their word count suggests, and a final safeguard keeps any remaining outlier inside the limit. That safeguard trims only the text used to build the chunk’s search vector — the chunk itself is still stored in full, so citations and content are unaffected.
    • (Ref: process_md, save_chunks, functions_content.py, functions_documents.py)
  • Chunk Size Limits Now Respect Their Unit
    • Chunk sizes are configured per file type in words, characters, or pages, but a single shared limit was applied to all of them. That let a word-based field be set to 16,384 words — far more than can be indexed — while implying the value was valid.
    • Word and character fields now have separate limits, both derived from the embedding model’s context window, and the Document Extraction tab shows the current values. A value above its limit is reduced on save and the page names the fields it changed.
    • Page and slide counts are left uncapped here, since how much text a page holds is not known until extraction runs. They are bounded when the chunk is indexed instead.
    • No shipping default changed. Only custom overrides that could never have been indexed are affected.
    • (Ref: get_chunk_size_cap, get_chunk_size_config, Document Extraction settings, admin_settings.js)
  • Logout No Longer Redirects To A Missing Easy Auth Endpoint
    • Logout could redirect to /.auth/logout?post_logout_redirect_uri=%2Flogin and return a 404 on Azure App Service deployments that were not actually serving App Service Easy Auth. This affected production deployments as well as development ones.
    • The root cause was Easy Auth detection treating the manually configured WEBSITE_AUTH_AAD_ALLOWED_TENANTS application setting as proof that Easy Auth was intercepting requests. SimpleChat’s own advanced environment variable guidance instructs operators to set that value by hand, so it was never a reliable signal.
    • Detection now relies only on the X-MS-CLIENT-PRINCIPAL request headers that App Service Easy Auth injects on requests it actually intercepts, so deployments genuinely behind Easy Auth still clear the upstream platform session, and everyone else gets a clean local logout.
    • Idle-timeout logout uses the same local logout path, so automatic session expiration follows the corrected behavior as well.
    • (Ref: route_frontend_authentication.py, _use_app_service_easy_auth_logout, test_app_service_easy_auth_logout.py, Easy Auth Logout Detection Fix)

New Features

  • Opt-Out For App Service Easy Auth Logout
    • Added the DISABLE_APP_SERVICE_EASY_AUTH_LOGOUT environment variable for deployments where Easy Auth is genuinely active but the platform /.auth/logout endpoint is not reachable on the public host, such as when a custom domain or gateway does not route /.auth/* to the App Service origin.
    • Setting it to true keeps logout on the local path instead of redirecting to the platform endpoint. Logout routing decisions are now also traced through debug logging, so FLASK_DEBUG=1 shows which path was taken and why.
    • (Ref: DISABLE_APP_SERVICE_EASY_AUTH_LOGOUT, config.py, example.env, Running SimpleChat Locally)