feat: file upload retry, secure file tokens, UI polish

- Add HMAC-based file token auth for secure AI model file access
- Add file upload retry with exponential backoff (max 3 retries)
- File endpoint now requires session auth or signed token
- Support assistant role messages in chat input
- Optimistic UI for attachments on message send
- Verify topic ownership before allowing messages
- Switch web scraping to Firecrawl API
- Agent profile page layout fixes (proper flex overflow)
- Add quick switcher (Ctrl+K) to sidenav
- Clean up longcat.ts and stale comments
This commit is contained in:
Zoe
2026-06-06 00:16:39 -05:00
parent 47009b1f0a
commit 8ccaa824dd
20 changed files with 827 additions and 406 deletions
+18 -1
View File
@@ -10,9 +10,14 @@ const props = defineProps<{
status?: 'uploading' | 'uploaded' | 'error';
url: string;
progress?: number;
retryCount?: number;
};
}>();
const emit = defineEmits<{
retry: [];
}>();
const isImage = computed(() => props.file.mimeType.startsWith('image/'));
const isVideo = computed(() => props.file.mimeType.startsWith('video/'));
const isAudio = computed(() => props.file.mimeType.startsWith('audio/'));
@@ -71,8 +76,20 @@ function openImageViewer() {
class="absolute inset-0 bg-black/50 rounded-lg flex items-center justify-center">
<div class="text-center">
<span class="i-svg-spinners-90-ring-with-bg text-6 text-white block mb-1"></span>
<span class="text-xs text-white">{{ file.progress || 0 }}%</span>
<span class="text-xs text-white">
{{ file.retryCount ? `Retry ${file.retryCount}/3` : `${file.progress || 0}%` }}
</span>
</div>
</div>
<div v-else-if="file.status === 'error'"
class="absolute inset-0 bg-black/60 rounded-lg flex flex-col items-center justify-center gap-1">
<span class="i-mynaui-danger-triangle text-6 text-red-400"></span>
<span class="text-xs text-red-300">Upload failed</span>
<button @click.stop="emit('retry')"
class="mt-1 flex items-center gap-1 px-2 py-0.5 rounded-md bg-white/10 hover:bg-white/20 text-xs text-white transition-colors">
<span class="i-mynaui-refresh text-3"></span>
Retry
</button>
</div>
</div>
</template>
+8 -2
View File
@@ -8,11 +8,13 @@ const props = defineProps<{
mimeType: string;
status: 'uploading' | 'uploaded' | 'error';
url: string;
retryCount?: number;
}
}>();
const emit = defineEmits<{
delete: [];
retry: [];
}>();
const handleDelete = async () => {
@@ -21,12 +23,16 @@ const handleDelete = async () => {
</script>
<template>
<div class="relative h-full w-fit flex">
<Display :file="props.file" />
<div class="relative h-full w-fit flex flex-shrink-0">
<Display :file="props.file" @retry="emit('retry')" />
<button @click="handleDelete"
class="absolute top-0 right-0 translate-x-1/2 -translate-y-1/2 flex items-center justify-center w-4 h-4 rounded-full bg-[var(--bg-base)] border border-[var(--color-border)] text-xs text-[#ff3b3b]">
<span class="i-mynaui-x text-3"></span>
</button>
<div v-if="file.status === 'error'"
class="absolute bottom-0 right-0 translate-x-1/4 translate-y-1/4 flex items-center justify-center w-4 h-4 rounded-full bg-red-500">
<span class="i-mynaui-danger-triangle text-2.5 text-white"></span>
</div>
</div>
</template>