From bacd1655a471fccd06f637dec525d943ead4ab10 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 21 Oct 2026 16:59:18 -0700 Subject: [PATCH 01/30] =?UTF-8?q?=F0=9F=93=98=20docs:=20Document=20Backgro?= =?UTF-8?q?und=20Responses=20and=20Agent=20Channels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../object_structure/agents.mdx | 34 ++++++ content/docs/features/agent_channels.mdx | 92 ++++++++++++++++ content/docs/features/agents_api.mdx | 2 + .../docs/features/background_responses.mdx | 100 ++++++++++++++++++ content/docs/features/meta.json | 2 + 5 files changed, 230 insertions(+) create mode 100644 content/docs/features/agent_channels.mdx create mode 100644 content/docs/features/background_responses.mdx diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index 4dc7e1fd0..8af813528 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1497,10 +1497,44 @@ Tokens must be unexpired and present a single, non-conflicting client identifier Unknown management-auth fields, duplicate client IDs, malformed user or tenant IDs, and enabled authentication without a client binding fail configuration validation. See [Agents API - Agent Management](/docs/features/agents_api#agent-management-api) for routes and examples. +## channels + +Configures the opt-in [Agent Channels integration](/docs/features/agent_channels). A compatible external gateway and enabled background Responses are required; this setting does not deploy a gateway or enable execution permissions. + +| Option | Default | Accepted values / purpose | +| --- | --- | --- | +| `enabled` | `false` | Enable channel setup and service routes | +| `transport` | `socket_mode` | `socket_mode` or `webhook`; integration metadata, not a receiver deployment | +| `gatewayUrl` | Omitted | Optional gateway URL advertised in setup metadata | +| `ticketLifetimeMs` | `600000` | Link ticket lifetime, `60000`–`3600000` ms | +| `linkLifetimeMs` | `2592000000` | Accepted link lifetime, `60000`–`7776000000` ms | +| `leaseMs` | `60000` | Run lease, `10000`–`300000` ms | +| `responseCredentialLifetimeMs` | `86400000` | Bound execution credential lifetime, `60000`–`604800000` ms | +| `artifactMaxBytes` | `10485760` | Per-artifact limit, `1`–`52428800` bytes | +| `artifactMaxFiles` | `5` | Artifacts per run, `1`–`20` | +| `artifactReadTimeoutMs` | `30000` | Read timeout, `1000`–`60000` ms | + +`cleanup` accepts `batchSize` (`25`, range `1`–`100`), `intervalMs` (`1000`, range `1000`–`60000`), and `maxIdleIntervalMs` (`30000`, range `1000`–`300000`). + +`feedback` accepts `maxConflictRetries` (`5`, range `1`–`20`), `exportTimeoutMs` (`10000`, range `1000`–`60000`), `exportLeaseMs` (`60000`, range `60000`–`300000`), `exportRetryMs` (`5000`, range `1000`–`300000`), and the same `batchSize`, `intervalMs`, and `maxIdleIntervalMs` defaults/ranges as `cleanup`. + +The gateway service boundary requires the server-side `CHANNEL_SERVICE_TOKEN`. Do not expose it to browsers or use it as a general Agent execution credential. Channel credential mode (`shared` or `per_user`) belongs to the channel record, not this deployment block. Both modes require explicit current actor linking; `shared` restricts linking to the channel creator's account rather than granting all external participants that account's privileges. + ## remoteApi Configuration for Remote Agent API authentication. Controls how external services authenticate when calling the Agents API endpoints. +### remoteApi.background + +Enables the opt-in [background Responses lifecycle](/docs/features/background_responses). It does not enable Remote Agents permissions or human approval by itself. + +| Option | Type | Default | Meaning | +| --- | --- | --- | --- | +| `enabled` | Boolean | `false` | Accept durable background Responses requests | +| `acknowledgementTimeoutMs` | Integer | `10000` | Worker admission acknowledgement timeout, from `100` through `60000` ms; not the model run timeout | + +Background requests require an Agent API key, stored responses, and non-streaming submission. Human-action resume requires durable MongoDB checkpoints and the corresponding existing approval/question policy. Set `DOMAIN_CLIENT` to the trusted public owner-review URL origin. + ### remoteApi.auth +Agent Channels require the matching channel runtime, feedback, HTTP, setup UI, and background Responses changes. They are disabled by default. A compatible Slack gateway is also required; this guide does not provide an installable gateway package or container. + + +Agent Channels connect external messaging events to [background Agent Responses](/docs/features/background_responses). Channel routes manage identity, admission, leases, delivery receipts, artifacts, and feedback. They are **not an alternative model-execution endpoint**: a compatible gateway submits execution through `/api/agents/v1/responses` using a server-provisioned, bound credential. + +## Configuration and prerequisites + +```yaml filename="endpoints / agents" +endpoints: + agents: + remoteApi: + background: + enabled: true + channels: + enabled: true + transport: socket_mode +``` + +Both enablement settings default to `false`. Existing Remote Agents permissions must also permit the relevant users to use the Agent API, and channel setup requires Agent sharing permission. Configure `DOMAIN_CLIENT` for trusted owner-review and account-link URLs. Configure a strong `CHANNEL_SERVICE_TOKEN` for the gateway-to-LibreChat service boundary; keep it server-side and distribute it only to a trusted integration process over a secure channel. It is not a browser token or a general Agent API key. + +The `transport` option accepts `socket_mode` (default) or `webhook`. This selects integration metadata; it does not deploy a receiver or create a public webhook automatically. `gatewayUrl` is an optional URL advertised by setup metadata. Deploy and secure a compatible gateway separately, with its own Slack transport configuration, event authenticity validation, and bot/app credentials. + +See the [channel configuration reference](/docs/configuration/librechat_yaml/object_structure/agents#channels) for limits and defaults. + +## Set up a channel + +1. Open the Agent's channel setup surface with an authorized LibreChat account. +2. Create a Slack channel configuration and explicitly choose `shared` or `per_user` credential mode. +3. Use the generated Slack manifest with your Slack app. Configure the gateway's chosen Slack transport separately; a manifest alone is not a running integration. +4. Activate the configuration with the matching Slack app ID and bot token. Supply the Slack signing secret when the chosen integration requires signature verification. LibreChat verifies the bot identity and stores credentials encrypted; normal setup responses do not return those secrets. +5. Complete account linking for the external actor. Send a test event only after the channel is active, the actor is linked, and the gateway is configured. + +Browser setup routes live under `/api/agents/{agentId}/channels`: list/create, read `/{channelId}/manifest`, update `/{channelId}`, and delete `/{channelId}`. These use authenticated Agent authorization, not the management API machine-token contract. The create body is `{ "type": "slack", "credentialMode": "per_user" }` (or `shared`). Activation updates use a `slack` object with `appId`, `botToken`, and optional `signingSecret`. To disable a channel, update its status to `disabled`. + +### Shared versus per-user credentials + +`per_user` binds each linked Slack actor to that actor's existing LibreChat account. Current tenant membership, account state, role capabilities, Agent permissions, and tool/provider credentials are evaluated for that user. + +`shared` does **not** make the Agent public to every Slack participant. Linking is restricted to the channel creator's LibreChat account; execution uses that explicitly linked principal's authority. Do not treat the activator's API key, a Slack display name, an email assertion, or another participant's thread history as consent for a new actor. + +Each actor/link revision has its own execution lane. Sharing a Slack thread does not share a LibreChat conversation or expose another actor's files, OAuth state, approvals, usage, or trace session. A different actor cannot inherit the first participant's pending question or approve its tool call. Mode/revision changes, unlinking, account removal, Agent access revocation, and key revocation invalidate old authority rather than silently remapping it. + +### Account linking + +The gateway can request an actor-bound, short-lived linking ticket. The user opens the trusted LibreChat URL, signs in, previews the request, and explicitly accepts it. A gateway then confirms the same ticket/actor binding; it must not infer linkage from a returned browser URL alone. + +Browser endpoints under `/api/channels/links` support preview, acceptance, listing, and revocation. Mutations require the normal authenticated browser and same-origin checks. Ticket lifetime defaults to 10 minutes; accepted links default to 30 days. Never post a bearer credential or provider OAuth URL into Slack. + +## Gateway protocol boundary + +Service requests use `Authorization: Bearer ` and the exact tenant/channel context. For routes without a tenant path parameter, send the channel's exact tenant in `x-tenant-id`; do not choose a tenant from untrusted message text. The service token permits this integration boundary, not arbitrary user impersonation. Never put it in client-side code, Slack messages, tracing payloads, or public logs. The credential bundle endpoint returns secrets to the trusted gateway and must not be exposed as a public discovery API. + +| Stage | Route under `/api/channels` | Responsibility | +| --- | --- | --- | +| Configuration | `GET /service/slack/{tenantId}/{channelId}` | Read the active channel and encrypted-at-rest credentials through an authenticated service boundary | +| Identity | `/service/{channelId}/identity/{externalUserId}` and its ticket/confirm operations | Resolve explicit actor linking; never infer a principal from thread history | +| Admission | `POST /service/{channelId}/runs` | Admit an idempotent event with verified team/app/actor identity | +| Ownership | `POST /service/{channelId}/runs/claim`, then `/{runId}/renew` | Claim and renew the exact run lease | +| Execution preparation | `POST /service/{channelId}/runs/{runId}/response/prepare` | Obtain the bound execution credential, request, and stable request key | +| Response binding | `POST /service/{channelId}/runs/{runId}/response/bind` | Bind the returned Responses identity to the admitted run | +| Progress and result | `/{runId}/advance`, `/{runId}/progress/*`, `/{runId}/plan`, `/{runId}/delivery/*`, `/{runId}/commit` | Project canonical state and record fenced delivery effects | +| Review projection | `POST /service/{channelId}/runs/{runId}/review` | Obtain the safe owner-review projection, not private approval/OAuth payloads | +| Artifacts | `POST /service/{channelId}/runs/{runId}/artifacts/{artifactId}` | Read only an artifact bound to the authorized run | +| Stop | `POST /service/{channelId}/runs/stop-thread` or `/{runId}/cancel` | Cancel only the authorized actor lane/run | +| Feedback | `POST /service/{channelId}/reactions` | Apply authenticated, deduplicated reaction events to confirmed delivered replies | + +Run-relative paths in the table are beneath `/service/{channelId}/runs`. Lease mutations carry the exact server-issued `{ runId, owner, epoch }` fence. Treat stale leases, changed authority, and ambiguous delivery outcomes as protocol states to reconcile, not permission to mint a new run or blindly resend a Slack message. + +Execution preparation returns an `apiKey`, `requestKey`, optional retained `responseId`, and a Responses `request` with the Agent ID, admitted input, `background: true`, `store: true`, and any authorized continuation. Submit that request to `/api/agents/v1/responses` using the bound key and `Idempotency-Key: `, then bind the returned response ID. Do not substitute a creator's unrestricted key, change the actor/Agent, or send the input to a channel bookkeeping route to execute it. + +The gateway owns Slack event verification, retry/deduplication, native message formatting, rate-limit handling, and delivery receipt reconciliation. Preserve exact event identifiers and timestamps. For feedback events, `eventTimestampUs` is an integer timestamp in microseconds; do not round it to milliseconds. Report confirmed, failed, or ambiguous side effects accurately before advancing delivery state. + +## Review, files, feedback, and privacy + +Only the owner-review link is projected for human actions. Private tool arguments, question payloads, and provider OAuth authorization URLs stay in the authenticated browser review view. The owner completes approval, question, or OAuth actions through the [background Responses lifecycle](/docs/features/background_responses#review-a-required-action). + +Artifacts are scoped to the authorized run and actor. Limits default to five files and 10 MiB per file, with a 30-second read timeout. Do not replace an unavailable artifact with another actor's file or an unauthenticated internal download URL. Usage and cost summaries identify incomplete or unavailable coverage instead of presenting a partial subtotal as the complete thread total. + +Reaction feedback maps only to confirmed delivered assistant messages. It does not overwrite the browser's feedback field. Export is constrained by recorded sampling/destination provenance and current export policy. Temporary-chat provenance is retained; an old mapping without that provenance is not treated as a permanent chat. A policy change can suppress export even when the original trace was sampled. + +## Operational limits + +Disabling a channel or changing its credential mode retires old authority; it does not undo external tool effects. Stop can remain pending until the exact provider is drained and canonical cancellation/cleanup completes. A gateway must poll/reconcile canonical state rather than interpreting an acknowledgement as terminal completion. + +This contract does not promise a public gateway distribution, arbitrary chat-platform support, automatic migration of legacy thread-wide identity, or restart-survival of an in-memory OAuth waiter. Legacy thread read/write bookkeeping is not a substitute for actor-scoped runs. diff --git a/content/docs/features/agents_api.mdx b/content/docs/features/agents_api.mdx index 5289b5cfc..e666f0fee 100644 --- a/content/docs/features/agents_api.mdx +++ b/content/docs/features/agents_api.mdx @@ -16,6 +16,8 @@ There are three parts: Endpoints, request formats, and responses may still change between releases. +For opt-in asynchronous execution, retained human actions, owner review, and Stop, see [Background Agent Responses](/docs/features/background_responses). [Agent Channels](/docs/features/agent_channels) use that same Responses execution path while managing external identity and delivery separately. + ## Get an API key Open **Settings**, go to **Data & Privacy**, and find **Agent API Keys** under **API keys**. Click **Manage**, then **Create API Key**, give it a name, pick an expiration (7 days up to 1 year, or never), and copy the key right away: it is shown only once. diff --git a/content/docs/features/background_responses.mdx b/content/docs/features/background_responses.mdx new file mode 100644 index 000000000..1de1e920e --- /dev/null +++ b/content/docs/features/background_responses.mdx @@ -0,0 +1,100 @@ +--- +title: Background Agent Responses +description: Run durable Agent Responses, review pending actions, and stop an owned execution +icon: Workflow +--- + + +These interfaces require a LibreChat version that includes the background Responses runtime and HTTP lifecycle routes. Background execution is disabled by default. Deploy all prerequisite runtime, storage, and route changes before enabling it. + + +Background Responses use the existing [Agents API](/docs/features/agents_api), not a separate model execution engine. A request returns a stored response identity while a worker executes the Agent. Clients poll that identity for output, required actions, and the canonical terminal result. + +## Enable background execution + +Merge this block into your existing configuration: + +```yaml filename="endpoints / agents" +endpoints: + agents: + remoteApi: + background: + enabled: true + acknowledgementTimeoutMs: 10000 +``` + +`enabled` defaults to `false`. `acknowledgementTimeoutMs` defaults to `10000` and accepts integers from `100` through `60000`; it bounds the worker admission acknowledgement, not total model execution time. Existing Remote Agents permissions, Agent access, terms acceptance, content checks, and provider/tool policies still apply. + +Background submission requires an **Agent API key**, including when ordinary inference also accepts OIDC. A management API machine token is not an execution credential. Configure [Remote Agents permissions](/docs/features/agents_api#enabling-the-agents-api) separately. + +Human tool approval and Ask User pauses require durable MongoDB checkpoint storage. Use the existing [`toolApproval`](/docs/configuration/librechat_yaml/object_structure/agents#toolapproval), Ask User, and [`checkpointer`](/docs/configuration/librechat_yaml/object_structure/agents#checkpointer) settings; background execution does not automatically enable approval or bypass a deny rule. A memory checkpointer does not provide durable background human-action resume. Ordinary requests without a human pause retain their normal execution path. + +Set `DOMAIN_CLIENT` to the trusted public browser URL so generated review links point to your deployment. Do not construct review destinations from incoming Host headers. + +## Submit and poll + +```bash +curl https://chat.example.com/api/agents/v1/responses \ + -H 'Authorization: Bearer YOUR_AGENT_API_KEY' \ + -H 'Content-Type: application/json' \ + -H 'Idempotency-Key: report-request-001' \ + -d '{"model":"AGENT_ID","input":"Summarize the latest report.","background":true,"store":true}' +``` + +Accepted background requests return HTTP `202` with a response object. `background: true` requires storage: omit `store` or set it to `true`. `store: false` and `stream: true` are rejected for background requests. Ordinary synchronous and streaming Responses remain separate supported modes when `background` is omitted or false. + +Use a stable `Idempotency-Key` for retries of the same logical submission. The optional key must be nonblank and at most 256 characters; do not reuse it for a different request. If omitted, the server creates a new request identity, so an ambiguous network retry can create another request. + +```bash +curl https://chat.example.com/api/agents/v1/responses/RESPONSE_ID \ + -H 'Authorization: Bearer YOUR_AGENT_API_KEY' +``` + +Poll the same response until its public status is `completed`, `failed`, `incomplete`, or `cancelled`. `queued` and `in_progress` are not terminal. The server rechecks the original source key and current authority; possession of a response ID is not permission to read or resume it. Use the returned response ID as `previous_response_id` for a subsequent supported continuation rather than resending the original user input. + +## Review a required action + +A public response can include: + +```json +{ + "status": "in_progress", + "required_action": { + "type": "librechat_review", + "kind": "tool_approval", + "action_id": "ACTION_ID", + "expires_at": 1800000000, + "review_url": "https://chat.example.com/responses/RESPONSE_ID/review" + } +} +``` + +`kind` is `tool_approval`, `question`, or `oauth`. `expires_at` is Unix time in seconds. Treat the action as actionable only while it is present and unexpired. The public projection intentionally omits private approval payloads and provider OAuth URLs. Do not infer that public `in_progress` means a provider is currently running: it also covers a retained action waiting for its owner. + +Open `review_url` in a browser and sign in as the response owner in the correct tenant. The owner can inspect the exact pending tool call, answer a question, or continue an MCP OAuth flow. An unrelated account cannot approve a request just because it can access the same Agent. + +The browser lifecycle uses session authentication, not an Agent API key or a management token: + +| Method | Route | Purpose | +| --- | --- | --- | +| `GET` | `/api/agents/responses/{id}/review` | Read the owner-only review view | +| `POST` | `/api/agents/responses/{id}/review` | Submit the current action decision | +| `POST` | `/api/agents/responses/{id}/cancel` | Request Stop for an owned response | + +Decision submissions include the exact current `actionId` and the payload appropriate to that action. Question submissions use `answer`, or `answers` keyed by the presented question identities. Tool approval submissions use `decisions` containing the exact `tool_call_id` and an allowed `decision` (`approve`, `reject`, `edit`, or `respond`), with the corresponding edited arguments or response text when needed. Use the supplied review UI to respect action-specific validation and offered scopes; an enum value in a transport schema is not a grant to choose an unavailable approval scope. + +A successful decision returns HTTP `202` with `responseId`, `actionId`, `intentId`, and `status` (`queued` or `settled`). This is an acknowledgement, not proof that execution completed. Refresh the canonical review/response state. Do not automatically resubmit an ambiguous decision with a different intent or replay a stale action after a conflict. Resume revalidates current Agent/model/tool/project/file authority and retained execution provenance before privileged work. + +## OAuth recovery limits + +MCP OAuth prompts are retained for owner-only replay until their deadline. Complete authorization through the supplied provider flow; do not submit an approval decision to replace an OAuth callback. A successful callback can continue the same waiting execution while its waiter is still active. + +Durable prompt visibility is not a guarantee that an in-memory OAuth waiter survives a server restart. Durable human question/tool-approval checkpoints and OAuth authorization waiters are different mechanisms. If the OAuth attempt expired or its waiting execution was lost, use the current failure/retry state; do not keep replaying an old authorization URL or assume authorization alone restarted the model. See [MCP authentication](/docs/features/mcp#oauth-authentication). + +## Stop and recovery + +API-key clients can request cancellation with `POST /api/agents/v1/responses/{id}/cancel`. Owners can use **Stop** in the review UI. Both paths operate on the same durable response; neither starts a replacement execution. + +A cancellation acknowledgement may still report a nonterminal status while provider drain, checkpoint cleanup, or terminal publication is pending. Continue polling until canonical `cancelled` (or another terminal result already won the race). Stop is not rollback: tools may already have performed external effects. Do not repeat an external operation merely because its answer was cancelled. + +Revoked source keys, changed channel/account bindings, missing authority, stale checkpoint identities, and changed privileged code targets fail closed. Temporary storage outages can delay terminal publication and cleanup; do not force-delete execution proof or manually replay tools to make the status change. diff --git a/content/docs/features/meta.json b/content/docs/features/meta.json index 184105df9..d13ce9856 100644 --- a/content/docs/features/meta.json +++ b/content/docs/features/meta.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", From 3b76ab53cf20aca1864c2f5985e659da37513545 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 28 Oct 2026 23:59:10 +0100 Subject: [PATCH 02/30] =?UTF-8?q?=F0=9F=93=98=20docs:=20Describe=20Native?= =?UTF-8?q?=20Channel=20Review=20and=20Safe=20Recovery?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/docs/features/agent_channels.mdx | 7 +++++-- content/docs/features/background_responses.mdx | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index e55946296..8b7ccbe7b 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -66,7 +66,8 @@ Service requests use `Authorization: Bearer ` and the exa | Execution preparation | `POST /service/{channelId}/runs/{runId}/response/prepare` | Obtain the bound execution credential, request, and stable request key | | Response binding | `POST /service/{channelId}/runs/{runId}/response/bind` | Bind the returned Responses identity to the admitted run | | Progress and result | `/{runId}/advance`, `/{runId}/progress/*`, `/{runId}/plan`, `/{runId}/delivery/*`, `/{runId}/commit` | Project canonical state and record fenced delivery effects | -| Review projection | `POST /service/{channelId}/runs/{runId}/review` | Obtain the safe owner-review projection, not private approval/OAuth payloads | +| Review projection | `POST /service/{channelId}/runs/{runId}/review` | Reauthorize the original actor; obtain the browser fallback and, for the exact external channel, the current private question/tool-review payload | +| Review decision | `POST /service/{channelId}/runs/{runId}/review/decision` | Submit the current actor's decision to the same canonical Response, using its immutable decision receipt and resume preflight | | Artifacts | `POST /service/{channelId}/runs/{runId}/artifacts/{artifactId}` | Read only an artifact bound to the authorized run | | Stop | `POST /service/{channelId}/runs/stop-thread` or `/{runId}/cancel` | Cancel only the authorized actor lane/run | | Feedback | `POST /service/{channelId}/reactions` | Apply authenticated, deduplicated reaction events to confirmed delivered replies | @@ -79,7 +80,9 @@ The gateway owns Slack event verification, retry/deduplication, native message f ## Review, files, feedback, and privacy -Only the owner-review link is projected for human actions. Private tool arguments, question payloads, and provider OAuth authorization URLs stay in the authenticated browser review view. The owner completes approval, question, or OAuth actions through the [background Responses lifecycle](/docs/features/background_responses#review-a-required-action). +The public run snapshot contains only an opaque action descriptor. A review request with the original verified actor, current channel revision, and exact `externalChannelId` can obtain minimal private question/tool-approval details. The backend derives the owner and Response from the run and checks the current actor link and source grant; it does not accept an arbitrary user ID. The gateway must show these details only to that actor, not publicly in a shared thread. Slack can use ephemeral choice buttons and private modals. Native tool approval is for the individual call only; unsupported/richer forms retain the browser fallback. + +Decision requests include that same actor, revision, external channel, and the existing Responses `decision` body. Backend decision receipts, expiry/conflict checks, full authorization preflight, and same-Response resume remain authoritative. A Slack click alone is not permission to resume work. Provider OAuth URLs remain exclusively in the authenticated browser review flow. See the [background Responses lifecycle](/docs/features/background_responses#review-a-required-action). Artifacts are scoped to the authorized run and actor. Limits default to five files and 10 MiB per file, with a 30-second read timeout. Do not replace an unavailable artifact with another actor's file or an unauthenticated internal download URL. Usage and cost summaries identify incomplete or unavailable coverage instead of presenting a partial subtotal as the complete thread total. diff --git a/content/docs/features/background_responses.mdx b/content/docs/features/background_responses.mdx index 1de1e920e..97c7dcebb 100644 --- a/content/docs/features/background_responses.mdx +++ b/content/docs/features/background_responses.mdx @@ -89,7 +89,7 @@ A successful decision returns HTTP `202` with `responseId`, `actionId`, `intentI MCP OAuth prompts are retained for owner-only replay until their deadline. Complete authorization through the supplied provider flow; do not submit an approval decision to replace an OAuth callback. A successful callback can continue the same waiting execution while its waiter is still active. -Durable prompt visibility is not a guarantee that an in-memory OAuth waiter survives a server restart. Durable human question/tool-approval checkpoints and OAuth authorization waiters are different mechanisms. If the OAuth attempt expired or its waiting execution was lost, use the current failure/retry state; do not keep replaying an old authorization URL or assume authorization alone restarted the model. See [MCP authentication](/docs/features/mcp#oauth-authentication). +Durable prompt visibility is not a guarantee that an in-memory OAuth waiter survives a server restart. Durable human question/tool-approval checkpoints and OAuth authorization waiters are different mechanisms. If exact execution state is missing or mismatched, the response reports nonterminal `recovery: "execution_state_unavailable"` and removes stale actionable prompts. This is not proof of completion or cancellation and does not replay work. Sign-in credentials may have been saved even though the original run did not continue. Check external results before retrying; an administrator must reconcile a persistently unknown execution before the held run can safely be cleared. Do not replay an old authorization URL or infer that sign-in restarted the model. See [MCP authentication](/docs/features/mcp#oauth-authentication). ## Stop and recovery From 8c1f3cab575babcd8f1c8cd2f70e6824552c64be Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 29 Oct 2026 02:59:37 +0100 Subject: [PATCH 03/30] docs: Explain Fenced Polling Yield and Private Decision Receipts --- content/docs/features/agent_channels.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 8b7ccbe7b..6f1de3c47 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -62,7 +62,7 @@ Service requests use `Authorization: Bearer ` and the exa | Configuration | `GET /service/slack/{tenantId}/{channelId}` | Read the active channel and encrypted-at-rest credentials through an authenticated service boundary | | Identity | `/service/{channelId}/identity/{externalUserId}` and its ticket/confirm operations | Resolve explicit actor linking; never infer a principal from thread history | | Admission | `POST /service/{channelId}/runs` | Admit an idempotent event with verified team/app/actor identity | -| Ownership | `POST /service/{channelId}/runs/claim`, then `/{runId}/renew` | Claim and renew the exact run lease | +| Ownership | `POST /service/{channelId}/runs/claim`, then `/{runId}/renew` or `/{runId}/yield` | Claim, renew, or safely yield the exact polling lease | | Execution preparation | `POST /service/{channelId}/runs/{runId}/response/prepare` | Obtain the bound execution credential, request, and stable request key | | Response binding | `POST /service/{channelId}/runs/{runId}/response/bind` | Bind the returned Responses identity to the admitted run | | Progress and result | `/{runId}/advance`, `/{runId}/progress/*`, `/{runId}/plan`, `/{runId}/delivery/*`, `/{runId}/commit` | Project canonical state and record fenced delivery effects | @@ -74,6 +74,8 @@ Service requests use `Authorization: Bearer ` and the exa Run-relative paths in the table are beneath `/service/{channelId}/runs`. Lease mutations carry the exact server-issued `{ runId, owner, epoch }` fence. Treat stale leases, changed authority, and ambiguous delivery outcomes as protocol states to reconcile, not permission to mint a new run or blindly resend a Slack message. +A gateway can yield a Responses-bound polling turn only after its progress writes and renewal loop have drained. The backend invalidates that polling fence and enforces a one-second reclaim cooldown; the next claim increments the epoch. This does not release the actor lane, cancel the provider, change the Response, or erase delivery evidence. Inflight or unknown remote writes cannot yield. If a host does not support yield or the request is uncertain, retain ordinary lease-expiry recovery instead of starting a new execution. + Execution preparation returns an `apiKey`, `requestKey`, optional retained `responseId`, and a Responses `request` with the Agent ID, admitted input, `background: true`, `store: true`, and any authorized continuation. Submit that request to `/api/agents/v1/responses` using the bound key and `Idempotency-Key: `, then bind the returned response ID. Do not substitute a creator's unrestricted key, change the actor/Agent, or send the input to a channel bookkeeping route to execute it. The gateway owns Slack event verification, retry/deduplication, native message formatting, rate-limit handling, and delivery receipt reconciliation. Preserve exact event identifiers and timestamps. For feedback events, `eventTimestampUs` is an integer timestamp in microseconds; do not round it to milliseconds. Report confirmed, failed, or ambiguous side effects accurately before advancing delivery state. @@ -84,6 +86,8 @@ The public run snapshot contains only an opaque action descriptor. A review requ Decision requests include that same actor, revision, external channel, and the existing Responses `decision` body. Backend decision receipts, expiry/conflict checks, full authorization preflight, and same-Response resume remain authoritative. A Slack click alone is not permission to resume work. Provider OAuth URLs remain exclusively in the authenticated browser review flow. See the [background Responses lifecycle](/docs/features/background_responses#review-a-required-action). +An actor-private receipt can confirm that a question answer or per-call tool approval/decline was accepted without disclosing tool arguments or claiming completion. A saved decision whose queue publication failed must remain retryable with the exact immutable decision; it cannot be replaced by a different answer. Keep Stop available while work remains active and update public progress only through the fenced delivery protocol. + Artifacts are scoped to the authorized run and actor. Limits default to five files and 10 MiB per file, with a 30-second read timeout. Do not replace an unavailable artifact with another actor's file or an unauthenticated internal download URL. Usage and cost summaries identify incomplete or unavailable coverage instead of presenting a partial subtotal as the complete thread total. Reaction feedback maps only to confirmed delivered assistant messages. It does not overwrite the browser's feedback field. Export is constrained by recorded sampling/destination provenance and current export policy. Temporary-chat provenance is retained; an old mapping without that provenance is not treated as a permanent chat. A policy change can suppress export even when the original trace was sampled. From 3d362b8cb0f901c15cd06ff3c5b304994d6ffa06 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 29 Oct 2026 03:45:52 +0100 Subject: [PATCH 04/30] docs: describe feature requirements without implementation history --- content/docs/features/agent_channels.mdx | 2 +- content/docs/features/background_responses.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 6f1de3c47..d53150391 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -5,7 +5,7 @@ icon: MessagesSquare --- -Agent Channels require the matching channel runtime, feedback, HTTP, setup UI, and background Responses changes. They are disabled by default. A compatible Slack gateway is also required; this guide does not provide an installable gateway package or container. +Agent Channels are a beta integration and are disabled by default. A compatible Slack gateway is also required; this guide does not provide an installable gateway package or container. Agent Channels connect external messaging events to [background Agent Responses](/docs/features/background_responses). Channel routes manage identity, admission, leases, delivery receipts, artifacts, and feedback. They are **not an alternative model-execution endpoint**: a compatible gateway submits execution through `/api/agents/v1/responses` using a server-provisioned, bound credential. diff --git a/content/docs/features/background_responses.mdx b/content/docs/features/background_responses.mdx index 97c7dcebb..512585f6a 100644 --- a/content/docs/features/background_responses.mdx +++ b/content/docs/features/background_responses.mdx @@ -5,7 +5,7 @@ icon: Workflow --- -These interfaces require a LibreChat version that includes the background Responses runtime and HTTP lifecycle routes. Background execution is disabled by default. Deploy all prerequisite runtime, storage, and route changes before enabling it. +Background execution is a beta feature and is disabled by default. Use a LibreChat version that supports background Responses before enabling it. Background Responses use the existing [Agents API](/docs/features/agents_api), not a separate model execution engine. A request returns a stored response identity while a worker executes the Agent. Clients poll that identity for output, required actions, and the canonical terminal result. From f5e48963ac8db26e7a2984c6db42f5b8404adc05 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:28:17 +0100 Subject: [PATCH 05/30] docs: Explain Standalone TypeScript Gateway Setup --- .../object_structure/agents.mdx | 6 +- content/docs/features/agent_channels.mdx | 114 ++++++++++++++++-- 2 files changed, 108 insertions(+), 12 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index 8af813528..b3f035f46 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1499,13 +1499,13 @@ Unknown management-auth fields, duplicate client IDs, malformed user or tenant I ## channels -Configures the opt-in [Agent Channels integration](/docs/features/agent_channels). A compatible external gateway and enabled background Responses are required; this setting does not deploy a gateway or enable execution permissions. +Configures the opt-in [Agent Channels integration](/docs/features/agent_channels). Enabled background Responses and a separately running gateway are required. The LibreChat source includes the standalone TypeScript Slack gateway in `packages/channel-gateway`; this setting does not start it or enable execution permissions. | Option | Default | Accepted values / purpose | | --- | --- | --- | | `enabled` | `false` | Enable channel setup and service routes | | `transport` | `socket_mode` | `socket_mode` or `webhook`; integration metadata, not a receiver deployment | -| `gatewayUrl` | Omitted | Optional gateway URL advertised in setup metadata | +| `gatewayUrl` | Omitted | Required HTTPS base URL for generating webhook callback URLs; not needed for Socket Mode | | `ticketLifetimeMs` | `600000` | Link ticket lifetime, `60000`–`3600000` ms | | `linkLifetimeMs` | `2592000000` | Accepted link lifetime, `60000`–`7776000000` ms | | `leaseMs` | `60000` | Run lease, `10000`–`300000` ms | @@ -1520,6 +1520,8 @@ Configures the opt-in [Agent Channels integration](/docs/features/agent_channels The gateway service boundary requires the server-side `CHANNEL_SERVICE_TOKEN`. Do not expose it to browsers or use it as a general Agent execution credential. Channel credential mode (`shared` or `per_user`) belongs to the channel record, not this deployment block. Both modes require explicit current actor linking; `shared` restricts linking to the channel creator's account rather than granting all external participants that account's privileges. +Set the gateway process's `SLACK_TRANSPORT` explicitly to match `transport`. The gateway environment defaults to `webhook`, while this manifest setting defaults to `socket_mode`. Gateway runtime settings, including its tenant/connection IDs, app-level Socket Mode token, native Slack session option, and optional `APP_TITLE` label, are documented in [Run the Slack gateway](/docs/features/agent_channels#run-the-slack-gateway). + ## remoteApi Configuration for Remote Agent API authentication. Controls how external services authenticate when calling the Agents API endpoints. diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index d53150391..991070fd1 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -5,7 +5,7 @@ icon: MessagesSquare --- -Agent Channels are a beta integration and are disabled by default. A compatible Slack gateway is also required; this guide does not provide an installable gateway package or container. +Agent Channels are a beta integration and are disabled by default. The standalone TypeScript Slack gateway lives in `packages/channel-gateway` in the LibreChat repository. Enabling Channels does not start that process or install a Slack app. Agent Channels connect external messaging events to [background Agent Responses](/docs/features/background_responses). Channel routes manage identity, admission, leases, delivery receipts, artifacts, and feedback. They are **not an alternative model-execution endpoint**: a compatible gateway submits execution through `/api/agents/v1/responses` using a server-provisioned, bound credential. @@ -25,20 +25,112 @@ endpoints: Both enablement settings default to `false`. Existing Remote Agents permissions must also permit the relevant users to use the Agent API, and channel setup requires Agent sharing permission. Configure `DOMAIN_CLIENT` for trusted owner-review and account-link URLs. Configure a strong `CHANNEL_SERVICE_TOKEN` for the gateway-to-LibreChat service boundary; keep it server-side and distribute it only to a trusted integration process over a secure channel. It is not a browser token or a general Agent API key. -The `transport` option accepts `socket_mode` (default) or `webhook`. This selects integration metadata; it does not deploy a receiver or create a public webhook automatically. `gatewayUrl` is an optional URL advertised by setup metadata. Deploy and secure a compatible gateway separately, with its own Slack transport configuration, event authenticity validation, and bot/app credentials. +The `transport` option accepts `socket_mode` (default) or `webhook`. This selects the generated Slack manifest; it does not deploy a receiver. Webhook manifests require an HTTPS `gatewayUrl` without credentials, a query, or a fragment. Set the gateway's `SLACK_TRANSPORT` explicitly to match this setting: the gateway process defaults to `webhook`, not `socket_mode`. See the [channel configuration reference](/docs/configuration/librechat_yaml/object_structure/agents#channels) for limits and defaults. ## Set up a channel -1. Open the Agent's channel setup surface with an authorized LibreChat account. -2. Create a Slack channel configuration and explicitly choose `shared` or `per_user` credential mode. -3. Use the generated Slack manifest with your Slack app. Configure the gateway's chosen Slack transport separately; a manifest alone is not a running integration. -4. Activate the configuration with the matching Slack app ID and bot token. Supply the Slack signing secret when the chosen integration requires signature verification. LibreChat verifies the bot identity and stores credentials encrypted; normal setup responses do not return those secrets. -5. Complete account linking for the external actor. Send a test event only after the channel is active, the actor is linked, and the gateway is configured. +1. Save the Agent, then select **Channels → Add** in the Agent builder. Choose per-user or owner-only mode and continue. You need permission to share the Agent. +2. Create a Slack app from the generated manifest and install it into your workspace. The manifest editor changes only the draft you download; it does not update an installed Slack app. +3. Under **Add Credentials**, enter the matching Slack app ID and bot token. For webhooks, also enter its signing secret. Activate the connection. LibreChat verifies the bot identity and stores credentials encrypted; normal setup responses do not return those secrets. +4. Copy the connection ID from the connection details. Configure and start the gateway as described below. It must be able to reach the active connection before startup can complete. +5. Invite the bot to a Slack channel and mention it. Each sender completes their own account-link flow before their request can run. Browser setup routes live under `/api/agents/{agentId}/channels`: list/create, read `/{channelId}/manifest`, update `/{channelId}`, and delete `/{channelId}`. These use authenticated Agent authorization, not the management API machine-token contract. The create body is `{ "type": "slack", "credentialMode": "per_user" }` (or `shared`). Activation updates use a `slack` object with `appId`, `botToken`, and optional `signingSecret`. To disable a channel, update its status to `disabled`. +## Run the Slack gateway + +The gateway is a separate Node.js 24+ process, not an in-process LibreChat plugin. It uses Slack's official Node SDKs and calls LibreChat over HTTP; it does not connect directly to MongoDB or require a general-purpose Agent API key. One gateway configuration binds to one tenant and connection. Run another configured process for another connection. + +From a LibreChat source checkout containing `packages/channel-gateway`: + +```sh +npm ci +npm run build --workspace @librechat/channel-gateway +node --env-file=/secure/channel-gateway.env packages/channel-gateway/dist/main.cjs +``` + +Supply the environment file through your normal secret-management process. Do not commit it. A Socket Mode configuration is: + +```dotenv filename="channel-gateway.env" +LIBRECHAT_INTERNAL_URL=http://127.0.0.1:3080 +CHANNEL_SERVICE_TOKEN= +CHANNEL_TENANT_ID= +CHANNEL_ID= +SLACK_TRANSPORT=socket_mode +SLACK_APP_TOKEN= +``` + +`LIBRECHAT_INTERNAL_URL` must be reachable from the gateway process. For example, `127.0.0.1` refers to the gateway's own container when running inside a container. Use the exact tenant ID for a multi-tenant deployment; use `_` only for a single-tenant deployment without a tenant ID. The gateway obtains the bot token and signing secret from LibreChat's authenticated connection bundle, so those values do not need separate gateway environment variables. + +For Socket Mode, enable Socket Mode for the same Slack app and create an app-level token with `connections:write`. Keep that token only in the gateway's secret configuration. No public callback URL is needed, but the gateway needs outbound access to Slack and LibreChat. + +For webhooks, set `SLACK_TRANSPORT=webhook` instead and omit `SLACK_APP_TOKEN`. Put the gateway behind HTTPS and set these Slack request URLs, replacing the placeholders with the configured, URL-encoded IDs: + +```text +Events: https://gateway.example.com/slack/events// +Interactivity: https://gateway.example.com/slack/interactions// +``` + +The webhook receiver verifies Slack signatures using the connection's signing secret. Keep LibreChat's channel service routes private to trusted integrations. Expose only the required Slack callback paths publicly; keep health and metrics endpoints on an internal network. + +### Docker Compose + +The source also includes an optional `docker-compose.channels.yml` overlay. It builds the standalone gateway from the repository root using `packages/channel-gateway/Dockerfile`; it does not pull a published gateway image or add the gateway to the default stack. + +With a compatible LibreChat `api` service already running in the same Compose project, run this from the LibreChat repository root: + +```sh +docker compose --env-file .env --env-file /secure/channel-gateway.env \ + -f docker-compose.yml -f docker-compose.channels.yml \ + --profile channels up -d --build channel-gateway +``` + +The second environment file supplies the connection and Socket Mode values from the example above. Keep the same `CHANNEL_SERVICE_TOKEN` in LibreChat's own `.env`; Compose variable substitution does not update the `.env` mounted into the API container. Use the same Compose project name and any existing deployment overrides as your running stack. + +The overlay defaults to Socket Mode and points `LIBRECHAT_INTERNAL_URL` at `http://api:${PORT:-3080}` on the Compose network. It does not use the example's host-loopback URL. The gateway itself listens on container port `8080`, with no published host ports. Socket Mode needs no inbound port; for webhooks, configure your HTTPS reverse proxy to reach `channel-gateway:8080` on that network and forward only the Slack callback paths. + +The Compose service runs as a non-root user with a read-only filesystem, dropped capabilities, and a health check. To build just the image, the build context must still be the repository root: + +```sh +docker build -f packages/channel-gateway/Dockerfile \ + -t librechat-channel-gateway:local . +``` + +### Gateway settings + +| Environment variable | Default | Purpose | +| --- | --- | --- | +| `PORT` | `8080` | Gateway HTTP port | +| `LISTEN_HOST` | `0.0.0.0` | Listen address; use loopback for a host-only local process | +| `LIBRECHAT_INTERNAL_URL` | `http://localhost:3080` | LibreChat service origin | +| `CHANNEL_SERVICE_TOKEN` | Required | Shared server-side service-boundary token | +| `CHANNEL_TENANT_ID` | Required | Exact connection tenant; `_` for single-tenant deployments | +| `CHANNEL_ID` | Required | Connection ID, not the Slack channel ID or Agent ID | +| `SLACK_TRANSPORT` | `webhook` | `webhook` or `socket_mode`; match LibreChat's manifest setting | +| `SLACK_APP_TOKEN` | Required for Socket Mode | App-level token for the same Slack app | +| `SLACK_NATIVE_SESSIONS` | `false` | Use Slack's native Agent loading, status, and Stop UI after app setup below | +| `SLACK_LIFECYCLE_REACTIONS` | `false` | Add processing/completion reactions to the sender's message | +| `APP_TITLE` | `LibreChat` | Application name in browser-review button labels, such as “Open in LibreChat” | +| `API_CALL_TIMEOUT_MS` | `10000` | Timeout for individual service and Slack API calls | +| `AGENT_INVOKE_TIMEOUT_MS` | `120000` | Timeout for initial background Response submission, not the full Agent run | +| `SLACK_SIGNATURE_TOLERANCE_SECS` | `300` | Maximum webhook signature timestamp age/skew | + +`SLACK_API_BASE_URL` defaults to `https://slack.com/api/`; leave it unchanged outside controlled tests. Existing `SLACK_SOCKET_TENANT_ID` and `SLACK_SOCKET_CHANNEL_ID` aliases remain accepted, but conflicting old and new values are rejected. Actor-bound durable execution cannot be disabled. + +The process exposes `/readyz` for liveness, `/healthz` for startup/Socket Mode readiness, and `/metrics` for Prometheus metrics. A successful connection activation confirms Slack credentials, not that a gateway is running or connected. Check gateway health and perform a real mention before treating setup as complete. + +### Native Agent UI and final replies + +By default, a stable working message provides Stop and, when needed, Review controls. Answers are posted after generation, rather than repeatedly replacing a growing reply. Formatting includes code, tables, links, file attachments, and qualified cost/time details; unavailable costs are not estimated. + +To opt into Slack's native Agent sessions, enable Agent mode in the Slack app, add the `assistant:write` bot scope and `agent_session_stopped` event subscription, and reinstall the app. These are additional to the basic generated manifest. Then set `SLACK_NATIVE_SESSIONS=true` and restart the gateway. Without the required permissions or Stop subscription, the gateway falls back to durable progress controls. See [Slack Agent sessions](https://docs.slack.dev/ai/agent-sessions/) for app configuration. + +Native sessions show processing or waiting-for-input status and return to active when the canonical run finishes. Completed answers can include Helpful/Not helpful controls. Optional lifecycle reactions are separate from native sessions and require the reaction permissions already present in the basic manifest. Neither an acknowledgement nor a reaction proves a tool completed; Stop requests cancellation of the sender's authorized work, not another participant's run. + +## Identity and permissions + ### Shared versus per-user credentials `per_user` binds each linked Slack actor to that actor's existing LibreChat account. Current tenant membership, account state, role capabilities, Agent permissions, and tool/provider credentials are evaluated for that user. @@ -49,7 +141,7 @@ Each actor/link revision has its own execution lane. Sharing a Slack thread does ### Account linking -The gateway can request an actor-bound, short-lived linking ticket. The user opens the trusted LibreChat URL, signs in, previews the request, and explicitly accepts it. A gateway then confirms the same ticket/actor binding; it must not infer linkage from a returned browser URL alone. +On the first mention, the gateway sends the actor a private linking prompt. Open its trusted LibreChat URL, sign in, preview the request, and accept it. Return to Slack and mention the bot again to receive the exact-account confirmation, then confirm it there. The next mention can run. The gateway does not replay the original request after linking, and browser acceptance alone does not activate the link. Browser endpoints under `/api/channels/links` support preview, acceptance, listing, and revocation. Mutations require the normal authenticated browser and same-origin checks. Ticket lifetime defaults to 10 minutes; accepted links default to 30 days. Never post a bearer credential or provider OAuth URL into Slack. @@ -86,7 +178,9 @@ The public run snapshot contains only an opaque action descriptor. A review requ Decision requests include that same actor, revision, external channel, and the existing Responses `decision` body. Backend decision receipts, expiry/conflict checks, full authorization preflight, and same-Response resume remain authoritative. A Slack click alone is not permission to resume work. Provider OAuth URLs remain exclusively in the authenticated browser review flow. See the [background Responses lifecycle](/docs/features/background_responses#review-a-required-action). -An actor-private receipt can confirm that a question answer or per-call tool approval/decline was accepted without disclosing tool arguments or claiming completion. A saved decision whose queue publication failed must remain retryable with the exact immutable decision; it cannot be replaced by a different answer. Keep Stop available while work remains active and update public progress only through the fenced delivery protocol. +The gateway uses private Slack controls for supported questions and individual tool approvals/declines. Tool names and argument previews, when supplied by the authorized review projection, remain private to that actor. Successful submission closes the modal and sends a private acknowledgement; it does not force a separate browser receipt page or claim the tool finished. Provider sign-in and unsupported review forms still open the authenticated browser flow. The Agent's existing approval policy determines whether a tool needs approval; connecting Slack does not make every tool manual or bypass that policy. + +A saved decision whose queue publication failed remains retryable with the exact immutable decision; it cannot be replaced by a different answer. Keep Stop available while work remains active and update public progress only through the fenced delivery protocol. Artifacts are scoped to the authorized run and actor. Limits default to five files and 10 MiB per file, with a 30-second read timeout. Do not replace an unavailable artifact with another actor's file or an unauthenticated internal download URL. Usage and cost summaries identify incomplete or unavailable coverage instead of presenting a partial subtotal as the complete thread total. @@ -96,4 +190,4 @@ Reaction feedback maps only to confirmed delivered assistant messages. It does n Disabling a channel or changing its credential mode retires old authority; it does not undo external tool effects. Stop can remain pending until the exact provider is drained and canonical cancellation/cleanup completes. A gateway must poll/reconcile canonical state rather than interpreting an acknowledgement as terminal completion. -This contract does not promise a public gateway distribution, arbitrary chat-platform support, automatic migration of legacy thread-wide identity, or restart-survival of an in-memory OAuth waiter. Legacy thread read/write bookkeeping is not a substitute for actor-scoped runs. +The gateway package is built from the LibreChat source tree; it is not published as an npm package. This integration does not promise arbitrary chat-platform support, automatic migration of legacy thread-wide identity, or restart-survival of an in-memory OAuth waiter. A restart can require a new browser sign-in; uncertain continuation must not be reported as completed or retried as new work. Legacy thread read/write bookkeeping is not a substitute for actor-scoped runs. From bf9a12d77a68a4cd81930d27721e02c8f7b2929c Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 29 Oct 2026 13:07:49 +0100 Subject: [PATCH 06/30] docs: align channel setup with the read-only manifest --- content/docs/features/agent_channels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 991070fd1..77ba28dcb 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -32,7 +32,7 @@ See the [channel configuration reference](/docs/configuration/librechat_yaml/obj ## Set up a channel 1. Save the Agent, then select **Channels → Add** in the Agent builder. Choose per-user or owner-only mode and continue. You need permission to share the Agent. -2. Create a Slack app from the generated manifest and install it into your workspace. The manifest editor changes only the draft you download; it does not update an installed Slack app. +2. Copy the read-only Slack app manifest into Slack's app setup and install the app into your workspace. Make any app changes in Slack's app settings. 3. Under **Add Credentials**, enter the matching Slack app ID and bot token. For webhooks, also enter its signing secret. Activate the connection. LibreChat verifies the bot identity and stores credentials encrypted; normal setup responses do not return those secrets. 4. Copy the connection ID from the connection details. Configure and start the gateway as described below. It must be able to reach the active connection before startup can complete. 5. Invite the bot to a Slack channel and mention it. Each sender completes their own account-link flow before their request can run. From 7c1fc9eead6426d36d54e4cd46c3488b074bd7f2 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Sat, 31 Oct 2026 00:11:33 +0100 Subject: [PATCH 07/30] =?UTF-8?q?=F0=9F=93=9A=20docs:=20Clarify=20Response?= =?UTF-8?q?=20Storage=20and=20Channel=20Consent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/docs/features/agent_channels.mdx | 4 +++- content/docs/features/background_responses.mdx | 8 ++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 77ba28dcb..6d4bd87c8 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -23,7 +23,7 @@ endpoints: transport: socket_mode ``` -Both enablement settings default to `false`. Existing Remote Agents permissions must also permit the relevant users to use the Agent API, and channel setup requires Agent sharing permission. Configure `DOMAIN_CLIENT` for trusted owner-review and account-link URLs. Configure a strong `CHANNEL_SERVICE_TOKEN` for the gateway-to-LibreChat service boundary; keep it server-side and distribute it only to a trusted integration process over a secure channel. It is not a browser token or a general Agent API key. +Both enablement settings default to `false`. Users need both Agent use and Remote Agents use permissions. Channel setup also requires Agent sharing permission or existing administrator management access; sharing access does not require permission to edit the Agent. Configure `DOMAIN_CLIENT` for trusted owner-review and account-link URLs. Configure a strong `CHANNEL_SERVICE_TOKEN` for the gateway-to-LibreChat service boundary; keep it server-side and distribute it only to a trusted integration process over a secure channel. It is not a browser token or a general Agent API key. The `transport` option accepts `socket_mode` (default) or `webhook`. This selects the generated Slack manifest; it does not deploy a receiver. Webhook manifests require an HTTPS `gatewayUrl` without credentials, a query, or a fragment. Set the gateway's `SLACK_TRANSPORT` explicitly to match this setting: the gateway process defaults to `webhook`, not `socket_mode`. @@ -143,6 +143,8 @@ Each actor/link revision has its own execution lane. Sharing a Slack thread does On the first mention, the gateway sends the actor a private linking prompt. Open its trusted LibreChat URL, sign in, preview the request, and accept it. Return to Slack and mention the bot again to receive the exact-account confirmation, then confirm it there. The next mention can run. The gateway does not replay the original request after linking, and browser acceptance alone does not activate the link. +Manage and revoke your links in Account settings. A link can become unavailable when the channel or account is no longer eligible; you can still withdraw that consent. Restoring eligibility does not reactivate a link you explicitly revoked. + Browser endpoints under `/api/channels/links` support preview, acceptance, listing, and revocation. Mutations require the normal authenticated browser and same-origin checks. Ticket lifetime defaults to 10 minutes; accepted links default to 30 days. Never post a bearer credential or provider OAuth URL into Slack. ## Gateway protocol boundary diff --git a/content/docs/features/background_responses.mdx b/content/docs/features/background_responses.mdx index 512585f6a..ddfa59b1b 100644 --- a/content/docs/features/background_responses.mdx +++ b/content/docs/features/background_responses.mdx @@ -25,7 +25,7 @@ endpoints: `enabled` defaults to `false`. `acknowledgementTimeoutMs` defaults to `10000` and accepts integers from `100` through `60000`; it bounds the worker admission acknowledgement, not total model execution time. Existing Remote Agents permissions, Agent access, terms acceptance, content checks, and provider/tool policies still apply. -Background submission requires an **Agent API key**, including when ordinary inference also accepts OIDC. A management API machine token is not an execution credential. Configure [Remote Agents permissions](/docs/features/agents_api#enabling-the-agents-api) separately. +Background submission requires an **Agent API key**, including when ordinary inference also accepts OIDC. A management API machine token is not an execution credential. Configure [Remote Agents permissions](/docs/features/agents_api#setup) separately. Human tool approval and Ask User pauses require durable MongoDB checkpoint storage. Use the existing [`toolApproval`](/docs/configuration/librechat_yaml/object_structure/agents#toolapproval), Ask User, and [`checkpointer`](/docs/configuration/librechat_yaml/object_structure/agents#checkpointer) settings; background execution does not automatically enable approval or bypass a deny rule. A memory checkpointer does not provide durable background human-action resume. Ordinary requests without a human pause retain their normal execution path. @@ -52,6 +52,10 @@ curl https://chat.example.com/api/agents/v1/responses/RESPONSE_ID \ Poll the same response until its public status is `completed`, `failed`, `incomplete`, or `cancelled`. `queued` and `in_progress` are not terminal. The server rechecks the original source key and current authority; possession of a response ID is not permission to read or resume it. Use the returned response ID as `previous_response_id` for a subsequent supported continuation rather than resending the original user input. +A background answer becomes terminal only after the provider has drained and its conversation history is committed with the response. A temporary storage outage keeps the selected outcome pending for recovery without running the provider again. During a rolling upgrade or rollback, keep a compatible worker available to finish pending results; an older worker cannot complete the newer history-bearing receipt format. + +Ordinary synchronous and streaming requests have a different storage contract: if optional saving fails, the generated answer can still succeed with `store: false`. Check that returned value before relying on retrieval or continuation. + ## Review a required action A public response can include: @@ -89,7 +93,7 @@ A successful decision returns HTTP `202` with `responseId`, `actionId`, `intentI MCP OAuth prompts are retained for owner-only replay until their deadline. Complete authorization through the supplied provider flow; do not submit an approval decision to replace an OAuth callback. A successful callback can continue the same waiting execution while its waiter is still active. -Durable prompt visibility is not a guarantee that an in-memory OAuth waiter survives a server restart. Durable human question/tool-approval checkpoints and OAuth authorization waiters are different mechanisms. If exact execution state is missing or mismatched, the response reports nonterminal `recovery: "execution_state_unavailable"` and removes stale actionable prompts. This is not proof of completion or cancellation and does not replay work. Sign-in credentials may have been saved even though the original run did not continue. Check external results before retrying; an administrator must reconcile a persistently unknown execution before the held run can safely be cleared. Do not replay an old authorization URL or infer that sign-in restarted the model. See [MCP authentication](/docs/features/mcp#oauth-authentication). +Durable prompt visibility is not a guarantee that an in-memory OAuth waiter survives a server restart. Durable human question/tool-approval checkpoints and OAuth authorization waiters are different mechanisms. If exact execution state is missing or mismatched, the response reports nonterminal `recovery: "execution_state_unavailable"` and removes stale actionable prompts. This is not proof of completion or cancellation and does not replay work. Sign-in credentials may have been saved even though the original run did not continue. Check external results before retrying; an administrator must reconcile a persistently unknown execution before the held run can safely be cleared. Do not replay an old authorization URL or infer that sign-in restarted the model. See [MCP authentication](/docs/features/mcp#sign-in-with-oauth). ## Stop and recovery From dfca2c008d367c8046429419c54b3256674317ba Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Sat, 31 Oct 2026 00:19:10 +0100 Subject: [PATCH 08/30] =?UTF-8?q?=F0=9F=93=9A=20docs:=20Include=20Channel?= =?UTF-8?q?=20Guides=20in=20Localized=20Navigation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/docs/features/meta.de.json | 2 ++ content/docs/features/meta.es.json | 2 ++ content/docs/features/meta.fr.json | 2 ++ content/docs/features/meta.id.json | 2 ++ content/docs/features/meta.it.json | 2 ++ content/docs/features/meta.ja.json | 2 ++ content/docs/features/meta.ko.json | 2 ++ content/docs/features/meta.nl.json | 2 ++ content/docs/features/meta.pl.json | 2 ++ content/docs/features/meta.pt-BR.json | 2 ++ content/docs/features/meta.tr.json | 2 ++ content/docs/features/meta.vi.json | 2 ++ content/docs/features/meta.zh.json | 2 ++ 13 files changed, 26 insertions(+) diff --git a/content/docs/features/meta.de.json b/content/docs/features/meta.de.json index f5ae5b04c..c721c1cbc 100644 --- a/content/docs/features/meta.de.json +++ b/content/docs/features/meta.de.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.es.json b/content/docs/features/meta.es.json index 0eeed4a73..3e7c2bc54 100644 --- a/content/docs/features/meta.es.json +++ b/content/docs/features/meta.es.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.fr.json b/content/docs/features/meta.fr.json index a5293817a..f9c55539a 100644 --- a/content/docs/features/meta.fr.json +++ b/content/docs/features/meta.fr.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.id.json b/content/docs/features/meta.id.json index b06ad51a7..0feb398a9 100644 --- a/content/docs/features/meta.id.json +++ b/content/docs/features/meta.id.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.it.json b/content/docs/features/meta.it.json index 1e6ccf7ac..d1b66fec1 100644 --- a/content/docs/features/meta.it.json +++ b/content/docs/features/meta.it.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.ja.json b/content/docs/features/meta.ja.json index d029e41fb..140509deb 100644 --- a/content/docs/features/meta.ja.json +++ b/content/docs/features/meta.ja.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.ko.json b/content/docs/features/meta.ko.json index c22242753..b1966d1dc 100644 --- a/content/docs/features/meta.ko.json +++ b/content/docs/features/meta.ko.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.nl.json b/content/docs/features/meta.nl.json index 5f9343787..a520d382a 100644 --- a/content/docs/features/meta.nl.json +++ b/content/docs/features/meta.nl.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.pl.json b/content/docs/features/meta.pl.json index d4c62d1a6..bcc344623 100644 --- a/content/docs/features/meta.pl.json +++ b/content/docs/features/meta.pl.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.pt-BR.json b/content/docs/features/meta.pt-BR.json index 3655d7896..766869701 100644 --- a/content/docs/features/meta.pt-BR.json +++ b/content/docs/features/meta.pt-BR.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.tr.json b/content/docs/features/meta.tr.json index a671ba18e..4ec97414b 100644 --- a/content/docs/features/meta.tr.json +++ b/content/docs/features/meta.tr.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.vi.json b/content/docs/features/meta.vi.json index 134efb300..9c704be71 100644 --- a/content/docs/features/meta.vi.json +++ b/content/docs/features/meta.vi.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", diff --git a/content/docs/features/meta.zh.json b/content/docs/features/meta.zh.json index df6d457e9..8814dee95 100644 --- a/content/docs/features/meta.zh.json +++ b/content/docs/features/meta.zh.json @@ -10,6 +10,8 @@ "agent_plugins", "subagents", "agents_api", + "background_responses", + "agent_channels", "artifacts", "code_interpreter", "pull_requests", From af5448ed35563f8af2f69f1318738c4961673d83 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Sat, 31 Oct 2026 03:04:55 +0100 Subject: [PATCH 09/30] =?UTF-8?q?=F0=9F=93=9A=20docs:=20Clarify=20Channel?= =?UTF-8?q?=20Artifact=20Budgets=20And=20Provenance?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configuration/librechat_yaml/object_structure/agents.mdx | 5 ++++- content/docs/features/agent_channels.mdx | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index b3f035f46..0940b73eb 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1512,7 +1512,10 @@ Configures the opt-in [Agent Channels integration](/docs/features/agent_channels | `responseCredentialLifetimeMs` | `86400000` | Bound execution credential lifetime, `60000`–`604800000` ms | | `artifactMaxBytes` | `10485760` | Per-artifact limit, `1`–`52428800` bytes | | `artifactMaxFiles` | `5` | Artifacts per run, `1`–`20` | -| `artifactReadTimeoutMs` | `30000` | Read timeout, `1000`–`60000` ms | +| `artifactReadTimeoutMs` | `30000` | Shared artifact-operation budget, `1000`–`60000` ms; not a separate timeout for each file | +| `artifactAnswerFileThresholdBytes` | `6000` | Create new plain-text answer files only above this UTF-8 byte length, `0`–`52428800`; fenced answers also qualify | + +The artifact budget covers catalog queries, storage acquisition/consumption and final authorization. Limits resolution is capped at the schema maximum of 60 seconds; once resolved, its elapsed time counts toward the configured budget. Expiry omits artifacts rather than returning files without current authorization. The threshold applies to new answer-file projections; existing saved descriptors remain bound to their bytes and require current owner, tenant, retention and maximum-size checks. `cleanup` accepts `batchSize` (`25`, range `1`–`100`), `intervalMs` (`1000`, range `1000`–`60000`), and `maxIdleIntervalMs` (`30000`, range `1000`–`300000`). diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 6d4bd87c8..a68def448 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -184,7 +184,9 @@ The gateway uses private Slack controls for supported questions and individual t A saved decision whose queue publication failed remains retryable with the exact immutable decision; it cannot be replaced by a different answer. Keep Stop available while work remains active and update public progress only through the fenced delivery protocol. -Artifacts are scoped to the authorized run and actor. Limits default to five files and 10 MiB per file, with a 30-second read timeout. Do not replace an unavailable artifact with another actor's file or an unauthenticated internal download URL. Usage and cost summaries identify incomplete or unavailable coverage instead of presenting a partial subtotal as the complete thread total. +Artifacts are scoped to the authorized run and actor. User-submitted rows do not count as server-generated provenance for artifacts or trace links. Limits default to five files and 10 MiB per file. One `artifactReadTimeoutMs` budget (30 seconds by default) covers catalog queries, storage reads and final authorization rather than restarting for every file. Limits resolution is separately capped at 60 seconds, and its elapsed time counts against the selected budget once available. An expired budget omits artifacts while retaining the answer for authorized text delivery. + +New plain-text answer files require more than `artifactAnswerFileThresholdBytes` UTF-8 bytes (6,000 by default); fenced answers also qualify. This threshold controls new projections, while saved descriptors retain their content identity and still require current authorization, retention and maximum-size checks. Do not replace an unavailable artifact with another actor's file or an unauthenticated internal download URL. Usage and cost summaries identify incomplete or unavailable coverage instead of presenting a partial subtotal as the complete thread total. Reaction feedback maps only to confirmed delivered assistant messages. It does not overwrite the browser's feedback field. Export is constrained by recorded sampling/destination provenance and current export policy. Temporary-chat provenance is retained; an old mapping without that provenance is not treated as a permanent chat. A policy change can suppress export even when the original trace was sampled. From 9966a92cef144aff5fec7e1397026345c98cca6c Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 3 Nov 2026 14:08:30 -0800 Subject: [PATCH 10/30] docs: consolidate transactional channel gateway setup --- .../object_structure/agents.mdx | 8 +- content/docs/features/agent_channels.mdx | 166 +++++++++++++++--- .../docs/features/background_responses.mdx | 2 + 3 files changed, 154 insertions(+), 22 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index 0940b73eb..6c8c4a5db 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1504,8 +1504,12 @@ Configures the opt-in [Agent Channels integration](/docs/features/agent_channels | Option | Default | Accepted values / purpose | | --- | --- | --- | | `enabled` | `false` | Enable channel setup and service routes | -| `transport` | `socket_mode` | `socket_mode` or `webhook`; integration metadata, not a receiver deployment | +| `transport` | `socket_mode` | Select `socket_mode` or `webhook` ingress and the generated manifest; the gateway runs separately | | `gatewayUrl` | Omitted | Required HTTPS base URL for generating webhook callback URLs; not needed for Socket Mode | +| `nativeSessions` | `false` | Enable optional Slack native Agent status emission after app setup | +| `lifecycleReactions` | `false` | Add optional processing/completion reactions | +| `signatureToleranceSeconds` | `300` | Webhook signature timestamp window; integer from 1 to 300 seconds | +| `socketReconnectDelayMs` | `5000` | Socket reconnect delay; integer from 100 to 60000 milliseconds | | `ticketLifetimeMs` | `600000` | Link ticket lifetime, `60000`–`3600000` ms | | `linkLifetimeMs` | `2592000000` | Accepted link lifetime, `60000`–`7776000000` ms | | `leaseMs` | `60000` | Run lease, `10000`–`300000` ms | @@ -1523,7 +1527,7 @@ The artifact budget covers catalog queries, storage acquisition/consumption and The gateway service boundary requires the server-side `CHANNEL_SERVICE_TOKEN`. Do not expose it to browsers or use it as a general Agent execution credential. Channel credential mode (`shared` or `per_user`) belongs to the channel record, not this deployment block. Both modes require explicit current actor linking; `shared` restricts linking to the channel creator's account rather than granting all external participants that account's privileges. -Set the gateway process's `SLACK_TRANSPORT` explicitly to match `transport`. The gateway environment defaults to `webhook`, while this manifest setting defaults to `socket_mode`. Gateway runtime settings, including its tenant/connection IDs, app-level Socket Mode token, native Slack session option, and optional `APP_TITLE` label, are documented in [Run the Slack gateway](/docs/features/agent_channels#run-the-slack-gateway). +The gateway reads this versioned policy from LibreChat before selecting ingress. `SLACK_TRANSPORT` is optional and asserts the selected mode; a mismatch or unsupported policy prevents startup. Native sessions, lifecycle reactions and signature policy are configured here rather than through gateway process flags. Gateway runtime settings, including its tenant/connection IDs, app-level Socket Mode token and optional `APP_TITLE` label, are documented in [Run the Slack gateway](/docs/features/agent_channels#run-the-slack-gateway). ## remoteApi diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index a68def448..6ce24fd11 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -21,11 +21,21 @@ endpoints: channels: enabled: true transport: socket_mode + nativeSessions: false + lifecycleReactions: false + signatureToleranceSeconds: 300 + socketReconnectDelayMs: 5000 ``` Both enablement settings default to `false`. Users need both Agent use and Remote Agents use permissions. Channel setup also requires Agent sharing permission or existing administrator management access; sharing access does not require permission to edit the Agent. Configure `DOMAIN_CLIENT` for trusted owner-review and account-link URLs. Configure a strong `CHANNEL_SERVICE_TOKEN` for the gateway-to-LibreChat service boundary; keep it server-side and distribute it only to a trusted integration process over a secure channel. It is not a browser token or a general Agent API key. -The `transport` option accepts `socket_mode` (default) or `webhook`. This selects the generated Slack manifest; it does not deploy a receiver. Webhook manifests require an HTTPS `gatewayUrl` without credentials, a query, or a fragment. Set the gateway's `SLACK_TRANSPORT` explicitly to match this setting: the gateway process defaults to `webhook`, not `socket_mode`. +The `transport` option accepts `socket_mode` (default) or `webhook`. This selects the generated Slack manifest; it does not deploy a receiver. Webhook manifests require an HTTPS `gatewayUrl` without credentials, a query, or a fragment. The gateway loads this policy from LibreChat before selecting ingress. `SLACK_TRANSPORT` is an optional deployment assertion; if supplied, it must match the server-selected mode. Missing or unsupported gateway policy prevents startup. + +### Database requirement + +Durable Channels and stored background Responses require MongoDB transactions. Use a MongoDB replica set or another verified transaction-capable deployment. Standalone MongoDB and FerretDB 2.7 can run ordinary LibreChat, but cannot enable this durable feature. Unsupported channel writes return `transactions_unavailable`; the Agent builder explains the setup requirement. Transactional reads use the primary even when the connection normally prefers secondary reads. + +API-key authentication must remain enabled for the gateway's bound execution credential. Linking does not grant Remote Agents permissions, Agent access, new tools or offline access to connected services. See the [channel configuration reference](/docs/configuration/librechat_yaml/object_structure/agents#channels) for limits and defaults. @@ -47,16 +57,19 @@ From a LibreChat source checkout containing `packages/channel-gateway`: ```sh npm ci +npm run build:packages npm run build --workspace @librechat/channel-gateway node --env-file=/secure/channel-gateway.env packages/channel-gateway/dist/main.cjs ``` +`npm run backend:dev` starts only LibreChat; it does not start the gateway. Build the application using LibreChat's normal development setup and run the gateway separately. If you reuse the application's `.env`, set the gateway port explicitly: `PORT=8080 node --env-file=.env packages/channel-gateway/dist/main.cjs`. This avoids binding the gateway to the application's port. + Supply the environment file through your normal secret-management process. Do not commit it. A Socket Mode configuration is: ```dotenv filename="channel-gateway.env" LIBRECHAT_INTERNAL_URL=http://127.0.0.1:3080 CHANNEL_SERVICE_TOKEN= -CHANNEL_TENANT_ID= +CHANNEL_TENANT_ID=_ CHANNEL_ID= SLACK_TRANSPORT=socket_mode SLACK_APP_TOKEN= @@ -77,27 +90,56 @@ The webhook receiver verifies Slack signatures using the connection's signing se ### Docker Compose -The source also includes an optional `docker-compose.channels.yml` overlay. It builds the standalone gateway from the repository root using `packages/channel-gateway/Dockerfile`; it does not pull a published gateway image or add the gateway to the default stack. +The optional `docker-compose.channels.yml` overlay builds both LibreChat and the standalone gateway from the source checkout. The separate `docker-compose.mongo-replica.yml` overlay initializes a single local MongoDB replica member and waits for a writable primary before the application starts. The gateway waits for application health, then authenticates its channel binding and selected Slack transport. Neither service is added to the default stack automatically. -With a compatible LibreChat `api` service already running in the same Compose project, run this from the LibreChat repository root: +For a **fresh local database**, run these commands from the LibreChat repository root: -```sh -docker compose --env-file .env --env-file /secure/channel-gateway.env \ - -f docker-compose.yml -f docker-compose.channels.yml \ - --profile channels up -d --build channel-gateway -``` +1. Prepare `.env` and `librechat.yaml` using the normal LibreChat setup and the channel policy above. Generate a private service token with `openssl rand -hex 32` and set `CHANNEL_SERVICE_TOKEN` in `.env`. Keep the same Compose files and project name on subsequent commands. +2. Start the source-built application and its dependencies: + + ```sh + docker compose -f docker-compose.yml -f docker-compose.channels.yml \ + -f docker-compose.mongo-replica.yml up -d --build api meilisearch + ``` + +3. Sign in, save an Agent, and [set up its Slack channel](#set-up-a-channel). Enter the bot token in the Agent builder. Set `CHANNEL_ID` in `.env` to the resulting connection ID. `CHANNEL_TENANT_ID` defaults to `_` for an ordinary OSS installation; supply the actual tenant ID for a tenant-scoped installation. For Socket Mode, also set `SLACK_APP_TOKEN` to the matching app-level token with `connections:write`. +4. Start the gateway: + + ```sh + docker compose -f docker-compose.yml -f docker-compose.channels.yml \ + -f docker-compose.mongo-replica.yml --profile channels up -d --build channel-gateway + ``` + +5. Check readiness and startup errors: + + ```sh + docker compose -f docker-compose.yml -f docker-compose.channels.yml \ + -f docker-compose.mongo-replica.yml --profile channels ps -a + docker compose -f docker-compose.yml -f docker-compose.channels.yml \ + -f docker-compose.mongo-replica.yml --profile channels logs --tail=100 api mongodb-init channel-gateway + ``` -The second environment file supplies the connection and Socket Mode values from the example above. Keep the same `CHANNEL_SERVICE_TOKEN` in LibreChat's own `.env`; Compose variable substitution does not update the `.env` mounted into the API container. Use the same Compose project name and any existing deployment overrides as your running stack. +`mongodb-init` exiting with status 0 is expected. The application and gateway should be running and healthy. A successful Slack credential activation does not prove the gateway is connected: check health and perform a real mention. Missing service/app bindings prevent gateway startup. -The overlay defaults to Socket Mode and points `LIBRECHAT_INTERNAL_URL` at `http://api:${PORT:-3080}` on the Compose network. It does not use the example's host-loopback URL. The gateway itself listens on container port `8080`, with no published host ports. Socket Mode needs no inbound port; for webhooks, configure your HTTPS reverse proxy to reach `channel-gateway:8080` on that network and forward only the Slack callback paths. +The overlay points `LIBRECHAT_INTERNAL_URL` at `http://api:${PORT:-3080}` on the Compose network. The gateway listens on container port `8080`, with no published host ports. Socket Mode needs no inbound port; webhooks need an HTTPS reverse proxy forwarding the required callback paths to `channel-gateway:8080`. The gateway runs as a non-root user with a read-only filesystem and dropped capabilities. -The Compose service runs as a non-root user with a read-only filesystem, dropped capabilities, and a health check. To build just the image, the build context must still be the repository root: +For an existing external transaction-capable database, omit the local MongoDB replica overlay and provide the application connection through your normal Compose override. The base Compose file sets the API service's `MONGO_URI`, so changing only `.env` does not replace that service environment entry. Never run the local initializer against an external database. + +A separate gateway environment file can be supplied through `--env-file .env --env-file /secure/channel-gateway.env`. Keep `CHANNEL_SERVICE_TOKEN` identical in LibreChat's own `.env`; Compose substitution does not update the file mounted into the application. + +To build only the gateway image, use the repository root as its build context: ```sh docker build -f packages/channel-gateway/Dockerfile \ -t librechat-channel-gateway:local . ``` +#### Existing local data + +Back up the database, stop LibreChat and every gateway/worker that writes to it, then stop the database before applying the replica overlay. Retain the existing `data-node` directory; do not delete it or remove its volume. Start with that same data directory and the overlays above. Initialization preserves existing documents and only initializes an unconfigured local `rs0` member at `mongodb:27017`. It refuses a different replica configuration rather than silently reconfiguring it. Verify existing users/history before enabling the gateway, and retain the overlay on future restarts. + +A single local replica member enables transactions but does not provide high availability. The overlay follows the base development Compose authentication/network settings; it is not a production replica-set recipe. For authenticated, multi-member or production deployments, use the [MongoDB conversion procedure](https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set/) and your deployment's backup/security practices. + ### Gateway settings | Environment variable | Default | Purpose | @@ -108,26 +150,75 @@ docker build -f packages/channel-gateway/Dockerfile \ | `CHANNEL_SERVICE_TOKEN` | Required | Shared server-side service-boundary token | | `CHANNEL_TENANT_ID` | Required | Exact connection tenant; `_` for single-tenant deployments | | `CHANNEL_ID` | Required | Connection ID, not the Slack channel ID or Agent ID | -| `SLACK_TRANSPORT` | `webhook` | `webhook` or `socket_mode`; match LibreChat's manifest setting | +| `SLACK_TRANSPORT` | Server policy | Optional assertion: `webhook` or `socket_mode`; must match the server policy | | `SLACK_APP_TOKEN` | Required for Socket Mode | App-level token for the same Slack app | -| `SLACK_NATIVE_SESSIONS` | `false` | Use Slack's native Agent loading, status, and Stop UI after app setup below | -| `SLACK_LIFECYCLE_REACTIONS` | `false` | Add processing/completion reactions to the sender's message | | `APP_TITLE` | `LibreChat` | Application name in browser-review button labels, such as “Open in LibreChat” | | `API_CALL_TIMEOUT_MS` | `10000` | Timeout for individual service and Slack API calls | | `AGENT_INVOKE_TIMEOUT_MS` | `120000` | Timeout for initial background Response submission, not the full Agent run | -| `SLACK_SIGNATURE_TOLERANCE_SECS` | `300` | Maximum webhook signature timestamp age/skew | -`SLACK_API_BASE_URL` defaults to `https://slack.com/api/`; leave it unchanged outside controlled tests. Existing `SLACK_SOCKET_TENANT_ID` and `SLACK_SOCKET_CHANNEL_ID` aliases remain accepted, but conflicting old and new values are rejected. Actor-bound durable execution cannot be disabled. +`SLACK_API_BASE_URL` defaults to `https://slack.com/api/`; leave it unchanged outside controlled tests. Ingress mode, native sessions, lifecycle reactions, signature tolerance and reconnect pacing come from `endpoints.agents.channels` in `librechat.yaml`, not process feature flags. Actor-bound durable execution cannot be disabled. -The process exposes `/readyz` for liveness, `/healthz` for startup/Socket Mode readiness, and `/metrics` for Prometheus metrics. A successful connection activation confirms Slack credentials, not that a gateway is running or connected. Check gateway health and perform a real mention before treating setup as complete. +The process exposes `/livez` for HTTP-process liveness, `/readyz` and `/healthz` for actual startup/transport readiness, and `/metrics` for Prometheus metrics. An observed ingress-mode or Socket app-binding mismatch makes the gateway unready. Restart gateway replicas after changing ingress mode or Socket app identity. A successful connection activation confirms Slack credentials, not that a gateway is running or connected. Check gateway health and perform a real mention before treating setup as complete. ### Native Agent UI and final replies By default, a stable working message provides Stop and, when needed, Review controls. Answers are posted after generation, rather than repeatedly replacing a growing reply. Formatting includes code, tables, links, file attachments, and qualified cost/time details; unavailable costs are not estimated. -To opt into Slack's native Agent sessions, enable Agent mode in the Slack app, add the `assistant:write` bot scope and `agent_session_stopped` event subscription, and reinstall the app. These are additional to the basic generated manifest. Then set `SLACK_NATIVE_SESSIONS=true` and restart the gateway. Without the required permissions or Stop subscription, the gateway falls back to durable progress controls. See [Slack Agent sessions](https://docs.slack.dev/ai/agent-sessions/) for app configuration. +To opt into Slack's native Agent sessions, enable Agent mode in the Slack app, add the `assistant:write` bot scope and `agent_session_stopped` event subscription, and reinstall the app. These are additional to the basic generated manifest. Then set `endpoints.agents.channels.nativeSessions: true` in `librechat.yaml`. Without the required permissions or Stop subscription, the gateway falls back to durable progress controls. See [Slack Agent sessions](https://docs.slack.dev/ai/agent-sessions/) for app configuration. + +Native sessions show processing or waiting-for-input status and return to active when the canonical run finishes. Completed answers can include Helpful/Not helpful controls. Optional lifecycle reactions use `endpoints.agents.channels.lifecycleReactions: true`, are separate from native sessions and require the reaction permissions already present in the basic manifest. Neither an acknowledgement nor a reaction proves a tool completed; Stop requests cancellation of the sender's authorized work, not another participant's run. + +## Rich Agent messages + +An Agent can return semantic presentation data in its final answer. The gateway validates the document and converts it deterministically to Slack Block Kit; it does not accept arbitrary Slack JSON, callback IDs, approval controls, file identifiers or modal definitions. Ordinary Markdown remains unchanged. This works in both ordinary threads and native Agent sessions, without a new OAuth scope or a configuration migration. + +To enable this behavior for an Agent, add the following to its instructions using the existing Agent editor (or include it in a request when testing): + +> When a chart, table, image or card would help, write a short readable answer followed by exactly one final, top-level fenced code block named `librechat-presentation`. Its JSON must be `{ "version": 1, "blocks": [...] }`. Use only the semantic components described below; never emit raw Slack blocks or interactive callback IDs. Use ordinary Markdown for other answers. Use public HTTPS URLs for images and links. The gateway generates complete text fallbacks from the data, so do not repeat every value in the introductory answer. -Native sessions show processing or waiting-for-input status and return to active when the canonical run finishes. Completed answers can include Helpful/Not helpful controls. Optional lifecycle reactions are separate from native sessions and require the reaction permissions already present in the basic manifest. Neither an acknowledgement nor a reaction proves a tool completed; Stop requests cancellation of the sender's authorized work, not another participant's run. +For example, ask the Agent to compare the following measured results and show both a chart and a table. Its final answer can be: + +````text +Latency fell from 20 ms to 17 ms. + +```librechat-presentation +{ + "version": 1, + "blocks": [ + { + "type": "chart", + "title": "Latency", + "chart": { + "type": "line", + "axis_config": { "categories": ["Mon", "Tue"], "y_label": "ms" }, + "series": [{ "name": "p95", "data": [{ "label": "Mon", "value": 20 }, { "label": "Tue", "value": 17 }] }] + } + }, + { "type": "table", "title": "Measurements", "columns": ["Day", "p95 (ms)"], "rows": [["Mon", 20], ["Tue", 17]] } + ] +} +``` +```` + +| Semantic component | Fields and constraints | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `text`, `header`, `context`, `code` | `text` string; maximum 3000, 150, 2000 and 3000 Unicode characters respectively. Text components use literal text, so mentions cannot grant interaction authority. Use ordinary Markdown outside the document for formatted prose. | +| `divider` | No additional fields. | +| `image` | `url`, `alt`, optional `title` (150 characters). HTTPS URLs only; alt text is required (2000 characters). The gateway never fetches remote media. | +| `card` | Required `title` (150), optional `subtitle` (150), `body` (200), `image: {url, alt}`, and up to three `links: [{label, url}]`. Labels are at most 75 characters. Links navigate only; they cannot run an Agent action. | +| `carousel` | `cards`: 1–10 cards. | +| `table` | `title` (150), `columns`: 1–20 labels (150 each), `rows`: 1–200 rectangular rows of strings or finite numbers. Maximum 20,000 characters across cells including headers. Numeric cells retain numeric sorting. | +| `chart` | `title` (50), `chart` as described below. | +| `container` | `title` (150), `blocks`: 1–10 text, header, context, code, divider or image components. | +| `layout` | `title` (150), `rows`: 1–5 arrays of 1–3 components, including containers. Charts, tables and carousels each occupy their own row. Layouts cannot nest. The gateway makes the title visible and generates explicit compatibility fallback blocks. | + +Charts support `line`, `bar` and `area` with `axis_config: {categories, x_label?, y_label?}` and `series: [{name, data: [{label, value}]}]`. Categories have 1–20 distinct labels; each series must have exactly one point per category. Series names are distinct; at most 12 series are allowed. Names and labels are at most 20 characters, axis titles 50. Values must be finite; negative values are supported. Pie charts instead use `chart: {type: "pie", segments: [{label, value}]}` with 1–12 distinct labels and positive finite values. + +A document has at most 40 components and the final answer must fit the 128,000-byte presentation parsing boundary. Malformed, incomplete, quoted, ambiguous or unrecognized documents stay on the ordinary text path. The gateway isolates components into messages, counts nested blocks, enforces two charts and 20,000 table characters per message, and preserves every value and link in generated text. Components which exceed Slack's nested block or serialized payload limits become text. The server's existing `maxDeliveryParts` policy still applies, with an explicit shortening notice when needed. + +The gateway freezes versioned blocks and text together before posting. Retries replay that plan. A definitive Slack `invalid_blocks` or `invalid_attachments` rejection permits a text-only retry; ambiguous network outcomes retain the existing reconciliation behavior. Clients that cannot render layouts receive the generated stable fallback blocks. + +This is rich **message** support. Existing app-owned Stop, approval, question and feedback workflows remain responsible for interactions. New input forms, App Home, modals, Work Objects, plan/task execution controls and embedded video are not exposed to Agent output. Authorized file attachments continue through the existing artifact delivery path. Slack may limit newer blocks by client or app availability; automated tests cover SDK payloads and rejection fallback, while live rendering requires a configured Slack workspace. ## Identity and permissions @@ -147,6 +238,39 @@ Manage and revoke your links in Account settings. A link can become unavailable Browser endpoints under `/api/channels/links` support preview, acceptance, listing, and revocation. Mutations require the normal authenticated browser and same-origin checks. Ticket lifetime defaults to 10 minutes; accepted links default to 30 days. Never post a bearer credential or provider OAuth URL into Slack. +## Delivery recovery + +The gateway preserves each frozen delivery operation and its receipt. A required operation whose provider result is unknown holds its actor lane: retrying blindly could post the same answer twice. Stopping a worker or requesting cancellation does not prove whether Slack accepted an earlier request. + +### Reconcile a verified provider result + +1. Pause gateway processing for the affected channel while investigating. Keep the channel enabled and preserve its actor link and source authority; disabling these is not a recovery bypass. +2. Inspect the frozen run plan and retained receipt. Verify in the provider that the exact operation reached the intended channel or thread. Record its message key or file ID, matching the retained attempt and any upload checkpoint. If the result cannot be verified, leave the receipt unknown and the lane held. +3. After the old lease expires, use `POST /api/channels/service/:channelId/runs/claim` with `{ "owner": "" }`, normal private service authentication and tenant binding. Verify that the returned run ID is the run being investigated; claims select eligible work and do not take a target run ID. Use the returned current fence, renewing it through `POST /renew` as needed. An expired or replaced worker's fence cannot reconcile the run. +4. Submit the confirmed receipt through the private channel API. These endpoints confirm existing attempts; they do not send messages, replace the frozen plan, reset attempts or accept a retryable outcome. + +All paths below are relative to `/api/channels/service/:channelId/runs/:runId`. Send the channel service bearer token and the configured tenant header, using the same internal service URL as the gateway. Preserve the complete fence returned by the claim. + +For a delivery operation, `POST /delivery/reconcile`: + +```json +{ + "fence": { "runId": "", "owner": "", "epoch": 1 }, + "receipt": { + "operationId": "", + "outcome": "confirmed", + "attempts": 1, + "externalMessageKey": ":" + } +} +``` + +Replace every illustrative value with the actual current fence and retained attempt count; do not assume the example epoch is current. Supply `externalFileId` for a verified file operation as required by its frozen operation and checkpoint. Existing provider identities are immutable; reconciliation cannot replace them with a different message or file. + +For a progress update, `POST /progress/reconcile` with the current `fence`, the retained progress `revision`, and a `receipt` containing `outcome: "confirmed"`, the retained `attempts` and verified `externalMessageKey`. The message identity remains fixed across progress revisions. + +Once every required delivery operation is confirmed, `POST /commit` with the current `fence` to complete delivery and release the actor lane. Resume normal gateway processing afterward. If any required result remains uncertain, keep the run held rather than resending or recreating it. Optional exhausted effects follow the gateway's bounded recovery policy and do not justify replaying a required answer. + ## Gateway protocol boundary Service requests use `Authorization: Bearer ` and the exact tenant/channel context. For routes without a tenant path parameter, send the channel's exact tenant in `x-tenant-id`; do not choose a tenant from untrusted message text. The service token permits this integration boundary, not arbitrary user impersonation. Never put it in client-side code, Slack messages, tracing payloads, or public logs. The credential bundle endpoint returns secrets to the trusted gateway and must not be exposed as a public discovery API. @@ -194,4 +318,6 @@ Reaction feedback maps only to confirmed delivered assistant messages. It does n Disabling a channel or changing its credential mode retires old authority; it does not undo external tool effects. Stop can remain pending until the exact provider is drained and canonical cancellation/cleanup completes. A gateway must poll/reconcile canonical state rather than interpreting an acknowledgement as terminal completion. +With the process-local job store, restarting the API while a tool approval is pending makes the review unavailable. The request stays held for reconciliation and a stale approval does not execute the tool. Durable checkpoint storage alone does not recreate the missing live execution state. Completed history and subsequent thread continuation survive restart. + The gateway package is built from the LibreChat source tree; it is not published as an npm package. This integration does not promise arbitrary chat-platform support, automatic migration of legacy thread-wide identity, or restart-survival of an in-memory OAuth waiter. A restart can require a new browser sign-in; uncertain continuation must not be reported as completed or retried as new work. Legacy thread read/write bookkeeping is not a substitute for actor-scoped runs. diff --git a/content/docs/features/background_responses.mdx b/content/docs/features/background_responses.mdx index ddfa59b1b..f7306615c 100644 --- a/content/docs/features/background_responses.mdx +++ b/content/docs/features/background_responses.mdx @@ -25,6 +25,8 @@ endpoints: `enabled` defaults to `false`. `acknowledgementTimeoutMs` defaults to `10000` and accepts integers from `100` through `60000`; it bounds the worker admission acknowledgement, not total model execution time. Existing Remote Agents permissions, Agent access, terms acceptance, content checks, and provider/tool policies still apply. +Stored background Responses require a MongoDB replica set or another verified transaction-capable database. Standalone MongoDB and FerretDB 2.7 do not support this durable feature; ordinary LibreChat remains available. See the [local replica setup](/docs/features/agent_channels#docker-compose). + Background submission requires an **Agent API key**, including when ordinary inference also accepts OIDC. A management API machine token is not an execution credential. Configure [Remote Agents permissions](/docs/features/agents_api#setup) separately. Human tool approval and Ask User pauses require durable MongoDB checkpoint storage. Use the existing [`toolApproval`](/docs/configuration/librechat_yaml/object_structure/agents#toolapproval), Ask User, and [`checkpointer`](/docs/configuration/librechat_yaml/object_structure/agents#checkpointer) settings; background execution does not automatically enable approval or bypass a deny rule. A memory checkpointer does not provide durable background human-action resume. Ordinary requests without a human pause retain their normal execution path. From 76c622c0107030b98097127a9d3e0337695a96e7 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 3 Nov 2026 15:06:06 -0800 Subject: [PATCH 11/30] docs: explain release images and optional gateway Helm setup --- content/docs/features/agent_channels.mdx | 41 +++++++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 6ce24fd11..5d79e13ff 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -90,16 +90,16 @@ The webhook receiver verifies Slack signatures using the connection's signing se ### Docker Compose -The optional `docker-compose.channels.yml` overlay builds both LibreChat and the standalone gateway from the source checkout. The separate `docker-compose.mongo-replica.yml` overlay initializes a single local MongoDB replica member and waits for a writable primary before the application starts. The gateway waits for application health, then authenticates its channel binding and selected Slack transport. Neither service is added to the default stack automatically. +The optional `docker-compose.channels.yml` overlay pulls release-matched LibreChat and gateway images. Set `LIBRECHAT_IMAGE_TAG` in `.env` to the release tag you are installing (including `-rcN` for a release candidate); both images use that same tag. If omitted, both use the latest stable release. Images are published for Linux AMD64 and ARM64 when the corresponding LibreChat release is published. A tag predating Agent Channels does not contain a gateway image. The separate `docker-compose.mongo-replica.yml` overlay initializes a single local MongoDB replica member and waits for a writable primary before the application starts. The gateway waits for application health, then authenticates its channel binding and selected Slack transport. Neither service is added to the default stack automatically. For a **fresh local database**, run these commands from the LibreChat repository root: -1. Prepare `.env` and `librechat.yaml` using the normal LibreChat setup and the channel policy above. Generate a private service token with `openssl rand -hex 32` and set `CHANNEL_SERVICE_TOKEN` in `.env`. Keep the same Compose files and project name on subsequent commands. -2. Start the source-built application and its dependencies: +1. Prepare `.env` and `librechat.yaml` using the normal LibreChat setup and the channel policy above. Set `LIBRECHAT_IMAGE_TAG` to the published LibreChat release containing Channels. Generate a private service token with `openssl rand -hex 32` and set `CHANNEL_SERVICE_TOKEN` in `.env`. Keep the same Compose files and project name on subsequent commands. +2. Pull and start the application and its dependencies: ```sh docker compose -f docker-compose.yml -f docker-compose.channels.yml \ - -f docker-compose.mongo-replica.yml up -d --build api meilisearch + -f docker-compose.mongo-replica.yml up -d --pull always api meilisearch ``` 3. Sign in, save an Agent, and [set up its Slack channel](#set-up-a-channel). Enter the bot token in the Agent builder. Set `CHANNEL_ID` in `.env` to the resulting connection ID. `CHANNEL_TENANT_ID` defaults to `_` for an ordinary OSS installation; supply the actual tenant ID for a tenant-scoped installation. For Socket Mode, also set `SLACK_APP_TOKEN` to the matching app-level token with `connections:write`. @@ -107,7 +107,7 @@ For a **fresh local database**, run these commands from the LibreChat repository ```sh docker compose -f docker-compose.yml -f docker-compose.channels.yml \ - -f docker-compose.mongo-replica.yml --profile channels up -d --build channel-gateway + -f docker-compose.mongo-replica.yml --profile channels up -d --pull always channel-gateway ``` 5. Check readiness and startup errors: @@ -127,6 +127,8 @@ For an existing external transaction-capable database, omit the local MongoDB re A separate gateway environment file can be supplied through `--env-file .env --env-file /secure/channel-gateway.env`. Keep `CHANNEL_SERVICE_TOKEN` identical in LibreChat's own `.env`; Compose substitution does not update the file mounted into the application. +For development or an unreleased checkout, add `-f docker-compose.channels-build.yml` immediately after `-f docker-compose.channels.yml` on **every** Compose command. This explicitly builds both services from the checkout instead of using release images. Use `up -d --build` instead of `up -d --pull always` on that path. The normal release path needs no local Node.js installation or image build. + To build only the gateway image, use the repository root as its build context: ```sh @@ -168,6 +170,35 @@ To opt into Slack's native Agent sessions, enable Agent mode in the Slack app, a Native sessions show processing or waiting-for-input status and return to active when the canonical run finishes. Completed answers can include Helpful/Not helpful controls. Optional lifecycle reactions use `endpoints.agents.channels.lifecycleReactions: true`, are separate from native sessions and require the reaction permissions already present in the basic manifest. Neither an acknowledgement nor a reaction proves a tool completed; Stop requests cancellation of the sender's authorized work, not another participant's run. +## Kubernetes and Helm + +The LibreChat Helm chart can run one optional gateway for a configured connection. Start with the gateway disabled, configure the channel/background policy above in your existing `librechat.yaml`, then create and activate the connection in the Agent builder. Enable the gateway after obtaining its connection ID. + +Pin `image.tag` to a published LibreChat release containing Channels. The gateway image tag defaults to that same value (or the chart's application version when no image override is supplied). Earlier releases have no gateway image. A custom `channelGateway.image.tag` is available for deliberate image overrides. + +```yaml filename="channel-values.yaml" +image: + tag: +channelGateway: + enabled: true + channelId: + tenantId: "_" + # Defaults to global.librechat.existingSecretName. + existingSecretName: librechat-credentials-env +``` + +The existing Secret must contain `CHANNEL_SERVICE_TOKEN` matching LibreChat's server configuration and `SLACK_APP_TOKEN` for the matching Socket Mode app. By default, the application's existing Secret supplies the same service token to LibreChat. The gateway references only these individual keys, not all provider/database credentials. If you choose a separate gateway Secret, keep its service token identical to the API's. Rotate through your normal secret-management process and restart the API and gateway after rotation; changing an existing Secret does not automatically restart pods. + +The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure resources, node selectors, tolerations, affinity, image pull secrets and pod annotations through the chart values. This installs a single gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. + +For webhook transport, set the server policy to `webhook`, configure its public HTTPS gateway URL and set `channelGateway.slackAppTokenKey: ""`. Route the required Slack callback paths through your existing HTTPS ingress to `-librechat-channel-gateway:8080` (use the rendered Service name when overriding chart names). The chart creates a ClusterIP Service, not a public Ingress. Keep readiness, liveness and metrics private. Socket Mode needs no public ingress. + +The gateway runs without Kubernetes API credentials, as a non-root user with a read-only filesystem and dropped capabilities. `/livez` drives liveness and `/readyz` drives readiness. Startup before the API or channel is available fails closed; Kubernetes retries the process, and it becomes ready after validating its active connection and transport. + +**The chart does not configure or convert MongoDB topology.** Supply a transaction-capable database before enabling Channels. The default standalone database cannot run this feature. See the [Helm database configuration](/docs/local/helm_chart) for external database credentials. Normal LibreChat remains usable without enabling Channels. + +After applying the values through your normal Helm upgrade, check the gateway Deployment, pod events, logs and readiness. Missing Secret keys block pod startup; incorrect credentials or channel bindings prevent readiness. Finish with a real Slack mention and account linking rather than treating a successful Helm release as proof of integration. + ## Rich Agent messages An Agent can return semantic presentation data in its final answer. The gateway validates the document and converts it deterministically to Slack Block Kit; it does not accept arbitrary Slack JSON, callback IDs, approval controls, file identifiers or modal definitions. Ordinary Markdown remains unchanged. This works in both ordinary threads and native Agent sessions, without a new OAuth scope or a configuration migration. From c2674c2aee8e373b0398d30999df8d32b825bd4d Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 3 Nov 2026 15:42:47 -0800 Subject: [PATCH 12/30] docs: clarify gateway release selection and branding --- content/docs/features/agent_channels.mdx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 5d79e13ff..a9ee6086e 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -172,9 +172,9 @@ Native sessions show processing or waiting-for-input status and return to active ## Kubernetes and Helm -The LibreChat Helm chart can run one optional gateway for a configured connection. Start with the gateway disabled, configure the channel/background policy above in your existing `librechat.yaml`, then create and activate the connection in the Agent builder. Enable the gateway after obtaining its connection ID. +The LibreChat Helm chart can run one optional gateway for a configured connection. First select a published LibreChat release containing Channels through `image.tag` and upgrade the application with the gateway disabled. Configure the channel/background policy above in your existing `librechat.yaml`, then create and activate the connection in the Agent builder. Enable the gateway after obtaining its connection ID. -Pin `image.tag` to a published LibreChat release containing Channels. The gateway image tag defaults to that same value (or the chart's application version when no image override is supplied). Earlier releases have no gateway image. A custom `channelGateway.image.tag` is available for deliberate image overrides. +Enabling the gateway requires an explicit `image.tag` selecting a published LibreChat release containing Channels; the chart refuses to silently use its older application-version default. The gateway image tag defaults to that same selected release. Earlier releases have no gateway image. A custom `channelGateway.image.tag` is available for deliberate image overrides. ```yaml filename="channel-values.yaml" image: @@ -187,6 +187,8 @@ channelGateway: existingSecretName: librechat-credentials-env ``` +For branding, `channelGateway.appTitle` defaults to `librechat.configEnv.APP_TITLE`, then `LibreChat`. Set it explicitly to the same application title when the API obtains `APP_TITLE` through a Secret or `global.librechat.env`. + The existing Secret must contain `CHANNEL_SERVICE_TOKEN` matching LibreChat's server configuration and `SLACK_APP_TOKEN` for the matching Socket Mode app. By default, the application's existing Secret supplies the same service token to LibreChat. The gateway references only these individual keys, not all provider/database credentials. If you choose a separate gateway Secret, keep its service token identical to the API's. Rotate through your normal secret-management process and restart the API and gateway after rotation; changing an existing Secret does not automatically restart pods. The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure resources, node selectors, tolerations, affinity, image pull secrets and pod annotations through the chart values. This installs a single gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. From 684484c52c46bf87791d10a89c117a46540b99c2 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 3 Nov 2026 15:57:15 -0800 Subject: [PATCH 13/30] docs: describe shared gateway platform settings --- content/docs/features/agent_channels.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index a9ee6086e..72821e8ff 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -191,11 +191,11 @@ For branding, `channelGateway.appTitle` defaults to `librechat.configEnv.APP_TIT The existing Secret must contain `CHANNEL_SERVICE_TOKEN` matching LibreChat's server configuration and `SLACK_APP_TOKEN` for the matching Socket Mode app. By default, the application's existing Secret supplies the same service token to LibreChat. The gateway references only these individual keys, not all provider/database credentials. If you choose a separate gateway Secret, keep its service token identical to the API's. Rotate through your normal secret-management process and restart the API and gateway after rotation; changing an existing Secret does not automatically restart pods. -The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure resources, node selectors, tolerations, affinity, image pull secrets and pod annotations through the chart values. This installs a single gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. +The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure gateway resources and annotations through `channelGateway`. Pod identity, `enableServiceLinks`, DNS, host aliases, image pull secrets, node selectors, tolerations and affinity follow the chart's shared platform settings. The configured ServiceAccount is reused while the gateway keeps its Kubernetes API token automount disabled. This installs a single gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. For webhook transport, set the server policy to `webhook`, configure its public HTTPS gateway URL and set `channelGateway.slackAppTokenKey: ""`. Route the required Slack callback paths through your existing HTTPS ingress to `-librechat-channel-gateway:8080` (use the rendered Service name when overriding chart names). The chart creates a ClusterIP Service, not a public Ingress. Keep readiness, liveness and metrics private. Socket Mode needs no public ingress. -The gateway runs without Kubernetes API credentials, as a non-root user with a read-only filesystem and dropped capabilities. `/livez` drives liveness and `/readyz` drives readiness. Startup before the API or channel is available fails closed; Kubernetes retries the process, and it becomes ready after validating its active connection and transport. +By default, the gateway runs without an automatically mounted Kubernetes API token, as a non-root user with a read-only filesystem and dropped capabilities. The chart's global pod/container security contexts are honored for platform-specific overrides. Gateway version labels follow its selected image tag. `/livez` drives liveness and `/readyz` drives readiness. Startup before the API or channel is available fails closed; Kubernetes retries the process, and it becomes ready after validating its active connection and transport. **The chart does not configure or convert MongoDB topology.** Supply a transaction-capable database before enabling Channels. The default standalone database cannot run this feature. See the [Helm database configuration](/docs/local/helm_chart) for external database credentials. Normal LibreChat remains usable without enabling Channels. From 3aed01f9ba84710b831e5a3a54114f266b1a06ac Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 3 Nov 2026 16:13:25 -0800 Subject: [PATCH 14/30] docs: explain gateway title validation and webhook ingress --- content/docs/features/agent_channels.mdx | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 72821e8ff..9ba71a4f1 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -187,13 +187,31 @@ channelGateway: existingSecretName: librechat-credentials-env ``` -For branding, `channelGateway.appTitle` defaults to `librechat.configEnv.APP_TITLE`, then `LibreChat`. Set it explicitly to the same application title when the API obtains `APP_TITLE` through a Secret or `global.librechat.env`. +For branding, `channelGateway.appTitle` defaults to `librechat.configEnv.APP_TITLE`, then `LibreChat`. Set it explicitly when the API obtains `APP_TITLE` through a Secret or `global.librechat.env`, or choose a shorter gateway title if the application name is not compatible. Gateway titles must be nonempty after trimming, at most 40 UTF-16 characters, and contain no `<`, `>`, `|` or control characters. Helm rejects incompatible inherited titles before deployment; the application can keep its existing longer name. The existing Secret must contain `CHANNEL_SERVICE_TOKEN` matching LibreChat's server configuration and `SLACK_APP_TOKEN` for the matching Socket Mode app. By default, the application's existing Secret supplies the same service token to LibreChat. The gateway references only these individual keys, not all provider/database credentials. If you choose a separate gateway Secret, keep its service token identical to the API's. Rotate through your normal secret-management process and restart the API and gateway after rotation; changing an existing Secret does not automatically restart pods. The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure gateway resources and annotations through `channelGateway`. Pod identity, `enableServiceLinks`, DNS, host aliases, image pull secrets, node selectors, tolerations and affinity follow the chart's shared platform settings. The configured ServiceAccount is reused while the gateway keeps its Kubernetes API token automount disabled. This installs a single gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. -For webhook transport, set the server policy to `webhook`, configure its public HTTPS gateway URL and set `channelGateway.slackAppTokenKey: ""`. Route the required Slack callback paths through your existing HTTPS ingress to `-librechat-channel-gateway:8080` (use the rendered Service name when overriding chart names). The chart creates a ClusterIP Service, not a public Ingress. Keep readiness, liveness and metrics private. Socket Mode needs no public ingress. +For webhook transport, set the server policy to `webhook`, configure its public HTTPS gateway URL and clear `channelGateway.slackAppTokenKey`. Enable the dedicated gateway Ingress using your installed ingress controller and a trusted TLS certificate: + +```yaml filename="channel-values.yaml" +channelGateway: + slackAppTokenKey: "" + ingress: + enabled: true + host: gateway.example.com + # Empty inherits ingress.className; set this for a different controller. + className: nginx + annotations: {} + tls: + - hosts: [gateway.example.com] + secretName: gateway-tls +``` + +Combine these settings with the enabled gateway and explicit application release above. Set the server's `gatewayUrl` to `https://gateway.example.com`, with no path prefix. The new Ingress routes only `/slack/events` and `/slack/interactions` to the gateway Service on port 8080; its health and metrics routes remain private. It can share the application's hostname: the more specific Slack paths route to the gateway while the existing application Ingress keeps its own backend. Gateway annotations are separate so application rewrite rules cannot silently change callback paths. The gateway Ingress requires Kubernetes 1.19+. + +The chart does not install an ingress controller or issue a TLS certificate. Configure TLS through the example Secret, your normal certificate controller/annotations, or an existing HTTPS termination layer. Slack needs a publicly trusted HTTPS endpoint. If you manage a separate external Ingress or need a custom base-path rewrite, leave `channelGateway.ingress.enabled: false` and route the callback paths to the rendered gateway Service yourself; do not add them as paths on the main application Ingress, whose backend is LibreChat. Socket Mode needs no public ingress. By default, the gateway runs without an automatically mounted Kubernetes API token, as a non-root user with a read-only filesystem and dropped capabilities. The chart's global pod/container security contexts are honored for platform-specific overrides. Gateway version labels follow its selected image tag. `/livez` drives liveness and `/readyz` drives readiness. Startup before the API or channel is available fails closed; Kubernetes retries the process, and it becomes ready after validating its active connection and transport. From 8f18cad39985cf5df17825dee6495bd6ee6784e5 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 4 Nov 2026 14:00:45 -0800 Subject: [PATCH 15/30] docs: Explain Shared Slack Workspace Setup and Management --- .../object_structure/agents.mdx | 16 +++ content/docs/features/agent_channels.mdx | 103 ++++++++++++++++-- 2 files changed, 112 insertions(+), 7 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index 6c8c4a5db..36af1fd5b 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1519,6 +1519,22 @@ Configures the opt-in [Agent Channels integration](/docs/features/agent_channels | `artifactReadTimeoutMs` | `30000` | Shared artifact-operation budget, `1000`–`60000` ms; not a separate timeout for each file | | `artifactAnswerFileThresholdBytes` | `6000` | Create new plain-text answer files only above this UTF-8 byte length, `0`–`52428800`; fenced answers also qualify | +`slackApp` configures the operator-owned app for organization workspace installations. Set `channels.enabled: true`, `transport: webhook` and `slackApp.enabled: true`; supply `appId`, `clientId`, `clientSecret` and `signingSecret`. Keep credentials server-side. The deployment opt-in `SLACK_WORKSPACES_ENABLED=true` supplies these settings from `SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET` and `SLACK_SIGNING_SECRET`, enables background Responses, and preserves other YAML settings. Nonempty environment app values take precedence; without the opt-in, YAML remains authoritative. `SLACK_GATEWAY_URL` supplies the public gateway URL. See [Organization workspaces](/docs/features/agent_channels#organization-workspaces) for deployment and UI steps. + +| `slackApp` option | Default | Purpose | +| --- | --- | --- | +| `enabled` | `false` | Enable browser-based workspace installation for the configured app | +| `appId`, `clientId`, `clientSecret`, `signingSecret` | Omitted | Required operator app identity and credentials | +| `flowLifetimeMs` | `600000` | Browser install lifetime, `60000`–`3600000` ms | +| `requestTimeoutMs` | `10000` | Slack installation/verification request deadline, `1000`–`30000` ms | +| `maxResponseBytes` | `65536` | Maximum Slack response bytes, `1024`–`262144` | +| `gateway.ingressConcurrency` | `32` | Concurrent shared ingress requests, `1`–`128` | +| `gateway.workerConcurrency` | `4` | Concurrent durable worker turns per process, `1`–`32` | +| `gateway.discoveryBatchSize` | `32` | Shared discovery page, `1`–`100`, also capped by `maxMetadataPageSize` | +| `gateway.pollIntervalMs` | `1000` | Discovery polling interval, `100`–`60000` ms | + +Workspace-bound Agent connections require personal identities. Shared gateway mode does not mean the manual owner-only `shared` credential mode; it shares transport and workers across installations, while every member retains their own execution identity. + The artifact budget covers catalog queries, storage acquisition/consumption and final authorization. Limits resolution is capped at the schema maximum of 60 seconds; once resolved, its elapsed time counts toward the configured budget. Expiry omits artifacts rather than returning files without current authorization. The threshold applies to new answer-file projections; existing saved descriptors remain bound to their bytes and require current owner, tenant, retention and maximum-size checks. `cleanup` accepts `batchSize` (`25`, range `1`–`100`), `intervalMs` (`1000`, range `1000`–`60000`), and `maxIdleIntervalMs` (`30000`, range `1000`–`300000`). diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 9ba71a4f1..076b3a3e9 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -12,6 +12,8 @@ Agent Channels connect external messaging events to [background Agent Responses] ## Configuration and prerequisites +Choose organization workspaces for one centrally configured Slack app and UI-managed workspace installations. The YAML example below is the manual single-connection setup; the shared-workspace deployment options also enable Channels and background Responses automatically. + ```yaml filename="endpoints / agents" endpoints: agents: @@ -39,7 +41,69 @@ API-key authentication must remain enabled for the gateway's bound execution cre See the [channel configuration reference](/docs/configuration/librechat_yaml/object_structure/agents#channels) for limits and defaults. -## Set up a channel +## Organization workspaces + +A deployment operator configures one Slack app once. Organization administrators then connect workspaces in LibreChat; members link their personal accounts in Slack. Installing an app does not give members access to an Agent or its tools. In a tenant-aware deployment, installations and routing belong to the active tenant. One app/workspace installation has one tenant owner; another tenant cannot claim an active installation. + +### One-time operator setup + +1. Create a Slack app, or use your deployment's existing app. Enable HTTP Events API delivery and interactivity, rather than Socket Mode. Configure these public HTTPS URLs: + + | Setting | URL | + | --- | --- | + | OAuth redirect | `https://chat.example.com/api/channels/workspaces/oauth/callback` | + | Events API | `https://slack.example.com/slack/events` | + | Interactivity | `https://slack.example.com/slack/interactions` | + + Use your configured `DOMAIN_SERVER`, including its application base path, for the OAuth URL. `DOMAIN_CLIENT` is the browser landing origin. The gateway callback URLs have no tenant or connection suffix. Expose only its Slack callback paths; keep gateway health and metrics private. +2. Request bot scopes `app_mentions:read`, `chat:write`, `reactions:read`, `reactions:write`, `files:write`, `im:write` and `im:history`. Subscribe to `app_mention`, `message.im`, `reaction_added`, `reaction_removed` and `agent_session_stopped`. Enable the app's messages tab. Keep token rotation and organization-wide installation disabled: this implementation accepts workspace bot grants, including individual workspaces in Enterprise Grid, and rejects rotating or organization-wide grants. +3. To install into other workspaces, complete Slack's [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. Store the app's ID, client ID, client secret and signing secret in the deployment's secret manager. Organization administrators never need these values or access to deployment environment variables. +4. Configure a transaction-capable database and a private `CHANNEL_SERVICE_TOKEN` shared by the API and gateway. Keep API-key authentication enabled for bound execution; retain normal Agent and Remote Agents permission controls. + +For Docker Compose, put the four app settings in the normal uncommitted `.env`: + +```dotenv +SLACK_APP_ID= +SLACK_CLIENT_ID= +SLACK_CLIENT_SECRET= +SLACK_SIGNING_SECRET= +SLACK_GATEWAY_URL=https://slack.example.com +CHANNEL_SERVICE_TOKEN= +DOMAIN_SERVER=https://chat.example.com +DOMAIN_CLIENT=https://chat.example.com +LIBRECHAT_IMAGE_TAG= +``` + +From a fresh LibreChat setup with `.env` and `librechat.yaml` prepared, start the release-matched application and shared gateway: + +```sh +docker compose -f docker-compose.yml -f docker-compose.channels.yml \ + -f docker-compose.slack-workspaces.yml -f docker-compose.mongo-replica.yml \ + --profile channels up -d api meilisearch channel-gateway +``` + +The replica overlay is for a **fresh local database**; read [Existing local data](#existing-local-data) before converting an existing installation. Omit that overlay when you already use a verified transaction-capable external database and supply its normal connection configuration. Use the same Compose project and files for subsequent commands. This does not configure a public reverse proxy or a trusted certificate; route the two Slack paths to the gateway on port 8080 through your normal ingress. + +The shared overlay supplies `SLACK_WORKSPACES_ENABLED=true`, which enables webhook Channels, shared app installation and stored background Responses while retaining unrelated YAML policy, limits and explicit API authentication settings. Supplied nonempty app environment values override the corresponding app fields in YAML. With the flag unset or false, YAML continues to control the feature. Choosing shared setup changes the deployment's channel transport to webhook; existing bound connections must use matching webhook configuration. Manual Socket Mode remains available when using the manual setup instead. + +No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in shared mode. The gateway receives its service token and private runtime policy; app client credentials stay in LibreChat, and installed bot tokens are encrypted in the database. For an unreleased source checkout, add `docker-compose.channels-build.yml` and use `up -d --build` rather than expecting an unpublished release image. `npm run backend:dev` still starts only the application; for a source gateway process, omit the bound IDs and app-level token and provide the internal API URL and service token. + +### Connect and use a workspace + +1. As an organization administrator, open **Settings → Account → Organization Slack workspaces → Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. +2. Save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Routing changes require organization administration and permission to share the Agent. +3. Choose **Workspace default** for new direct messages and mentions without a channel-specific assignment, or enter a **Specific Slack channel** ID. If another Agent is already assigned, confirm **Use this agent instead**. Existing conversations keep their original Agent. +4. Activate the connection, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. + +### Disconnect and remove + +- **Agent Builder → Channels → Manage connection → Remove** removes an assignment for new conversations. Deleting the connection also removes its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. +- **Settings → Account → Your channel account links** lets a member revoke their own identity link. +- **Settings → Account → Organization Slack workspaces → Disconnect workspace** retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. +- Removing the configuring person does not delete the organization's installation. Their personal links and credentials are cleaned up, and their Agent connections are retired through the normal channel cleanup. +- To stop the optional service, run the same Compose file list and project with `stop channel-gateway`, or set `channelGateway.enabled: false` and remove the shared opt-in from Helm/API configuration. Ordinary LibreChat can continue. Database topology is independent: do not remove an external replica configuration or convert existing data merely to stop the gateway. + +## Set up a manual Slack app connection 1. Save the Agent, then select **Channels → Add** in the Agent builder. Choose per-user or owner-only mode and continue. You need permission to share the Agent. 2. Copy the read-only Slack app manifest into Slack's app setup and install the app into your workspace. Make any app changes in Slack's app settings. @@ -51,7 +115,7 @@ Browser setup routes live under `/api/agents/{agentId}/channels`: list/create, r ## Run the Slack gateway -The gateway is a separate Node.js 24+ process, not an in-process LibreChat plugin. It uses Slack's official Node SDKs and calls LibreChat over HTTP; it does not connect directly to MongoDB or require a general-purpose Agent API key. One gateway configuration binds to one tenant and connection. Run another configured process for another connection. +The gateway is a separate Node.js 24+ process, not an in-process LibreChat plugin. It uses Slack's official Node SDKs and calls LibreChat over HTTP; it does not connect directly to MongoDB or require a general-purpose Agent API key. Manual single-connection mode binds one process to one tenant and connection. Shared mode omits those IDs and serves all installed workspaces with a bounded worker pool. From a LibreChat source checkout containing `packages/channel-gateway`: @@ -102,7 +166,7 @@ For a **fresh local database**, run these commands from the LibreChat repository -f docker-compose.mongo-replica.yml up -d --pull always api meilisearch ``` -3. Sign in, save an Agent, and [set up its Slack channel](#set-up-a-channel). Enter the bot token in the Agent builder. Set `CHANNEL_ID` in `.env` to the resulting connection ID. `CHANNEL_TENANT_ID` defaults to `_` for an ordinary OSS installation; supply the actual tenant ID for a tenant-scoped installation. For Socket Mode, also set `SLACK_APP_TOKEN` to the matching app-level token with `connections:write`. +3. Sign in, save an Agent, and [set up its Slack channel](#set-up-a-manual-slack-app-connection). Enter the bot token in the Agent builder. Set `CHANNEL_ID` in `.env` to the resulting connection ID. `CHANNEL_TENANT_ID` defaults to `_` for an ordinary OSS installation; supply the actual tenant ID for a tenant-scoped installation. For Socket Mode, also set `SLACK_APP_TOKEN` to the matching app-level token with `connections:write`. 4. Start the gateway: ```sh @@ -172,10 +236,35 @@ Native sessions show processing or waiting-for-input status and return to active ## Kubernetes and Helm -The LibreChat Helm chart can run one optional gateway for a configured connection. First select a published LibreChat release containing Channels through `image.tag` and upgrade the application with the gateway disabled. Configure the channel/background policy above in your existing `librechat.yaml`, then create and activate the connection in the Agent builder. Enable the gateway after obtaining its connection ID. +The LibreChat Helm chart supports a shared workspace gateway or a manually bound gateway. For manual single-connection setup, first select a published LibreChat release containing Channels through `image.tag` and upgrade the application with the gateway disabled. Configure the channel/background policy above in your existing `librechat.yaml`, then create and activate the connection in the Agent builder. Enable the gateway after obtaining its connection ID. Enabling the gateway requires an explicit `image.tag` selecting a published LibreChat release containing Channels; the chart refuses to silently use its older application-version default. The gateway image tag defaults to that same selected release. Earlier releases have no gateway image. A custom `channelGateway.image.tag` is available for deliberate image overrides. +### Shared workspace deployment + +Select a release containing organization workspaces and provide an existing Secret with `CHANNEL_SERVICE_TOKEN`, `SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET` and `SLACK_SIGNING_SECRET`. The service token is shared with LibreChat; the four app settings are referenced only by its API pod. You may use separate gateway-service and app Secrets. Existing explicit API environment entries take precedence over generated Secret references. + +```yaml filename="shared-workspace-values.yaml" +image: + tag: +channelGateway: + enabled: true + mode: shared + replicaCount: 2 + existingSecretName: gateway-service-credentials + slackAppSecretName: slack-app-credentials + ingress: + enabled: true + host: slack.example.com + tls: + - hosts: [slack.example.com] + secretName: slack-gateway-tls +``` + +Set `DOMAIN_SERVER` and `DOMAIN_CLIENT` through the application's normal environment settings. Use a transaction-capable database; the chart does not convert MongoDB topology. Shared mode supplies the app enablement flag and derives `SLACK_GATEWAY_URL` from its ingress host unless explicitly configured in `librechat.configEnv`. It omits connection IDs, tenant IDs and the Socket Mode token. Shared replicas use rolling updates and the existing durable claims; `mode: single` requires one replica and uses replacement updates. Configure the Slack app's public URLs as above, then use Account settings and Agent Builder; no per-workspace Helm values or pods are required. + +### Manual connection deployment + ```yaml filename="channel-values.yaml" image: tag: @@ -189,9 +278,9 @@ channelGateway: For branding, `channelGateway.appTitle` defaults to `librechat.configEnv.APP_TITLE`, then `LibreChat`. Set it explicitly when the API obtains `APP_TITLE` through a Secret or `global.librechat.env`, or choose a shorter gateway title if the application name is not compatible. Gateway titles must be nonempty after trimming, at most 40 UTF-16 characters, and contain no `<`, `>`, `|` or control characters. Helm rejects incompatible inherited titles before deployment; the application can keep its existing longer name. -The existing Secret must contain `CHANNEL_SERVICE_TOKEN` matching LibreChat's server configuration and `SLACK_APP_TOKEN` for the matching Socket Mode app. By default, the application's existing Secret supplies the same service token to LibreChat. The gateway references only these individual keys, not all provider/database credentials. If you choose a separate gateway Secret, keep its service token identical to the API's. Rotate through your normal secret-management process and restart the API and gateway after rotation; changing an existing Secret does not automatically restart pods. +For manual Socket Mode, the existing Secret must contain `CHANNEL_SERVICE_TOKEN` matching LibreChat's server configuration and `SLACK_APP_TOKEN` for the matching app. By default, the application's existing Secret supplies the same service token to LibreChat. The gateway references only these individual keys, not all provider/database credentials. If you choose a separate gateway Secret, keep its service token identical to the API's. Rotate through your normal secret-management process and restart the API and gateway after rotation; changing an existing Secret does not automatically restart pods. -The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure gateway resources and annotations through `channelGateway`. Pod identity, `enableServiceLinks`, DNS, host aliases, image pull secrets, node selectors, tolerations and affinity follow the chart's shared platform settings. The configured ServiceAccount is reused while the gateway keeps its Kubernetes API token automount disabled. This installs a single gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. +The gateway derives the API URL from the chart's internal Service and port. Override `channelGateway.internalUrl` for a deliberately different service boundary. Configure gateway resources and annotations through `channelGateway`. Pod identity, `enableServiceLinks`, DNS, host aliases, image pull secrets, node selectors, tolerations and affinity follow the chart's shared platform settings. The configured ServiceAccount is reused while the gateway keeps its Kubernetes API token automount disabled. Manual single mode installs one gateway with replacement updates, so an upgrade may briefly interrupt Slack connectivity; it does not create another channel or Slack app. For webhook transport, set the server policy to `webhook`, configure its public HTTPS gateway URL and clear `channelGateway.slackAppTokenKey`. Enable the dedicated gateway Ingress using your installed ingress controller and a trusted TLS certificate: @@ -213,7 +302,7 @@ Combine these settings with the enabled gateway and explicit application release The chart does not install an ingress controller or issue a TLS certificate. Configure TLS through the example Secret, your normal certificate controller/annotations, or an existing HTTPS termination layer. Slack needs a publicly trusted HTTPS endpoint. If you manage a separate external Ingress or need a custom base-path rewrite, leave `channelGateway.ingress.enabled: false` and route the callback paths to the rendered gateway Service yourself; do not add them as paths on the main application Ingress, whose backend is LibreChat. Socket Mode needs no public ingress. -By default, the gateway runs without an automatically mounted Kubernetes API token, as a non-root user with a read-only filesystem and dropped capabilities. The chart's global pod/container security contexts are honored for platform-specific overrides. Gateway version labels follow its selected image tag. `/livez` drives liveness and `/readyz` drives readiness. Startup before the API or channel is available fails closed; Kubernetes retries the process, and it becomes ready after validating its active connection and transport. +By default, the gateway runs without an automatically mounted Kubernetes API token, as a non-root user with a read-only filesystem and dropped capabilities. The chart's global pod/container security contexts are honored for platform-specific overrides. Gateway version labels follow its selected image tag. `/livez` drives liveness and `/readyz` drives readiness. Startup before the API or channel is available fails closed; Kubernetes retries the process, and it becomes ready after validating the shared app policy or its bound active connection and transport. **The chart does not configure or convert MongoDB topology.** Supply a transaction-capable database before enabling Channels. The default standalone database cannot run this feature. See the [Helm database configuration](/docs/local/helm_chart) for external database credentials. Normal LibreChat remains usable without enabling Channels. From 541e965d5797c43efd9776c85c6b8182dfa915d2 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 4 Nov 2026 14:19:25 -0800 Subject: [PATCH 16/30] docs: Clarify the Explicit Slack OAuth Public URL --- content/docs/features/agent_channels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 076b3a3e9..09a58882b 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -55,7 +55,7 @@ A deployment operator configures one Slack app once. Organization administrators | Events API | `https://slack.example.com/slack/events` | | Interactivity | `https://slack.example.com/slack/interactions` | - Use your configured `DOMAIN_SERVER`, including its application base path, for the OAuth URL. `DOMAIN_CLIENT` is the browser landing origin. The gateway callback URLs have no tenant or connection suffix. Expose only its Slack callback paths; keep gateway health and metrics private. + Use your configured `DOMAIN_SERVER`, including its application base path, for the OAuth URL. The shared deployment opt-in requires this value explicitly; it is not inferred from the gateway hostname. `DOMAIN_CLIENT` is the browser landing origin. The gateway callback URLs have no tenant or connection suffix. Expose only its Slack callback paths; keep gateway health and metrics private. 2. Request bot scopes `app_mentions:read`, `chat:write`, `reactions:read`, `reactions:write`, `files:write`, `im:write` and `im:history`. Subscribe to `app_mention`, `message.im`, `reaction_added`, `reaction_removed` and `agent_session_stopped`. Enable the app's messages tab. Keep token rotation and organization-wide installation disabled: this implementation accepts workspace bot grants, including individual workspaces in Enterprise Grid, and rejects rotating or organization-wide grants. 3. To install into other workspaces, complete Slack's [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. Store the app's ID, client ID, client secret and signing secret in the deployment's secret manager. Organization administrators never need these values or access to deployment environment variables. 4. Configure a transaction-capable database and a private `CHANNEL_SERVICE_TOKEN` shared by the API and gateway. Keep API-key authentication enabled for bound execution; retain normal Agent and Remote Agents permission controls. From 376ef311ba9ed7482d3eab1aff5775aee2477ea7 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 4 Nov 2026 14:31:19 -0800 Subject: [PATCH 17/30] docs: Require Public HTTPS for Shared Slack Deployment --- content/docs/features/agent_channels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 09a58882b..241007fb5 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -55,7 +55,7 @@ A deployment operator configures one Slack app once. Organization administrators | Events API | `https://slack.example.com/slack/events` | | Interactivity | `https://slack.example.com/slack/interactions` | - Use your configured `DOMAIN_SERVER`, including its application base path, for the OAuth URL. The shared deployment opt-in requires this value explicitly; it is not inferred from the gateway hostname. `DOMAIN_CLIENT` is the browser landing origin. The gateway callback URLs have no tenant or connection suffix. Expose only its Slack callback paths; keep gateway health and metrics private. + Use your configured `DOMAIN_SERVER`, including its application base path, for the OAuth URL. `DOMAIN_CLIENT` is the browser landing origin. Replace the localhost defaults in `.env` with public HTTPS addresses for both; the shared deployment opt-in rejects local addresses and does not infer the API URL from the gateway hostname. Any configured `SLACK_GATEWAY_URL` must also be public HTTPS. The gateway callback URLs have no tenant or connection suffix. Expose only its Slack callback paths; keep gateway health and metrics private. 2. Request bot scopes `app_mentions:read`, `chat:write`, `reactions:read`, `reactions:write`, `files:write`, `im:write` and `im:history`. Subscribe to `app_mention`, `message.im`, `reaction_added`, `reaction_removed` and `agent_session_stopped`. Enable the app's messages tab. Keep token rotation and organization-wide installation disabled: this implementation accepts workspace bot grants, including individual workspaces in Enterprise Grid, and rejects rotating or organization-wide grants. 3. To install into other workspaces, complete Slack's [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. Store the app's ID, client ID, client secret and signing secret in the deployment's secret manager. Organization administrators never need these values or access to deployment environment variables. 4. Configure a transaction-capable database and a private `CHANNEL_SERVICE_TOKEN` shared by the API and gateway. Keep API-key authentication enabled for bound execution; retain normal Agent and Remote Agents permission controls. From a2b429c6e19806f5b4a91d1ac25a945b6a98bdc2 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 4 Nov 2026 21:23:20 -0800 Subject: [PATCH 18/30] docs: Explain Organization-Owned Slack App Setup --- .../object_structure/agents.mdx | 5 +-- content/docs/features/agent_channels.mdx | 42 ++++++++----------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index 36af1fd5b..a3f794019 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1519,12 +1519,11 @@ Configures the opt-in [Agent Channels integration](/docs/features/agent_channels | `artifactReadTimeoutMs` | `30000` | Shared artifact-operation budget, `1000`–`60000` ms; not a separate timeout for each file | | `artifactAnswerFileThresholdBytes` | `6000` | Create new plain-text answer files only above this UTF-8 byte length, `0`–`52428800`; fenced answers also qualify | -`slackApp` configures the operator-owned app for organization workspace installations. Set `channels.enabled: true`, `transport: webhook` and `slackApp.enabled: true`; supply `appId`, `clientId`, `clientSecret` and `signingSecret`. Keep credentials server-side. The deployment opt-in `SLACK_WORKSPACES_ENABLED=true` supplies these settings from `SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET` and `SLACK_SIGNING_SECRET`, enables background Responses, and preserves other YAML settings. Nonempty environment app values take precedence; without the opt-in, YAML remains authoritative. `SLACK_GATEWAY_URL` supplies the public gateway URL. See [Organization workspaces](/docs/features/agent_channels#organization-workspaces) for deployment and UI steps. +`slackApp` enables organization-owned apps and sets installation/runtime policy. Set `channels.enabled: true`, `transport: webhook` and `slackApp.enabled: true`. Organization admins register app credentials through LibreChat’s workspace UI; credentials are encrypted in the database and are not YAML or environment settings. The deployment opt-in `SLACK_WORKSPACES_ENABLED=true` enables these policies and background Responses while preserving other YAML settings. Without the opt-in, YAML remains authoritative. `SLACK_GATEWAY_URL` supplies the public gateway URL. See [Organization workspaces](/docs/features/agent_channels#organization-workspaces) for deployment and UI steps. | `slackApp` option | Default | Purpose | | --- | --- | --- | -| `enabled` | `false` | Enable browser-based workspace installation for the configured app | -| `appId`, `clientId`, `clientSecret`, `signingSecret` | Omitted | Required operator app identity and credentials | +| `enabled` | `false` | Enable organization app registration and workspace installation | | `flowLifetimeMs` | `600000` | Browser install lifetime, `60000`–`3600000` ms | | `requestTimeoutMs` | `10000` | Slack installation/verification request deadline, `1000`–`30000` ms | | `maxResponseBytes` | `65536` | Maximum Slack response bytes, `1024`–`262144` | diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 241007fb5..77862054e 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -12,7 +12,7 @@ Agent Channels connect external messaging events to [background Agent Responses] ## Configuration and prerequisites -Choose organization workspaces for one centrally configured Slack app and UI-managed workspace installations. The YAML example below is the manual single-connection setup; the shared-workspace deployment options also enable Channels and background Responses automatically. +Choose organization workspaces for UI-managed, organization-owned Slack apps and workspace installations. The YAML example below is the manual single-connection setup; the shared-workspace deployment options also enable Channels and background Responses automatically. ```yaml filename="endpoints / agents" endpoints: @@ -43,30 +43,17 @@ See the [channel configuration reference](/docs/configuration/librechat_yaml/obj ## Organization workspaces -A deployment operator configures one Slack app once. Organization administrators then connect workspaces in LibreChat; members link their personal accounts in Slack. Installing an app does not give members access to an Agent or its tools. In a tenant-aware deployment, installations and routing belong to the active tenant. One app/workspace installation has one tenant owner; another tenant cannot claim an active installation. +A deployment operator enables the shared gateway once, without creating Slack apps or handling customer credentials. Organization administrators register their own Slack apps and connect workspaces in LibreChat; members link their personal accounts in Slack. Installing an app does not give members access to an Agent or its tools. In a tenant-aware deployment, installations and routing belong to the active tenant. One app/workspace installation has one tenant owner; another tenant cannot claim an active installation. ### One-time operator setup -1. Create a Slack app, or use your deployment's existing app. Enable HTTP Events API delivery and interactivity, rather than Socket Mode. Configure these public HTTPS URLs: +1. Configure transaction-capable MongoDB and a private `CHANNEL_SERVICE_TOKEN` shared by the API and gateway. Keep API-key authentication enabled for bound execution and retain normal Agent and Remote Agents permission controls. +2. Configure public HTTPS `DOMAIN_SERVER` and `DOMAIN_CLIENT`, replacing the localhost defaults in `.env`. Include the application base path when present. Set `SLACK_GATEWAY_URL` to the public gateway origin; it must also use public HTTPS. The shared deployment opt-in rejects local addresses. +3. Route `/slack/events/` and `/slack/interactions/`, including their organization/app suffixes, to the gateway on port 8080. Route the application and OAuth callback to LibreChat. Keep gateway health and metrics private. No Slack dashboard access, app credentials or per-organization infrastructure settings are required. - | Setting | URL | - | --- | --- | - | OAuth redirect | `https://chat.example.com/api/channels/workspaces/oauth/callback` | - | Events API | `https://slack.example.com/slack/events` | - | Interactivity | `https://slack.example.com/slack/interactions` | - - Use your configured `DOMAIN_SERVER`, including its application base path, for the OAuth URL. `DOMAIN_CLIENT` is the browser landing origin. Replace the localhost defaults in `.env` with public HTTPS addresses for both; the shared deployment opt-in rejects local addresses and does not infer the API URL from the gateway hostname. Any configured `SLACK_GATEWAY_URL` must also be public HTTPS. The gateway callback URLs have no tenant or connection suffix. Expose only its Slack callback paths; keep gateway health and metrics private. -2. Request bot scopes `app_mentions:read`, `chat:write`, `reactions:read`, `reactions:write`, `files:write`, `im:write` and `im:history`. Subscribe to `app_mention`, `message.im`, `reaction_added`, `reaction_removed` and `agent_session_stopped`. Enable the app's messages tab. Keep token rotation and organization-wide installation disabled: this implementation accepts workspace bot grants, including individual workspaces in Enterprise Grid, and rejects rotating or organization-wide grants. -3. To install into other workspaces, complete Slack's [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. Store the app's ID, client ID, client secret and signing secret in the deployment's secret manager. Organization administrators never need these values or access to deployment environment variables. -4. Configure a transaction-capable database and a private `CHANNEL_SERVICE_TOKEN` shared by the API and gateway. Keep API-key authentication enabled for bound execution; retain normal Agent and Remote Agents permission controls. - -For Docker Compose, put the four app settings in the normal uncommitted `.env`: +For Docker Compose, use the normal uncommitted `.env`: ```dotenv -SLACK_APP_ID= -SLACK_CLIENT_ID= -SLACK_CLIENT_SECRET= -SLACK_SIGNING_SECRET= SLACK_GATEWAY_URL=https://slack.example.com CHANNEL_SERVICE_TOKEN= DOMAIN_SERVER=https://chat.example.com @@ -84,13 +71,20 @@ docker compose -f docker-compose.yml -f docker-compose.channels.yml \ The replica overlay is for a **fresh local database**; read [Existing local data](#existing-local-data) before converting an existing installation. Omit that overlay when you already use a verified transaction-capable external database and supply its normal connection configuration. Use the same Compose project and files for subsequent commands. This does not configure a public reverse proxy or a trusted certificate; route the two Slack paths to the gateway on port 8080 through your normal ingress. -The shared overlay supplies `SLACK_WORKSPACES_ENABLED=true`, which enables webhook Channels, shared app installation and stored background Responses while retaining unrelated YAML policy, limits and explicit API authentication settings. Supplied nonempty app environment values override the corresponding app fields in YAML. With the flag unset or false, YAML continues to control the feature. Choosing shared setup changes the deployment's channel transport to webhook; existing bound connections must use matching webhook configuration. Manual Socket Mode remains available when using the manual setup instead. +The shared overlay supplies `SLACK_WORKSPACES_ENABLED=true`, which enables webhook Channels, shared app installation and stored background Responses while retaining unrelated YAML policy, limits and explicit API authentication settings. Slack app credentials are entered by organization admins through the UI and stored encrypted; they are not deployment environment variables or YAML fields. With the flag unset or false, YAML continues to control the feature. Choosing shared setup changes the deployment's channel transport to webhook; existing bound connections must use matching webhook configuration. Manual Socket Mode remains available when using the manual setup instead. No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in shared mode. The gateway receives its service token and private runtime policy; app client credentials stay in LibreChat, and installed bot tokens are encrypted in the database. For an unreleased source checkout, add `docker-compose.channels-build.yml` and use `up -d --build` rather than expecting an unpublished release image. `npm run backend:dev` still starts only the application; for a source gateway process, omit the bound IDs and app-level token and provide the internal API URL and service token. +### Register an organization’s Slack app + +1. As an organization administrator, open **Settings → Account → Organization Slack workspaces → Add Slack app**. Create an app from scratch in Slack, or open an existing app your organization controls. Copy its app ID, client ID, client secret and signing secret from **Basic Information → App Credentials**, then save them in LibreChat. Credentials are write-only and encrypted; other members cannot read them back. +2. Expand **Configure these URLs in your Slack app**. Apply the displayed manifest under Slack’s **App Manifest**, including its scopes and event subscriptions. Turn Socket Mode off and configure the displayed OAuth redirect, Events API and Interactivity URLs. Copy the exact URLs: event and interaction callbacks contain your organization and app IDs. Saving the app first lets Slack verify the event URL before workspace installation. +3. Keep token rotation and organization-wide installation disabled. Workspace bot grants, including individual workspaces in Enterprise Grid, are supported. To install into other workspaces, complete Slack’s [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. +4. Each organization may register multiple apps and install each app into multiple workspaces. Use **Replace credentials** after a Slack credential rotation. A stale edit or pending authorization cannot overwrite a newer registration; refresh before retrying a conflicted edit. + ### Connect and use a workspace -1. As an organization administrator, open **Settings → Account → Organization Slack workspaces → Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. +1. Under the registered app, select **Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. 2. Save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Routing changes require organization administration and permission to share the Agent. 3. Choose **Workspace default** for new direct messages and mentions without a channel-specific assignment, or enter a **Specific Slack channel** ID. If another Agent is already assigned, confirm **Use this agent instead**. Existing conversations keep their original Agent. 4. Activate the connection, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. @@ -100,6 +94,7 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in - **Agent Builder → Channels → Manage connection → Remove** removes an assignment for new conversations. Deleting the connection also removes its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. - **Settings → Account → Your channel account links** lets a member revoke their own identity link. - **Settings → Account → Organization Slack workspaces → Disconnect workspace** retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. +- After disconnecting an app’s active workspaces, select **Remove app** and confirm to delete its saved app credentials. This does not delete the Slack app itself. - Removing the configuring person does not delete the organization's installation. Their personal links and credentials are cleaned up, and their Agent connections are retired through the normal channel cleanup. - To stop the optional service, run the same Compose file list and project with `stop channel-gateway`, or set `channelGateway.enabled: false` and remove the shared opt-in from Helm/API configuration. Ordinary LibreChat can continue. Database topology is independent: do not remove an external replica configuration or convert existing data merely to stop the gateway. @@ -242,7 +237,7 @@ Enabling the gateway requires an explicit `image.tag` selecting a published Libr ### Shared workspace deployment -Select a release containing organization workspaces and provide an existing Secret with `CHANNEL_SERVICE_TOKEN`, `SLACK_APP_ID`, `SLACK_CLIENT_ID`, `SLACK_CLIENT_SECRET` and `SLACK_SIGNING_SECRET`. The service token is shared with LibreChat; the four app settings are referenced only by its API pod. You may use separate gateway-service and app Secrets. Existing explicit API environment entries take precedence over generated Secret references. +Select a release containing organization workspaces and provide an existing Secret with `CHANNEL_SERVICE_TOKEN`. The service token is shared with LibreChat. No Slack app credentials belong in this Secret: organization admins register their apps in the UI after deployment. Existing explicit API environment entries take precedence over the generated service-token reference. ```yaml filename="shared-workspace-values.yaml" image: @@ -252,7 +247,6 @@ channelGateway: mode: shared replicaCount: 2 existingSecretName: gateway-service-credentials - slackAppSecretName: slack-app-credentials ingress: enabled: true host: slack.example.com @@ -261,7 +255,7 @@ channelGateway: secretName: slack-gateway-tls ``` -Set `DOMAIN_SERVER` and `DOMAIN_CLIENT` through the application's normal environment settings. Use a transaction-capable database; the chart does not convert MongoDB topology. Shared mode supplies the app enablement flag and derives `SLACK_GATEWAY_URL` from its ingress host unless explicitly configured in `librechat.configEnv`. It omits connection IDs, tenant IDs and the Socket Mode token. Shared replicas use rolling updates and the existing durable claims; `mode: single` requires one replica and uses replacement updates. Configure the Slack app's public URLs as above, then use Account settings and Agent Builder; no per-workspace Helm values or pods are required. +Set `DOMAIN_SERVER` and `DOMAIN_CLIENT` through the application's normal environment settings. Use a transaction-capable database; the chart does not convert MongoDB topology. Shared mode supplies the app enablement flag and derives `SLACK_GATEWAY_URL` from its ingress host unless explicitly configured in `librechat.configEnv`. It omits connection IDs, tenant IDs and the Socket Mode token. Shared replicas use rolling updates and the existing durable claims; `mode: single` requires one replica and uses replacement updates. After deployment, organization admins register their apps and configure the displayed Slack URLs through Account settings, then use Agent Builder; no per-workspace Helm values or pods are required. ### Manual connection deployment From bb468c8047c52316e14aeb6d929fdbb3d2955a03 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Wed, 4 Nov 2026 21:35:48 -0800 Subject: [PATCH 19/30] docs: Clarify Slack Manifest URL Verification --- content/docs/features/agent_channels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 77862054e..a5bbd2212 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -78,7 +78,7 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in ### Register an organization’s Slack app 1. As an organization administrator, open **Settings → Account → Organization Slack workspaces → Add Slack app**. Create an app from scratch in Slack, or open an existing app your organization controls. Copy its app ID, client ID, client secret and signing secret from **Basic Information → App Credentials**, then save them in LibreChat. Credentials are write-only and encrypted; other members cannot read them back. -2. Expand **Configure these URLs in your Slack app**. Apply the displayed manifest under Slack’s **App Manifest**, including its scopes and event subscriptions. Turn Socket Mode off and configure the displayed OAuth redirect, Events API and Interactivity URLs. Copy the exact URLs: event and interaction callbacks contain your organization and app IDs. Saving the app first lets Slack verify the event URL before workspace installation. +2. Expand **Configure these URLs in your Slack app**. Apply the displayed manifest under Slack’s **App Manifest**, including its scopes and event subscriptions. Turn Socket Mode off and configure the displayed OAuth redirect, Events API and Interactivity URLs. Copy the exact URLs: event and interaction callbacks contain your organization and app IDs. Saving the app first lets Slack verify the event URL before workspace installation. If Slack reports that the manifest’s event URL is not verified, choose **Click here to verify**, wait for verification to succeed, and finish saving the Slack settings. 3. Keep token rotation and organization-wide installation disabled. Workspace bot grants, including individual workspaces in Enterprise Grid, are supported. To install into other workspaces, complete Slack’s [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. 4. Each organization may register multiple apps and install each app into multiple workspaces. Use **Replace credentials** after a Slack credential rotation. A stale edit or pending authorization cannot overwrite a newer registration; refresh before retrying a conflicted edit. From ca10dee5445a087c9776de40decd1a962106609b Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 5 Nov 2026 00:01:26 -0800 Subject: [PATCH 20/30] docs: Clarify Shared Gateway Proxy and MongoDB Prerequisites --- content/docs/features/agent_channels.mdx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index a5bbd2212..fe5070834 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -48,8 +48,8 @@ A deployment operator enables the shared gateway once, without creating Slack ap ### One-time operator setup 1. Configure transaction-capable MongoDB and a private `CHANNEL_SERVICE_TOKEN` shared by the API and gateway. Keep API-key authentication enabled for bound execution and retain normal Agent and Remote Agents permission controls. -2. Configure public HTTPS `DOMAIN_SERVER` and `DOMAIN_CLIENT`, replacing the localhost defaults in `.env`. Include the application base path when present. Set `SLACK_GATEWAY_URL` to the public gateway origin; it must also use public HTTPS. The shared deployment opt-in rejects local addresses. -3. Route `/slack/events/` and `/slack/interactions/`, including their organization/app suffixes, to the gateway on port 8080. Route the application and OAuth callback to LibreChat. Keep gateway health and metrics private. No Slack dashboard access, app credentials or per-organization infrastructure settings are required. +2. Configure public HTTPS `DOMAIN_SERVER` and `DOMAIN_CLIENT`, replacing the localhost defaults in `.env`. Both are required and must have no surrounding whitespace. Include the application base path when present. Set `SLACK_GATEWAY_URL` to the public gateway origin; it must also use public HTTPS. The shared deployment opt-in rejects local addresses. +3. Route `/slack/events/` and `/slack/interactions/`, including their organization/app suffixes, to the gateway. Its container listens on port 8080; the shared Compose overlay publishes it at `127.0.0.1:3081` for a host-level HTTPS proxy. Route the application and OAuth callback to LibreChat. Keep gateway health and metrics private. No Slack dashboard access, app credentials or per-organization infrastructure settings are required. For Docker Compose, use the normal uncommitted `.env`: @@ -69,7 +69,7 @@ docker compose -f docker-compose.yml -f docker-compose.channels.yml \ --profile channels up -d api meilisearch channel-gateway ``` -The replica overlay is for a **fresh local database**; read [Existing local data](#existing-local-data) before converting an existing installation. Omit that overlay when you already use a verified transaction-capable external database and supply its normal connection configuration. Use the same Compose project and files for subsequent commands. This does not configure a public reverse proxy or a trusted certificate; route the two Slack paths to the gateway on port 8080 through your normal ingress. +The replica overlay is for a **fresh local database**; read [Existing local data](#existing-local-data) before converting an existing installation. Omit that overlay when you already use a verified transaction-capable external database and supply its normal connection configuration. Use the same Compose project and files for subsequent commands. This does not configure a public reverse proxy or a trusted certificate. A host-level proxy forwards the two Slack paths to `http://127.0.0.1:3081`, preserving the organization/app suffixes. Set `CHANNEL_GATEWAY_PORT` in `.env` to change that loopback port. A proxy in the same Compose network can instead forward to `http://channel-gateway:8080`. The shared overlay supplies `SLACK_WORKSPACES_ENABLED=true`, which enables webhook Channels, shared app installation and stored background Responses while retaining unrelated YAML policy, limits and explicit API authentication settings. Slack app credentials are entered by organization admins through the UI and stored encrypted; they are not deployment environment variables or YAML fields. With the flag unset or false, YAML continues to control the feature. Choosing shared setup changes the deployment's channel transport to webhook; existing bound connections must use matching webhook configuration. Manual Socket Mode remains available when using the manual setup instead. @@ -239,9 +239,13 @@ Enabling the gateway requires an explicit `image.tag` selecting a published Libr Select a release containing organization workspaces and provide an existing Secret with `CHANNEL_SERVICE_TOKEN`. The service token is shared with LibreChat. No Slack app credentials belong in this Secret: organization admins register their apps in the UI after deployment. Existing explicit API environment entries take precedence over the generated service-token reference. +The example below selects a replica set for a **fresh bundled MongoDB**. For an existing standalone database, plan and complete its data migration before changing topology; a Helm value does not migrate existing data. To use an external transaction-capable database, set `mongodb.enabled: false` and supply its connection through your normal application configuration. Shared mode refuses to render with a bundled standalone MongoDB. + ```yaml filename="shared-workspace-values.yaml" image: tag: +mongodb: + architecture: replicaset channelGateway: enabled: true mode: shared From 29f03bb481fc837647ee0ce238e80835d7c7f081 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 5 Nov 2026 00:04:47 -0800 Subject: [PATCH 21/30] docs: Clarify External MongoDB Overrides for Shared Workspaces --- content/docs/features/agent_channels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index fe5070834..3459eb97e 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -239,7 +239,7 @@ Enabling the gateway requires an explicit `image.tag` selecting a published Libr Select a release containing organization workspaces and provide an existing Secret with `CHANNEL_SERVICE_TOKEN`. The service token is shared with LibreChat. No Slack app credentials belong in this Secret: organization admins register their apps in the UI after deployment. Existing explicit API environment entries take precedence over the generated service-token reference. -The example below selects a replica set for a **fresh bundled MongoDB**. For an existing standalone database, plan and complete its data migration before changing topology; a Helm value does not migrate existing data. To use an external transaction-capable database, set `mongodb.enabled: false` and supply its connection through your normal application configuration. Shared mode refuses to render with a bundled standalone MongoDB. +The example below selects a replica set for a **fresh bundled MongoDB**. For an existing standalone database, plan and complete its data migration before changing topology; a Helm value does not migrate existing data. For an external transaction-capable database, supply its connection through your normal application configuration and disable the unused bundled database with `mongodb.enabled: false`. Shared mode refuses to render when LibreChat would use a bundled standalone MongoDB; existing external connection overrides remain supported. ```yaml filename="shared-workspace-values.yaml" image: From 88a9921da56072b878be3164467053ac01cd14c0 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 5 Nov 2026 06:33:28 -0800 Subject: [PATCH 22/30] docs: clarify member-owned Slack agent connections --- content/docs/features/agent_channels.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 3459eb97e..848442359 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -85,8 +85,8 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in ### Connect and use a workspace 1. Under the registered app, select **Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. -2. Save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Routing changes require organization administration and permission to share the Agent. -3. Choose **Workspace default** for new direct messages and mentions without a channel-specific assignment, or enter a **Specific Slack channel** ID. If another Agent is already assigned, confirm **Use this agent instead**. Existing conversations keep their original Agent. +2. As an Agent owner or member with permission to share it, save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Members with permission to use Remote Agents and share the Agent can create and manage their own connections to installed workspaces. App registration, workspace installation, disconnect and removal remain organization-admin actions. +3. Choose **Workspace default** for new direct messages and mentions without a channel-specific assignment, or enter a **Specific Slack channel** ID. If another connection you own is already assigned, confirm **Use this agent instead**. Replacing another member's assignment requires an organization administrator; members can instead choose an unassigned Slack channel. Existing conversations keep their original Agent. 4. Activate the connection, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. ### Disconnect and remove From 5df77a0c1432483ccb7b385014bcf3d08267554e Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 5 Nov 2026 06:58:31 -0800 Subject: [PATCH 23/30] docs: explain bot-scoped Slack agent assignments --- content/docs/features/agent_channels.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 848442359..2d9f343e2 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -86,8 +86,8 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in 1. Under the registered app, select **Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. 2. As an Agent owner or member with permission to share it, save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Members with permission to use Remote Agents and share the Agent can create and manage their own connections to installed workspaces. App registration, workspace installation, disconnect and removal remain organization-admin actions. -3. Choose **Workspace default** for new direct messages and mentions without a channel-specific assignment, or enter a **Specific Slack channel** ID. If another connection you own is already assigned, confirm **Use this agent instead**. Replacing another member's assignment requires an organization administrator; members can instead choose an unassigned Slack channel. Existing conversations keep their original Agent. -4. Activate the connection, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. +3. Choose **Default for this bot** for that bot’s new direct messages and mentions without a channel-specific assignment, or select **For a specific channel** and enter its Slack channel ID. These choices affect the selected Slack bot, not other bots in the workspace. If another connection you own is already assigned, confirm **Replace this bot’s current default agent** or **Replace this bot’s agent in this channel**, then select **Replace default agent** or **Replace channel agent**. Replacing another member's assignment requires an organization administrator; members can instead choose an unassigned Slack channel. Existing conversations keep their original Agent. +4. Select **Assign agent** for an unassigned destination, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. ### Disconnect and remove From 63dbe66557be7078229899cc686764069cafbdde Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 5 Nov 2026 07:10:22 -0800 Subject: [PATCH 24/30] docs: describe separate Slack assignment management and confirmations --- content/docs/features/agent_channels.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 2d9f343e2..1460cdc7c 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -86,12 +86,12 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in 1. Under the registered app, select **Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. 2. As an Agent owner or member with permission to share it, save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Members with permission to use Remote Agents and share the Agent can create and manage their own connections to installed workspaces. App registration, workspace installation, disconnect and removal remain organization-admin actions. -3. Choose **Default for this bot** for that bot’s new direct messages and mentions without a channel-specific assignment, or select **For a specific channel** and enter its Slack channel ID. These choices affect the selected Slack bot, not other bots in the workspace. If another connection you own is already assigned, confirm **Replace this bot’s current default agent** or **Replace this bot’s agent in this channel**, then select **Replace default agent** or **Replace channel agent**. Replacing another member's assignment requires an organization administrator; members can instead choose an unassigned Slack channel. Existing conversations keep their original Agent. +3. Choose **Default for this bot** for that bot’s new direct messages and mentions without a channel-specific assignment, or select **For a specific channel** and enter its Slack channel ID. These choices affect the selected Slack bot, not other bots in the workspace. If another connection you own is already assigned, select **Replace default agent** or **Replace channel agent**, review the focused confirmation dialog, then confirm the replacement. Replacing another member's assignment requires an organization administrator; members can instead choose an unassigned Slack channel. Existing conversations keep their original Agent. 4. Select **Assign agent** for an unassigned destination, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. ### Disconnect and remove -- **Agent Builder → Channels → Manage connection → Remove** removes an assignment for new conversations. Deleting the connection also removes its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. +- **Agent Builder → Channels → Manage connection** lists current assignments. Select **Add assignment** to configure another destination, or **Remove** beside an assignment and confirm **Remove assignment** to stop using it for new conversations. Select **Delete connection** and confirm to remove the connection and all its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. - **Settings → Account → Your channel account links** lets a member revoke their own identity link. - **Settings → Account → Organization Slack workspaces → Disconnect workspace** retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. - After disconnecting an app’s active workspaces, select **Remove app** and confirm to delete its saved app credentials. This does not delete the Slack app itself. From beef625b9f2dc7cdc6bb9d667e3d559d4232e31c Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Thu, 5 Nov 2026 08:00:07 -0800 Subject: [PATCH 25/30] docs: explain administrator-assigned Slack bot managers --- .../librechat_yaml/object_structure/agents.mdx | 2 ++ content/docs/features/agent_channels.mdx | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index a3f794019..43ca93338 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1499,6 +1499,8 @@ Unknown management-auth fields, duplicate client IDs, malformed user or tenant I ## channels +For organization workspaces, `channels.maxBotManagers` limits the number of explicitly granted bot managers per app/workspace installation (default `50`, range `1`–`1000`). Administrators grant these users through **Manage bot access**; bot management does not grant Agent sharing or installation-administration permissions. + Configures the opt-in [Agent Channels integration](/docs/features/agent_channels). Enabled background Responses and a separately running gateway are required. The LibreChat source includes the standalone TypeScript Slack gateway in `packages/channel-gateway`; this setting does not start it or enable execution permissions. | Option | Default | Accepted values / purpose | diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 1460cdc7c..dec068c47 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -85,12 +85,15 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in ### Connect and use a workspace 1. Under the registered app, select **Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. -2. As an Agent owner or member with permission to share it, save the Agent, then open **Channels → Add → Organization workspace** and choose the connected workspace. Members with permission to use Remote Agents and share the Agent can create and manage their own connections to installed workspaces. App registration, workspace installation, disconnect and removal remain organization-admin actions. -3. Choose **Default for this bot** for that bot’s new direct messages and mentions without a channel-specific assignment, or select **For a specific channel** and enter its Slack channel ID. These choices affect the selected Slack bot, not other bots in the workspace. If another connection you own is already assigned, select **Replace default agent** or **Replace channel agent**, review the focused confirmation dialog, then confirm the replacement. Replacing another member's assignment requires an organization administrator; members can instead choose an unassigned Slack channel. Existing conversations keep their original Agent. -4. Select **Assign agent** for an unassigned destination, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. +2. In **Organization Slack workspaces**, an administrator selects **Manage bot access** on the connected workspace and adds the LibreChat users who may manage that bot. Grants apply to this app/workspace installation; they do not grant Agent access, Slack credentials or installation-administration rights. Only administrators can change the manager list. +3. As a bot manager, save an Agent you have permission to share, then open **Channels → Add → Organization workspace** and choose an available workspace. You still need permission to use Remote Agents. Only bots you can manage are offered; installation administrators can also assign agents. +4. Choose **Default for this bot** for that bot’s new direct messages and mentions without a channel-specific assignment, or select **For a specific channel** and enter its Slack channel ID. These choices affect the selected Slack bot, not other bots in the workspace. If another connection is already assigned, a bot manager or administrator can select **Replace default agent** or **Replace channel agent**, review the confirmation dialog, then confirm. The dialog names the current Agent only when you can view it. Existing conversations keep their original Agent. +5. Select **Assign agent** for an unassigned destination, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. ### Disconnect and remove +- Administrators revoke bot management under **Manage bot access**. Removed managers cannot create or change assignments, but can still remove assignments or delete their own Agent connection. Existing assignments and conversations keep running; management access is separate from permission to talk to the bot. Disconnecting a workspace clears its manager grants; a fresh installation requires new grants. Reauthorizing an active installation preserves managers. + - **Agent Builder → Channels → Manage connection** lists current assignments. Select **Add assignment** to configure another destination, or **Remove** beside an assignment and confirm **Remove assignment** to stop using it for new conversations. Select **Delete connection** and confirm to remove the connection and all its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. - **Settings → Account → Your channel account links** lets a member revoke their own identity link. - **Settings → Account → Organization Slack workspaces → Disconnect workspace** retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. From 4d7db5a7456a75ad0251cb798355d5c41b2ea5d1 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Mon, 9 Nov 2026 23:52:12 -0800 Subject: [PATCH 26/30] =?UTF-8?q?=F0=9F=93=9A=20docs:=20Align=20Slack=20Se?= =?UTF-8?q?tup=20With=20App=20Onboarding?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../object_structure/agents.mdx | 6 +- content/docs/features/agent_channels.mdx | 85 ++++++++++++++----- content/docs/features/agents_api.mdx | 6 -- 3 files changed, 68 insertions(+), 29 deletions(-) diff --git a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx index 43ca93338..0bcfbfcb6 100644 --- a/content/docs/configuration/librechat_yaml/object_structure/agents.mdx +++ b/content/docs/configuration/librechat_yaml/object_structure/agents.mdx @@ -1499,14 +1499,14 @@ Unknown management-auth fields, duplicate client IDs, malformed user or tenant I ## channels -For organization workspaces, `channels.maxBotManagers` limits the number of explicitly granted bot managers per app/workspace installation (default `50`, range `1`–`1000`). Administrators grant these users through **Manage bot access**; bot management does not grant Agent sharing or installation-administration permissions. +For organization workspaces, `channels.maxBotManagers` limits the number of explicitly granted bot managers per app/workspace installation (default `50`, range `1`–`1000`). Administrators grant these users through the workspace’s **Manage access** button (**Manage bot access** dialog); bot management does not grant Agent sharing or installation-administration permissions. Configures the opt-in [Agent Channels integration](/docs/features/agent_channels). Enabled background Responses and a separately running gateway are required. The LibreChat source includes the standalone TypeScript Slack gateway in `packages/channel-gateway`; this setting does not start it or enable execution permissions. | Option | Default | Accepted values / purpose | | --- | --- | --- | | `enabled` | `false` | Enable channel setup and service routes | -| `transport` | `socket_mode` | Select `socket_mode` or `webhook` ingress and the generated manifest; the gateway runs separately | +| `transport` | `socket_mode` | Select `socket_mode` or `webhook` ingress; manual connections generate a matching manifest and the gateway runs separately | | `gatewayUrl` | Omitted | Required HTTPS base URL for generating webhook callback URLs; not needed for Socket Mode | | `nativeSessions` | `false` | Enable optional Slack native Agent status emission after app setup | | `lifecycleReactions` | `false` | Add optional processing/completion reactions | @@ -1521,7 +1521,7 @@ Configures the opt-in [Agent Channels integration](/docs/features/agent_channels | `artifactReadTimeoutMs` | `30000` | Shared artifact-operation budget, `1000`–`60000` ms; not a separate timeout for each file | | `artifactAnswerFileThresholdBytes` | `6000` | Create new plain-text answer files only above this UTF-8 byte length, `0`–`52428800`; fenced answers also qualify | -`slackApp` enables organization-owned apps and sets installation/runtime policy. Set `channels.enabled: true`, `transport: webhook` and `slackApp.enabled: true`. Organization admins register app credentials through LibreChat’s workspace UI; credentials are encrypted in the database and are not YAML or environment settings. The deployment opt-in `SLACK_WORKSPACES_ENABLED=true` enables these policies and background Responses while preserving other YAML settings. Without the opt-in, YAML remains authoritative. `SLACK_GATEWAY_URL` supplies the public gateway URL. See [Organization workspaces](/docs/features/agent_channels#organization-workspaces) for deployment and UI steps. +`slackApp` enables organization-owned apps and sets installation/runtime policy. Set `channels.enabled: true`, `transport: webhook` and `slackApp.enabled: true`. Each registered app supports one active workspace. Organization admins register an existing Slack app through **Settings → Account → Slack → Set up/Manage → Add Slack app**, with an optional friendly name and app/client credentials; credentials are encrypted in the database and are not YAML or environment settings. The deployment opt-in `SLACK_WORKSPACES_ENABLED=true` enables these policies and background Responses while preserving other YAML settings. Without the opt-in, YAML remains authoritative. `SLACK_GATEWAY_URL` supplies the public gateway URL. See [Organization workspaces](/docs/features/agent_channels#organization-workspaces) for deployment and UI steps. | `slackApp` option | Default | Purpose | | --- | --- | --- | diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index dec068c47..96d7742da 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -31,11 +31,11 @@ endpoints: Both enablement settings default to `false`. Users need both Agent use and Remote Agents use permissions. Channel setup also requires Agent sharing permission or existing administrator management access; sharing access does not require permission to edit the Agent. Configure `DOMAIN_CLIENT` for trusted owner-review and account-link URLs. Configure a strong `CHANNEL_SERVICE_TOKEN` for the gateway-to-LibreChat service boundary; keep it server-side and distribute it only to a trusted integration process over a secure channel. It is not a browser token or a general Agent API key. -The `transport` option accepts `socket_mode` (default) or `webhook`. This selects the generated Slack manifest; it does not deploy a receiver. Webhook manifests require an HTTPS `gatewayUrl` without credentials, a query, or a fragment. The gateway loads this policy from LibreChat before selecting ingress. `SLACK_TRANSPORT` is an optional deployment assertion; if supplied, it must match the server-selected mode. Missing or unsupported gateway policy prevents startup. +The `transport` option accepts `socket_mode` (default) or `webhook`. Manual connections generate a matching Slack manifest; organization workspaces use the webhook setup below. Selecting a transport does not deploy a receiver. Webhook manifests require an HTTPS `gatewayUrl` without credentials, a query, or a fragment. The gateway loads this policy from LibreChat before selecting ingress. `SLACK_TRANSPORT` is an optional deployment assertion; if supplied, it must match the server-selected mode. Missing or unsupported gateway policy prevents startup. ### Database requirement -Durable Channels and stored background Responses require MongoDB transactions. Use a MongoDB replica set or another verified transaction-capable deployment. Standalone MongoDB and FerretDB 2.7 can run ordinary LibreChat, but cannot enable this durable feature. Unsupported channel writes return `transactions_unavailable`; the Agent builder explains the setup requirement. Transactional reads use the primary even when the connection normally prefers secondary reads. +Durable Channels and stored background Responses require MongoDB transactions. Use a MongoDB replica set or another verified transaction-capable deployment. Standalone MongoDB and FerretDB 2.7 can run ordinary LibreChat, but cannot enable this durable feature. Unsupported channel writes return `transactions_unavailable`; the Agent builder explains the setup requirement. Transactional reads use the primary even when the connection normally prefers secondary reads. The database must also support the required indexes, including partial indexes; transaction support by itself is not sufficient. [Amazon DocumentDB 4.0 lacks partial-index support](https://docs.aws.amazon.com/documentdb/latest/devguide/indexes-single-field.html) and cannot run this gateway. Other MongoDB-compatible engines need their own compatibility validation. API-key authentication must remain enabled for the gateway's bound execution credential. Linking does not grant Remote Agents permissions, Agent access, new tools or offline access to connected services. @@ -77,33 +77,78 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in ### Register an organization’s Slack app -1. As an organization administrator, open **Settings → Account → Organization Slack workspaces → Add Slack app**. Create an app from scratch in Slack, or open an existing app your organization controls. Copy its app ID, client ID, client secret and signing secret from **Basic Information → App Credentials**, then save them in LibreChat. Credentials are write-only and encrypted; other members cannot read them back. -2. Expand **Configure these URLs in your Slack app**. Apply the displayed manifest under Slack’s **App Manifest**, including its scopes and event subscriptions. Turn Socket Mode off and configure the displayed OAuth redirect, Events API and Interactivity URLs. Copy the exact URLs: event and interaction callbacks contain your organization and app IDs. Saving the app first lets Slack verify the event URL before workspace installation. If Slack reports that the manifest’s event URL is not verified, choose **Click here to verify**, wait for verification to succeed, and finish saving the Slack settings. -3. Keep token rotation and organization-wide installation disabled. Workspace bot grants, including individual workspaces in Enterprise Grid, are supported. To install into other workspaces, complete Slack’s [distribution setup](https://docs.slack.dev/app-management/distribution/). Slack workspace approval policies still apply. -4. Each organization may register multiple apps and install each app into multiple workspaces. Use **Replace credentials** after a Slack credential rotation. A stale edit or pending authorization cannot overwrite a newer registration; refresh before retrying a conflicted edit. +Complete [operator setup](#one-time-operator-setup) first. The gateway must be running and reachable over public HTTPS before Slack can verify its callback. A Slack app is the bot's identity and credentials; its workspace installation is the grant that lets it operate in a particular Slack workspace. LibreChat supports **one active workspace per registered app**. Use separate Slack apps for additional workspaces. + +1. Open [Your Apps](https://api.slack.com/apps) in Slack and create an app from scratch (**Pick features** in the current dashboard, or **Blank app** in Slack’s quickstart). Give it a name and select the workspace where you will manage it. You can instead use an existing app your organization controls. Do not install it yet; finish its settings below first. +2. In LibreChat, open **Settings → Account → Slack → Set up** (or **Manage**), then **Add Slack app**. Copy **App ID**, **Client ID**, **Client Secret**, and **Signing Secret** from that app's **Basic Information → App Credentials**. The optional **Name** identifies the app in LibreChat; it does not rename the bot in Slack. Save the registration. Secrets are encrypted and cannot be read back. +3. Turn **Socket Mode off** in that Slack app before configuring HTTP callbacks. Expand the saved app in LibreChat and open the gear button, **Connection settings**. Configure all three copied URLs in that same Slack app: + + | LibreChat value | Slack setting | + | --- | --- | + | OAuth redirect URL | **OAuth & Permissions → Redirect URLs**; add the URL and save | + | Events URL | **Event Subscriptions → Enable Events** on; paste into **Request URL** and wait for **Verified** | + | Interactivity URL | **Interactivity & Shortcuts → Interactivity** on; paste into **Request URL** and save | + + Copy the exact URLs, including application base paths and organization/app suffixes. Saving the credentials first lets the gateway authenticate Slack's verification request before installation. If verification fails, check the matching signing secret, public gateway address, and running gateway before continuing. +4. Under **OAuth & Permissions → Bot Token Scopes**, add all seven scopes below. No user-token scopes are required: + + ```text + app_mentions:read + chat:write + reactions:read + reactions:write + files:write + im:write + im:history + ``` + +5. Under **Event Subscriptions → Subscribe to bot events**, add `app_mention`, `message.im`, `reaction_added`, `reaction_removed`, `app_uninstalled`, and `tokens_revoked`, then save. The last two require no additional OAuth scopes. The optional [native Agent sessions](#native-agent-ui-and-final-replies) setup additionally uses `agent_session_stopped`. +6. Under **App Home**, enable the **Messages tab** and allow users to send messages from it so direct messages can reach the bot. Leave token rotation and organization-wide installation disabled. Workspace approval policies still apply. + +These are manual Slack settings; LibreChat's organization app screen does not generate a manifest or create the Slack app for you. See Slack's [app setup](https://docs.slack.dev/app-management/quickstart-app-settings/) and [interactive request setup](https://docs.slack.dev/interactivity/handling-user-interaction/) for its dashboard controls. + +Use the pencil button, **Edit App**, to change its friendly name or credentials later. Leaving a secret blank preserves its saved value; clearing **Name** removes the custom LibreChat name. Changing the client ID requires entering the corresponding client secret again. The saved app ID cannot be edited: register another app for a different ID. After adding Slack scopes to an installed app, reconnect it through LibreChat and approve the updated grant; changing app settings alone does not upgrade existing tokens. A conflicted edit requires refreshing the registration before retrying. + +The organization flow does **not** ask you to paste a bot token or an app-level token. A bot token beginning `xoxb-` is used only by [manual connection activation](#set-up-a-manual-slack-app-connection); an app-level token beginning `xapp-` is used only by the manual Socket Mode gateway. Neither is the client secret, signing secret, or `CHANNEL_SERVICE_TOKEN`. ### Connect and use a workspace -1. Under the registered app, select **Connect a Slack workspace**. Approve installation in Slack. Cancel from LibreChat if you do not want to finish; closing Account settings retires an unfinished attempt. -2. In **Organization Slack workspaces**, an administrator selects **Manage bot access** on the connected workspace and adds the LibreChat users who may manage that bot. Grants apply to this app/workspace installation; they do not grant Agent access, Slack credentials or installation-administration rights. Only administrators can change the manager list. -3. As a bot manager, save an Agent you have permission to share, then open **Channels → Add → Organization workspace** and choose an available workspace. You still need permission to use Remote Agents. Only bots you can manage are offered; installation administrators can also assign agents. -4. Choose **Default for this bot** for that bot’s new direct messages and mentions without a channel-specific assignment, or select **For a specific channel** and enter its Slack channel ID. These choices affect the selected Slack bot, not other bots in the workspace. If another connection is already assigned, a bot manager or administrator can select **Replace default agent** or **Replace channel agent**, review the confirmation dialog, then confirm. The dialog names the current Agent only when you can view it. Existing conversations keep their original Agent. -5. Select **Assign agent** for an unassigned destination, invite the bot to the Slack channel and mention it, or send it a direct message. Each member follows **Link your account**, signs into LibreChat, accepts there, then confirms from the same Slack account. Requests use that member's current Agent and tool permissions; installation does not authorize tools or grant offline access to connected services. +1. Under the registered app, select **Add to workspace** and approve installation in Slack. LibreChat shows a **Connecting to Slack…** dialog while this is pending. Use **Cancel** there to abandon the attempt, or **Retry** after a failure. On success, the dialog closes and the workspace appears as **Connected** below the app. Each app can have only one active workspace; reconnect that workspace to refresh its grant, or disconnect it before installing the app elsewhere. +2. An administrator opens the workspace's users button, **Manage access**, and adds the LibreChat users allowed to assign agents through that bot. The dialog is titled **Manage bot access**. Without explicit managers, administrators can still assign agents. These grants do not grant Agent sharing permission, Slack credentials, or installation-administration rights, and are not required just to talk to the bot. +3. Save an Agent you have permission to share. In the Agent builder's **Channels** section, select **Add Slack channel**, choose the **Slack bot**, then **Continue**. You need Remote Agents permission as well as permission to share the Agent. The picker offers only bots you can manage; installation administrators can also assign agents. +4. Choose **Default** for new direct messages and mentions without a channel-specific assignment, or choose **Channel Specific** and enter the **Slack channel ID**. Find the ID in Slack's channel details; it is not the channel name. Select **Assign agent**. If already assigned, **Replace default agent** or **Replace channel agent** opens a confirmation. The current Agent is named only when you can view it. Existing conversations keep their original Agent. +5. In Slack, invite the bot to your test channel, for example `/invite @YourBot`, then mention it with `@YourBot hello`. Installing the app alone does not add it to every channel. You can also send a direct message when the Messages tab is enabled. +6. Follow the private **Link your account** prompt. Sign into the intended LibreChat account, inspect the request, and accept it in the browser. Return to Slack and mention the bot again if no confirmation prompt is present. Confirm the account from that **same Slack account**, then send a **fresh request** to the bot. The original request is not replayed automatically. + +A successful first response completes setup. Each person repeats the personal linking step and runs with their own current Agent permissions, tool credentials, and approvals. Sharing a Slack thread does not lend another participant's MCP connection or authority. To verify tool access, ask for a task using a tool that the linked account is permitted to use, and complete any required approval as that account. + +#### If the bot does not respond + +| Symptom | Check | +| --- | --- | +| Events URL will not verify, or Slack callbacks return `401` | Gateway is running and publicly reachable over HTTPS; URL matches the saved organization/app; **Signing Secret** belongs to that same Slack app. Check clock synchronization against the signature window. Do not disable signature checks. | +| Gateway calls to LibreChat return `401` | API and gateway use the same private `CHANNEL_SERVICE_TOKEN`, and `LIBRECHAT_INTERNAL_URL` reaches the intended LibreChat instance. This is separate from Slack signature verification. | +| Mention produces no response | Check gateway readiness and logs, **Socket Mode off**, **Events on** with the subscriptions above, bot invited to the channel, and an Agent assigned to this bot/destination. Confirm the sender's personal link is active. | +| Confirmation, approval, or Stop buttons do nothing | **Interactivity** is on, its exact Request URL is saved, and the gateway is reachable. The Events URL does not substitute for the Interactivity URL. | +| Link says **Awaiting confirmation** | Browser acceptance is incomplete until that same Slack account confirms in Slack. Mention again to obtain the prompt, confirm, then send a new request. | +| Installation reports missing permissions after scopes changed | Add all required bot scopes, then reconnect through LibreChat and approve the updated grant. Existing installations do not receive new scopes automatically. | + +Use the same Compose project and overlays from operator setup when checking `ps` and `logs --tail=100 api channel-gateway`. A healthy application alone does not prove the separate gateway is ready. See [gateway readiness checks](#docker-compose). ### Disconnect and remove -- Administrators revoke bot management under **Manage bot access**. Removed managers cannot create or change assignments, but can still remove assignments or delete their own Agent connection. Existing assignments and conversations keep running; management access is separate from permission to talk to the bot. Disconnecting a workspace clears its manager grants; a fresh installation requires new grants. Reauthorizing an active installation preserves managers. +- Administrators revoke bot management through the workspace’s **Manage access** users button. Removed managers cannot create or change assignments, but can still remove assignments or delete their own Agent connection. Existing assignments and conversations keep running; management access is separate from permission to talk to the bot. Disconnecting a workspace clears its manager grants; a fresh installation requires new grants. Reauthorizing an active installation preserves managers. -- **Agent Builder → Channels → Manage connection** lists current assignments. Select **Add assignment** to configure another destination, or **Remove** beside an assignment and confirm **Remove assignment** to stop using it for new conversations. Select **Delete connection** and confirm to remove the connection and all its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. -- **Settings → Account → Your channel account links** lets a member revoke their own identity link. -- **Settings → Account → Organization Slack workspaces → Disconnect workspace** retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. -- After disconnecting an app’s active workspaces, select **Remove app** and confirm to delete its saved app credentials. This does not delete the Slack app itself. +- **Agent Builder → Channels → Manage connection** lists current assignments. When another destination is available, select **Add assignment** to configure it, or **Remove** beside an assignment and confirm **Remove assignment** to stop using it for new conversations. Select **Delete connection** and confirm to remove the connection and all its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. +- **Settings → Account → Your channel account links** shows personal links once any exist. Status pills distinguish **In progress**, **Awaiting confirmation**, **Active**, **Revoked**, **Expired**, and **Unavailable**. Select **Revoke link** and confirm to withdraw your own consent, including an unavailable link. Completed actions are not undone. +- **Settings → Account → Slack → Manage**, then the workspace’s **Disconnect workspace** icon retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. +- After disconnecting an app’s active workspace, use the app’s trash button, **Remove app**, and confirm to delete its saved app credentials. This does not delete the Slack app itself. - Removing the configuring person does not delete the organization's installation. Their personal links and credentials are cleaned up, and their Agent connections are retired through the normal channel cleanup. - To stop the optional service, run the same Compose file list and project with `stop channel-gateway`, or set `channelGateway.enabled: false` and remove the shared opt-in from Helm/API configuration. Ordinary LibreChat can continue. Database topology is independent: do not remove an external replica configuration or convert existing data merely to stop the gateway. ## Set up a manual Slack app connection -1. Save the Agent, then select **Channels → Add** in the Agent builder. Choose per-user or owner-only mode and continue. You need permission to share the Agent. +1. Save the Agent, then select **Channels → Add Slack channel** in the Agent builder. Choose per-user or owner-only mode and continue. You need permission to share the Agent. 2. Copy the read-only Slack app manifest into Slack's app setup and install the app into your workspace. Make any app changes in Slack's app settings. 3. Under **Add Credentials**, enter the matching Slack app ID and bot token. For webhooks, also enter its signing secret. Activate the connection. LibreChat verifies the bot identity and stores credentials encrypted; normal setup responses do not return those secrets. 4. Copy the connection ID from the connection details. Configure and start the gateway as described below. It must be able to reach the active connection before startup can complete. @@ -228,9 +273,9 @@ The process exposes `/livez` for HTTP-process liveness, `/readyz` and `/healthz` By default, a stable working message provides Stop and, when needed, Review controls. Answers are posted after generation, rather than repeatedly replacing a growing reply. Formatting includes code, tables, links, file attachments, and qualified cost/time details; unavailable costs are not estimated. -To opt into Slack's native Agent sessions, enable Agent mode in the Slack app, add the `assistant:write` bot scope and `agent_session_stopped` event subscription, and reinstall the app. These are additional to the basic generated manifest. Then set `endpoints.agents.channels.nativeSessions: true` in `librechat.yaml`. Without the required permissions or Stop subscription, the gateway falls back to durable progress controls. See [Slack Agent sessions](https://docs.slack.dev/ai/agent-sessions/) for app configuration. +To opt into Slack's native Agent sessions, enable Agent mode in the Slack app, add the `assistant:write` bot scope and `agent_session_stopped` event subscription, and reinstall the app. These are additional to the basic bot configuration above. Then set `endpoints.agents.channels.nativeSessions: true` in `librechat.yaml`. Without the required permissions or Stop subscription, the gateway falls back to durable progress controls. See [Slack Agent sessions](https://docs.slack.dev/ai/agent-sessions/) for app configuration. -Native sessions show processing or waiting-for-input status and return to active when the canonical run finishes. Completed answers can include Helpful/Not helpful controls. Optional lifecycle reactions use `endpoints.agents.channels.lifecycleReactions: true`, are separate from native sessions and require the reaction permissions already present in the basic manifest. Neither an acknowledgement nor a reaction proves a tool completed; Stop requests cancellation of the sender's authorized work, not another participant's run. +Native sessions show processing or waiting-for-input status and return to active when the canonical run finishes. Completed answers can include Helpful/Not helpful controls. Optional lifecycle reactions use `endpoints.agents.channels.lifecycleReactions: true`, are separate from native sessions and require the reaction permissions already listed in the basic bot scopes. Neither an acknowledgement nor a reaction proves a tool completed; Stop requests cancellation of the sender's authorized work, not another participant's run. ## Kubernetes and Helm @@ -461,4 +506,4 @@ Disabling a channel or changing its credential mode retires old authority; it do With the process-local job store, restarting the API while a tool approval is pending makes the review unavailable. The request stays held for reconciliation and a stale approval does not execute the tool. Durable checkpoint storage alone does not recreate the missing live execution state. Completed history and subsequent thread continuation survive restart. -The gateway package is built from the LibreChat source tree; it is not published as an npm package. This integration does not promise arbitrary chat-platform support, automatic migration of legacy thread-wide identity, or restart-survival of an in-memory OAuth waiter. A restart can require a new browser sign-in; uncertain continuation must not be reported as completed or retried as new work. Legacy thread read/write bookkeeping is not a substitute for actor-scoped runs. +The gateway package is built from the LibreChat source tree; it is not published as an npm package. This integration does not promise arbitrary chat-platform support or restart-survival of an in-memory OAuth waiter. A restart can require a new browser sign-in; uncertain continuation must not be reported as completed or retried as new work. diff --git a/content/docs/features/agents_api.mdx b/content/docs/features/agents_api.mdx index e666f0fee..3eaef7297 100644 --- a/content/docs/features/agents_api.mdx +++ b/content/docs/features/agents_api.mdx @@ -22,12 +22,6 @@ For opt-in asynchronous execution, retained human actions, owner review, and Sto Open **Settings**, go to **Data & Privacy**, and find **Agent API Keys** under **API keys**. Click **Manage**, then **Create API Key**, give it a name, pick an expiration (7 days up to 1 year, or never), and copy the key right away: it is shown only once. - - A key acts as you. Anything you can reach through the API, anyone holding the key can reach too, so delete keys you no longer use. Deleting a key cuts off applications using it immediately. If you do not see the section, your role has not been given access to the Agents API. From 5fb6f50275a85cac40f417974adb66176bc77baa Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 10 Nov 2026 01:20:19 -0800 Subject: [PATCH 27/30] =?UTF-8?q?=F0=9F=93=9A=20docs:=20Clarify=20Slack=20?= =?UTF-8?q?Connection=20Reactivation=20Consent?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- content/docs/features/agent_channels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 96d7742da..eba2ab3d7 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -139,7 +139,7 @@ Use the same Compose project and overlays from operator setup when checking `ps` - Administrators revoke bot management through the workspace’s **Manage access** users button. Removed managers cannot create or change assignments, but can still remove assignments or delete their own Agent connection. Existing assignments and conversations keep running; management access is separate from permission to talk to the bot. Disconnecting a workspace clears its manager grants; a fresh installation requires new grants. Reauthorizing an active installation preserves managers. -- **Agent Builder → Channels → Manage connection** lists current assignments. When another destination is available, select **Add assignment** to configure it, or **Remove** beside an assignment and confirm **Remove assignment** to stop using it for new conversations. Select **Delete connection** and confirm to remove the connection and all its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. +- **Agent Builder → Channels → Manage connection** lists current assignments. When another destination is available, select **Add assignment** to configure it, or **Remove** beside an assignment and confirm **Remove assignment** to stop using it for new conversations. Select **Delete connection** and confirm to remove the connection and all its assignments atomically; existing threads retain their original identity and cannot silently move to another Agent. Disabling a connection stops execution without replacing its routing choices. To resume, select **Activate channel** and confirm the retained assignment. Each sender must link and confirm their account again after reactivation. - **Settings → Account → Your channel account links** shows personal links once any exist. Status pills distinguish **In progress**, **Awaiting confirmation**, **Active**, **Revoked**, **Expired**, and **Unavailable**. Select **Revoke link** and confirm to withdraw your own consent, including an unavailable link. Completed actions are not undone. - **Settings → Account → Slack → Manage**, then the workspace’s **Disconnect workspace** icon retires the installation's access in LibreChat. It does not uninstall the app in Slack. A later installation gets a fresh identity, so old connections do not resume automatically. Reconnect an active installation to update its grant; disconnect it first if you want to retire existing connections. - After disconnecting an app’s active workspace, use the app’s trash button, **Remove app**, and confirm to delete its saved app credentials. This does not delete the Slack app itself. From fac552521d05e791a2351c68a3d17f3169fb7209 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 10 Nov 2026 01:47:18 -0800 Subject: [PATCH 28/30] =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=20ci:=20Pin=20Brows?= =?UTF-8?q?er=20Jobs=20to=20Supported=20Ubuntu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 3 ++- .github/workflows/update-screenshots.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 401cf08e1..f3274c8b5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,8 @@ jobs: e2e: name: End-to-end tests - runs-on: ubuntu-latest + # Match the Ubuntu version supported by the locked Playwright browsers. + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/update-screenshots.yml b/.github/workflows/update-screenshots.yml index d14b945c6..8e91d7391 100644 --- a/.github/workflows/update-screenshots.yml +++ b/.github/workflows/update-screenshots.yml @@ -16,7 +16,8 @@ permissions: jobs: screenshots: name: Capture and open PR - runs-on: ubuntu-latest + # Match the Ubuntu version supported by the locked Playwright browsers. + runs-on: ubuntu-24.04 environment: Production steps: - uses: actions/checkout@v4 From b261cbcab1d99b065cd54b94b04062238294e897 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 10 Nov 2026 13:59:40 -0800 Subject: [PATCH 29/30] docs: Align Slack Setup With the Tested Linking Flow --- content/docs/features/agent_channels.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index eba2ab3d7..24b1d6fa9 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -79,7 +79,7 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in Complete [operator setup](#one-time-operator-setup) first. The gateway must be running and reachable over public HTTPS before Slack can verify its callback. A Slack app is the bot's identity and credentials; its workspace installation is the grant that lets it operate in a particular Slack workspace. LibreChat supports **one active workspace per registered app**. Use separate Slack apps for additional workspaces. -1. Open [Your Apps](https://api.slack.com/apps) in Slack and create an app from scratch (**Pick features** in the current dashboard, or **Blank app** in Slack’s quickstart). Give it a name and select the workspace where you will manage it. You can instead use an existing app your organization controls. Do not install it yet; finish its settings below first. +1. Open [Your Apps](https://api.slack.com/apps) in Slack and create an app from scratch (**Pick features** in the current dashboard, or **Blank app** in Slack’s quickstart). Give it a name and select the workspace where you will manage it. In the **Pick features** wizard, continue without adding scopes or events, then select **Create → Create Anyway**. Configure those features after registering the app in LibreChat below. You can instead use an existing app your organization controls. Do not install it yet. 2. In LibreChat, open **Settings → Account → Slack → Set up** (or **Manage**), then **Add Slack app**. Copy **App ID**, **Client ID**, **Client Secret**, and **Signing Secret** from that app's **Basic Information → App Credentials**. The optional **Name** identifies the app in LibreChat; it does not rename the bot in Slack. Save the registration. Secrets are encrypted and cannot be read back. 3. Turn **Socket Mode off** in that Slack app before configuring HTTP callbacks. Expand the saved app in LibreChat and open the gear button, **Connection settings**. Configure all three copied URLs in that same Slack app: @@ -113,12 +113,12 @@ The organization flow does **not** ask you to paste a bot token or an app-level ### Connect and use a workspace -1. Under the registered app, select **Add to workspace** and approve installation in Slack. LibreChat shows a **Connecting to Slack…** dialog while this is pending. Use **Cancel** there to abandon the attempt, or **Retry** after a failure. On success, the dialog closes and the workspace appears as **Connected** below the app. Each app can have only one active workspace; reconnect that workspace to refresh its grant, or disconnect it before installing the app elsewhere. +1. Under the registered app, select **Add to workspace**. If Slack asks where to install, choose **A workspace** and the intended workspace, then approve installation. LibreChat shows a **Connecting to Slack…** dialog while this is pending. Use **Cancel** there to abandon the attempt, or **Retry** after a failure. On success, the dialog closes and the workspace appears as **Connected** below the app. Each app can have only one active workspace; reconnect that workspace to refresh its grant, or disconnect it before installing the app elsewhere. 2. An administrator opens the workspace's users button, **Manage access**, and adds the LibreChat users allowed to assign agents through that bot. The dialog is titled **Manage bot access**. Without explicit managers, administrators can still assign agents. These grants do not grant Agent sharing permission, Slack credentials, or installation-administration rights, and are not required just to talk to the bot. 3. Save an Agent you have permission to share. In the Agent builder's **Channels** section, select **Add Slack channel**, choose the **Slack bot**, then **Continue**. You need Remote Agents permission as well as permission to share the Agent. The picker offers only bots you can manage; installation administrators can also assign agents. 4. Choose **Default** for new direct messages and mentions without a channel-specific assignment, or choose **Channel Specific** and enter the **Slack channel ID**. Find the ID in Slack's channel details; it is not the channel name. Select **Assign agent**. If already assigned, **Replace default agent** or **Replace channel agent** opens a confirmation. The current Agent is named only when you can view it. Existing conversations keep their original Agent. 5. In Slack, invite the bot to your test channel, for example `/invite @YourBot`, then mention it with `@YourBot hello`. Installing the app alone does not add it to every channel. You can also send a direct message when the Messages tab is enabled. -6. Follow the private **Link your account** prompt. Sign into the intended LibreChat account, inspect the request, and accept it in the browser. Return to Slack and mention the bot again if no confirmation prompt is present. Confirm the account from that **same Slack account**, then send a **fresh request** to the bot. The original request is not replayed automatically. +6. Select **Link account** in the bot's private message. Sign into the intended LibreChat account, inspect the request, and accept it in the browser. The original Slack message changes to show the account name and **Confirm account**. Return to that message and confirm from the **same Slack account**. Once it shows **Account connected**, send a **fresh request** to the bot; the original request is not replayed automatically. If the confirmation does not appear, mention the bot again to recover the prompt. A successful first response completes setup. Each person repeats the personal linking step and runs with their own current Agent permissions, tool credentials, and approvals. Sharing a Slack thread does not lend another participant's MCP connection or authority. To verify tool access, ask for a task using a tool that the linked account is permitted to use, and complete any required approval as that account. @@ -130,7 +130,7 @@ A successful first response completes setup. Each person repeats the personal li | Gateway calls to LibreChat return `401` | API and gateway use the same private `CHANNEL_SERVICE_TOKEN`, and `LIBRECHAT_INTERNAL_URL` reaches the intended LibreChat instance. This is separate from Slack signature verification. | | Mention produces no response | Check gateway readiness and logs, **Socket Mode off**, **Events on** with the subscriptions above, bot invited to the channel, and an Agent assigned to this bot/destination. Confirm the sender's personal link is active. | | Confirmation, approval, or Stop buttons do nothing | **Interactivity** is on, its exact Request URL is saved, and the gateway is reachable. The Events URL does not substitute for the Interactivity URL. | -| Link says **Awaiting confirmation** | Browser acceptance is incomplete until that same Slack account confirms in Slack. Mention again to obtain the prompt, confirm, then send a new request. | +| Link says **Awaiting confirmation** | Return to the bot's private message and select **Confirm account** from the same Slack account. If the message did not update, mention the bot again to recover the prompt. After confirmation, send a new request. | | Installation reports missing permissions after scopes changed | Add all required bot scopes, then reconnect through LibreChat and approve the updated grant. Existing installations do not receive new scopes automatically. | Use the same Compose project and overlays from operator setup when checking `ps` and `logs --tail=100 api channel-gateway`. A healthy application alone does not prove the separate gateway is ready. See [gateway readiness checks](#docker-compose). From 0b55e9567fdf4cc976da06d217fcd09999a7d3b0 Mon Sep 17 00:00:00 2001 From: Dustin Healy <54083382+dustinhealy@users.noreply.github.com> Date: Tue, 10 Nov 2026 19:06:46 -0800 Subject: [PATCH 30/30] docs: Clarify Slack Secret Copying And Account Confirmation --- content/docs/features/agent_channels.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/docs/features/agent_channels.mdx b/content/docs/features/agent_channels.mdx index 24b1d6fa9..20278498e 100644 --- a/content/docs/features/agent_channels.mdx +++ b/content/docs/features/agent_channels.mdx @@ -80,7 +80,7 @@ No `CHANNEL_ID`, `CHANNEL_TENANT_ID` or app-level `SLACK_APP_TOKEN` is needed in Complete [operator setup](#one-time-operator-setup) first. The gateway must be running and reachable over public HTTPS before Slack can verify its callback. A Slack app is the bot's identity and credentials; its workspace installation is the grant that lets it operate in a particular Slack workspace. LibreChat supports **one active workspace per registered app**. Use separate Slack apps for additional workspaces. 1. Open [Your Apps](https://api.slack.com/apps) in Slack and create an app from scratch (**Pick features** in the current dashboard, or **Blank app** in Slack’s quickstart). Give it a name and select the workspace where you will manage it. In the **Pick features** wizard, continue without adding scopes or events, then select **Create → Create Anyway**. Configure those features after registering the app in LibreChat below. You can instead use an existing app your organization controls. Do not install it yet. -2. In LibreChat, open **Settings → Account → Slack → Set up** (or **Manage**), then **Add Slack app**. Copy **App ID**, **Client ID**, **Client Secret**, and **Signing Secret** from that app's **Basic Information → App Credentials**. The optional **Name** identifies the app in LibreChat; it does not rename the bot in Slack. Save the registration. Secrets are encrypted and cannot be read back. +2. In LibreChat, open **Settings → Account → Slack → Set up** (or **Manage**), then **Add Slack app**. Copy **App ID**, **Client ID**, **Client Secret**, and **Signing Secret** from that app's **Basic Information → App Credentials**. Select **Show** beside each secret before copying; the masked dots are not the secret. The optional **Name** identifies the app in LibreChat; it does not rename the bot in Slack. Save the registration. Secrets are encrypted and cannot be read back. 3. Turn **Socket Mode off** in that Slack app before configuring HTTP callbacks. Expand the saved app in LibreChat and open the gear button, **Connection settings**. Configure all three copied URLs in that same Slack app: | LibreChat value | Slack setting | @@ -418,7 +418,7 @@ Each actor/link revision has its own execution lane. Sharing a Slack thread does ### Account linking -On the first mention, the gateway sends the actor a private linking prompt. Open its trusted LibreChat URL, sign in, preview the request, and accept it. Return to Slack and mention the bot again to receive the exact-account confirmation, then confirm it there. The next mention can run. The gateway does not replay the original request after linking, and browser acceptance alone does not activate the link. +On the first mention, the gateway sends the actor a private linking prompt. Open its trusted LibreChat URL, sign in, preview the request, and accept it. The same private Slack message updates to show the account name and **Confirm account**. Confirm it from the same Slack account, then send a fresh request once it shows **Account connected**. If the prompt has expired or does not update, mention the bot again to recover it. The gateway does not replay the original request after linking, and browser acceptance alone does not activate the link. Manage and revoke your links in Account settings. A link can become unavailable when the channel or account is no longer eligible; you can still withdraw that consent. Restoring eligibility does not reactivate a link you explicitly revoked.