From e090c339a76d43bc8f72ed40d5ce331d1d98937a Mon Sep 17 00:00:00 2001
From: Marco Beretta <81851188+berry-13@users.noreply.github.com>
Date: Wed, 7 Oct 2026 22:47:39 +0200
Subject: [PATCH 1/3] docs: Add Conversation Pull Requests Documentation
---
content/docs/configuration/dotenv.mdx | 46 ++++
.../object_structure/agents.mdx | 129 ++++++++++
.../object_structure/config.mdx | 7 +-
content/docs/features/code_interpreter.mdx | 2 +
content/docs/features/meta.json | 1 +
content/docs/features/pull_requests.mdx | 240 ++++++++++++++++++
lib/icons.tsx | 2 +
7 files changed, 426 insertions(+), 1 deletion(-)
create mode 100644 content/docs/features/pull_requests.mdx
diff --git a/content/docs/configuration/dotenv.mdx b/content/docs/configuration/dotenv.mdx
index cd3c3feec..35c06a71a 100644
--- a/content/docs/configuration/dotenv.mdx
+++ b/content/docs/configuration/dotenv.mdx
@@ -1582,6 +1582,52 @@ Each Agent can scope its stateful workspace to the signed-in user, the user and
Named attached environments can also expose a self-service pairing control plane with `pairing.allowPrincipalWorkers: true`. Authorized users manage those owner-bound workers under **Settings > Code environments**; pairing-only entries do not replace `LIBRECHAT_CODE_BASEURL_STATEFUL` and cannot serve as the deployment default.
+## Conversation Pull Requests
+
+Settings for showing a conversation's GitHub pull request. See [Conversation Pull Requests](/docs/features/pull_requests) and [`endpoints.agents.pullRequests`](/docs/configuration/librechat_yaml/object_structure/agents#pullrequests).
+
+
+ The three fallback token variables are part of LibreChat-AI/LibreChat#16876. In older versions,
+ set the variable that `token: "${NAME}"` refers to.
+
+
+
+
+GitHub requests use the deployment's proxy settings (`PROXY`, `HTTP_PROXY`, `HTTPS_PROXY`, `NO_PROXY`, and their lowercase forms), and `NO_PROXY` is honored. These are shared with other LibreChat outbound traffic and are not specific to this feature.
+
## Artifacts
Artifacts leverage the CodeSandbox library for secure rendering of HTML/JS code. By default, the public CDN hosted by CodeSandbox is used.
diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx
index 0e822337f..1e6df8d66 100644
--- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx
+++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx
@@ -550,6 +550,135 @@ eventDriven:
Event Actor detached Action completion is selected automatically from the built-in generation store. In-memory execution is process-local; Redis generation streams add durable restart recovery and replica handoff. No `librechat.yaml` switch or environment feature flag is required. See [Agent Event Runtime](/docs/configuration/dotenv#agent-event-runtime).
+## pullRequests
+
+{/* Pending items (LibreChat-AI/LibreChat#16876): delete the "Older versions" notes and Pending markers once it merges. Re-verify defaults and ranges against packages/data-provider/src/config.ts. */}
+
+Shows the GitHub pull request for a conversation's attached code workspace in the chat header and sidebar. See [Conversation Pull Requests](/docs/features/pull_requests) for setup, behavior and troubleshooting. Every key is optional.
+
+Most administrators set only a token, a repository scope, and possibly `enabled: false`. The remaining keys are for tuning, and their defaults are fine.
+
+
+ Default-on behavior, the environment variable token fallback, and `allowAllRepositories` are part
+ of LibreChat-AI/LibreChat#16876. In older versions `enabled` defaults to `false` and `token` is
+ required.
+
+
+
+
+
+ With this on, any user who can run code can point the server's token at any repository that token
+ can read, and see the pull request title, size and check status. Use a read-only token scoped to
+ the repositories you are willing to show.
+
+
+```yaml filename="endpoints / agents / pullRequests"
+endpoints:
+ agents:
+ pullRequests:
+ token: '${GITHUB_PULL_REQUEST_TOKEN}'
+ allowedRepositories:
+ - 'LibreChat-AI/LibreChat'
+ - 'my-org/*'
+ cacheTtlSeconds: 30
+ maxConcurrentLookups: 4
+```
+
+On older versions, add `enabled: true`.
+
## backgroundTasks
Controls whether supported completed background tools and detached Subagents automatically resume their saved parent Agent.
diff --git a/content/docs/configuration/librechat_yaml/object_structure/config.mdx b/content/docs/configuration/librechat_yaml/object_structure/config.mdx
index 257f0ec60..15d4d70d0 100644
--- a/content/docs/configuration/librechat_yaml/object_structure/config.mdx
+++ b/content/docs/configuration/librechat_yaml/object_structure/config.mdx
@@ -1497,7 +1497,12 @@ see: [Model Specs Object Structure](/docs/configuration/librechat_yaml/object_st
['azureOpenAI', 'Object', 'Azure OpenAI endpoint-specific configuration', ''],
['assistants', 'Object', 'Assistants endpoint-specific configuration.', ''],
['azureAssistants', 'Object', 'Azure Assistants endpoint-specific configuration.', ''],
- ['agents', 'Object', 'Agents endpoint-specific configuration.', ''],
+ [
+ 'agents',
+ 'Object',
+ 'Agents endpoint-specific configuration, including [`pullRequests`](/docs/configuration/librechat_yaml/object_structure/agents#pullrequests).',
+ '',
+ ],
[
'all',
'Object',
diff --git a/content/docs/features/code_interpreter.mdx b/content/docs/features/code_interpreter.mdx
index ac55ec18b..61f80f5d2 100644
--- a/content/docs/features/code_interpreter.mdx
+++ b/content/docs/features/code_interpreter.mdx
@@ -125,6 +125,8 @@ Agents using an attached workspace can list its directory tree, read files, sear
In the chat, a failed attached-workspace Bash command shows its exit code, terminating signal, or timeout, and its stderr is styled separately from stdout. See [Activity Groups](/docs/features/agents#activity-groups) for how Bash output is displayed.
+To show a conversation's GitHub pull request in the chat header and sidebar, the attached worker must report its git branch. That needs a worker built from `LibreChat-AI/code-interpreter` PR #311 or later and `CODEAPI_BRIDGE_LANE_GIT=true` set on the Code API (not on LibreChat). See [Conversation Pull Requests](/docs/features/pull_requests).
+
An attached worker advertises the workspace roots it makes available. The composer lets the user select one workspace for each attached environment reachable through the Agent or its Subagents; a single unambiguous workspace is selected automatically for a new conversation. LibreChat stores these selections on the conversation, revalidates them against the live worker before execution, and keeps them fixed through approval pauses and resumed runs. Sending is blocked when a required selection is missing or unavailable, and LibreChat never silently substitutes another workspace. At the start of a run, LibreChat can load repository instructions from the selected workspace so the Agent follows that repository's guidance; administrators can bound discovery with [`repositoryInstructions.timeoutMs`](/docs/configuration/librechat_yaml/object_structure/agents#repositoryinstructions). Native file and Bash workspace tools can use an advertised root even when the worker does not support reusable runtime sessions. Workspace-aware Programmatic Bash is available on compatible Code API and worker builds when the Agent's programmatic-tool configuration permits it, the authorized attached worker is ready and advertises `programmaticLanguages: ['bash']`, and both the selected workspace and worker allow `execute_command`. LibreChat passes the server-validated workspace ID and conversation workspace-instance ID, when present, to the programmatic tool; model arguments cannot replace that selection. Without these capabilities, Programmatic Bash is disabled; use direct Bash for workspace-aware commands. When the worker supports file relay, chat uploads are staged separately under `$LIBRECHAT_CODE_DATA_DIR` for the programmatic run, not copied into the selected workspace. **Stop** cancels a signal-aware in-flight BYOM command without invalidating the workspace for later commands; detached work retains its separate cancellation lifecycle.
For an attached execution environment, the Agent Builder can set a **Workspace default** to one currently advertised root. It is validated against that attached environment and used to initialize new conversations for that Agent. Choose **Last used** to use the signed-in user's browser-local preference for that Agent and environment; it is only a convenience hint, never an authorization grant or conversation binding. Changing the execution environment clears an explicit default, and a saved root that is no longer advertised remains visible but cannot be selected until it is reconfigured.
diff --git a/content/docs/features/meta.json b/content/docs/features/meta.json
index 7f98e9c0e..184105df9 100644
--- a/content/docs/features/meta.json
+++ b/content/docs/features/meta.json
@@ -12,6 +12,7 @@
"agents_api",
"artifacts",
"code_interpreter",
+ "pull_requests",
"---Search & Knowledge---",
"web_search",
"search",
diff --git a/content/docs/features/pull_requests.mdx b/content/docs/features/pull_requests.mdx
new file mode 100644
index 000000000..f9271d038
--- /dev/null
+++ b/content/docs/features/pull_requests.mdx
@@ -0,0 +1,240 @@
+---
+title: Conversation Pull Requests
+icon: GitPullRequest
+description: Show the GitHub pull request, size and CI status for chats that run code in an attached workspace.
+---
+
+{/*
+ PUBLISHING GATE. Do not merge this page until LibreChat-AI/LibreChat#16876 (default-on, token
+ fallback, allowAllRepositories) is merged to dev. Until then, only the blocks marked
+ "Pending" are unreleased. After it merges: re-check the schema in
+ packages/data-provider/src/config.ts, delete the "Older versions" blocks and every Pending marker.
+ TODO(maintainer): first release version for each part (do not guess).
+ TODO(maintainer): requirement 4 (where an admin sets the workspace environment's repository).
+ Add it to "Requirements" once confirmed. Do not publish without it.
+*/}
+
+When a chat runs code in an attached workspace, the worker reports the git branch and commit it is on. LibreChat uses that branch to find the matching GitHub pull request, with a token held on the server, and shows it in two places:
+
+- **Chat header**: a chip with the pull request icon and a CI dot. Hovering or focusing it opens a card.
+- **Sidebar conversation list**: the same icon and CI dot at the end of the row. The row keeps the conversation's own title; the pull request title appears only in the card.
+
+## Requirements
+
+All of these must be true for a chat to show a pull request:
+
+1. LibreChat has a GitHub token and a repository scope. See [Setup](#setup).
+2. The chat uses an **attached code workspace** (a code worker), not a plain chat.
+3. The worker reports its branch. This needs a worker built from `LibreChat-AI/code-interpreter` PR #311 or later, and `CODEAPI_BRIDGE_LANE_GIT=true` set on the Code API. See [Code Interpreter](/docs/features/code_interpreter#attached-environments-and-pairing).
+
+If any requirement is missing, chats simply show no pull request. No error is shown to the user.
+
+## Setup
+
+### 1. Create a token
+
+Use a fine-grained GitHub token limited to the repositories you want to show, with **read-only** permissions:
+
+- Pull requests
+- Checks
+- Contents
+
+
+ Without **Checks**, every matched pull request fails to load. Without **Contents**, a chat whose
+ branch has moved on since its last command fails to load.
+
+
+### 2. Give LibreChat the token
+
+
+ Environment variable fallback is part of the default-on change (LibreChat-AI/LibreChat#16876).
+
+
+LibreChat looks for a token in this order:
+
+1. `token: "${MY_VAR}"` in `librechat.yaml`. This is an environment variable **reference**; the YAML never holds the token itself.
+2. If `token` is not set, the first of these environment variables that is set: `GITHUB_PULL_REQUEST_TOKEN`, `GITHUB_TOKEN`, `GH_TOKEN`.
+3. No token anywhere: the feature stays dormant.
+
+A `token` that is set but does not resolve (the variable is empty or missing) fails with `NOT_CONFIGURED`. It does **not** fall back to the three variables above.
+
+
+ If your deployment already uses `GITHUB_TOKEN` for something else, the default-on behavior starts
+ using it here as soon as a repository scope is set. Set `token` explicitly, or use
+ `GITHUB_PULL_REQUEST_TOKEN`, to avoid sharing it.
+
+
+**Older versions:** `token` is required when the feature is enabled, and must be a `${NAME}` reference such as `"${GITHUB_PULL_REQUEST_TOKEN}"`. There is no environment variable fallback.
+
+### 3. Choose which repositories it may look up
+
+The worker reports its own repository, so the server must decide which repositories the token may be used for. Without a scope the feature stays dormant. There are two ways:
+
+- `allowedRepositories`: a list of `owner/name` or `owner/*` entries (up to 256). Matching is case-insensitive. Entries such as `*/*`, `*`, `owner`, or ones containing `..` are rejected by the schema.
+- `allowAllRepositories: true` (**Pending**): look up any repository the token can read. Default is `false`.
+
+
+ With this on, any user who can run code can point the server's token at any repository that token
+ can read, and see the pull request title, size and check status. Use a read-only token scoped to
+ the repositories you are willing to show.
+
+
+### 4. Turn it on
+
+
+ Default-on behavior is part of LibreChat-AI/LibreChat#16876.
+
+
+The feature is on as soon as there is a token and a repository scope. There is no `enabled` switch to set. `enabled: false` turns it off, whatever else is set.
+
+**Older versions:** `enabled: true` is required, and the schema rejects `enabled: true` without both `token` and a non-empty `allowedRepositories`.
+
+### Minimal examples
+
+Default-on form (**Pending**), with `GITHUB_TOKEN` set in the server environment:
+
+```yaml filename="librechat.yaml"
+endpoints:
+ agents:
+ pullRequests:
+ allowAllRepositories: true
+```
+
+Restricted to specific repositories (**Pending**, same token fallback):
+
+```yaml filename="librechat.yaml"
+endpoints:
+ agents:
+ pullRequests:
+ allowedRepositories:
+ - 'LibreChat-AI/LibreChat'
+ - 'my-org/*'
+```
+
+Form that works on older versions:
+
+```yaml filename="librechat.yaml"
+endpoints:
+ agents:
+ pullRequests:
+ enabled: true
+ token: '${GITHUB_PULL_REQUEST_TOKEN}'
+ allowedRepositories: ['LibreChat-AI/LibreChat']
+```
+
+See the [`pullRequests` reference](/docs/configuration/librechat_yaml/object_structure/agents#pullrequests) for every key, including the tuning options.
+
+## What users see
+
+### Chat header chip
+
+- **Desktop**: the chip sits on the left of the header, next to the other left controls. Hovering or focusing it opens the card to its right.
+- **Mobile**: the entry is in the header's overflow (three dots) menu and opens a dialog.
+- The header refreshes on its own: about every 20 seconds while checks are running or mergeability is still being computed, about every 60 seconds otherwise, and not at all once a pull request is merged or closed with no checks running.
+
+### Sidebar mark
+
+- A pull request icon with a CI dot sits at the end of the conversation row. It appears only for conversations that have a pull request.
+- Hover, focus or click opens the same card to the right of the mark. Clicking the mark does not open the conversation.
+- The sidebar never polls. A row is as fresh as the last time the list loaded, and it refreshes when the window regains focus and its data is older than a minute.
+- If a lookup fails, the row shows a warning icon with a retry button in its card, so a failure is not mistaken for "no pull request".
+
+### The card
+
+The card shows `PR #number`, `+additions` in green, `-deletions` in red, a link that opens the pull request on GitHub, the pull request title, and two badges:
+
+- **State**: Open, Draft, Merged or Closed.
+- **Checks**: Passing, Failing, Running, or none.
+
+{/* TODO(docs): add the screenshots from LibreChat PRs #16794 and #16815. */}
+
+### Icon and dot meaning
+
+| Situation | Icon color | CI dot |
+| --------------------------------------- | ------------------------- | ------------------------------------- |
+| Open, no conflicts, checks passing | Green (ready to merge) | Green |
+| Open, no conflicts, no checks at all | Green | None |
+| Open, merge conflicts | Red (cannot merge) | By checks |
+| Draft | Neutral | By checks |
+| Merged or closed | Neutral | None (amber while checks still run) |
+
+CI dot colors: green for passing, red for failing, amber for running, and none when there are no checks or the pull request is finished. A failed check outranks one still running. A rollup with more check runs than were read is never reported as passing.
+
+## How a pull request is matched
+
+1. The worker reports the repository, branch and commit (head) the chat last ran at.
+2. LibreChat lists open pull requests for that branch first, so closed history on a reused branch name cannot hide an open one. Then it checks open pull requests from forks (found through the commit), then closed ones.
+3. With a recorded commit, a pull request counts only if its head is that commit or builds on it. This keeps a deleted and reused branch name from showing an old pull request.
+4. A branch with no commit yet (a new, empty branch) matches nothing.
+5. The result is cached per credential, repository, branch and commit.
+6. Check runs are read for the pull request's current head. For a pull request from a fork, checks are read from the fork only when that fork's repository is in scope (listed, or `allowAllRepositories`). Otherwise the base repository is read and the token never goes to an unlisted fork.
+
+## Behavior
+
+### Rate limits
+
+- A GitHub rate limit applies to the credential, so it pauses lookups for every branch under that token.
+- The minimum pause is 10 seconds. A secondary limit with no wait given waits 60 seconds. A wait that GitHub names is honored, capped at 1 hour.
+- During a pause, lookups answer `RATE_LIMITED` and rows show the retry state.
+
+### Rolling upgrades
+
+- The sidebar asks the batch route only when the startup config says the server has it (`pullRequestsBatchVersion`).
+- If a replica without the route answers 404, the client falls back to the single route, one call at a time, or at `pullRequestsMaxConcurrentLookups` when the server advertised it. A mixed-version deployment is slower on first paint, not broken.
+
+### Defaults when unset
+
+- With no token or no repository scope, the feature is dormant: nothing is advertised in the startup config, nothing is recorded, nothing is shown.
+- With the feature off in the config, existing chats are unchanged and the client never calls the new routes.
+
+## Security model
+
+- The token lives on the server. It is never sent to the browser, and error responses never include GitHub's response text, the token, or stack traces.
+- The token is used only for repositories in scope. It is never sent to a fork that is not in scope.
+- All routes require an authenticated user and are owner-scoped. A conversation that is missing, expired, or belongs to another user looks the same as one with no pull request.
+- Use a read-only, fine-grained token limited to the repositories you are willing to show.
+
+## Troubleshooting
+
+| Symptom | Likely cause | Fix |
+| ------------------------------------------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
+| No chip and no sidebar mark anywhere | No token, no repository scope, or `enabled: false` | Check [Setup](#setup). Open `/api/config` while signed in and look for `pullRequestsEnabled: true`. |
+| Header chip works, sidebar rows show nothing | `pullRequestsBatchVersion` is missing from `/api/config` (old build, or a stale tab) | Rebuild or upgrade the server, restart, and hard reload. Confirm `pullRequestsBatchVersion: 1`. |
+| Chip appears for some chats only | Only chats on an attached code workspace that has reported a branch have a lane | Confirm `CODEAPI_BRIDGE_LANE_GIT=true` on the Code API and a worker built from code-interpreter PR #311 or later. |
+| Warning icon with retry | Lookup failed (rate limit, GitHub error, or `NOT_CONFIGURED`) | Retry. If it is constant, check the token and its permissions. |
+| `NOT_CONFIGURED` | `token` is set but its variable is empty or missing | Set the variable. **Pending:** or remove `token` to use the fallback variables. |
+| Pull requests load but checks look wrong or fail | The token lacks Checks or Contents permission | Grant read-only Checks and Contents. |
+| Pull request from a fork shows no checks | The fork is not in scope, so checks are read from the base repository | Add the fork owner to `allowedRepositories`. **Pending:** or set `allowAllRepositories: true`. |
+| An old pull request shows for a reused branch name | `maxCandidatePullRequests` or `maxCandidatePages` is too low for how often the name is reused | Raise them. |
+| Slow or timing-out lookups behind a proxy | `requestTimeoutSeconds` is too low | Raise it. Check `HTTPS_PROXY` and `NO_PROXY`. |
+
+## API reference
+
+All routes require an authenticated user and are owner-scoped.
+
+### Get one conversation's pull request
+
+`GET /api/convos/:conversationId/pull-request`
+
+- **200**: `{ "pullRequest": null }` or `{ "pullRequest": { number, title, url, additions, deletions, state, isDraft, mergeable, checks } }`.
+- `state` is `open`, `closed` or `merged`. `mergeable` is `clean`, `conflicting` or `unknown`. `checks` is `passing`, `failing`, `running` or `none`.
+- **503**: `{ "error": "...", "code": "NOT_CONFIGURED" | "RATE_LIMITED" | "UPSTREAM_ERROR" }`.
+- **404**: invalid conversation id. **500**: storage error with fixed text.
+
+### Get many conversations' pull requests
+
+`POST /api/convos/pull-requests`
+
+- Body: `{ "conversationIds": ["..."] }`, with 1 to 50 ids. Duplicates collapse. Anything else is a 400.
+- **200**: `{ "results": [ { "conversationId", "pullRequest" } | { "conversationId", "error": { "code" } } ] }`, in the order asked. One failing lookup does not hide the others.
+- A missing token fails only the entries that needed it.
+
+### Startup config
+
+`GET /api/config` includes these fields. The server sets them; they are not settings.
+
+- `pullRequestsEnabled` (boolean)
+- `pullRequestsBatchVersion` (`1`, present only with the feature on)
+- `pullRequestsMaxConcurrentLookups` (number, present only with the feature on)
+
+Only the error codes listed above are stable.
diff --git a/lib/icons.tsx b/lib/icons.tsx
index 71e187c54..047336d10 100644
--- a/lib/icons.tsx
+++ b/lib/icons.tsx
@@ -146,9 +146,11 @@ import {
ListChecks,
UserPlus,
Settings2,
+ GitPullRequest,
} from 'lucide-react'
const icons: Record = {
+ GitPullRequest: ,
Rocket: ,
Sparkles: ,
Monitor: ,
From a15cd1e0fb1565728aab66ba724623eed2fb8456 Mon Sep 17 00:00:00 2001
From: Marco Beretta <81851188+berry-13@users.noreply.github.com>
Date: Thu, 8 Oct 2026 08:48:09 +0200
Subject: [PATCH 2/3] docs: Address Review Findings on Pull Request Docs
---
.../librechat_yaml/object_structure/agents.mdx | 2 +-
.../librechat_yaml/object_structure/config.mdx | 9 +++------
content/docs/features/pull_requests.mdx | 4 ++--
3 files changed, 6 insertions(+), 9 deletions(-)
diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx
index 1e6df8d66..e39923ea8 100644
--- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx
+++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx
@@ -617,7 +617,7 @@ Most administrators set only a token, a repository scope, and possibly `enabled:
[
'batchTimeoutSeconds',
'Number',
- 'Longest one sidebar request stays open (1-120). Entries still waiting then answer with an upstream error, and the row shows nothing until the next refresh. Default: 20.',
+ 'Longest one sidebar request stays open (1-120). Entries still waiting then answer with an upstream error, and their rows show the warning icon with a retry button. Default: 20.',
'batchTimeoutSeconds: 20',
],
[
diff --git a/content/docs/configuration/librechat_yaml/object_structure/config.mdx b/content/docs/configuration/librechat_yaml/object_structure/config.mdx
index 15d4d70d0..fe27838ee 100644
--- a/content/docs/configuration/librechat_yaml/object_structure/config.mdx
+++ b/content/docs/configuration/librechat_yaml/object_structure/config.mdx
@@ -1497,12 +1497,7 @@ see: [Model Specs Object Structure](/docs/configuration/librechat_yaml/object_st
['azureOpenAI', 'Object', 'Azure OpenAI endpoint-specific configuration', ''],
['assistants', 'Object', 'Assistants endpoint-specific configuration.', ''],
['azureAssistants', 'Object', 'Azure Assistants endpoint-specific configuration.', ''],
- [
- 'agents',
- 'Object',
- 'Agents endpoint-specific configuration, including [`pullRequests`](/docs/configuration/librechat_yaml/object_structure/agents#pullrequests).',
- '',
- ],
+ ['agents', 'Object', 'Agents endpoint-specific configuration.', ''],
[
'all',
'Object',
@@ -1520,6 +1515,8 @@ see: [Model Specs Object Structure](/docs/configuration/librechat_yaml/object_st
> **Note:** Endpoints support [Shared Endpoint Settings](/docs/configuration/librechat_yaml/object_structure/shared_endpoint_settings) such as `streamRate`, `headers`, `titleModel`, `titleMethod`, `titlePrompt`, `titlePromptTemplate`, `titleEndpoint`, and `maxToolResultChars`. These can be configured individually per endpoint or globally using the `all` key. `headers` are merged with endpoint-level values winning on key collisions. The `all` key does not accept `baseURL`.
+> **Note:** `endpoints.agents.pullRequests` configures the conversation pull request chip and sidebar mark. See [`pullRequests`](/docs/configuration/librechat_yaml/object_structure/agents#pullrequests).
+
> **Note:** `endpoints.allowedAddresses` applies to user-provided `baseURL` values (when an admin configures a custom endpoint with `apiKey: 'user_provided'` and `baseURL: 'user_provided'`). Each user-supplied baseURL is validated against the SSRF block at request time; entries listed here are exempted. See [`mcpSettings.allowedAddresses`](/docs/configuration/librechat_yaml/object_structure/mcp_settings#allowedaddresses) for the field semantics — same rules apply (private IP space only, port required, no URLs/paths/CIDR/bare hosts/public IP literals).
## mcpSettings
diff --git a/content/docs/features/pull_requests.mdx b/content/docs/features/pull_requests.mdx
index f9271d038..fde343d34 100644
--- a/content/docs/features/pull_requests.mdx
+++ b/content/docs/features/pull_requests.mdx
@@ -158,7 +158,7 @@ The card shows `PR #number`, `+additions` in green, `-deletions` in red, a link
| Draft | Neutral | By checks |
| Merged or closed | Neutral | None (amber while checks still run) |
-CI dot colors: green for passing, red for failing, amber for running, and none when there are no checks or the pull request is finished. A failed check outranks one still running. A rollup with more check runs than were read is never reported as passing.
+CI dot colors: green for passing, red for failing, amber for running, and none when there are no checks, or when the pull request is merged or closed and no checks are still running. A failed check outranks one still running. A rollup with more check runs than were read is never reported as passing.
## How a pull request is matched
@@ -180,7 +180,7 @@ CI dot colors: green for passing, red for failing, amber for running, and none w
### Rolling upgrades
- The sidebar asks the batch route only when the startup config says the server has it (`pullRequestsBatchVersion`).
-- If a replica without the route answers 404, the client falls back to the single route, one call at a time, or at `pullRequestsMaxConcurrentLookups` when the server advertised it. A mixed-version deployment is slower on first paint, not broken.
+- If a replica without the route answers 404, the client falls back to the single route, one call at a time, or at `pullRequestsMaxConcurrentLookups` when the server advertised it. This covers a client that received the new startup flag from an upgraded replica and then reached a replica without the route. If `/api/config` is served by a replica without the flag, the sidebar never asks the batch route and rows stay empty, so upgrade every replica before relying on sidebar marks.
### Defaults when unset
From e06af27038b6e53f2dbd406f4cec7df66ee7a06d Mon Sep 17 00:00:00 2001
From: Marco Beretta <81851188+berry-13@users.noreply.github.com>
Date: Thu, 8 Oct 2026 09:03:42 +0200
Subject: [PATCH 3/3] docs: Correct Pull Request Docs Error, Auth and Limits
Wording
---
content/docs/features/pull_requests.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/content/docs/features/pull_requests.mdx b/content/docs/features/pull_requests.mdx
index fde343d34..9d21570d8 100644
--- a/content/docs/features/pull_requests.mdx
+++ b/content/docs/features/pull_requests.mdx
@@ -27,7 +27,7 @@ All of these must be true for a chat to show a pull request:
2. The chat uses an **attached code workspace** (a code worker), not a plain chat.
3. The worker reports its branch. This needs a worker built from `LibreChat-AI/code-interpreter` PR #311 or later, and `CODEAPI_BRIDGE_LANE_GIT=true` set on the Code API. See [Code Interpreter](/docs/features/code_interpreter#attached-environments-and-pairing).
-If any requirement is missing, chats simply show no pull request. No error is shown to the user.
+If a requirement is missing, chats simply show no pull request and no error is shown to the user. The exception is a `token` that is set but whose environment variable is empty or missing: lookups then fail with `NOT_CONFIGURED`, and sidebar rows show the warning icon with a retry button.
## Setup
@@ -191,7 +191,7 @@ CI dot colors: green for passing, red for failing, amber for running, and none w
- The token lives on the server. It is never sent to the browser, and error responses never include GitHub's response text, the token, or stack traces.
- The token is used only for repositories in scope. It is never sent to a fork that is not in scope.
-- All routes require an authenticated user and are owner-scoped. A conversation that is missing, expired, or belongs to another user looks the same as one with no pull request.
+- The two `/api/convos` lookup routes require an authenticated user and are owner-scoped. A conversation that is missing, expired, or belongs to another user looks the same as one with no pull request.
- Use a read-only, fine-grained token limited to the repositories you are willing to show.
## Troubleshooting
@@ -205,12 +205,12 @@ CI dot colors: green for passing, red for failing, amber for running, and none w
| `NOT_CONFIGURED` | `token` is set but its variable is empty or missing | Set the variable. **Pending:** or remove `token` to use the fallback variables. |
| Pull requests load but checks look wrong or fail | The token lacks Checks or Contents permission | Grant read-only Checks and Contents. |
| Pull request from a fork shows no checks | The fork is not in scope, so checks are read from the base repository | Add the fork owner to `allowedRepositories`. **Pending:** or set `allowAllRepositories: true`. |
-| An old pull request shows for a reused branch name | `maxCandidatePullRequests` or `maxCandidatePages` is too low for how often the name is reused | Raise them. |
+| No pull request for a branch name that has been reused many times | `maxCandidatePullRequests`, `maxCandidatePages` or `maxHeadComparisons` is too low for how often the name is reused, so the search stops before it reaches the matching pull request | Raise them. |
| Slow or timing-out lookups behind a proxy | `requestTimeoutSeconds` is too low | Raise it. Check `HTTPS_PROXY` and `NO_PROXY`. |
## API reference
-All routes require an authenticated user and are owner-scoped.
+Both `/api/convos` routes below require an authenticated user and are owner-scoped. The startup config endpoint is not owner-scoped.
### Get one conversation's pull request