feat(web): workspace components — ComparePane, Memory page, McpDialog, error boundaries, message-parts
- Add ComparePane.tsx: side-by-side AI response comparison - Add Memory.tsx: memory management page with CRUD UI - Add McpPermissionDialog.tsx: MCP tool permission approval dialog - Add McpResponseDisplay.tsx: MCP response visualization - Add MessageBoundary.tsx + MessageListErrorBoundary.tsx: error resilience - Add EmptyState.tsx: contextual empty state component - Add KeyboardShortcutsDialog.tsx: keyboard shortcut reference - Add message-parts/: ActionRow, CompactCard, MistakeRecoverySentinel, ReasoningBlock, SendToTerminalMenu, StatsLine, SummaryCard - Add useDraftPersistence.ts: draft message persistence hook - Add useTerminals.ts: terminal session management hook - Add keyboard-shortcuts.ts + tool-utils.ts: shared utilities - Extend components: ChatInput, MessageBubble, MessageList, Workspace, panes - Extend hooks: useTerminalSocket, useSessionStream test suite - Update pages: Home, Project — workspace layout and session flow
This commit is contained in:
@@ -275,7 +275,7 @@ export const api = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body ?? {}),
|
||||
}),
|
||||
update: (chatId: string, body: { name: string }) =>
|
||||
update: (chatId: string, body: { name?: string; model?: string }) =>
|
||||
request<Chat>(`/api/chats/${chatId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(body),
|
||||
@@ -331,6 +331,17 @@ export const api = {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ skill_name: skillName, user_message: userMessage }),
|
||||
}),
|
||||
// v2.8-compare: send the same message to N models and stream back
|
||||
// parallel responses. Returns compare_group_id + per-model message ids.
|
||||
compare: (chatId: string, message: string, models: string[]) =>
|
||||
request<{
|
||||
compare_group_id: string;
|
||||
user_message_id: string;
|
||||
responses: Array<{ model: string; assistant_message_id: string }>;
|
||||
}>(`/api/chats/${chatId}/compare`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ message, models }),
|
||||
}),
|
||||
// v1.13.17-cross-repo-reads: resume a paused request_read_access. On
|
||||
// 'allow' the server re-resolves the grant root and appends it to
|
||||
// sessions.allowed_read_paths; the returned list reflects the post-
|
||||
@@ -348,6 +359,14 @@ export const api = {
|
||||
request<ToolTraceResponse>(
|
||||
`/api/chats/${chatId}/traces?limit=${limit}&offset=${offset}`,
|
||||
),
|
||||
exportChat: (chatId: string, format: 'json' | 'markdown') =>
|
||||
request<string>(`/api/chats/${chatId}/export?format=${format}`),
|
||||
// MCP permission: approve/deny a tool call from an 'ask' state server.
|
||||
mcpApprove: (chatId: string, toolCallId: string, permission: 'allow_once' | 'allow_always' | 'deny') =>
|
||||
request<{ ok: true }>(`/api/chats/${chatId}/mcp-approve`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ tool_call_id: toolCallId, permission }),
|
||||
}),
|
||||
},
|
||||
|
||||
messages: {
|
||||
@@ -388,6 +407,11 @@ export const api = {
|
||||
request<{ html_content: string; char_count: number; title: string }>(
|
||||
`/api/chats/${chatId}/messages/${messageId}/html_artifact`,
|
||||
),
|
||||
feedback: (chatId: string, messageId: string, value: 'up' | 'down') =>
|
||||
request<{ ok: boolean }>(
|
||||
`/api/chats/${chatId}/messages/${messageId}/feedback`,
|
||||
{ method: 'POST', body: JSON.stringify({ value }) },
|
||||
),
|
||||
},
|
||||
|
||||
models: () => request<ModelInfo[]>('/api/models'),
|
||||
@@ -654,17 +678,27 @@ export const api = {
|
||||
// cols/rows are optional. When passed, booterm sizes the per-pane tmux
|
||||
// session at creation time so the inner bash (and any TUI it spawns) is
|
||||
// born with the correct PTY dimensions instead of tmux's 80x24 default.
|
||||
start: (sessionId: string, paneId: string, cols?: number, rows?: number) =>
|
||||
request<{ tmux_session: string }>(
|
||||
start: (
|
||||
sessionId: string,
|
||||
paneId: string,
|
||||
cols?: number,
|
||||
rows?: number,
|
||||
description?: string,
|
||||
parentAgent?: string,
|
||||
) => {
|
||||
const body: Record<string, unknown> = {};
|
||||
if (cols !== undefined) body.cols = cols;
|
||||
if (rows !== undefined) body.rows = rows;
|
||||
if (description !== undefined) body.description = description;
|
||||
if (parentAgent !== undefined) body.parentAgent = parentAgent;
|
||||
return request<{ tmux_session: string }>(
|
||||
`/api/term/sessions/${sessionId}/panes/${paneId}/start`,
|
||||
{
|
||||
method: 'POST',
|
||||
body:
|
||||
cols !== undefined && rows !== undefined
|
||||
? JSON.stringify({ cols, rows })
|
||||
: undefined,
|
||||
body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined,
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
kill: (sessionId: string, paneId: string) =>
|
||||
request<{ ok: true }>(
|
||||
`/api/term/sessions/${sessionId}/panes/${paneId}/kill`,
|
||||
|
||||
Reference in New Issue
Block a user