Fix queued bubbles, queue persistence, duplicate confirm UX, semantic check
- Queued message bubbles now match user bubble style (primary colour, right-aligned, opacity 0.45) in both ChatView and WorkspaceView - Queue persisted to localStorage (fa_conv_queue_<id>); survives page refresh, restored on fetchConversation, cleared on delete - ToolCallCard confirm/deny: buttons now inline in header row; "Create anyway" calls POST /api/notes or /api/tasks directly (no LLM round-trip); shows "✓ Created" / "Skipped" state; removed chatStore dependency - POST /api/notes and POST /api/tasks now accept project (name string) and resolve to project_id server-side, matching tools.py behaviour - Remove semantic similarity duplicate check from create_note and create_task — 0.87 threshold was too aggressive for topically-related notes; title-based exact/fuzzy checks are sufficient Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -89,9 +89,32 @@ export const useChatStore = defineStore("chat", () => {
|
||||
return id ? (convQueues.value[id] ?? []) : [];
|
||||
});
|
||||
|
||||
function _saveQueue(convId: number) {
|
||||
const q = convQueues.value[convId] ?? [];
|
||||
if (q.length) {
|
||||
localStorage.setItem(`fa_conv_queue_${convId}`, JSON.stringify(q));
|
||||
} else {
|
||||
localStorage.removeItem(`fa_conv_queue_${convId}`);
|
||||
}
|
||||
}
|
||||
|
||||
function _loadQueue(convId: number) {
|
||||
try {
|
||||
const raw = localStorage.getItem(`fa_conv_queue_${convId}`);
|
||||
if (raw) {
|
||||
convQueues.value[convId] = JSON.parse(raw) as QueuedMessage[];
|
||||
}
|
||||
} catch {
|
||||
// ignore corrupt data
|
||||
}
|
||||
}
|
||||
|
||||
function clearQueue() {
|
||||
const id = currentConversation.value?.id;
|
||||
if (id) convQueues.value[id] = [];
|
||||
if (id) {
|
||||
convQueues.value[id] = [];
|
||||
_saveQueue(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Chat is usable when Ollama is up and model is at least installed (cold starts still work)
|
||||
@@ -134,6 +157,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
currentConversation.value = await apiGet<ConversationDetail>(
|
||||
`/api/chat/conversations/${id}`
|
||||
);
|
||||
_loadQueue(id);
|
||||
} catch (e) {
|
||||
useToastStore().show("Failed to load conversation", "error");
|
||||
throw e;
|
||||
@@ -153,6 +177,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
for (const id of ids) {
|
||||
delete convStreams.value[id];
|
||||
delete convQueues.value[id];
|
||||
localStorage.removeItem(`fa_conv_queue_${id}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,6 +190,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
}
|
||||
delete convStreams.value[id];
|
||||
delete convQueues.value[id];
|
||||
localStorage.removeItem(`fa_conv_queue_${id}`);
|
||||
} catch (e) {
|
||||
useToastStore().show("Failed to delete conversation", "error");
|
||||
throw e;
|
||||
@@ -212,6 +238,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
content, contextNoteId, includeNoteIds, think, contextNoteTitle,
|
||||
excludeNoteIds, ragProjectId, workspaceProjectId,
|
||||
});
|
||||
_saveQueue(convId);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -409,6 +436,7 @@ export const useChatStore = defineStore("chat", () => {
|
||||
const queue = convQueues.value[convId];
|
||||
if (queue?.length && currentConversation.value?.id === convId) {
|
||||
const next = queue.shift()!;
|
||||
_saveQueue(convId);
|
||||
setTimeout(() => sendMessage(
|
||||
next.content,
|
||||
next.contextNoteId,
|
||||
|
||||
Reference in New Issue
Block a user