mirror of
https://github.com/siteboon/claudecodeui.git
synced 2026-04-12 16:41:29 +00:00
feat: unified message architecture with provider adapters and session store (#558)
- Add provider adapter layer (server/providers/) with registry pattern
- Claude, Cursor, Codex, Gemini adapters normalize native formats to NormalizedMessage
- Shared types.js defines ProviderAdapter interface and message kinds
- Registry enables polymorphic provider lookup
- Add unified REST endpoint: GET /api/sessions/:id/messages?provider=...
- Replaces four provider-specific message endpoints with one
- Delegates to provider adapters via registry
- Add frontend session-keyed store (useSessionStore)
- Per-session Map with serverMessages/realtimeMessages/merged
- Dedup by ID, stale threshold for re-fetch, background session accumulation
- No localStorage for messages — backend JSONL is source of truth
- Add normalizedToChatMessages converter (useChatMessages)
- Converts NormalizedMessage[] to existing ChatMessage[] UI format
- Wire unified store into ChatInterface, useChatSessionState, useChatRealtimeHandlers
- Session switch uses store cache for instant render
- Background WebSocket messages routed to correct session slot
This commit is contained in:
@@ -54,25 +54,18 @@ export const api = {
|
||||
projects: () => authenticatedFetch('/api/projects'),
|
||||
sessions: (projectName, limit = 5, offset = 0) =>
|
||||
authenticatedFetch(`/api/projects/${projectName}/sessions?limit=${limit}&offset=${offset}`),
|
||||
sessionMessages: (projectName, sessionId, limit = null, offset = 0, provider = 'claude') => {
|
||||
// Unified endpoint — all providers through one URL
|
||||
unifiedSessionMessages: (sessionId, provider = 'claude', { projectName = '', projectPath = '', limit = null, offset = 0 } = {}) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append('provider', provider);
|
||||
if (projectName) params.append('projectName', projectName);
|
||||
if (projectPath) params.append('projectPath', projectPath);
|
||||
if (limit !== null) {
|
||||
params.append('limit', limit);
|
||||
params.append('offset', offset);
|
||||
params.append('limit', String(limit));
|
||||
params.append('offset', String(offset));
|
||||
}
|
||||
const queryString = params.toString();
|
||||
|
||||
let url;
|
||||
if (provider === 'codex') {
|
||||
url = `/api/codex/sessions/${sessionId}/messages${queryString ? `?${queryString}` : ''}`;
|
||||
} else if (provider === 'cursor') {
|
||||
url = `/api/cursor/sessions/${sessionId}/messages${queryString ? `?${queryString}` : ''}`;
|
||||
} else if (provider === 'gemini') {
|
||||
url = `/api/gemini/sessions/${sessionId}/messages${queryString ? `?${queryString}` : ''}`;
|
||||
} else {
|
||||
url = `/api/projects/${projectName}/sessions/${sessionId}/messages${queryString ? `?${queryString}` : ''}`;
|
||||
}
|
||||
return authenticatedFetch(url);
|
||||
return authenticatedFetch(`/api/sessions/${encodeURIComponent(sessionId)}/messages${queryString ? `?${queryString}` : ''}`);
|
||||
},
|
||||
renameProject: (projectName, displayName) =>
|
||||
authenticatedFetch(`/api/projects/${projectName}/rename`, {
|
||||
|
||||
Reference in New Issue
Block a user