prepare 0.5.25 changelog (#778)
This commit is contained in:
@@ -41,22 +41,72 @@ const statusItems = computed(() => {
|
||||
];
|
||||
});
|
||||
|
||||
type DisplayContentFile = {
|
||||
type: 'image' | 'file'
|
||||
name: string
|
||||
path?: string
|
||||
url?: string
|
||||
}
|
||||
|
||||
function getBlockText(block: any): string {
|
||||
if (!block || typeof block !== 'object') return ''
|
||||
if (block.type === 'text' || block.type === 'input_text') {
|
||||
return typeof block.text === 'string' ? block.text : ''
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
function getImageUrlFromBlock(block: any): string | null {
|
||||
if (!block || typeof block !== 'object') return null
|
||||
if (block.type !== 'input_image' && block.type !== 'image_url') return null
|
||||
const raw = block.image_url
|
||||
if (typeof raw === 'string') return raw
|
||||
if (raw && typeof raw === 'object' && typeof raw.url === 'string') return raw.url
|
||||
return null
|
||||
}
|
||||
|
||||
function imageNameFromDataUrl(url: string, index: number): string {
|
||||
const match = url.match(/^data:image\/([^;,]+)/i)
|
||||
const ext = match?.[1] === 'jpeg' ? 'jpg' : match?.[1] || 'png'
|
||||
return `image-${index + 1}.${ext}`
|
||||
}
|
||||
|
||||
function parseContentBlocks(content: string): Array<ContentBlock | Record<string, unknown>> | null {
|
||||
const trimmed = content.trim()
|
||||
if (!trimmed) return null
|
||||
|
||||
const parse = (value: string) => {
|
||||
const parsed = JSON.parse(value)
|
||||
return Array.isArray(parsed) && parsed.length > 0 && 'type' in parsed[0]
|
||||
? parsed as Array<ContentBlock | Record<string, unknown>>
|
||||
: null
|
||||
}
|
||||
|
||||
try {
|
||||
return parse(trimmed)
|
||||
} catch {
|
||||
// Hermes Agent stored some multimodal user messages via Python str(list),
|
||||
// e.g. [{'type': 'text'}, {'type': 'image_url', ...}]. Convert that
|
||||
// legacy repr into JSON for display only.
|
||||
if (!trimmed.startsWith("[{'") && !trimmed.startsWith('[{"')) return null
|
||||
try {
|
||||
return parse(
|
||||
trimmed
|
||||
.replace(/\bNone\b/g, 'null')
|
||||
.replace(/\bTrue\b/g, 'true')
|
||||
.replace(/\bFalse\b/g, 'false')
|
||||
.replace(/'/g, '"'),
|
||||
)
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse ContentBlock[] from JSON string
|
||||
const contentBlocks = computed(() => {
|
||||
const content = props.message.content || '';
|
||||
if (!content.trim()) return null;
|
||||
|
||||
try {
|
||||
// Try to parse as ContentBlock[] array
|
||||
const parsed = JSON.parse(content);
|
||||
if (Array.isArray(parsed) && parsed.length > 0 && 'type' in parsed[0]) {
|
||||
return parsed as ContentBlock[];
|
||||
}
|
||||
} catch {
|
||||
// Not valid JSON, treat as plain text
|
||||
}
|
||||
|
||||
return null;
|
||||
return parseContentBlocks(content);
|
||||
});
|
||||
|
||||
// Check if content is in ContentBlock[] format
|
||||
@@ -70,16 +120,40 @@ const displayText = computed(() => {
|
||||
|
||||
// Extract text from blocks
|
||||
return contentBlocks.value!
|
||||
.filter(block => block.type === 'text')
|
||||
.map(block => block.text)
|
||||
.map(block => getBlockText(block))
|
||||
.filter(Boolean)
|
||||
.join('\n');
|
||||
});
|
||||
|
||||
// Extract files from ContentBlock[]
|
||||
const contentFiles = computed(() => {
|
||||
const contentFiles = computed<DisplayContentFile[] | null>(() => {
|
||||
if (!isContentBlockArray.value) return null;
|
||||
|
||||
return contentBlocks.value!.filter(block => block.type === 'image' || block.type === 'file');
|
||||
return contentBlocks.value!.flatMap<DisplayContentFile>((block, index) => {
|
||||
if (block.type === 'image') {
|
||||
return [{
|
||||
type: 'image' as const,
|
||||
name: String((block as any).name || `image-${index + 1}`),
|
||||
path: String((block as any).path || ''),
|
||||
}].filter(file => file.path)
|
||||
}
|
||||
if (block.type === 'file') {
|
||||
return [{
|
||||
type: 'file' as const,
|
||||
name: String((block as any).name || `file-${index + 1}`),
|
||||
path: String((block as any).path || ''),
|
||||
}].filter(file => file.path)
|
||||
}
|
||||
const imageUrl = getImageUrlFromBlock(block)
|
||||
if (imageUrl?.startsWith('data:image/')) {
|
||||
return [{
|
||||
type: 'image' as const,
|
||||
name: imageNameFromDataUrl(imageUrl, index),
|
||||
url: imageUrl,
|
||||
}]
|
||||
}
|
||||
return []
|
||||
});
|
||||
});
|
||||
|
||||
// Generate download URL with auth token
|
||||
@@ -89,6 +163,11 @@ function getDownloadUrl(path: string, name: string): string {
|
||||
return token ? `${base}&token=${encodeURIComponent(token)}` : base;
|
||||
}
|
||||
|
||||
function getContentFileUrl(file: DisplayContentFile): string {
|
||||
if (file.url) return file.url
|
||||
return file.path ? getDownloadUrl(file.path, file.name) : ''
|
||||
}
|
||||
|
||||
const toolExpanded = ref(false);
|
||||
const previewUrl = ref<string | null>(null);
|
||||
|
||||
@@ -721,16 +800,16 @@ onBeforeUnmount(() => {
|
||||
>
|
||||
<template v-if="file.type === 'image'">
|
||||
<img
|
||||
:src="getDownloadUrl(file.path, file.name)"
|
||||
:src="getContentFileUrl(file)"
|
||||
:alt="file.name"
|
||||
class="msg-attachment-thumb"
|
||||
@click="previewUrl = getDownloadUrl(file.path, file.name)"
|
||||
@click="previewUrl = getContentFileUrl(file)"
|
||||
/>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div
|
||||
class="msg-attachment-file"
|
||||
@click="downloadFile(file.path, file.name).catch(err => toast.error(err.message || t('download.downloadFailed')))"
|
||||
@click="file.path && downloadFile(file.path, file.name).catch(err => toast.error(err.message || t('download.downloadFailed')))"
|
||||
style="cursor: pointer;"
|
||||
:title="t('download.downloadFile')"
|
||||
>
|
||||
|
||||
@@ -5,6 +5,20 @@ export interface ChangelogEntry {
|
||||
}
|
||||
|
||||
export const changelog: ChangelogEntry[] = [
|
||||
{
|
||||
version: '0.5.25',
|
||||
date: '2026-05-16',
|
||||
changes: [
|
||||
'changelog.new_0_5_25_1',
|
||||
'changelog.new_0_5_25_2',
|
||||
'changelog.new_0_5_25_3',
|
||||
'changelog.new_0_5_25_4',
|
||||
'changelog.new_0_5_25_5',
|
||||
'changelog.new_0_5_25_6',
|
||||
'changelog.new_0_5_25_7',
|
||||
'changelog.new_0_5_25_8',
|
||||
],
|
||||
},
|
||||
{
|
||||
version: '0.5.24',
|
||||
date: '2026-05-15',
|
||||
|
||||
@@ -909,6 +909,14 @@ jobTriggered: 'Job ausgelost',
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
new_0_5_5_1: '🎉 Tag der Arbeit! Heute wird nicht gearbeitet, bitte habt Verständnis',
|
||||
new_0_5_5_2: 'Verlaufsseite für Hermes-Sitzungshistorie hinzugefügt',
|
||||
new_0_5_5_3: 'Verlaufsseite verwaltet Sitzungen unabhängig ohne Störung des aktiven Chats',
|
||||
|
||||
@@ -1192,6 +1192,14 @@ export default {
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
|
||||
new_0_5_6_1: 'Add voice playback feature with Web Speech API: manual button, auto-play toggle, rainbow border animation, and mobile optimization',
|
||||
new_0_5_6_2: 'Add robust LLM JSON parser with tolerance for Python format and extract text from streaming events',
|
||||
|
||||
@@ -905,6 +905,14 @@ jobTriggered: 'Job ejecutado',
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
new_0_5_5_1: '🎉 ¡Feliz Día del Trabajo! Hoy no se trabaja, agradezcan su comprensión',
|
||||
new_0_5_5_2: 'Añadida página de historial para sesiones Hermes',
|
||||
new_0_5_5_3: 'La página de historial gestiona sesiones de forma independiente',
|
||||
|
||||
@@ -904,6 +904,14 @@ jobTriggered: 'Job declenche',
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
new_0_5_5_1: '🎉 Joyeuse Fête du Travail! Pas de travail aujourd\'hui, merci de votre compréhension',
|
||||
new_0_5_5_2: 'Ajout d\'une page d\'historique pour les sessions Hermes',
|
||||
new_0_5_5_3: 'La page d\'historique gère les sessions de manière indépendante',
|
||||
|
||||
@@ -905,6 +905,14 @@ export default {
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
new_0_5_5_1: '🎉 労働者の日!今日はお休みです、何卒ご理解ください',
|
||||
new_0_5_5_2: 'Hermesセッション履歴ページを追加',
|
||||
new_0_5_5_3: '履歴ページはアクティブチャットに干渉せずにセッション管理',
|
||||
|
||||
@@ -905,6 +905,14 @@ export default {
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
new_0_5_5_1: '🎉 노동절 감사합니다! 오늘은 쉬니까 양해 부탁드립니다',
|
||||
new_0_5_5_2: 'Hermes 세션 기록 페이지 추가',
|
||||
new_0_5_5_3: '기록 페이지는 독립적으로 세션 관리',
|
||||
|
||||
@@ -905,6 +905,14 @@ jobTriggered: 'Job acionado',
|
||||
new_0_5_23_4: 'Reserve the Web UI port during gateway allocation to avoid startup conflicts',
|
||||
new_0_5_23_5: 'Fix self-update restart handling so successful helper exits are not reported as failures',
|
||||
new_0_5_24_1: 'Align Bridge chat with API Server handling for multimodal input, system prompt, and workspace context',
|
||||
new_0_5_25_1: 'Add group chat room reset and clone actions',
|
||||
new_0_5_25_2: 'Make the Web UI state directory configurable for custom deployment layouts',
|
||||
new_0_5_25_3: 'Add MiMo as a TTS provider in voice settings',
|
||||
new_0_5_25_4: 'Fetch custom provider model lists through the backend to avoid browser CORS failures',
|
||||
new_0_5_25_5: 'Fix tool approval flow for bridge sessions',
|
||||
new_0_5_25_6: 'Remove the forced CLI platform hint from bridge prompts so custom media/file instructions are preserved',
|
||||
new_0_5_25_7: 'Show base64 image content correctly in user message history',
|
||||
new_0_5_25_8: 'Add Playwright browser tests, chat streaming contract coverage, provider model coverage, and coverage baseline',
|
||||
new_0_5_5_1: '🎉 Feliz Dia do Trabalhador! Hoje não se trabalha, obrigado pela compreensão',
|
||||
new_0_5_5_2: 'Adicionada página de histórico para sessões Hermes',
|
||||
new_0_5_5_3: 'Página de histórico gerencia sessões de forma independente',
|
||||
|
||||
@@ -1194,6 +1194,14 @@ export default {
|
||||
new_0_5_23_4: 'gateway 分配連接埠時保留 Web UI 連接埠,避免啟動連接埠衝突',
|
||||
new_0_5_23_5: '修復自更新重啟邏輯,避免將 restart helper 的成功退出誤報為失敗',
|
||||
new_0_5_24_1: '對齊 Bridge 聊天與 API Server 的多模態輸入、系統提示詞和工作區上下文處理',
|
||||
new_0_5_25_1: '新增群聊房間重設和複製操作',
|
||||
new_0_5_25_2: '支援設定 Web UI 狀態目錄,方便自訂部署目錄結構',
|
||||
new_0_5_25_3: '語音設定新增 MiMo TTS 提供商',
|
||||
new_0_5_25_4: '自訂 Provider 模型清單改由後端代理請求,避免瀏覽器跨域失敗',
|
||||
new_0_5_25_5: '修復 Bridge 工作階段的工具授權流程',
|
||||
new_0_5_25_6: '移除 Bridge 強制注入的 CLI 平台提示,保留使用者自訂媒體和檔案輸出規則',
|
||||
new_0_5_25_7: '使用者訊息歷史支援正確展示 base64 圖片內容',
|
||||
new_0_5_25_8: '新增 Playwright 瀏覽器測試、聊天串流契約覆蓋、Provider 模型測試和覆蓋率基線',
|
||||
new_0_5_6_1: '新增語音播放功能:使用 Web Speech API,支援手動播放按鈕、自動播放開關、彩虹邊框動畫和行動端最佳化',
|
||||
new_0_5_6_2: '新增強健的 LLM JSON 解析器,相容 Python 格式並從串流事件中擷取文字',
|
||||
new_0_5_6_3: 'Skills 功能增強:使用統計、來源過濾、封存技能、來源追溯和釘選切換',
|
||||
|
||||
@@ -1194,6 +1194,14 @@ export default {
|
||||
new_0_5_23_4: 'gateway 分配端口时保留 Web UI 端口,避免启动端口冲突',
|
||||
new_0_5_23_5: '修复自更新重启逻辑,避免将 restart helper 的成功退出误报为失败',
|
||||
new_0_5_24_1: '对齐 Bridge 聊天与 API Server 的多模态输入、系统提示词和工作区上下文处理',
|
||||
new_0_5_25_1: '新增群聊房间重置和克隆操作',
|
||||
new_0_5_25_2: '支持配置 Web UI 状态目录,方便自定义部署目录结构',
|
||||
new_0_5_25_3: '语音设置新增 MiMo TTS 提供商',
|
||||
new_0_5_25_4: '自定义 Provider 模型列表改由后端代理请求,避免浏览器跨域失败',
|
||||
new_0_5_25_5: '修复 Bridge 会话的工具授权流程',
|
||||
new_0_5_25_6: '移除 Bridge 强制注入的 CLI 平台提示,保留用户自定义媒体和文件输出规则',
|
||||
new_0_5_25_7: '用户消息历史支持正确展示 base64 图片内容',
|
||||
new_0_5_25_8: '新增 Playwright 浏览器测试、聊天流式契约覆盖、Provider 模型测试和覆盖率基线',
|
||||
|
||||
new_0_5_6_1: '新增语音播放功能:使用 Web Speech API,支持手动播放按钮、自动播放开关、彩虹边框动画和移动端优化',
|
||||
new_0_5_6_2: '新增健壮的 LLM JSON 解析器,兼容 Python 格式并从流式事件中提取文本',
|
||||
|
||||
Reference in New Issue
Block a user