refactor: extract shared message parsing helpers into lib/messageExtract

- Move extractText and extractThinking from useGateway and useSecondarySession into shared lib
- Add comprehensive unit tests (13 tests) for both functions
- Eliminate code duplication between the two hooks
This commit is contained in:
Nicolas Varrot
2026-02-23 21:02:45 +00:00
parent ecdff58dca
commit 59a4da1933
4 changed files with 125 additions and 54 deletions

View File

@@ -5,35 +5,9 @@ import { getStoredCredentials, storeCredentials, clearCredentials, type AuthMode
import { getOrCreateDeviceIdentity } from '../lib/deviceIdentity';
import { isSystemEvent } from '../lib/systemEvent';
import { getCachedMessages, setCachedMessages, mergeWithCache } from '../lib/messageCache';
import { extractText, extractThinking, type ChatPayloadMessage } from '../lib/messageExtract';
import type { ChatMessage, MessageBlock, ConnectionStatus, Session, AgentIdentity } from '../types';
interface ChatPayloadMessage {
content?: string | Array<{ type: string; text?: string; thinking?: string }>;
}
function extractText(message: ChatPayloadMessage | undefined): string {
if (!message) return '';
const content = message.content;
if (typeof content === 'string') return content;
if (Array.isArray(content)) {
return content
.filter((b) => b.type === 'text' && typeof b.text === 'string')
.map((b) => b.text as string)
.join('\n');
}
return '';
}
function extractThinking(message: ChatPayloadMessage | undefined): string {
if (!message) return '';
const content = message.content;
if (!Array.isArray(content)) return '';
return content
.filter((b) => b.type === 'thinking')
.map((b) => b.thinking || b.text || '')
.join('\n');
}
export function useGateway() {
const clientRef = useRef<GatewayClient | null>(null);
const [status, setStatus] = useState<ConnectionStatus>('disconnected');

View File

@@ -2,33 +2,8 @@ import { useState, useCallback, useEffect, useRef } from 'react';
import type { GatewayClient, JsonPayload } from '../lib/gateway';
import type { ChatMessage, MessageBlock } from '../types';
import { isSystemEvent } from '../lib/systemEvent';
interface ChatPayloadMessage {
content?: string | Array<{ type: string; text?: string; thinking?: string }>;
}
function extractText(message: ChatPayloadMessage | undefined): string {
if (!message) return '';
const content = message.content;
if (typeof content === 'string') return content;
if (Array.isArray(content)) {
return content
.filter((b) => b.type === 'text' && typeof b.text === 'string')
.map((b) => b.text as string)
.join('\n');
}
return '';
}
function extractThinking(message: ChatPayloadMessage | undefined): string {
if (!message) return '';
const content = message.content;
if (!Array.isArray(content)) return '';
return content
.filter((b) => b.type === 'thinking')
.map((b) => b.thinking || b.text || '')
.join('\n');
}
import { extractText, extractThinking } from '../lib/messageExtract';
import type { ChatPayloadMessage } from '../lib/messageExtract';
/**
* Hook to manage a secondary session for split view.