mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(tui): drain message queue on every busy → false transition
Previously the queue only drained inside the message.complete event handler, so anything enqueued while a shell.exec (!sleep, !cmd) or a failed agent turn was running would stay stuck forever — neither of those paths emits message.complete. After Ctrl+C an interrupted session would also orphan the queue because idle() flips busy=false locally without going through message.complete. Single source of truth: a useEffect that watches ui.busy. When the session is settled (sid present, busy false, not editing a queue item), pull one message and send it. Covers agent turn end, interrupt, shell.exec completion, error recovery, and the original startup hydration (first-sid case) all at once. Dropped the now-redundant dequeue/sendQueued from createGatewayEventHandler.message.complete and the accompanying GatewayEventHandlerContext.composer field — the effect handles it.
This commit is contained in:
parent
393175e60c
commit
d32e8d2ace
3 changed files with 6 additions and 25 deletions
|
|
@ -46,7 +46,6 @@ const pushNote = pushUnique(6)
|
||||||
const pushTool = pushUnique(8)
|
const pushTool = pushUnique(8)
|
||||||
|
|
||||||
export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: GatewayEvent) => void {
|
export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev: GatewayEvent) => void {
|
||||||
const { dequeue, queueEditRef, sendQueued } = ctx.composer
|
|
||||||
const { rpc } = ctx.gateway
|
const { rpc } = ctx.gateway
|
||||||
const { STARTUP_RESUME_ID, newSession, resumeById, setCatalog } = ctx.session
|
const { STARTUP_RESUME_ID, newSession, resumeById, setCatalog } = ctx.session
|
||||||
const { bellOnComplete, stdout, sys } = ctx.system
|
const { bellOnComplete, stdout, sys } = ctx.system
|
||||||
|
|
@ -394,16 +393,6 @@ export function createGatewayEventHandler(ctx: GatewayEventHandlerContext): (ev:
|
||||||
patchUiState(state => ({ ...state, usage: { ...state.usage, ...ev.payload!.usage } }))
|
patchUiState(state => ({ ...state, usage: { ...state.usage, ...ev.payload!.usage } }))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queueEditRef.current !== null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const next = dequeue()
|
|
||||||
|
|
||||||
if (next) {
|
|
||||||
sendQueued(next)
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -193,11 +193,6 @@ export interface InputHandlerResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface GatewayEventHandlerContext {
|
export interface GatewayEventHandlerContext {
|
||||||
composer: {
|
|
||||||
dequeue: () => string | undefined
|
|
||||||
queueEditRef: MutableRefObject<null | number>
|
|
||||||
sendQueued: (text: string) => void
|
|
||||||
}
|
|
||||||
gateway: GatewayServices
|
gateway: GatewayServices
|
||||||
session: {
|
session: {
|
||||||
STARTUP_RESUME_ID: string
|
STARTUP_RESUME_ID: string
|
||||||
|
|
|
||||||
|
|
@ -380,12 +380,13 @@ export function useMainApp(gw: GatewayClient) {
|
||||||
sys
|
sys
|
||||||
})
|
})
|
||||||
|
|
||||||
const prevSidRef = useRef<null | string>(null)
|
// Drain one queued message whenever the session settles (busy → false):
|
||||||
|
// agent turn ends, interrupt, shell.exec finishes, error recovered, or the
|
||||||
|
// session first comes up with pre-queued messages. Without this, shell.exec
|
||||||
|
// and error paths never emit message.complete, so anything enqueued while
|
||||||
|
// `!sleep` / a failed turn was running would stay stuck forever.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const prev = prevSidRef.current
|
if (!ui.sid || ui.busy || composerRefs.queueEditRef.current !== null) {
|
||||||
prevSidRef.current = ui.sid
|
|
||||||
|
|
||||||
if (prev !== null || !ui.sid || ui.busy || composerRefs.queueEditRef.current !== null) {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -416,7 +417,6 @@ export function useMainApp(gw: GatewayClient) {
|
||||||
const onEvent = useMemo(
|
const onEvent = useMemo(
|
||||||
() =>
|
() =>
|
||||||
createGatewayEventHandler({
|
createGatewayEventHandler({
|
||||||
composer: { dequeue: composerActions.dequeue, queueEditRef: composerRefs.queueEditRef, sendQueued },
|
|
||||||
gateway,
|
gateway,
|
||||||
session: {
|
session: {
|
||||||
STARTUP_RESUME_ID,
|
STARTUP_RESUME_ID,
|
||||||
|
|
@ -432,11 +432,8 @@ export function useMainApp(gw: GatewayClient) {
|
||||||
[
|
[
|
||||||
appendMessage,
|
appendMessage,
|
||||||
bellOnComplete,
|
bellOnComplete,
|
||||||
composerActions,
|
|
||||||
composerRefs,
|
|
||||||
gateway,
|
gateway,
|
||||||
panel,
|
panel,
|
||||||
sendQueued,
|
|
||||||
session.newSession,
|
session.newSession,
|
||||||
session.resetSession,
|
session.resetSession,
|
||||||
session.resumeById,
|
session.resumeById,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue