mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-06-21 23:54:22 +08:00
fix(hermes): restore active profile after group chat and isolate run events
Group chat switched profiles via hermesProfileUse but never restored the user's original active profile (comment promised restore since v0.14). Also tighten hermes-run-* filtering so events from other concurrent runs cannot complete a pending group-chat reply before run_id is known. Co-authored-by: 晴天 <1186258278@users.noreply.github.com>
This commit is contained in:
7
src/engines/hermes/lib/hermes-run-events.js
Normal file
7
src/engines/hermes/lib/hermes-run-events.js
Normal file
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* Predicate for Hermes `hermes-run-*` Tauri events.
|
||||
* Requires a known run_id so concurrent runs cannot leak output across listeners.
|
||||
*/
|
||||
export function matchesHermesRun(runId, eventRunId) {
|
||||
return runId != null && eventRunId === runId
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
import { t } from '../../../lib/i18n.js'
|
||||
import { api, isTauriRuntime, safeTauriListen } from '../../../lib/tauri-api.js'
|
||||
import { matchesHermesRun } from '../lib/hermes-run-events.js'
|
||||
import { svgIcon } from '../lib/svg-icons.js'
|
||||
|
||||
/**
|
||||
@@ -58,27 +59,27 @@ async function runHermesAgentAndWaitFinal(input) {
|
||||
cleanup()
|
||||
reject(err)
|
||||
}
|
||||
const matchesRun = (rid) => !runId || !rid || rid === runId
|
||||
;(async () => {
|
||||
try {
|
||||
unsubs.push(await safeTauriListen('hermes-run-started', (e) => {
|
||||
if (!runId && e?.payload?.run_id) runId = e.payload.run_id
|
||||
const rid = e?.payload?.run_id
|
||||
if (!runId && rid) runId = rid
|
||||
}))
|
||||
unsubs.push(await safeTauriListen('hermes-run-delta', (e) => {
|
||||
if (!matchesRun(e?.payload?.run_id)) return
|
||||
if (!matchesHermesRun(runId, e?.payload?.run_id)) return
|
||||
accumulated += e?.payload?.delta || ''
|
||||
}))
|
||||
unsubs.push(await safeTauriListen('hermes-run-done', (e) => {
|
||||
if (!matchesRun(e?.payload?.run_id)) return
|
||||
if (!matchesHermesRun(runId, e?.payload?.run_id)) return
|
||||
const out = (e?.payload?.output || accumulated || '').trim()
|
||||
finish(out)
|
||||
}))
|
||||
unsubs.push(await safeTauriListen('hermes-run-error', (e) => {
|
||||
if (!matchesRun(e?.payload?.run_id)) return
|
||||
if (!matchesHermesRun(runId, e?.payload?.run_id)) return
|
||||
fail(new Error(e?.payload?.error || 'unknown error'))
|
||||
}))
|
||||
unsubs.push(await safeTauriListen('hermes-run-cancelled', (e) => {
|
||||
if (!matchesRun(e?.payload?.run_id)) return
|
||||
if (!matchesHermesRun(runId, e?.payload?.run_id)) return
|
||||
finish(accumulated.trim() || '(cancelled)')
|
||||
}))
|
||||
|
||||
@@ -89,7 +90,7 @@ async function runHermesAgentAndWaitFinal(input) {
|
||||
|
||||
// 防御:如果 done 事件因为顺序问题尚未派发(理论上不会发生),等一拍兜底
|
||||
setTimeout(() => {
|
||||
if (!settled) finish(accumulated.trim())
|
||||
if (!settled && runId) finish(accumulated.trim())
|
||||
}, 300)
|
||||
} catch (e) {
|
||||
fail(e)
|
||||
@@ -303,11 +304,13 @@ export function render() {
|
||||
// 每个 profile run 完后切到下一个。
|
||||
// 这是个 trade-off — 真正的并发需要后端改造支持 per-call profile。
|
||||
let activeProfile = null
|
||||
let initialProfile = null
|
||||
try {
|
||||
// 记下当前 active profile 用于最后还原
|
||||
const curResp = await api.hermesProfilesList().catch(() => null)
|
||||
const curArr = Array.isArray(curResp) ? curResp : (curResp?.profiles || [])
|
||||
activeProfile = curResp?.active || curArr.find(p => p.active)?.name || 'default'
|
||||
initialProfile = curResp?.active || curArr.find(p => p.active)?.name || 'default'
|
||||
activeProfile = initialProfile
|
||||
} catch {}
|
||||
|
||||
for (let i = 0; i < targets.length; i++) {
|
||||
@@ -333,6 +336,11 @@ export function render() {
|
||||
}
|
||||
|
||||
// 还原 active profile(如果改了)— 静默尝试
|
||||
if (initialProfile && activeProfile !== initialProfile) {
|
||||
try {
|
||||
await api.hermesProfileUse(initialProfile)
|
||||
} catch {}
|
||||
}
|
||||
sending = false
|
||||
draw()
|
||||
}
|
||||
|
||||
16
tests/hermes-group-chat-run-events.test.js
Normal file
16
tests/hermes-group-chat-run-events.test.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import test from 'node:test'
|
||||
import assert from 'node:assert/strict'
|
||||
import { matchesHermesRun } from '../src/engines/hermes/lib/hermes-run-events.js'
|
||||
|
||||
test('matchesHermesRun rejects events before run_id is known', () => {
|
||||
assert.equal(matchesHermesRun(null, 'run_abc'), false)
|
||||
assert.equal(matchesHermesRun(undefined, 'run_abc'), false)
|
||||
})
|
||||
|
||||
test('matchesHermesRun rejects events from a different run', () => {
|
||||
assert.equal(matchesHermesRun('run_a', 'run_b'), false)
|
||||
})
|
||||
|
||||
test('matchesHermesRun accepts events for the active run', () => {
|
||||
assert.equal(matchesHermesRun('run_a', 'run_a'), true)
|
||||
})
|
||||
Reference in New Issue
Block a user