[pull] main from danny-avila:main - #231
Merged
Merged
Conversation
…#15186) * 📌 fix: Keep the Settled Turn Mounted Through Final Content Compaction The agent aggregator writes content parts at provider-source indexes, so the streamed array is sparse wherever a step produced nothing; the final SSE event carries the persisted, compacted array. Adopting it verbatim shifted every part after a hole, re-keying every index-derived React identity: the settled message remounted wholesale, activity-phase groups replayed their fold-in entrance, code panes re-highlighted, and the thread visibly snapped up and down at the end of every tool-calling run. finalHandler now pairs the compacted parts with their streamed counterparts in order and stamps each with the index it streamed at (`streamedIndex`, client-only); render keys read the stamp while all coordinate logic (edit indexes, phase bounds, cursor) stays on the live compacted positions the server persisted. Phase-segment keys also anchor to their first defined part instead of the segment ordinal, since phantom hole-only segments vanish at compaction and shifted every segment after them. * 🔁 fix: Carry Identity Stamps Through Re-Delivered Finals and Parallel Attribution Codex round 1, both real: - P1: a later final event can re-deliver an already-settled message as a fresh compact array (Assistants runMessages resync); index-aligned pairing returned it unstamped, wiping the previous settle's stamps and re-keying the older turn all over again. The pairing now carries the matched current part's stamp forward, so a settled turn keeps its keys through every subsequent final. - P2: ParallelContentRenderer's sequential stretches invoked renderResumeAttribution with only the live index, so steer attribution nodes in parallel content still re-keyed at the swap. The stable key index now threads through both call sites; getPartKeyIndex moves to utils/messages beside the stamp writer it reads. * 🧿 fix: Require Content Agreement Before Pairing Streamed Identity Codex round 2 (P2, real): hide_sequential_outputs runs omit intermediate parts from the final array, so a type-only match could hand the retained output an omitted intermediate's identity — transferring its key and any UI state. Non-tool pairing now requires content agreement: mutual-prefix text for TEXT/THINK/ACTIVITY_LABEL (one side extending the other is the same part observed at two moments), the Open Responses phase for TEXT, and the label kind for activity labels — a blank reservation still pairs with its filled label. Ambiguous shapes fall back to the pre-stamp full re-key, which is honest for a final that visibly removes parts. * 🪢 fix: Refuse Stamping When the Server Removed Content; Strip Stamps on Edited Reruns Codex round 3, two of three real: - Prefix agreement alone still mis-paired when an omitted intermediate happened to prefix the retained output. Pairing now also requires that no substantial streamed part is left over: leftovers mean the server removed content (hide_sequential_outputs), so every in-order pairing is suspect and the message re-keys plainly instead. - An edited resubmission clones the settled (stamped) prefix and appends the rerun's parts at the prefix length; a retained stamp at or above that length collides with an appended part's key. The clone now strips the client-only stamps, reverting the retained prefix to physical identity for the rerun. The third finding (content-segment keys under late-phase recovery) is declined with rationale on the PR: user expansion overrides survive via the message-wide expansion map with stable group ids, recovery is a genuine restructure at the moment a phase materializes, and first-child anchoring is the only choice stable under the two high-frequency events (streaming appends and final compaction).
) The timer sat at the footer's flush left while everything around it is inset 6px: the streaming dot pads (24 − 12) / 2 to center on the size-6 header icon's axis, and the hover-button glyphs that replace the timer sit behind their own p-1.5. The same ps-1.5 inline-start inset lines the reading up with the dot above it and the glyphs that follow it — measured in the live app: timer x 382, dot x 382, first settled glyph x 382.
Resolve the transactions config from the request and forward it to both abort write paths, so `transactions.enabled: false` is honored when a generation is stopped.
* 🧵 feat: Background Execution Toggles for Actions & Plugin Tools * 🩹 fix: Resolve action background opt-in across encoded-domain forms and scope it per action * 🧹 refactor: Resolve action domain in a single pass * 🧩 fix: Merge Normalized Action Background Options * 🪢 fix: Reconcile Action Background Aliases * 🧭 fix: Harden Action Background Compatibility * 🕰️ test: Allow Settled Task TTL Expiry * 🧬 fix: Merge Refreshed Action Tool Registrations
Adds helmet's CSP-independent headers (HSTS, X-Frame-Options, X-Content-Type-Options, COOP, CORP, Referrer-Policy) on every response, with contentSecurityPolicy explicitly disabled. Every header that can break a deployment is configurable, so there is no allow-list to go stale the way #7377's hardcoded CSP directives did. HSTS includeSubDomains defaults off rather than matching helmet's on-by-default: it would otherwise pin every sibling subdomain to HTTPS for a year in every visitor's browser, and undoing that requires serving max-age=0 from each affected host.
…ce (#15201) Both floated over the chat on surfaces one step too close to it — the question popover on surface-secondary, the subagent thread panel on the chat's own surface-primary. Both now use surface-primary-alt, the conversation-list sidebar's role, verified in the running app: popover, panel, and sidebar all resolve to the same computed background in dark (rgb 23,23,23) and light (rgb 247,247,248). Inline question cards keep surface-secondary deliberately — that is the tool-record family's surface, and settled questions collapse into that family.
* 🧾 fix: Honor Disabled Transactions on the Assistants Usage Path Thread the resolved transactions config through `recordUsage` from each of its callers, so `transactions.enabled: false` is honored on the assistants token spend path. * 🧾 fix: Thread the transactions config through the vision-request caller Address review: `ToolService.processVisionRequest` also records usage without the resolved config, and `recordUsage`'s documented return type did not match the function. * 🧾 fix: Set the resolved transactions config after the usage spread - provider usage could carry a `transactions` key that overwrote the trusted value - matches the ordering the other `recordUsage` callers already use
) `useGetModelsQuery` seeds from a static fallback config, so `modelsQuery.data` describes a hardcoded model list both before the mounted fetch resolves and after it fails outright. The agent builder read that seed as authoritative and offered models the active server configuration never exposed. Blank the catalogue until the mounted fetch actually succeeds, surface the failure in the model panel instead of silently falling back to the seed, and refuse to create an agent against a provider/model pair the resolved catalogue does not offer. Also wires the builder's orphaned `htmlFor` labels to the controls they name.
* 🛡️ feat: Configurable Baseline HTTP Security Headers Adds helmet's CSP-independent headers (HSTS, X-Frame-Options, X-Content-Type-Options, COOP, CORP, Referrer-Policy) on every response, with contentSecurityPolicy explicitly disabled. Every header that can break a deployment is configurable, so there is no allow-list to go stale the way #7377's hardcoded CSP directives did. HSTS includeSubDomains defaults off rather than matching helmet's on-by-default: it would otherwise pin every sibling subdomain to HTTPS for a year in every visitor's browser, and undoing that requires serving max-age=0 from each affected host. * 🛡️ feat: Nonce-Based Content Security Policy for the SPA Shell Adds an opt-in, per-response nonce CSP on the HTML response, resolved once at startup so each request only mints a nonce and concatenates the header. Report-only by default, since that is the rollout step #7377 skipped. Rebase and correctness pass over #13226: - Styles carry no nonce. A nonce in style-src makes browsers ignore 'unsafe-inline', which would have blocked the <style> element the theme script injects at runtime, plus every style third-party components inject. - frame-ancestors 'self' is now a default rather than opt-in, so enabling CSP actually covers the clickjacking half of #7110. - CSP_SCRIPT_SRC_EXTRA now drops 'strict-dynamic', which would otherwise make browsers ignore the very hosts the operator configured. - Nonce stamping runs after the query-devtools bootstrap injection so that injected script is covered too. * fix: replace frame-ancestors instead of merging it Merging the configured value into the default turned a deliberate CSP_FRAME_ANCESTORS='none' into `frame-ancestors 'self' 'none'`, which browsers resolve back to 'self'. Also bail out if the serialized policy somehow lacks the nonce slot rather than emitting a header the shell cannot match. * fix: address Codex review findings on the CSP defaults All five were real against LibreChat's actual runtime: - CSP_REPORT_ONLY now only enforces on an explicit false/off/0/no. A typo or `1` previously fell through isEnabled() to enforcing, turning a config slip into a blocked SPA. Shares the parse helper with headers.ts via a new security/env.ts. - Module preloads are stamped. A production client/dist/index.html carries 32 parser-inserted `<link rel="modulepreload">` tags, which 'strict-dynamic' does not cover and 'self' cannot rescue. - Stale nonce attributes are replaced rather than preserved; only the current response's nonce is authorized. - worker-src allows data:, which Monaco's default CDN loader needs to bootstrap its workers (there is no loader.config() in the client). - script-src allows 'wasm-unsafe-eval' for the HEIC upload path, which compiles WebAssembly through heic-to. Narrower than 'unsafe-eval'. Verified against the real built shell: 4 scripts and all 32 preloads nonced, stylesheets/icons/manifest and <style> untouched. * fix: address second Codex round on CSP rollout controls - SECURITY_HEADERS=false now disables CSP too. It is documented as the global kill switch, and an operator reaching for it to recover a shell broken by an enforcing policy must not be left with that policy on. - The SPA shell is forced to `no-store` while CSP is enabled, ignoring INDEX_CACHE_CONTROL/INDEX_PRAGMA/INDEX_EXPIRES and warning when they are set. A cacheable shell pins one nonce across page loads and users, which is the whole thing a nonce policy defends against. - Added CSP_ALLOW_WASM and CSP_ALLOW_DATA_WORKERS. The previous commit's .env.example claimed CSP_ADDITIONAL_DIRECTIVES could drop 'wasm-unsafe-eval' and data:, but merging only ever appends sources, so the documented hardening step was impossible. These toggles make it real.
The event subagent group's child rows are raw buttons with no text color of their own, and the section root set none either, so the agent name labels inherited straight from the unthemed black body color — invisible on the dark surface (and silently off-token in light mode: pure black where --text-primary is 33 33 33). The slug and status lines carried explicit text-text-secondary, which is why only the names vanished. Root gets text-text-primary, matching SubagentActivity and SubagentThreadPanel, so every descendant inherits the theme role and the rows' secondary lines keep their explicit overrides. Verified against the live cascade: the label computes rgb(0,0,0) in both modes today and the token color (236/236/236 dark, 33/33/33 light) with the root themed.
* 🛑 fix: Separate Agent Event Backpressure From User Bans * fix: Address Agent Event Review Findings * fix: Mirror Case-Insensitive Agent Control Routing
…5204) * ⏳ fix: Anchor Resumed Elapsed Time at the Generation's Real Start A reload emptied the Recoil anchor, so the indicator fell back to its mount time and visibly reset to 0s over a run that had been generating for much longer. The stream status the resume path already reads carries the server-recorded generation start; the fill now prefers it, so a reattached run reports real elapsed time. The fill remains fill-only: a same-session reattach keeps its original ask baseline, and the indicator's existing clamp absorbs any client/server clock skew. * 🕰️ fix: Rebuild the Resumed Baseline From the Server-Computed Age Codex round 1: anchoring at the server's raw createdAt compares two clocks — a client behind the server froze the resumed reading at 0s for the skew, one ahead inflated it. The status route now also reports the generation's age computed on its own clock, and the client rebuilds a clock-local anchor as Date.now() minus that age, so each machine only ever compares to itself. Raw createdAt stays as the fallback for an older server mid-rolling-deploy. * 📥 fix: Compute Elapsed Age in TypeScript, Anchor It at Status Receipt Codex round 2: the elapsed computation moves into packages/api as getGenerationElapsedMs — the route now just delegates, keeping the response contract type-checked and the /api surface a thin wrapper — and the client subtracts the age from the moment the status response arrived (dataUpdatedAt) rather than from apply time, so a slow history fetch between receipt and apply can no longer shrink the reading. Declined with rationale: a shared clock source across replicas — the residual is inter-replica NTP drift, milliseconds against the minutes-scale client skew this PR eliminates, and the helper gives any future shared-clock upgrade a single home.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )