LibreChat/api/server/services/__tests__/AssistantService.logging.spec.js
Danny Avila 67b7b441b2
🛂 feat: Filter Model-Bound Content by Source (#14425)
* feat: introduce optional content protection seam

* feat: enforce source-aware content filters

* feat: complete source-aware content enforcement

* test: activate skill file-text fail-close fixtures

* fix: harden source-aware content filters

* fix: harden model-bound content filtering

* fix: preserve legacy filters and generated files

* fix: inspect shared scalar metadata

* test: align mocks with current dev dependencies

* feat: add persisted content filter safeguards

* feat: complete source-aware content filter enforcement

* fix: move resume content preflight into TypeScript

* fix: close content inspection edge cases

* fix: harden content protection boundaries

* fix: complete content protection safeguards

* test: align persisted memory filter coverage

* fix: reconcile content protection with current dev

* fix: reconcile content protection with latest dev

* fix: close content protection review gaps

* fix: enforce source-aware provider boundaries

* fix: preserve legacy PII preflight semantics

* test: stabilize stored branch preflight fixture

* fix: defer agent writes until protected model admission

* perf: harden source-aware model-bound filtering

* fix: canonicalize provider lineage before validation

* fix: satisfy model-bound callback type checks

* perf: Bound content protection filtering work

* fix: Bound submission array traversal

* fix: Stabilize bounded content snapshots

* fix: Scope model-bound traversal overflows

* fix: Preserve scoped content inspection

* fix: Accumulate aggregate traversal scopes

* fix: centralize content policy boundaries

* test: align deferred tool policy context

* test: align controller policy mocks

* style: normalize content protection imports

* fix: close content policy review gaps

* fix: narrow active skill policy config

* fix: address content protection review boundaries

* fix: retain exact provenance overflow sentinel

* fix: preserve literal and scoped provenance updates

* fix: narrow persisted edit provenance

* fix: isolate exact overflow attribution

* fix: centralize stored prompt protection

* fix: fail closed on incomplete transcript evidence

* fix: align canonical transcript routing

* refactor: centralize content policy preflights

* fix: isolate upload policy error typing

* style: sort policy preflight imports

* refactor: centralize content policy boundaries
2026-08-21 22:43:32 -04:00

91 lines
2.7 KiB
JavaScript

const mockSendEvent = jest.fn();
const mockLogger = {
debug: jest.fn(),
error: jest.fn(),
warn: jest.fn(),
};
jest.mock('@librechat/api', () => ({
...jest.requireActual('@librechat/api'),
sendEvent: (...args) => mockSendEvent(...args),
}));
jest.mock('@librechat/data-schemas', () => ({
...jest.requireActual('@librechat/data-schemas'),
logger: mockLogger,
}));
const { createOnTextProgress } = require('../AssistantService');
const StreamRunManager = require('../Runs/StreamRunManager');
describe('Assistant service log hygiene', () => {
beforeEach(() => {
jest.clearAllMocks();
});
it('logs only structural metadata for non-text assistant content', async () => {
const privateArguments = 'PRIVATE-TOOL-ARGUMENTS';
const openai = { res: {} };
await createOnTextProgress({
openai,
conversationId: 'conversation-1',
userMessageId: 'user-message-1',
messageId: 'assistant-message-1',
thread_id: 'thread-1',
});
openai.addContentData({
type: 'tool_call',
index: 0,
tool_call: {
type: 'function',
function: { name: 'example', arguments: privateArguments },
},
});
expect(JSON.stringify(mockLogger.debug.mock.calls)).not.toContain(privateArguments);
expect(mockLogger.debug).toHaveBeenCalledWith(
'Assistant content event',
expect.objectContaining({
type: 'tool_call',
index: 0,
hasContent: true,
}),
);
expect(JSON.stringify(mockSendEvent.mock.calls)).toContain(privateArguments);
});
it('does not include raw tool deltas in warning logs', async () => {
const privateDelta = 'PRIVATE-DELTA';
const manager = new StreamRunManager({
req: {},
res: {},
openai: { apiKey: 'test-key' },
parentMessageId: 'parent-1',
thread_id: 'thread-1',
runBody: {},
responseMessage: { content: [], messageId: 'message-1', conversationId: 'conversation-1' },
attachedFileIds: new Set(),
handlers: {},
});
const handler = manager.createToolCallStream(0, {
type: 'function',
function: { name: 'example', arguments: '' },
});
await handler({ unexpected: privateDelta });
await manager.handleRunStepDeltaEvent({
data: { id: 'step-1', delta: { unknown: privateDelta } },
});
expect(JSON.stringify(mockLogger.warn.mock.calls)).not.toContain(privateDelta);
expect(mockLogger.warn).toHaveBeenCalledWith(
'Unhandled tool call delta key',
expect.objectContaining({ key: 'unexpected' }),
);
expect(mockLogger.warn).toHaveBeenCalledWith(
'Undefined or unhandled run step delta',
expect.objectContaining({ stepId: 'step-1' }),
);
});
});