import { describe, expect, it, vi } from 'vitest'; import type { RuntimeScope } from '@mosaicstack/types'; import { HermesRuntimeProvider, type HermesRuntimeTransport } from './hermes-runtime-provider.js'; const scope: RuntimeScope = { actorId: 'a', tenantId: 't', channelId: 'c', correlationId: 'r' }; const transport = (capabilities = ['session.list', 'session.tree']): HermesRuntimeTransport => ({ capabilities: vi.fn(async () => capabilities), health: vi.fn(async () => ({ status: 'healthy' })), sessions: vi.fn(async () => [ { conversation_id: 'child', agent_id: 'hermes-a', parent_conversation_id: 'parent', status: 'running', created_at: '2026-01-01T00:00:00Z', updated_at: '2026-01-01T00:00:00Z', }, { conversation_id: 'parent', agent_id: 'hermes-a', status: 'unknown', created_at: '2026-01-01T00:00:00Z', updated_at: '2026-01-01T00:00:00Z', }, ]), stream: async function* () {}, send: vi.fn(), attach: vi.fn(), detach: vi.fn(), terminate: vi.fn(), }); describe('HermesRuntimeProvider normalization boundary', () => { it('normalizes legacy sessions without exposing legacy fields', async () => { const provider = new HermesRuntimeProvider(transport()); await expect(provider.listSessions(scope)).resolves.toEqual( expect.arrayContaining([ expect.objectContaining({ id: 'child', runtimeId: 'hermes-a', state: 'active' }), ]), ); const result = await provider.listSessions(scope); expect(result[0]).not.toHaveProperty('conversation_id'); }); it('forms normalized hierarchy and fails closed for unbridged operations', async () => { const provider = new HermesRuntimeProvider(transport()); await expect(provider.getSessionTree(scope)).resolves.toEqual([ expect.objectContaining({ session: expect.objectContaining({ id: 'parent', state: 'failed' }), children: [expect.objectContaining({ session: expect.objectContaining({ id: 'child' }) })], }), ]); await expect( provider.sendMessage('parent', { content: 'x', idempotencyKey: 'i' }, scope), ).rejects.toMatchObject({ code: 'capability_unsupported' }); }); });