mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-24 10:52:21 +00:00
clarify.request is a one-shot blocking event: the gateway turn blocks on clarify.respond. The desktop handler dropped it for any non-focused session (`if (!isActiveEvent) return`) and stored at most one request in a single global atom, so a background session that asked a clarifying question hung forever and re-focusing it could never recover (the event was already gone). - store/clarify.ts: key pending requests by runtime session id; expose the active session's request via a focus-scoped computed view (ClarifyTool is unchanged). clearClarifyRequest takes an optional session id for targeted clears, with a request-id fallback. - use-message-stream.ts: park every session's clarify (drop the isActiveEvent early return); toast when one lands for a background session since the row otherwise just keeps spinning like normal work. - clarify-tool.tsx: clear by session id so answering one chat can't wipe another's pending request. - store/clarify.test.ts: concurrent independence, focus-scoped view, targeted/stale/fallback clears.
81 lines
2.4 KiB
TypeScript
81 lines
2.4 KiB
TypeScript
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
|
|
import {
|
|
$clarifyRequest,
|
|
$clarifyRequests,
|
|
type ClarifyRequest,
|
|
clearClarifyRequest,
|
|
setClarifyRequest
|
|
} from './clarify'
|
|
import { $activeSessionId } from './session'
|
|
|
|
function clarify(sessionId: string | null, requestId: string): ClarifyRequest {
|
|
return {
|
|
requestId,
|
|
question: `question-${requestId}`,
|
|
choices: null,
|
|
sessionId
|
|
}
|
|
}
|
|
|
|
describe('clarify store', () => {
|
|
beforeEach(() => {
|
|
$clarifyRequests.set({})
|
|
$activeSessionId.set(null)
|
|
})
|
|
|
|
afterEach(() => {
|
|
$clarifyRequests.set({})
|
|
$activeSessionId.set(null)
|
|
})
|
|
|
|
it('keeps clarify requests from concurrent sessions independent', () => {
|
|
setClarifyRequest(clarify('session-a', 'req-a'))
|
|
setClarifyRequest(clarify('session-b', 'req-b'))
|
|
|
|
expect($clarifyRequests.get()['session-a']?.requestId).toBe('req-a')
|
|
expect($clarifyRequests.get()['session-b']?.requestId).toBe('req-b')
|
|
})
|
|
|
|
it('exposes only the active session via the focus-scoped view', () => {
|
|
setClarifyRequest(clarify('session-a', 'req-a'))
|
|
setClarifyRequest(clarify('session-b', 'req-b'))
|
|
|
|
$activeSessionId.set('session-a')
|
|
expect($clarifyRequest.get()?.requestId).toBe('req-a')
|
|
|
|
$activeSessionId.set('session-b')
|
|
expect($clarifyRequest.get()?.requestId).toBe('req-b')
|
|
|
|
$activeSessionId.set('session-c')
|
|
expect($clarifyRequest.get()).toBeNull()
|
|
})
|
|
|
|
it('clears only the targeted session, leaving the other pending', () => {
|
|
setClarifyRequest(clarify('session-a', 'req-a'))
|
|
setClarifyRequest(clarify('session-b', 'req-b'))
|
|
|
|
clearClarifyRequest('req-a', 'session-a')
|
|
|
|
expect($clarifyRequests.get()['session-a']).toBeUndefined()
|
|
expect($clarifyRequests.get()['session-b']?.requestId).toBe('req-b')
|
|
})
|
|
|
|
it('ignores a stale clear whose request id no longer matches', () => {
|
|
setClarifyRequest(clarify('session-a', 'req-a2'))
|
|
|
|
clearClarifyRequest('req-a1', 'session-a')
|
|
|
|
expect($clarifyRequests.get()['session-a']?.requestId).toBe('req-a2')
|
|
})
|
|
|
|
it('clears by request id across sessions when no session hint is given', () => {
|
|
setClarifyRequest(clarify('session-a', 'shared'))
|
|
setClarifyRequest(clarify('session-b', 'other'))
|
|
|
|
clearClarifyRequest('shared')
|
|
|
|
expect($clarifyRequests.get()['session-a']).toBeUndefined()
|
|
expect($clarifyRequests.get()['session-b']?.requestId).toBe('other')
|
|
})
|
|
})
|