mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-09-10 08:31:37 +00:00
🐛 fix: Thread req into liveness checks + skip credential-less staleness probes
initializeAgent primed resources with principal only, so checkSessionsAlive minted JWT headers from undefined and every ref older than the 6h window failed its liveness check unauthorized, churning live sandbox files through re-provisioning each turn. req now flows through primeResources (adopting the canonical ~/types ServerRequest), and the staleness probe only runs when it can actually authenticate: a legacy key, or a req to mint bearer auth from.
This commit is contained in:
parent
106f8d7fcb
commit
82040ea5c6
3 changed files with 44 additions and 7 deletions
|
|
@ -1198,6 +1198,7 @@ export async function initializeAgent(
|
|||
provisionState,
|
||||
warnings: provisionWarnings,
|
||||
} = await primeResources({
|
||||
req: params.req,
|
||||
principal: user,
|
||||
getFiles: db.getFiles as never,
|
||||
filterFiles: db.filterFilesByAgentAccess,
|
||||
|
|
|
|||
|
|
@ -2004,5 +2004,33 @@ describe('primeResources', () => {
|
|||
expect(result.provisionState).toBeUndefined();
|
||||
expect(refFile.metadata?.codeEnvRef).toBeDefined();
|
||||
});
|
||||
|
||||
it('skips the liveness check when JWT auth has no req to mint from', async () => {
|
||||
process.env.CODEAPI_AUTH_PROVIDER = 'librechat-jwt';
|
||||
const checkSessionsAlive = jest.fn();
|
||||
const refFile = makeCodeFile({
|
||||
file_id: 'principal-file',
|
||||
metadata: {
|
||||
codeEnvRef: { kind: 'user', id: 'user1', storage_session_id: 'sess', file_id: 'remote' },
|
||||
},
|
||||
});
|
||||
|
||||
const result = await primeResources({
|
||||
principal: { id: 'user1', role: 'USER' },
|
||||
appConfig: mockAppConfig,
|
||||
getFiles: mockGetFiles,
|
||||
filterFiles: mockFilterFiles,
|
||||
tool_resources: {},
|
||||
attachments: Promise.resolve([refFile]),
|
||||
requestFileSet,
|
||||
agentId: 'agent1',
|
||||
enabledToolResources: new Set([EToolResources.execute_code]),
|
||||
checkSessionsAlive,
|
||||
});
|
||||
|
||||
expect(checkSessionsAlive).not.toHaveBeenCalled();
|
||||
expect(result.provisionState).toBeUndefined();
|
||||
expect(refFile.metadata?.codeEnvRef).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { EModelEndpoint, EToolResources, AgentCapabilities } from 'librechat-dat
|
|||
import type { AgentToolResources, TFile, AgentBaseResource } from 'librechat-data-provider';
|
||||
import type { IMongoFile, AppConfig, IUser } from '@librechat/data-schemas';
|
||||
import type { FilterQuery, QueryOptions, ProjectionType } from 'mongoose';
|
||||
import type { Request as ServerRequest } from 'express';
|
||||
import type { ServerRequest } from '~/types';
|
||||
|
||||
import { isCodeApiJwtAuthEnabled } from '~/auth/codeapi';
|
||||
import { TOOL_RESOURCE_KEYS } from './orphans';
|
||||
|
|
@ -37,7 +37,7 @@ export type TFileUpdate = {
|
|||
* @returns The codeEnvRef and a deferred DB update object
|
||||
*/
|
||||
export type TProvisionToCodeEnv = (params: {
|
||||
req: ServerRequest & { user?: IUser };
|
||||
req: ServerRequest;
|
||||
file: TFile;
|
||||
entity_id?: string;
|
||||
}) => Promise<{ codeEnvRef: Record<string, unknown>; fileUpdate: TFileUpdate }>;
|
||||
|
|
@ -47,7 +47,7 @@ export type TProvisionToCodeEnv = (params: {
|
|||
* @returns Object with embedded status and a deferred DB update object
|
||||
*/
|
||||
export type TProvisionToVectorDB = (params: {
|
||||
req: ServerRequest & { user?: IUser };
|
||||
req: ServerRequest;
|
||||
file: TFile;
|
||||
entity_id?: string;
|
||||
existingStream?: unknown;
|
||||
|
|
@ -60,7 +60,7 @@ export type TProvisionToVectorDB = (params: {
|
|||
*/
|
||||
export type TCheckSessionsAlive = (params: {
|
||||
files: TFile[];
|
||||
req?: ServerRequest & { user?: IUser };
|
||||
req?: ServerRequest;
|
||||
apiKey?: string;
|
||||
staleSafeWindowMs?: number;
|
||||
}) => Promise<Set<string>>;
|
||||
|
|
@ -239,7 +239,7 @@ export const primeResources = async ({
|
|||
checkSessionsAlive,
|
||||
loadCodeApiKey,
|
||||
}: {
|
||||
req?: ServerRequest & { user?: IUser };
|
||||
req?: ServerRequest;
|
||||
principal?: Pick<IUser, 'id' | 'role'>;
|
||||
appConfig?: AppConfig;
|
||||
requestFileSet: Set<string>;
|
||||
|
|
@ -467,9 +467,17 @@ export const primeResources = async ({
|
|||
* LIBRECHAT_CODE_API_KEY is not required for code-env provisioning. */
|
||||
const codeAuthAvailable = codeApiKey != null || jwtCodeAuth;
|
||||
|
||||
// Batch staleness check: identify which code env files are still alive
|
||||
/** Batch staleness check: identify which code env files are still alive.
|
||||
* Requires credentials the callback can actually send: a legacy key, or a
|
||||
* req to mint JWT bearer auth from. Without either, skip the check so an
|
||||
* unauthorized 401 cannot mark live sandbox files as expired. */
|
||||
let aliveFileIds: Set<string> | undefined;
|
||||
if (needsCodeEnv && codeAuthAvailable && checkSessionsAlive) {
|
||||
if (
|
||||
needsCodeEnv &&
|
||||
codeAuthAvailable &&
|
||||
checkSessionsAlive &&
|
||||
(codeApiKey != null || req != null)
|
||||
) {
|
||||
const filesWithIdentifiers = attachments.filter(
|
||||
(f) => f?.metadata?.codeEnvRef && f.file_id,
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue