Allow message retries for "pending" status, refactor message context handling, remove workspace import/export routes, and add SQLite-backed rate limiting.
This commit is contained in:
@@ -77,7 +77,8 @@ export function createComposerController({
|
||||
const visible = () => state.activeChatId === chatId;
|
||||
let userCard, loadingMsg, rendering, completedReply = null;
|
||||
let completedThinking = "", completedSources = null;
|
||||
const userMessage = {role: "user", content: message, attachments};
|
||||
const userMessage = {role: "user", content: message, attachments,
|
||||
...(retryMessage?.id ? {id: retryMessage.id, deliveryStatus: retryMessage.deliveryStatus, errorMessage: retryMessage.errorMessage} : {})};
|
||||
if (!retryMessage) {
|
||||
msgInput.value = "";
|
||||
state.chatDrafts.set(chatId ?? "new", "");
|
||||
@@ -135,7 +136,9 @@ export function createComposerController({
|
||||
if (loadingBody) setMessageContent(loadingBody, text);
|
||||
})
|
||||
});
|
||||
await api.stream("/chat/stream", {message, attachments: attachments.map(item => item.id), model, chatId, webSearch, reasoning}, {
|
||||
await api.stream("/chat/stream", {message, attachments: attachments.map(item => item.id), model, chatId,
|
||||
...(retryMessage?.id && ["failed", "pending"].includes(retryMessage.deliveryStatus) ? {userMessageId: retryMessage.id} : {}),
|
||||
webSearch, reasoning}, {
|
||||
...rendering,
|
||||
onStatus: ({status, sourceCount, searchState}) => {
|
||||
if (status === "accepted" || !visible() || !loadingLabel) return;
|
||||
|
||||
@@ -52,7 +52,23 @@ export function createMemoryPanel({state}) {
|
||||
summary.input.rows = 6;
|
||||
const summaryHelp = document.createElement("p"); summaryHelp.className = "subtitle";
|
||||
summaryHelp.textContent = "Correct outdated information here. Future automatic summaries build on your corrections. Clear the field and save to remove the summary.";
|
||||
panel.content.append(summary.wrapper, summaryHelp, actionButton("Save summary", () => run(put(`/chats/${id}/summary`, {summary: summary.input.value, previousSummary: result.summary}), "summary")));
|
||||
panel.content.append(summary.wrapper, summaryHelp,
|
||||
actionButton("Save summary", () => run(put(`/chats/${id}/summary`, {summary: summary.input.value, previousSummary: result.summary}), "summary")));
|
||||
if (result.summary) {
|
||||
const forget = actionButton("Forget running summary", () => run(put(`/chats/${id}/summary`, {summary: "", previousSummary: result.summary}), "summary"));
|
||||
forget.title = "Remove the automatic summary from conversation memory";
|
||||
panel.content.append(forget);
|
||||
const sourceHeading = document.createElement("h4"); sourceHeading.textContent = "Messages included in this summary";
|
||||
panel.content.append(sourceHeading);
|
||||
for (const source of result.summarySources || []) {
|
||||
const item = document.createElement("details"); item.className = "memory-summary-source";
|
||||
const label = document.createElement("summary");
|
||||
const excerpt = source.content.length > 160 ? `${source.content.slice(0, 157)}...` : source.content;
|
||||
label.textContent = `#${source.id} · ${source.role === "user" ? "You" : "Assistant"}: ${excerpt}`;
|
||||
const content = document.createElement("p"); content.textContent = source.content;
|
||||
item.append(label, content); panel.content.append(item);
|
||||
}
|
||||
}
|
||||
const heading = document.createElement("h4"); heading.textContent = "Saved facts";
|
||||
const hint = document.createElement("p"); hint.className = "subtitle";
|
||||
hint.textContent = `The ${context.memoryFactLimit} most recently updated facts are included in context. Edit or remove facts that are no longer accurate.`;
|
||||
|
||||
@@ -249,12 +249,12 @@ export function createMessageRenderer({
|
||||
});
|
||||
actions.appendChild(copyBtn);
|
||||
|
||||
if (message.deliveryStatus === "failed" && isMessageUser) {
|
||||
if (["failed", "pending"].includes(message.deliveryStatus) && isMessageUser) {
|
||||
const retryFailedBtn = document.createElement("button");
|
||||
retryFailedBtn.type = "button";
|
||||
retryFailedBtn.className = "msg-action-btn";
|
||||
retryFailedBtn.dataset.messageAction = "retry-failed";
|
||||
retryFailedBtn.textContent = "Retry";
|
||||
retryFailedBtn.textContent = message.deliveryStatus === "pending" ? "Resume" : "Retry";
|
||||
retryFailedBtn.disabled = state.isProcessing;
|
||||
retryFailedBtn.addEventListener("click", () => { void sendMessage({ retryMessage: message }); });
|
||||
actions.appendChild(retryFailedBtn);
|
||||
|
||||
Reference in New Issue
Block a user