feat(chat): Add undo button to trim conversation to a prior message
Lets you click Undo under a user message to drop it and everything after it, refilling the prompt with that message's text/images so it can be edited and resent.
This commit is contained in:
+35
-8
@@ -97,6 +97,23 @@
|
||||
margin-left: auto;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
.undo-btn {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-top: 0.4rem;
|
||||
background: rgba(255, 255, 255, 0.15);
|
||||
color: var(--text-user);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
border-radius: 0.3rem;
|
||||
padding: 0.15rem 0.5rem;
|
||||
font-size: 0.8em;
|
||||
cursor: pointer;
|
||||
opacity: 0.7;
|
||||
transition: opacity 0.2s;
|
||||
}
|
||||
.undo-btn:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
.system-message {
|
||||
background: var(--bg-secondary);
|
||||
margin-right: auto;
|
||||
@@ -283,6 +300,7 @@
|
||||
<img :src="img.dataUrl" style="max-width: 100%; border-radius: 0.3rem; display: block; margin-bottom: 0.3rem;" />
|
||||
</template>
|
||||
<div class="text" x-text="msg.content"></div>
|
||||
<button class="undo-btn" title="Trim conversation back to before this message" @click="trimTo(msg)">Undo</button>
|
||||
</div>
|
||||
</template>
|
||||
<template x-if="msg.role === 'assistant'">
|
||||
@@ -355,9 +373,8 @@
|
||||
You are a helpful AI assistant.
|
||||
- Do not preach about implications, do not praise excessively.
|
||||
- Keep a critical mindset, do not assume blindly.
|
||||
- Answer in valid markdown only, no exceptions.
|
||||
|
||||
- When I ask something about code, or software development, keep in mind that I am a senior backend developer (but do not mention that explicitly), and do not explain excessively, but and challenge my statements with better alternatives if I don't sound right, especially in coding. Do not bring it up otherwise.
|
||||
- When I ask something about code, or software development, keep in mind that I am a senior backend developer (but do not mention that explicitly), and do not explain excessively, but and challenge my statements where needed with better alternatives if I don't sound right, especially in coding. Do not bring it up otherwise.
|
||||
- Do not give me code if the topic is not about programming or software development.
|
||||
`
|
||||
.replace(/^\s+/gm, "")
|
||||
@@ -375,9 +392,9 @@
|
||||
sessionId: null,
|
||||
|
||||
models: [
|
||||
{ name: "gpt-5.4-mini", chat: chatWithOpenAI, key: "OPENAI_API_KEY" },
|
||||
{ name: "gemini-3.5-flash-lite", chat: chatWithGemini, key: "GEMINI_API_KEY" },
|
||||
{ name: "claude-haiku-4-5-20251001", chat: chatWithClaude, key: "ANTHROPIC_API_KEY" },
|
||||
{ name: "gpt-5.4-mini", chat: chatWithOpenAI, key: window.env.OPENAI_API_KEY },
|
||||
{ name: "gemini-3.5-flash-lite", chat: chatWithGemini, key: window.env.GEMINI_API_KEY },
|
||||
{ name: "claude-haiku-4-5-20251001", chat: chatWithClaude, key: window.env.ANTHROPIC_API_KEY },
|
||||
],
|
||||
|
||||
async init() {
|
||||
@@ -444,7 +461,7 @@
|
||||
const modelObj = this.models.find((m) => m.name === this.activeModelName);
|
||||
await modelObj.chat({
|
||||
model: this.activeModelName,
|
||||
apiKey: window.env[modelObj.key],
|
||||
apiKey: modelObj.key,
|
||||
messages: this.messages,
|
||||
signal: this.abortController.signal,
|
||||
onContent: (chunk) => {
|
||||
@@ -492,6 +509,17 @@
|
||||
});
|
||||
},
|
||||
|
||||
trimTo(msg) {
|
||||
if (this.isBusy) return;
|
||||
const idx = this.messages.indexOf(msg);
|
||||
if (idx === -1) return;
|
||||
this.messages = this.messages.slice(0, idx);
|
||||
updateSessionHistory(this.sessionId, this.messages);
|
||||
this.promptText = msg.content;
|
||||
this.pendingImages = msg.images ? JSON.parse(JSON.stringify(msg.images)) : [];
|
||||
this.$nextTick(() => this.$refs.promptInput.focus());
|
||||
},
|
||||
|
||||
restoreConversation(msgs) {
|
||||
this.messages = JSON.parse(JSON.stringify(msgs));
|
||||
this.userHasScrolledUp = false;
|
||||
@@ -564,11 +592,10 @@
|
||||
"anthropic-version": "2023-06-01",
|
||||
"anthropic-dangerous-direct-browser-access": "true",
|
||||
},
|
||||
apiKey: window.env.ANTHROPIC_API_KEY,
|
||||
});
|
||||
}
|
||||
|
||||
async function chatWithGemini({ onContent, onError, messages, signal, apiKey = window.env.GEMINI_API_KEY, model, ...rest }) {
|
||||
async function chatWithGemini({ onContent, onError, messages, signal, apiKey, model, ...rest }) {
|
||||
const contents = messages.map((msg, i, arr) => {
|
||||
const role = msg.role === "assistant" ? "model" : "user";
|
||||
let parts = [{ text: msg.content }];
|
||||
|
||||
Reference in New Issue
Block a user