Enable automatic web search by default; improve toggle behavior and search planning.
This commit is contained in:
+1
-1
@@ -174,7 +174,7 @@
|
||||
<div class="persona-section-actions">
|
||||
<button id="clearUserPersona"
|
||||
class="secondary-action"
|
||||
type="button">Clear</button>
|
||||
type="button">Clear for this chat</button>
|
||||
<a href="/app/personas"
|
||||
class="secondary-action">Manage</a>
|
||||
</div>
|
||||
|
||||
@@ -125,13 +125,18 @@ export function createPersonaController({
|
||||
}
|
||||
|
||||
function renderPersonaSection() {
|
||||
updateActivePersonaStatus(state.userPersonas, state.activeUserPersonaId, activeUserPersonaStatus, "No default user persona set.", "Default user persona");
|
||||
if (chatDrawerPersonaValue) {
|
||||
const active = state.userPersonas.find((persona) => persona.id === state.activeUserPersonaId);
|
||||
chatDrawerPersonaValue.textContent = active ? active.name : "None";
|
||||
if (headerPersonaName) headerPersonaName.textContent = active ? active.name : "None";
|
||||
const activeChat = state.chatSessions.find((chat) => chat.id === state.activeChatId);
|
||||
const chatPersona = state.userPersonas.find((persona) => persona.id === activeChat?.user_persona_id);
|
||||
if (activeUserPersonaStatus) {
|
||||
activeUserPersonaStatus.textContent = activeChat
|
||||
? `Using in this chat: ${chatPersona?.name || "yourself"}. Default: ${getPersonaName(state.activeUserPersonaId, state.userPersonas) || "yourself"}.`
|
||||
: `Default user persona: ${getPersonaName(state.activeUserPersonaId, state.userPersonas) || "yourself"}.`;
|
||||
}
|
||||
if (clearUserPersonaBtn) clearUserPersonaBtn.disabled = !state.activeUserPersonaId;
|
||||
if (chatDrawerPersonaValue) {
|
||||
chatDrawerPersonaValue.textContent = chatPersona?.name || "Yourself";
|
||||
if (headerPersonaName) headerPersonaName.textContent = chatPersona?.name || "Yourself";
|
||||
}
|
||||
if (clearUserPersonaBtn) clearUserPersonaBtn.disabled = !activeChat?.user_persona_id;
|
||||
}
|
||||
|
||||
function maybeShowPersonaNudge() {
|
||||
@@ -142,12 +147,6 @@ export function createPersonaController({
|
||||
setNotice("Want to personalize responses? Try personas in Tools.", "success");
|
||||
}
|
||||
|
||||
function updateActivePersonaStatus(items, activeId, statusEl, emptyText, prefix) {
|
||||
if (!statusEl) return;
|
||||
const active = items.find((persona) => persona.id === activeId);
|
||||
statusEl.textContent = active ? `${prefix}: ${active.name}` : emptyText;
|
||||
}
|
||||
|
||||
function openPersonaForm(persona = null, personaType = "assistant") {
|
||||
closeChatDrawer();
|
||||
closePopup(false);
|
||||
@@ -263,13 +262,17 @@ export function createPersonaController({
|
||||
renderPersonaSection();
|
||||
return;
|
||||
}
|
||||
const selectedId = personaType === "user"
|
||||
? state.chatSessions.find((chat) => chat.id === state.activeChatId)?.user_persona_id ?? null
|
||||
: activeId;
|
||||
items.forEach((persona) => {
|
||||
const item = document.createElement("div"), titleRow = document.createElement("div"), title = document.createElement("h4");
|
||||
const tag = document.createElement("span"), meta = document.createElement("p"), actions = document.createElement("div");
|
||||
item.className = `persona-item${personaType === "user" && persona.id === activeId ? " active" : ""}`; titleRow.className = "persona-title-row"; actions.className = "persona-item-actions";
|
||||
item.className = `persona-item${personaType === "user" && persona.id === selectedId ? " active" : ""}`; titleRow.className = "persona-title-row"; actions.className = "persona-item-actions";
|
||||
tag.className = `persona-role-tag ${personaType === "user" ? "user" : "ai"}`; tag.textContent = personaType === "user" ? "You" : "AI";
|
||||
title.textContent = persona.name; meta.textContent = persona.pronouns ? `Pronouns: ${persona.pronouns}` : "Pronouns: n/a";
|
||||
[[personaType === "assistant" ? "Start roleplay" : "Set default", () => equipPersona(persona.id, personaType), personaType === "user" && persona.id === activeId],
|
||||
[[personaType === "assistant" ? "Start roleplay" : "Use in this chat", () => personaType === "user" ? setChatUserPersona(persona.id) : equipPersona(persona.id, personaType), personaType === "user" && persona.id === selectedId],
|
||||
...(personaType === "user" ? [["Set default", () => equipPersona(persona.id, personaType), persona.id === state.activeUserPersonaId]] : []),
|
||||
["Edit", () => openPersonaForm(persona), false],
|
||||
[state.publishedPersonaIds.has(persona.id) ? "Update listing" : "Publish", () => publishPersona(persona.id), false],
|
||||
["Delete", () => deletePersona(persona.id), false]]
|
||||
@@ -309,13 +312,24 @@ export function createPersonaController({
|
||||
setNotice("User persona updated.", "success");
|
||||
}
|
||||
|
||||
async function clearPersona(type) {
|
||||
if (type !== "user") return;
|
||||
const res = await post("/personas/user/clear", {});
|
||||
async function setChatUserPersona(id) {
|
||||
if (!state.activeChatId) return setNotice("Open a chat before choosing a user persona.", "error");
|
||||
const res = await put(`/chats/${state.activeChatId}/user-persona`, {userPersonaId: id});
|
||||
if (res.error) return setNotice(res.error, "error");
|
||||
state.activeUserPersonaId = null;
|
||||
renderPersonaList(state.userPersonas, state.activeUserPersonaId, userPersonaList, "user");
|
||||
setNotice("Persona cleared.", "success");
|
||||
const chat = state.chatSessions.find((item) => item.id === state.activeChatId);
|
||||
if (chat) Object.assign(chat, res.chat);
|
||||
renderPersonaList(state.userPersonas, res.chat.user_persona_id, userPersonaList, "user");
|
||||
setNotice("User persona switched for this chat.", "success");
|
||||
}
|
||||
|
||||
async function clearChatUserPersona() {
|
||||
if (!state.activeChatId) return;
|
||||
const res = await put(`/chats/${state.activeChatId}/user-persona`, {userPersonaId: null});
|
||||
if (res.error) return setNotice(res.error, "error");
|
||||
const chat = state.chatSessions.find((item) => item.id === state.activeChatId);
|
||||
if (chat) Object.assign(chat, res.chat);
|
||||
renderPersonaList(state.userPersonas, null, userPersonaList, "user");
|
||||
setNotice("This chat will use yourself.", "success");
|
||||
}
|
||||
|
||||
async function savePersona() {
|
||||
@@ -406,6 +420,7 @@ export function createPersonaController({
|
||||
}
|
||||
|
||||
return {
|
||||
renderPersonaSection,
|
||||
updateRoleplaySuggestions,
|
||||
setRoleplayStarterNotice,
|
||||
renderRoleplayStarterStep,
|
||||
@@ -415,7 +430,7 @@ export function createPersonaController({
|
||||
openRoleplayStarter,
|
||||
closeRoleplayStarter,
|
||||
loadPersonas,
|
||||
clearPersona,
|
||||
clearChatUserPersona,
|
||||
savePersona,
|
||||
startRoleplay
|
||||
};
|
||||
|
||||
+4
-2
@@ -151,7 +151,8 @@ const {
|
||||
openRoleplayStarter,
|
||||
closeRoleplayStarter,
|
||||
loadPersonas,
|
||||
clearPersona,
|
||||
clearChatUserPersona,
|
||||
renderPersonaSection,
|
||||
savePersona,
|
||||
startRoleplay
|
||||
} = createPersonaController({
|
||||
@@ -448,6 +449,7 @@ function updateWorkspaceCopy() {
|
||||
}
|
||||
|
||||
renderDrawerSummary();
|
||||
renderPersonaSection();
|
||||
updateComposerPlaceholder();
|
||||
}
|
||||
|
||||
@@ -986,7 +988,7 @@ saveGenerationSettingsBtn.addEventListener("click", () => { void saveGenerationS
|
||||
roleplayNewPersonaBtn.addEventListener("click", () => { closeRoleplayStarter(); openPersonaForm(null, "assistant"); });
|
||||
clearUserPersonaBtn.addEventListener("click", () => {
|
||||
closeChatDrawer();
|
||||
void clearPersona("user");
|
||||
void clearChatUserPersona();
|
||||
});
|
||||
personaForm.addEventListener("submit", (event) => { event.preventDefault(); void savePersona(); }); personaCloseBtn.addEventListener("click", closePersonaForm);
|
||||
personaTypeSelect.addEventListener("change", () => {
|
||||
|
||||
@@ -111,6 +111,7 @@ export function createChatStatements(db) {
|
||||
LIMIT 1
|
||||
`),
|
||||
updateChatSessionTitle: db.prepare("UPDATE chat_sessions SET title = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND username = ?"),
|
||||
updateChatUserPersona: db.prepare("UPDATE chat_sessions SET user_persona_id = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND username = ?"),
|
||||
updateChatSessionScene: db.prepare("UPDATE chat_sessions SET scenario_prompt = ?, scenario_summary = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND username = ?"),
|
||||
updateChatContextSummary: db.prepare("UPDATE chat_sessions SET context_summary = ?, context_summary_message_id = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND username = ?"),
|
||||
updateChatGenerationSettings: db.prepare(`
|
||||
@@ -432,6 +433,7 @@ const failChatTurnTransaction = db.transaction((chatId, userMessageId, errorMess
|
||||
return statements.getChatSession.get(chatId, username);
|
||||
},
|
||||
updateChatTitle: (chatId, username, title) => statements.updateChatSessionTitle.run(title, chatId, username),
|
||||
updateChatUserPersona: (chatId, username, personaId) => statements.updateChatUserPersona.run(personaId ?? null, chatId, username),
|
||||
updateChatScene: (chatId, username, scenarioPrompt, scenarioSummary) => statements.updateChatSessionScene.run(scenarioPrompt, scenarioSummary, chatId, username),
|
||||
updateChatContextSummary: (chatId, username, summary, messageId) => statements.updateChatContextSummary.run(summary, Number(messageId || 0), chatId, username),
|
||||
getPersonaChatState: (chatId, username) => statements.getPersonaChatState.get(chatId, username) || null,
|
||||
|
||||
@@ -116,6 +116,13 @@ const preferredModelValidator = (body) => {
|
||||
return {value: {model}};
|
||||
};
|
||||
|
||||
const userPersonaValidator = (body) => {
|
||||
if (body?.userPersonaId == null || body.userPersonaId === "") return {value: {userPersonaId: null}};
|
||||
const userPersonaId = Number(body.userPersonaId);
|
||||
if (!Number.isInteger(userPersonaId) || userPersonaId < 1) return {error: "Invalid user persona"};
|
||||
return {value: {userPersonaId}};
|
||||
};
|
||||
|
||||
export function createChatsRouter({repositories, chatService, modelService, config, chatRateLimiters, attachmentService}) {
|
||||
const router = express.Router();
|
||||
router.use(requireLogin);
|
||||
@@ -272,6 +279,32 @@ export function createChatsRouter({repositories, chatService, modelService, conf
|
||||
return res.json({chat: repositories.getChat(chatId, req.session.user)});
|
||||
});
|
||||
|
||||
router.put("/chats/:id/user-persona", validateBody(userPersonaValidator), (req, res) => {
|
||||
const chatId = Number(req.params.id);
|
||||
const user = req.session.user;
|
||||
const chat = repositories.getChat(chatId, user);
|
||||
if (!chat) return res.status(404).json({error: "Chat not found"});
|
||||
const {userPersonaId} = req.validatedBody;
|
||||
if (userPersonaId) {
|
||||
const persona = repositories.getPersona(userPersonaId, user);
|
||||
if (!persona || persona.persona_type !== "user") return res.status(404).json({error: "User persona not found"});
|
||||
}
|
||||
repositories.updateChatUserPersona(chatId, user, userPersonaId);
|
||||
if (chat.assistant_persona_id) {
|
||||
const assistantPersona = repositories.getPersona(chat.assistant_persona_id, user);
|
||||
const userPersona = userPersonaId ? repositories.getPersona(userPersonaId, user) : null;
|
||||
if (assistantPersona) {
|
||||
repositories.updateChatScene(
|
||||
chatId,
|
||||
user,
|
||||
chat.scenario_prompt,
|
||||
chatService.buildRoleplaySceneSummary(assistantPersona, userPersona, chat.scenario_prompt)
|
||||
);
|
||||
}
|
||||
}
|
||||
return res.json({chat: repositories.getChat(chatId, user)});
|
||||
});
|
||||
|
||||
router.post("/chats/:id/branches/:messageId/activate", (req, res) => {
|
||||
const result = chatService.activateBranch({
|
||||
user: req.session.user,
|
||||
|
||||
Reference in New Issue
Block a user