mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
fix(desktop): tolerate unparsed display_metadata from an older backend
The desktop and the Hermes backend it talks to version independently — a remote VM running an older build still serves display_metadata as JSON text. Indexing into that string with `in` threw and failed the whole resume, so narrow the type to admit a string and parse it before reading task_count. Falling back to the generic label keeps a delegation event renderable even when the metadata is unusable. Co-authored-by: xxxigm <xxxigm@users.noreply.github.com> Co-authored-by: Studio729 <Studio729@users.noreply.github.com>
This commit is contained in:
parent
19dc35cf57
commit
0c40f00ad1
3 changed files with 54 additions and 5 deletions
|
|
@ -1,5 +1,7 @@
|
|||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { SessionMessage } from '@/types/hermes'
|
||||
|
||||
import type { ChatMessage, ChatMessagePart } from './chat-messages'
|
||||
import {
|
||||
appendAssistantTextPart,
|
||||
|
|
@ -191,6 +193,30 @@ describe('toChatMessages', () => {
|
|||
'background agent work finished'
|
||||
])
|
||||
})
|
||||
|
||||
// A backend older than this app serves display_metadata as unparsed JSON
|
||||
// text. Indexing into that string used to throw and fail the whole resume.
|
||||
it.each([
|
||||
['an object', { delegation_id: 'deleg_1', task_count: 2 }, '2 background agents finished'],
|
||||
['JSON text', JSON.stringify({ delegation_id: 'deleg_1', task_count: 1 }), '1 background agent finished'],
|
||||
['unparseable text', '{not-json', 'background agent work finished'],
|
||||
['text that is not an object', '"deleg_1"', 'background agent work finished'],
|
||||
['a missing task count', { delegation_id: 'deleg_1' }, 'background agent work finished']
|
||||
])('labels a delegation event given %s', (_case, displayMetadata, expected) => {
|
||||
const read = () =>
|
||||
toChatMessages([
|
||||
{
|
||||
role: 'user',
|
||||
content: 'opaque delegation context payload',
|
||||
display_kind: 'async_delegation_complete',
|
||||
display_metadata: displayMetadata as SessionMessage['display_metadata'],
|
||||
timestamp: 1
|
||||
}
|
||||
])
|
||||
|
||||
expect(read).not.toThrow()
|
||||
expect(chatMessageText(read()[0])).toBe(expected)
|
||||
})
|
||||
})
|
||||
|
||||
describe('renderMediaTags', () => {
|
||||
|
|
|
|||
|
|
@ -311,16 +311,35 @@ function transcriptContent(displayKind: SessionMessage['display_kind'], content:
|
|||
return displayKind === 'hidden' ? null : content
|
||||
}
|
||||
|
||||
// A remote backend older than this app serves display_metadata as raw JSON text,
|
||||
// and `in` throws on a primitive — which used to fail the whole session resume.
|
||||
function timelineTaskCount(metadata: SessionMessage['display_metadata']): number | undefined {
|
||||
let parsed: unknown = metadata
|
||||
|
||||
if (typeof parsed === 'string') {
|
||||
try {
|
||||
parsed = JSON.parse(parsed)
|
||||
} catch {
|
||||
return undefined
|
||||
}
|
||||
}
|
||||
|
||||
if (!parsed || typeof parsed !== 'object') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
const count = (parsed as { task_count?: unknown }).task_count
|
||||
|
||||
return typeof count === 'number' ? count : undefined
|
||||
}
|
||||
|
||||
function timelineDisplayContent(message: SessionMessage, content: string): string {
|
||||
if (message.display_kind === 'model_switch') {
|
||||
return 'model changed'
|
||||
}
|
||||
|
||||
if (message.display_kind === 'async_delegation_complete') {
|
||||
const count =
|
||||
message.display_metadata && 'task_count' in message.display_metadata
|
||||
? message.display_metadata.task_count
|
||||
: undefined
|
||||
const count = timelineTaskCount(message.display_metadata)
|
||||
|
||||
return count === undefined
|
||||
? 'background agent work finished'
|
||||
|
|
|
|||
|
|
@ -494,7 +494,11 @@ export interface SessionMessage {
|
|||
reasoning_content?: null | string
|
||||
reasoning_details?: unknown
|
||||
display_kind?: 'async_delegation_complete' | 'hidden' | 'model_switch' | string
|
||||
display_metadata?: TimelineDisplayMetadata
|
||||
/**
|
||||
* A backend older than this app can still serve this as unparsed JSON text,
|
||||
* so readers must narrow before indexing into it.
|
||||
*/
|
||||
display_metadata?: string | TimelineDisplayMetadata
|
||||
role: 'assistant' | 'system' | 'tool' | 'user'
|
||||
text?: unknown
|
||||
timestamp?: number
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue