Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
8fda87f
🧾 perf: Load Tool-Call Previews and Fetch Full Parts on Demand
danny-avila Oct 4, 2026
a322168
🧾 fix: Validate Part Reads in Parallel and Preview Fork Responses
danny-avila Oct 4, 2026
f7d8985
🧾 fix: Key Hydrated Parts by Preview Revision and Call Identity
danny-avila Oct 4, 2026
7c9b3c8
🧾 fix: Release Hydrated Parts With Their History and Bound JSON Work
danny-avila Oct 4, 2026
261aa5c
🧾 fix: Count Property Names Before Cloning a JSON Preview
danny-avila Oct 4, 2026
c7b5447
🧾 fix: Preview Artifact and Branch Responses and Rehydrate Subagent P…
danny-avila Oct 5, 2026
318f6ee
🧾 fix: Preview Only Tool Calls That Can Be Fetched Back by Identity
danny-avila Oct 5, 2026
68b1f1a
🧾 fix: Fetch Parts by Exact Identity and Preview Only Unique Ones
danny-avila Oct 5, 2026
7e5ff7b
🧾 fix: Bound the JSON Fit Walk Before Queueing and Normalize Empty Id…
danny-avila Oct 5, 2026
9f223b1
🧾 fix: Key Fetched Parts to the Stored Version and Hydrate Search Det…
danny-avila Oct 5, 2026
9782a7e
🧾 fix: Cache Fetched Parts by Identity and Hold Copy Until Hydrated
danny-avila Oct 5, 2026
77977ef
🧾 fix: Shape Shared Forks With the Recipient's Bounds and Keep JSON N…
danny-avila Oct 5, 2026
4505867
Merge remote-tracking branch 'origin/dev' into danny-avila/tool-outpu…
danny-avila Oct 5, 2026
0a3e460
Merge remote-tracking branch 'origin/dev' into danny-avila/tool-outpu…
danny-avila Oct 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/server/middleware/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const validateEmailLogin = require('./validateEmailLogin');
const validateMessageReq = require('./validateMessageReq');
const {
canReadActiveJobConversation,
createMessageRequestValidation,
prepareMessageRequestValidation,
sendValidationResponse,
} = require('./messageValidation');
Expand Down Expand Up @@ -67,6 +68,7 @@ module.exports = {
validateMessageReq,
canReadActiveJobConversation,
sendValidationResponse,
createMessageRequestValidation,
prepareMessageRequestValidation,
buildEndpointOption,
validateRegistration,
Expand Down
1 change: 1 addition & 0 deletions api/server/routes/__test-utils__/convos-route-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ module.exports = {
agents: () => ({ sleep: jest.fn() }),

api: (overrides = {}) => ({
withToolCallPreviews: (_req, result) => result,
createGeneratedTitleHandler: jest.fn(() => jest.fn()),
createRenameConversationHandler: jest.fn((deps) => {
renameHandlerInputs.push(deps);
Expand Down
6 changes: 6 additions & 0 deletions api/server/routes/__tests__/messages-content-edit.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ jest.mock('@librechat/agents', () => ({
}));

jest.mock('@librechat/api', () => ({
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
unescapeLaTeX: jest.fn((value) => value),
countTokens: jest.fn().mockResolvedValue(2),
createPrivateTextView: jest.fn(() => (_req, _res, next) => next()),
Expand All @@ -26,6 +30,8 @@ jest.mock('@librechat/api', () => ({
applyForcedRetention: jest.fn(),
}));

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({}));

jest.mock('@librechat/data-schemas', () => ({
Expand Down
6 changes: 6 additions & 0 deletions api/server/routes/__tests__/messages-delete.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ jest.mock('@librechat/agents', () => ({
}));

jest.mock('@librechat/api', () => ({
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
createPrivateTextView: jest.fn(() => (_req, _res, next) => next()),
createContentFilter: jest.fn(() => (req, res, next) => next()),
inspectContent: jest.fn(() => null),
Expand All @@ -24,6 +28,8 @@ jest.mock('@librechat/api', () => ({
requireFeedbackEnabled: (req, res, next) => next(),
}));

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({}));

jest.mock('@librechat/data-schemas', () => ({
Expand Down
6 changes: 6 additions & 0 deletions api/server/routes/__tests__/messages-feedback.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ jest.mock('@librechat/agents', () => ({
}));

jest.mock('@librechat/api', () => ({
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
unescapeLaTeX: jest.fn((value) => value),
countTokens: jest.fn().mockResolvedValue(10),
createPrivateTextView: jest.fn(() => (_req, _res, next) => next()),
Expand All @@ -18,6 +22,8 @@ jest.mock('@librechat/api', () => ({
applyForcedRetention: jest.fn(),
}));

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({}));

jest.mock('@librechat/data-schemas', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ jest.mock('@librechat/agents', () => ({
}));

jest.mock('@librechat/api', () => ({
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
createPrivateTextView: jest.fn(() => (_req, _res, next) => next()),
createContentFilter: jest.fn(() => (req, res, next) => next()),
inspectContent: jest.fn(() => null),
Expand All @@ -43,6 +47,8 @@ jest.mock('@librechat/api', () => ({
requireFeedbackEnabled: (req, res, next) => next(),
}));

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({}));

jest.mock('@librechat/data-schemas', () => ({
Expand Down
6 changes: 6 additions & 0 deletions api/server/routes/__tests__/messages-get.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ jest.mock('@librechat/api', () => {
};

return {
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
/** The real helper, without loading the rest of the package this suite mocks around. */
withoutTraceRefs: jest.requireActual('../../../../packages/api/src/langfuse/trace.ts')
.withoutTraceRefs,
Expand Down Expand Up @@ -126,6 +130,8 @@ jest.mock('@librechat/api', () => {
};
});

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({}));

jest.mock('@librechat/data-schemas', () => ({
Expand Down
6 changes: 6 additions & 0 deletions api/server/routes/__tests__/messages-retention.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ jest.mock('@librechat/agents', () => ({
}));

jest.mock('@librechat/api', () => ({
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
createPrivateTextView: jest.fn(() => (_req, _res, next) => next()),
stripPrivateMessageFields: jest.requireActual(
'../../../../packages/api/src/protection/private/view',
Expand Down Expand Up @@ -39,6 +43,8 @@ jest.mock('@librechat/data-schemas', () => ({
},
}));

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({}));

jest.mock('~/models', () => ({
Expand Down
6 changes: 6 additions & 0 deletions api/server/routes/__tests__/messages-subagent-thread.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ const mockIsSubagentThreadWriteBlocked = jest.fn();
jest.mock('@librechat/agents', () => ({ sleep: jest.fn() }));

jest.mock('@librechat/api', () => ({
prepareToolCallPreviews: jest.fn(() => (messages) => Promise.resolve(messages)),
createToolCallPartHandler: jest.fn(() => (_req, res) => res.status(404).end()),
rejectToolCallPreviewWrites: (_req, _res, next) => next(),
withMessageToolCallPreviews: (_req, message) => message,
withoutTraceRefs: jest.fn((message) => message),
createPrivateTextView: jest.fn(() => (_req, _res, next) => next()),
createContentFilter: jest.fn(() => (_req, _res, next) => next()),
Expand Down Expand Up @@ -52,6 +56,8 @@ jest.mock('~/models', () => ({
getMessagesByCursor: jest.fn(),
}));

jest.mock('~/server/services/Config', () => ({ getAppConfig: jest.fn() }));

jest.mock('~/server/services/Endpoints/agents/subagentThreadStore', () => ({
isThreadActiveForOwner: jest.fn(),
}));
Expand Down
Loading
Loading