θΏ™ζ˜―indexlocζδΎ›ηš„ζœεŠ‘οΌŒδΈθ¦θΎ“ε…₯任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 11 additions & 5 deletions server/endpoints/api/workspace/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,8 @@ function apiWorkspaceEndpoints(app) {
mime: "image/png",
contentString: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
reset: false
}
}
}
Expand Down Expand Up @@ -645,6 +646,7 @@ function apiWorkspaceEndpoints(app) {
mode = "query",
sessionId = null,
attachments = [],
reset = false,
} = reqBody(request);
const workspace = await Workspace.get({ slug: String(slug) });

Expand All @@ -660,15 +662,15 @@ function apiWorkspaceEndpoints(app) {
return;
}

if (!message?.length || !VALID_CHAT_MODE.includes(mode)) {
if ((!message?.length || !VALID_CHAT_MODE.includes(mode)) && !reset) {
response.status(400).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: !message?.length
? "message parameter cannot be empty."
? "Message is empty"
: `${mode} is not a valid mode.`,
});
return;
Expand All @@ -682,6 +684,7 @@ function apiWorkspaceEndpoints(app) {
thread: null,
sessionId: !!sessionId ? String(sessionId) : null,
attachments,
reset,
});

await Telemetry.sendTelemetry("sent_chat", {
Expand Down Expand Up @@ -732,7 +735,8 @@ function apiWorkspaceEndpoints(app) {
mime: "image/png",
contentString: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
reset: false
}
}
}
Expand Down Expand Up @@ -788,6 +792,7 @@ function apiWorkspaceEndpoints(app) {
mode = "query",
sessionId = null,
attachments = [],
reset = false,
} = reqBody(request);
const workspace = await Workspace.get({ slug: String(slug) });

Expand All @@ -803,7 +808,7 @@ function apiWorkspaceEndpoints(app) {
return;
}

