mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
feat: add immediate context compaction API, UI button, and /compact slash command
- Add POST /bots/:bot_id/sessions/:session_id/compact endpoint for synchronous context compaction with fallback to chat model when no dedicated compaction model is configured - Add "Compact Now" button to session info panel in the web UI - Add /compact slash command for triggering compaction from chat - Regenerate OpenAPI spec and TypeScript SDK
This commit is contained in:
@@ -229,7 +229,10 @@
|
||||
"infoCacheWrite": "Cache Write",
|
||||
"infoSkills": "Skills",
|
||||
"infoNoSkills": "No skills used in this session",
|
||||
"infoNoData": "No data available"
|
||||
"infoNoData": "No data available",
|
||||
"compactNow": "Compact Now",
|
||||
"compactSuccess": "Context compaction completed",
|
||||
"compactFailed": "Context compaction failed"
|
||||
},
|
||||
"models": {
|
||||
"title": "Models",
|
||||
|
||||
@@ -225,7 +225,10 @@
|
||||
"infoCacheWrite": "Cache 写入",
|
||||
"infoSkills": "Skills",
|
||||
"infoNoSkills": "此会话未使用任何 Skill",
|
||||
"infoNoData": "暂无数据"
|
||||
"infoNoData": "暂无数据",
|
||||
"compactNow": "立即压缩",
|
||||
"compactSuccess": "上下文压缩完成",
|
||||
"compactFailed": "上下文压缩失败"
|
||||
},
|
||||
"models": {
|
||||
"title": "模型",
|
||||
|
||||
@@ -65,6 +65,26 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Compact Now -->
|
||||
<div class="mt-3">
|
||||
<button
|
||||
type="button"
|
||||
class="flex items-center justify-center gap-1.5 w-full px-2 py-1.5 rounded-md text-xs font-medium text-foreground bg-accent hover:bg-accent/80 transition-colors disabled:opacity-50 disabled:pointer-events-none"
|
||||
:disabled="!sessionId || usedTokens <= 0 || isCompacting"
|
||||
@click="triggerCompact"
|
||||
>
|
||||
<Loader2
|
||||
v-if="isCompacting"
|
||||
class="size-3 animate-spin"
|
||||
/>
|
||||
<Minimize2
|
||||
v-else
|
||||
class="size-3"
|
||||
/>
|
||||
{{ $t('chat.compactNow') }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Skills -->
|
||||
<div class="mt-3">
|
||||
<p class="text-[11px] font-medium text-muted-foreground uppercase tracking-wider mb-1.5">
|
||||
@@ -99,13 +119,16 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed, inject } from 'vue'
|
||||
import { computed, inject, ref } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useQuery } from '@pinia/colada'
|
||||
import { Sparkles, ExternalLink } from 'lucide-vue-next'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { useQuery, useQueryCache } from '@pinia/colada'
|
||||
import { toast } from 'vue-sonner'
|
||||
import { Sparkles, ExternalLink, Loader2, Minimize2 } from 'lucide-vue-next'
|
||||
import { ScrollArea } from '@memohai/ui'
|
||||
import { getBotsByBotIdSessionsBySessionIdStatus } from '@memohai/sdk'
|
||||
import { getBotsByBotIdSessionsBySessionIdStatus, postBotsByBotIdSessionsBySessionIdCompact } from '@memohai/sdk'
|
||||
import type { HandlersSessionInfoResponse } from '@memohai/sdk'
|
||||
import { resolveApiErrorMessage } from '@/utils/api-error'
|
||||
import { useChatStore } from '@/store/chat-list'
|
||||
import { openInFileManagerKey } from '../composables/useFileManagerProvider'
|
||||
|
||||
@@ -114,9 +137,11 @@ const props = defineProps<{
|
||||
overrideModelId?: string
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const chatStore = useChatStore()
|
||||
const { currentBotId, sessionId } = storeToRefs(chatStore)
|
||||
const openInFileManager = inject(openInFileManagerKey, undefined)
|
||||
const queryCache = useQueryCache()
|
||||
|
||||
const { data: info } = useQuery({
|
||||
key: () => ['session-status', currentBotId.value ?? '', sessionId.value ?? '', props.overrideModelId ?? ''],
|
||||
@@ -165,4 +190,28 @@ function formatTokenCount(n: number): string {
|
||||
function openSkillFile(skillName: string) {
|
||||
openInFileManager?.(`/data/skills/${skillName}/SKILL.md`, false)
|
||||
}
|
||||
|
||||
const isCompacting = ref(false)
|
||||
|
||||
async function triggerCompact() {
|
||||
const botId = currentBotId.value
|
||||
const sid = sessionId.value
|
||||
if (!botId || !sid || isCompacting.value) return
|
||||
|
||||
isCompacting.value = true
|
||||
try {
|
||||
await postBotsByBotIdSessionsBySessionIdCompact({
|
||||
path: { bot_id: botId, session_id: sid },
|
||||
throwOnError: true,
|
||||
})
|
||||
toast.success(t('chat.compactSuccess'))
|
||||
queryCache.invalidateQueries({ key: ['session-status', botId, sid] })
|
||||
}
|
||||
catch (error) {
|
||||
toast.error(resolveApiErrorMessage(error, t('chat.compactFailed')))
|
||||
}
|
||||
finally {
|
||||
isCompacting.value = false
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user