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
parent 3d74d78698
commit 9a9416c99c
129 changed files with 7017 additions and 1838 deletions
+1 -5
View File
@@ -1,5 +1,5 @@
import { io, type Socket } from 'socket.io-client'
import { request, getBaseUrlValue, getApiKey } from '../client'
import { getBaseUrlValue, getApiKey } from '../client'
export type ContentBlock =
| { type: 'text'; text: string }
@@ -616,7 +616,3 @@ export function startRunViaSocket(
},
}
}
export async function fetchModels(): Promise<{ data: Array<{ id: string }> }> {
return request('/api/hermes/v1/models')
}
+2 -1
View File
@@ -72,10 +72,11 @@ export async function fetchConfig(sections?: string[]): Promise<AppConfig> {
export async function updateConfigSection(
section: string,
values: Record<string, any>,
options?: { restart?: boolean },
): Promise<void> {
await request('/api/hermes/config', {
method: 'PUT',
body: JSON.stringify({ section, values }),
body: JSON.stringify({ section, values, ...options }),
})
}
@@ -1,39 +0,0 @@
import { request } from '../client'
export interface GatewayStatus {
profile: string
port: number
host: string
url: string
running: boolean
pid?: number
diagnostics?: {
pid_path: string
config_path: string
pid_file_exists: boolean
config_exists: boolean
health_url: string
health_checked_at: string
health_ok?: boolean
reason: string
}
}
export async function fetchGateways(): Promise<GatewayStatus[]> {
const res = await request<{ gateways: GatewayStatus[] }>('/api/hermes/gateways')
return res.gateways
}
export async function startGateway(name: string): Promise<GatewayStatus> {
const res = await request<{ success: boolean; gateway: GatewayStatus }>(`/api/hermes/gateways/${name}/start`, { method: 'POST' })
return res.gateway
}
export async function stopGateway(name: string): Promise<void> {
await request(`/api/hermes/gateways/${name}/stop`, { method: 'POST' })
}
export async function checkGatewayHealth(name: string): Promise<GatewayStatus> {
const res = await request<{ gateway: GatewayStatus }>(`/api/hermes/gateways/${name}/health`)
return res.gateway
}
@@ -30,6 +30,22 @@ export interface ChatMessage {
senderName: string
content: string
timestamp: number
role?: string
tool_call_id?: string | null
tool_calls?: any[] | null
tool_name?: string | null
finish_reason?: string | null
reasoning?: string | null
reasoning_details?: string | null
reasoning_content?: string | null
isStreaming?: boolean
toolName?: string
toolCallId?: string
toolArgs?: string
toolPreview?: string
toolResult?: string
toolStatus?: 'running' | 'done' | 'error'
attachments?: Array<{ id: string; name: string; type: string; size: number; url: string }>
}
export interface MemberInfo {
@@ -4,7 +4,6 @@ export interface HermesProfile {
name: string
active: boolean
model: string
gateway: string
alias: string
}
@@ -13,7 +12,6 @@ export interface HermesProfileDetail {
path: string
model: string
provider: string
gateway: string
skills: number
hasEnv: boolean
hasSoulMd: boolean
+6 -2
View File
@@ -2,6 +2,7 @@ import { request, getApiKey, getBaseUrlValue } from '../client'
export interface SessionSummary {
id: string
profile?: string
source: string
model: string
provider?: string
@@ -48,10 +49,11 @@ export interface HermesMessage {
reasoning: string | null
}
export async function fetchSessions(source?: string, limit?: number): Promise<SessionSummary[]> {
export async function fetchSessions(source?: string, limit?: number, profile?: string): Promise<SessionSummary[]> {
const params = new URLSearchParams()
if (source) params.set('source', source)
if (limit) params.set('limit', String(limit))
if (profile) params.set('profile', profile)
const query = params.toString()
const res = await request<{ sessions: SessionSummary[] }>(`/api/hermes/sessions${query ? `?${query}` : ''}`)
return res.sessions
@@ -231,9 +233,11 @@ export async function fetchSessionUsageSingle(id: string): Promise<{ input_token
}
}
export async function fetchContextLength(profile?: string): Promise<number> {
export async function fetchContextLength(profile?: string, provider?: string, model?: string): Promise<number> {
const params = new URLSearchParams()
if (profile) params.set('profile', profile)
if (provider) params.set('provider', provider)
if (model) params.set('model', model)
const query = params.toString()
const res = await request<{ context_length: number }>(`/api/hermes/sessions/context-length${query ? `?${query}` : ''}`)
return res.context_length
+20 -2
View File
@@ -45,11 +45,19 @@ export interface AvailableModelGroup {
model_meta?: Record<string, { preview?: boolean; disabled?: boolean; alias?: string }>
}
export interface ProfileAvailableModels {
profile: string
default: string
default_provider: string
groups: AvailableModelGroup[]
}
export interface AvailableModelsResponse {
default: string
default_provider: string
groups: AvailableModelGroup[]
allProviders: AvailableModelGroup[]
profiles?: ProfileAvailableModels[]
/** Web UI-only display aliases keyed by provider -> canonical model ID. */
model_aliases?: Record<string, Record<string, string>>
model_visibility?: ModelVisibility
@@ -76,8 +84,18 @@ export async function fetchConfigModels(): Promise<ConfigModelsResponse> {
return request<ConfigModelsResponse>('/api/hermes/config/models')
}
export async function fetchAvailableModels(): Promise<AvailableModelsResponse> {
return request<AvailableModelsResponse>('/api/hermes/available-models')
function currentProfileName(): string {
try {
return localStorage.getItem('hermes_active_profile_name') || 'default'
} catch {
return 'default'
}
}
export async function fetchAvailableModels(profile = currentProfileName()): Promise<AvailableModelsResponse> {
const params = new URLSearchParams()
params.set('profile', profile || 'default')
return request<AvailableModelsResponse>(`/api/hermes/available-models?${params.toString()}`)
}
export async function fetchProviderModels(data: {