Fix bridge history, profile models, and Windows gateway handling (#845)

* feat: support profile-aware group chat bridge flows

* feat: route cron jobs through hermes cli

* Fix group chat routing and isolate bridge tests

* Add Grok image-to-video media skill

* Default Grok videos to media directory

* Fix bridge profile fallback and cron repeat clearing

* Refine bridge chat and gateway platform handling

* Filter bridge tool-call text deltas

* Preserve structured bridge chat history

* Prepare beta release build artifacts

* Fix Windows run profile resolution

* Fix Windows path compatibility checks

* Fix profile-scoped model page display

* Hide Windows subprocess windows for jobs and updates

* Hide Windows file backend subprocess windows

* Avoid Windows gateway restart lock conflicts

* Treat Windows gateway lock as running on startup

* Force release Windows gateway lock on restart

* Tighten Windows gateway lock cleanup

* Update chat e2e source expectation

* Bump package version to 0.5.30

---------

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
ekko
2026-05-19 16:09:59 +08:00
committed by GitHub
co-authored by Codex
parent 3d74d78698
commit 9a9416c99c
129 changed files with 7016 additions and 1837 deletions
@@ -2,11 +2,12 @@
import { computed, ref, onUnmounted } from 'vue'
import { NPopconfirm, NCheckbox } from 'naive-ui'
import { useI18n } from 'vue-i18n'
import multiavatar from '@multiavatar/multiavatar'
import type { Session } from '@/stores/hermes/chat'
import { useAppStore } from '@/stores/hermes/app'
import { formatTimestampMs } from '@/shared/session-display'
const props = defineProps<{
const props = withDefaults(defineProps<{
session: Session
active: boolean
pinned: boolean
@@ -14,7 +15,10 @@ const props = defineProps<{
streaming?: boolean
selectable?: boolean
selected?: boolean
}>()
showProfile?: boolean
}>(), {
showProfile: true,
})
const emit = defineEmits<{
select: []
@@ -30,6 +34,8 @@ const sessionModelName = computed(() =>
? appStore.displayModelName(props.session.model, props.session.provider)
: '',
)
const profileName = computed(() => props.session.profile || 'default')
const profileAvatar = computed(() => multiavatar(profileName.value))
let longPressTimer: ReturnType<typeof setTimeout> | null = null
const longPressTriggered = ref(false)
@@ -107,6 +113,10 @@ onUnmounted(() => {
<span v-if="sessionModelName" class="session-item-model" :title="session.model">{{ sessionModelName }}</span>
<span class="session-item-time">{{ formatTimestampMs(session.createdAt) }}</span>
</span>
<span v-if="props.showProfile" class="session-item-profile">
<span class="session-item-profile-avatar" v-html="profileAvatar" />
<span class="session-item-profile-name">{{ profileName }}</span>
</span>
</div>
<NPopconfirm v-if="canDelete && !selectable" @positive-click="emit('delete')">
<template #trigger>
@@ -118,3 +128,38 @@ onUnmounted(() => {
</NPopconfirm>
</button>
</template>
<style scoped>
.session-item-profile {
display: flex;
align-items: center;
gap: 5px;
min-width: 0;
margin-top: 4px;
}
.session-item-profile-avatar {
display: inline-flex;
width: 16px;
height: 16px;
flex: 0 0 16px;
border-radius: 50%;
overflow: hidden;
}
.session-item-profile-avatar :deep(svg) {
width: 16px;
height: 16px;
display: block;
}
.session-item-profile-name {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 11px;
line-height: 16px;
color: var(--text-muted);
}
</style>