[pull] main from danny-avila:main - #578
Merged
Merged
Conversation
* 📄 fix: Serve Stored Text for Text-Source File Downloads "Upload as Text" attachments store extracted content in the DB with source 'text'; OCR uploads persist the OCR strategy name (e.g. 'mistral_ocr') as a filepath placeholder since no backing file exists. The download route resolved these records to the local strategy and passed the placeholder to fs.createReadStream, which failed with ENOENT — and the response was never ended after the stream error, so the request hung until the client timed out. Serve the stored text directly as a .txt download for text-source files (re-fetched by _id, as getFiles excludes 'text' by default), and end the response on stream errors: 500 without the download headers before headers are sent, otherwise abort the truncated response so clients detect the failure. * fix: Preserve text-source preview semantics * fix: Complete text-source download coverage * fix: Tie text downloads to blob lifecycle * fix: Isolate preview downloads and share text snapshots * fix: Keep shared previews in share scope * style: Sort text download imports --------- Co-authored-by: Danny Avila <danny@librechat.ai>
#14788) * fix(client): preserve resumable response identity Fixes #14787 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(client): align resumable sync regressions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(client): clarify resumable response ownership Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(client): preserve resumed regeneration ordering Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * test(client): cover missing resumed response row Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(client): preserve resume identity on page reload * fix(client): replace reassigned resume placeholder * fix(client): preserve content during response id handoff * fix(client): limit resume placeholder handoff * fix(client): preserve resume display metadata * fix(client): reconcile resume metadata in one pass * fix(client): reconcile preliminary resume user * fix(client): restore regenerated branch on early abort * test(client): cover external regeneration resume * fix(client): preserve regeneration history on errors * fix(client): replace reused regeneration error ids * fix(client): preserve exact-id regeneration rollback --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Danny Avila <danny@librechat.ai>
* ✂️ fix: Strip Redundant Server-Name Prefixes from MCP Tool Keys MCP servers that prefix every tool with their own name produce model-facing keys that embed the server twice once the _mcp_<server> suffix is appended, pushing long tool names past provider 64-character function-name limits. Tool keys now drop a leading <normalizedServerName>_ prefix (case-insensitive, skipped when a sibling tool already owns the stripped name). The original upstream name is recorded as serverToolName on the cached definition and is always what tool calls send to the server, and runtime lookups also try the stripped spelling of persisted pre-strip keys so existing agents keep resolving. * 🩹 fix: Keep Stripped MCP Tool Keys Provider-Safe and Collision-Free Assistant writers submit catalog entries verbatim, so the internal serverToolName mapping is now removed from provider-facing definitions before they reach create/update payloads. Prefix stripping is collision-guarded over the resulting name set rather than raw siblings only, which also covers case-variant prefixed pairs under the case-insensitive match. Assistant payload healing now rewrites a pre-strip persisted key to the stripped catalog key when that key actually exists in the loaded definitions, and legacy agent references keep their persisted spelling as the runtime instance name so per-tool options stay applied while the upstream call still uses the matched entry's raw name. * 🧷 fix: Harden Stripped MCP Tool Keys Against Heal, Collision, and Cache Edges The pre-strip heal now resolves the key boundary against both raw and normalized server spellings, mapping back to the raw name for the shadow and membership guards, so keys persisted after server-name normalization heal too. Collision detection iterates to a fixpoint so a fallback to a raw name cannot silently collide with another sibling's stripped result, and a stripped remainder equal to a synthetic marker (wildcard or server pin) is never produced. MCP catalog cache slices are versioned so replicas that predate serverToolName never read stripped entries during a rolling deploy; stale slices expire on their own. * 🔎 fix: Resolve Pre-Strip Keys in Event-Driven Definitions and Reinspect Persisted Catalogs The event-driven definitions loader now tries the stripped spelling of a persisted key when the exact lookup misses, keeping the persisted name so it matches the runtime instance, which stops legacy agents from failing initialization with expected tools unavailable. The registry storage schema version is bumped so followers rebuild persisted toolFunctions instead of republishing pre-strip definitions into the versioned catalog namespace. The assistants heal also fails closed when a normalized-suffix reference lands on a contested server-name slot, since rewriting persisted data must not bind an ambiguous reference to the tie-break winner. * 🛰️ fix: Reserve the Synthetic OAuth Name and Heal User-Owned Server Keys A stripped remainder equal to oauth would make the client stream handlers treat a real tool call as a synthetic authentication prompt, so it joins the reserved remainders alongside the wildcard and pin markers. The assistants heal now audits the FULL accessible server set on every run instead of operator config names only, since assistants reference user-owned servers whose catalogs the definitions loader already resolves; an unavailable audit still skips healing entirely. * 🧬 fix: Verify Upstream Identity for Legacy Keys and Reserve Sibling Raw Names Stripped results now reserve every sibling's raw name even when that sibling itself strips, so a stripped key can never shadow another tool's pre-rollout persisted references within the same snapshot. Every legacy fallback (runtime lookup, event-driven definitions, assistants heal) accepts a stripped-spelling match only when the entry's recorded serverToolName proves the same upstream tool, so a stale key for a removed tool degrades to unavailable instead of calling a different sibling. To keep that identity visible to the heal, assistant tool definitions retain serverToolName and the controllers sanitize entries through toProviderToolDefinition at the provider submission boundary instead. The agent editor migrates pre-strip persisted ids the same identity-verified way, with the upstream name exposed on the MCP tools payload. * 🧭 fix: Heal Wildcard Tool Options and Reserve the OAuth Namespace Wildcard-expanded catalogs rename stripped tools without any agent.tools entry to preserve the spelling, so buildToolClassification now aliases persisted pre-strip tool_options keys onto the current instance names in place, identity-gated on the definition's recorded upstream name and never overriding an explicit entry. Both loading modes flow through it: instances carry mcpServerToolName from createToolInstance and event-driven definitions thread serverToolName from the catalog. stripServerNamePrefix also reserves the entire oauth namespace rather than the exact name, since the client stream handlers classify every oauth-prefixed key as a synthetic authentication call. * 🛡️ fix: Derive the Full Reserved Namespace and Heal Approval Policies The reservation guard now covers every namespace consumers classify by prefix: the wildcard and server-pin markers alongside oauth, plus the server-scoped mcp_ pluginKey namespace that pre-strip keys could never enter. Stripping also never produces a key whose isActionTool classification differs from the raw key's, since a server whose normalized name contains _action_ would otherwise see a real MCP tool routed down the OpenAPI action path past MCP authorization. Admin toolApproval globs written against upstream tool naming keep applying: pattern lists are healed at run wiring with the current names of tools whose pre-strip spelling matches, list-level so deny, ask, and allow precedence is unchanged and a non-matching deny can no longer fail open. The MCP tools wire type also declares serverToolName end to end. * 🪪 fix: Alias Both Key Spellings for Approval Policies and Hook Matchers Identity aliases are now collected once at tool classification, in both directions: a stripped instance aliases its pre-strip spelling and a legacy-named instance aliases its current catalog spelling, with the current name recorded on legacy matches by the runtime lookup and the event-driven definitions loader alike. The aliases ride the agent config through both loading modes, so approval pattern healing applies to deny rules written against either spelling, closing the bypass where a rule targeting the current name missed an unedited agent's legacy instance. Programmatic approval hook matchers get the same treatment: each hook is additionally registered under an anchored exact-name pattern for tools whose other spelling its regex matches, keeping the admin's matcher semantics intact while argument, user, and tenant specific deny or ask decisions keep executing for renamed tools. * 🔁 fix: Alias Tool Options in Both Spelling Directions Options aliasing now consumes the same bidirectional alias pairs as policy healing and hook matchers, so options the editor migrated to the current catalog spelling still reach a legacy-named instance retained by an unedited agent.tools entry. The previous serverToolName-only derivation skipped exactly that case since the legacy key equals the instance name there. * 🤝 fix: Reserve the Agent Handoff Namespace Before Stripping The client renders any lc_transfer_to_ prefixed call as an agent handoff and the background and intent passes exclude such names, so a stripped remainder inside that namespace would misclassify a real upstream tool. It joins the mcp_ pluginKey namespace as a bare-prefix reservation, which pre-strip keys could never enter. * ⚡ fix: Reuse the Loader's Server Snapshot and Index the Editor Catalog getAssistantToolDefinitions now returns the accessible-server snapshot from the same merged registry read that resolved the catalogs, and the heal consumes it instead of repeating the app-config and registry round trips on the assistant write path; without a snapshot the heal still fetches and fails closed as before. The agent editor's id migration uses a memoized tool_id map, so the per-key form heal does constant-time lookups instead of scanning the catalog per option. --------- Co-authored-by: Danny Avila <danny@librechat.ai>
…5095) * fix: Unify MCP request-scoped headers * fix: address request-scoped MCP review findings * test: preserve request scope on status errors * fix: treat authorized on-demand MCP servers as ready * refactor: separate MCP readiness from connection state * fix: preserve on-demand MCP readiness labels * test: satisfy OpenAI conversation ownership guard * fix: keep MCP action predicates boolean * fix: close deferred MCP request context gaps * fix: preserve on-demand MCP configuration actions * fix: fail closed on unavailable MCP parent context * test: complete MCP connecting-state mocks * fix: preserve missing MCP parent on continuations * fix: align native MCP request identities * fix: preserve edited MCP parent identity * test: use scoped Agent initializer fixture * test: expose MCP request body helper * fix: preserve MCP turn identity across resume * style: sort stream metadata imports * fix: carry normalized MCP identity to execution
* 🙋 feat: Collapse Settled Question Records by Default The durable `ask_user_question` record rendered as a permanently open card. Answers are frequently long, multi-paragraph text, so a settled Q&A buried the reply that followed it. It now reads as one collapsed tool-call line — the same `ProgressText` primitive `ToolCall`/`SkillCall` use — naming the question (or the batch count, reusing the keys `ToolCallGroup` already had) and opening on demand under the existing `autoExpandTools` preference. Only the settled record collapses; the live pause and the interim progress card are untouched. The expanded panel was also hard to read. Authored text rendered without `pre-wrap`, so a numbered or paragraphed answer collapsed into one wall; the answer ran on from its inline label; and batch items sat flush against their divider. Line breaks are now content, the answer sits under its own label behind a rule, and dividers have air on both sides. `ProgressText`'s subtitle now truncates and absorbs the flex shrink, so arbitrary authored text ellipsizes instead of pushing the line past the message column — this also fixes long MCP server names on tool cards. * 🩹 fix: Address Codex Round 1 on the Collapsed Question Record - Settle the summary tense. A live, unanswered pause returns before the header, so every state reaching it is settled — an abandoned pause read "Asking" forever, and the collapse hid the "no answer" line that used to qualify it. Past tense unconditionally, matching `ToolCallGroup`. - Move the rejection announcement out of the disclosure. `useExpandCollapse` marks the closed panel `inert`, so the failure explanation's `role="status"` could never reach the accessibility tree; it is now an sr-only status outside the panel, carrying both the label and the explanation. - Count records, not repeated text, in the Bombadil observation. With Auto-expand tool details on, one settled record shows the question in both its summary line and its panel, so the old selector double-counted it and broke the `<= 1` singularity invariant.
* feat: unify subagent activity panel * fix: fence durable activity to selected task * fix: preserve exact panel activity semantics * fix: scope panel identity to parent turn * fix: keep detached readiness status neutral * fix: harden subagent activity invariants * test: support backend TypeScript target * fix: preserve subagent invocation identity * fix: bound subagent activity correlation * fix: drain exact-parent subagent updates
…5047) * perf: warm feature catalogs in the background after first paint Prompt groups and MCP server/tool queries no longer fire on the app startup path. A catalog warmup store releases them after first paint on browser idle, staggered with jitter so a fleet of clients does not burst the API all at once. Panels opened before warmup activates their catalog immediately and fall back to their existing loading states. The prompts list endpoints now also run their independent access lookups in parallel instead of in three serial rounds. * perf: gate MCP icon observers and re-arm warmup across sessions MCP icon/name observers mounted from rendered messages now wait for the warmup gate like every other server-catalog consumer, so conversations with MCP tool calls no longer pull the server list onto the first-render path. The warmup schedule resets on logout so a second login in the same tab warms on its own stagger instead of releasing every catalog at once. Panel mount activations now require a visible sidebar, since a persisted active panel stays mounted while hidden. * perf: void stale warmup callbacks and gate the agent panel tools query Reset now bumps a generation captured by every idle callback and its stagger timer, so callbacks pending across a logout can no longer release catalogs into the next session. The agent form's MCP tools query keeps its own readiness gate so a hidden persisted panel cannot pull the tools request ahead of its stagger once the server list resolves. * perf: reset warmup on Root unmount and honor the insights route collapse Root can unmount in the same render that flips authentication on logout, so the warmup effect now resets from its cleanup as well as the unauthenticated branch. Panel activations mirror UnifiedSidebar's panelExpanded condition, treating the insights route as collapsed instead of reading the raw sidebar atom. * test: re-expand the approval tool card the saved message remounts The helper opened the card once and then waited on its body. Saving the response swaps the placeholder message id for the persisted one, which rekeys every part in the turn: the card remounts collapsed, its body unmounts, and the output assertion waits out its timeout against a disclosure nothing is going to reopen. The redis transport lane pays a round trip per stream event, so its finalization lands late enough to catch the helper mid-assertion. Wait for the closing model turn before expanding anything, then re-open the group and the card on each attempt until the scoped output is on screen. * Update AgentPanelContext.tsx import order --------- Co-authored-by: Danny Avila <danny@librechat.ai>
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 : )