From 9bc01f40e98d80fe5e0427f80a148e84c7267ca0 Mon Sep 17 00:00:00 2001 From: Danny Avila Date: Mon, 31 Aug 2026 11:54:20 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix:=20Never=20queue=20text-sour?= =?UTF-8?q?ce=20records=20for=20provisioning?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Legacy context files keep their content in the database with no backing object, which the download route reconstructs from the stored text. Queueing them sent them to a storage stream that correctly refuses the source, and since a code provisioning failure now aborts the preflight, an agent holding one could not run code at all. They are skipped rather than queued; provisioning them from their stored text needs a text re-fetch and is tracked as follow-up work. --- packages/api/src/agents/resources.test.ts | 20 ++++++++++++++++++++ packages/api/src/agents/resources.ts | 8 ++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/api/src/agents/resources.test.ts b/packages/api/src/agents/resources.test.ts index a6446259d4..cf26b6eb6f 100644 --- a/packages/api/src/agents/resources.test.ts +++ b/packages/api/src/agents/resources.test.ts @@ -2131,6 +2131,26 @@ describe('primeResources', () => { expect(searchResource?.files?.map((f) => f.file_id) ?? []).not.toContain('embedded-context'); }); + it('never queues a text-source record, which has no streamable backing', async () => { + process.env.CODEAPI_AUTH_PROVIDER = 'librechat-jwt'; + const textFile = makeCodeFile({ file_id: 'text-record', source: FileSources.text }); + + const result = await primeResources({ + req: mockReq, + appConfig: mockAppConfig, + getFiles: mockGetFiles, + filterFiles: mockFilterFiles, + tool_resources: {}, + attachments: Promise.resolve([textFile]), + requestFileSet, + agentId: 'agent1', + enabledToolResources: new Set([EToolResources.execute_code, EToolResources.file_search]), + }); + + expect(result.provisionState).toBeUndefined(); + expect(result.attachments?.map((f) => f?.file_id)).toContain('text-record'); + }); + it('grants agent scope only to agent setup files', () => { expect(isAgentScopedFile({ context: FileContext.agents })).toBe(true); expect(isAgentScopedFile({ context: FileContext.execute_code })).toBe(false); diff --git a/packages/api/src/agents/resources.ts b/packages/api/src/agents/resources.ts index 23f1c4b699..200ecb2b2d 100644 --- a/packages/api/src/agents/resources.ts +++ b/packages/api/src/agents/resources.ts @@ -4,6 +4,7 @@ import { EToolResources, AgentCapabilities, FileContext, + FileSources, } from 'librechat-data-provider'; import type { AgentToolResources, @@ -366,6 +367,13 @@ const computeProvisionState = async ({ continue; } + /** Text-source records keep their content in the database with no backing object + * to stream, so provisioning them would fail and, for code, abort the turn. + * Provisioning them from their stored text is tracked as follow-up work. */ + if (file.source === FileSources.text) { + continue; + } + if (needsCodeEnv) { const legacyRef = file.metadata?.codeEnvRef; const isDefaultRoute = legacyRef != null && codeEnvRouteKey(legacyRef) === 'default';