if (!message?.length || !VALID_CHAT_MODE.includes(mode)) {
if ((!message?.length || !VALID_CHAT_MODE.includes(mode)) && !reset) {
response.status(400).json({
id: uuidv4(),
type: "abort",
Expand Down Expand Up @@ -832,6 +837,7 @@ function apiWorkspaceEndpoints(app) {
thread: null,
sessionId: !!sessionId ? String(sessionId) : null,
attachments,
reset,
});
await Telemetry.sendTelemetry("sent_chat", {
LLMSelection:
Expand Down
16 changes: 11 additions & 5 deletions server/endpoints/api/workspaceThread/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ function apiWorkspaceThreadEndpoints(app) {
mime: "image/png",
contentString: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
reset: false
}
}
}
Expand Down Expand Up @@ -386,6 +387,7 @@ function apiWorkspaceThreadEndpoints(app) {
mode = "query",
userId,
attachments = [],
reset = false,
} = reqBody(request);
const workspace = await Workspace.get({ slug });
const thread = await WorkspaceThread.get({
Expand All @@ -405,15 +407,15 @@ function apiWorkspaceThreadEndpoints(app) {
return;
}

if (!message?.length || !VALID_CHAT_MODE.includes(mode)) {
if ((!message?.length || !VALID_CHAT_MODE.includes(mode)) && !reset) {
response.status(400).json({
id: uuidv4(),
type: "abort",
textResponse: null,
sources: [],
close: true,
error: !message?.length
? "message parameter cannot be empty."
? "Message is empty"
: `${mode} is not a valid mode.`,
});
return;
Expand All @@ -427,6 +429,7 @@ function apiWorkspaceThreadEndpoints(app) {
user,
thread,
attachments,
reset,
});
await Telemetry.sendTelemetry("sent_chat", {
LLMSelection: process.env.LLM_PROVIDER || "openai",
Expand Down Expand Up @@ -489,7 +492,8 @@ function apiWorkspaceThreadEndpoints(app) {
mime: "image/png",
contentString: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
reset: false
}
}
}
Expand Down Expand Up @@ -545,6 +549,7 @@ function apiWorkspaceThreadEndpoints(app) {
mode = "query",
userId,
attachments = [],
reset = false,
} = reqBody(request);
const workspace = await Workspace.get({ slug });
const thread = await WorkspaceThread.get({
Expand All @@ -564,7 +569,7 @@ function apiWorkspaceThreadEndpoints(app) {
return;
}

if (!message?.length || !VALID_CHAT_MODE.includes(mode)) {
if ((!message?.length || !VALID_CHAT_MODE.includes(mode)) && !reset) {
response.status(400).json({
id: uuidv4(),
type: "abort",
Expand Down Expand Up @@ -594,6 +599,7 @@ function apiWorkspaceThreadEndpoints(app) {
user,
thread,
attachments,
reset,
});
await Telemetry.sendTelemetry("sent_chat", {
LLMSelection: process.env.LLM_PROVIDER || "openai",
Expand Down
28 changes: 28 additions & 0 deletions server/models/workspaceChats.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ const WorkspaceChats = {
}
},

/**
* @deprecated Use markThreadHistoryInvalidV2 instead.
*/
markHistoryInvalid: async function (workspaceId = null, user = null) {
if (!workspaceId) return;
try {
Expand All @@ -123,6 +126,9 @@ const WorkspaceChats = {
}
},

/**
* @deprecated Use markThreadHistoryInvalidV2 instead.
*/
markThreadHistoryInvalid: async function (
workspaceId = null,
user = null,
Expand All @@ -146,6 +152,28 @@ const WorkspaceChats = {
}
},

/**
* @description This function is used to mark a thread's history as invalid.
* and works with an arbitrary where clause.
* @param {Object} whereClause - The where clause to update the chats.
* @param {Object} data - The data to update the chats with.
* @returns {Promise<void>}
*/
markThreadHistoryInvalidV2: async function (whereClause = {}) {
if (!whereClause) return;
try {
await prisma.workspace_chats.updateMany({
where: whereClause,
data: {
include: false,
},
});
return;
} catch (error) {
console.error(error.message);
}
},

get: async function (clause = {}, limit = null, orderBy = null) {
try {
const chat = await prisma.workspace_chats.findFirst({
Expand Down
12 changes: 8 additions & 4 deletions server/swagger/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -2280,7 +2280,8 @@
"mime": "image/png",
"contentString": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
"reset": false
}
}
}
Expand Down Expand Up @@ -2382,7 +2383,8 @@
"mime": "image/png",
"contentString": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
"reset": false
}
}
}
Expand Down Expand Up @@ -3143,7 +3145,8 @@
"mime": "image/png",
"contentString": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
"reset": false
}
}
}
Expand Down Expand Up @@ -3255,7 +3258,8 @@
"mime": "image/png",
"contentString": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
]
],
"reset": false
}
}
}
Expand Down
69 changes: 68 additions & 1 deletion server/utils/chats/apiChatHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ const { DocumentManager } = require("../DocumentManager");
const { WorkspaceChats } = require("../../models/workspaceChats");
const { getVectorDbClass, getLLMProvider } = require("../helpers");
const { writeResponseChunk } = require("../helpers/chat/responses");
const { chatPrompt, sourceIdentifier, recentChatHistory } = require("./index");
const {
chatPrompt,
sourceIdentifier,
recentChatHistory,
grepAllSlashCommands,
} = require("./index");
const {
EphemeralAgentHandler,
EphemeralEventListener,
Expand Down Expand Up @@ -31,6 +36,7 @@ const { Telemetry } = require("../../models/telemetry");
* thread: import("@prisma/client").workspace_threads|null,
* sessionId: string|null,
* attachments: { name: string; mime: string; contentString: string }[],
* reset: boolean,
* }} parameters
* @returns {Promise<ResponseObject>}
*/
Expand All @@ -42,10 +48,39 @@ async function chatSync({
thread = null,
sessionId = null,
attachments = [],
reset = false,
}) {
const uuid = uuidv4();
const chatMode = mode ?? "chat";

// If the user wants to reset the chat history we do so pre-flight
// and continue execution. If no message is provided then the user intended
// to reset the chat history only and we can exit early with a confirmation.
if (reset) {
await WorkspaceChats.markThreadHistoryInvalidV2({
workspaceId: workspace.id,
user_id: user?.id,
thread_id: thread?.id,
api_session_id: sessionId,
});
if (!message?.length) {
return {
id: uuid,
type: "textResponse",
textResponse: "Chat history was reset!",
sources: [],
close: true,
error: null,
metrics: {},
};
}
}

// Process slash commands
// Since preset commands are not supported in API calls, we can just process the message here
const processedMessage = await grepAllSlashCommands(message);
message = processedMessage;

if (EphemeralAgentHandler.isAgentInvocation({ message })) {
await Telemetry.sendTelemetry("agent_chat_started");

Expand Down Expand Up @@ -320,6 +355,7 @@ async function chatSync({
* thread: import("@prisma/client").workspace_threads|null,
* sessionId: string|null,
* attachments: { name: string; mime: string; contentString: string }[],
* reset: boolean,
* }} parameters
* @returns {Promise<VoidFunction>}
*/
Expand All @@ -332,10 +368,41 @@ async function streamChat({
thread = null,
sessionId = null,
attachments = [],
reset = false,
}) {
const uuid = uuidv4();
const chatMode = mode ?? "chat";

// If the user wants to reset the chat history we do so pre-flight
// and continue execution. If no message is provided then the user intended
// to reset the chat history only and we can exit early with a confirmation.
if (reset) {
await WorkspaceChats.markThreadHistoryInvalidV2({
workspaceId: workspace.id,
user_id: user?.id,
thread_id: thread?.id,
api_session_id: sessionId,
});
if (!message?.length) {
writeResponseChunk(response, {
id: uuid,
type: "textResponse",
textResponse: "Chat history was reset!",
sources: [],
attachments: [],
close: true,
error: null,
metrics: {},
});
return;
}
}

// Check for and process slash commands
// Since preset commands are not supported in API calls, we can just process the message here
const processedMessage = await grepAllSlashCommands(message);
message = processedMessage;

if (EphemeralAgentHandler.isAgentInvocation({ message })) {
await Telemetry.sendTelemetry("agent_chat_started");

Expand Down
23 changes: 23 additions & 0 deletions server/utils/chats/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,28 @@ async function grepCommand(message, user = null) {
return updatedMessage;
}

/**
* @description This function will do recursive replacement of all slash commands with their corresponding prompts.
* @notice This function is used for API calls and is not user-scoped. THIS FUNCTION DOES NOT SUPPORT PRESET COMMANDS.
* @returns {Promise<string>}
*/
async function grepAllSlashCommands(message) {
const allPresets = await SlashCommandPresets.where({});

// Replace all preset commands with their corresponding prompts
// Allows multiple commands in one message
let updatedMessage = message;
for (const preset of allPresets) {
const regex = new RegExp(
`(?:\\b\\s|^)(${preset.command})(?:\\b\\s|$)`,
"g"
);
updatedMessage = updatedMessage.replace(regex, preset.prompt);
}

return updatedMessage;
}

async function recentChatHistory({
user = null,
workspace,
Expand Down Expand Up @@ -80,5 +102,6 @@ module.exports = {
recentChatHistory,
chatPrompt,
grepCommand,
grepAllSlashCommands,
VALID_COMMANDS,
};