batch4.1-5.1: dedup audit, archive 400 fix, sidebar Delete, landing-page enrichment, auto-name tool-call fix
- Fastify global empty-JSON-body parser fixes archive/unarchive/stop 400s - Removed redundant local sessionEvents.emit at all 5+2 sites with server-side WS publishers; added dedupe guards in useSidebar/Workspace/Project handlers - Sidebar session right-click adds Delete (destructive) with confirm Dialog - Session.tsx navigates away on session_deleted/session_archived for the active session - SessionLandingPage chat rows show message_count, effective_context_tokens, last_message_preview via LATERAL joins on GET /api/sessions/:id/chats - Workspace.tsx pane drag-to-reorder using native HTML5 events (no new deps) - CompactCard: Copy toast, Send-to-chat with target chat name, empty-state in share popover, Re-run button - auto_name.ts: filter count gate and assistant-fetch by content <> '' so tool-call assistant rows don't trip the once-and-only-once guard - Adds CLAUDE.md and apps/web/src/lib/format.ts Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,6 +24,22 @@ async function main() {
|
||||
logger: { level: config.LOG_LEVEL },
|
||||
});
|
||||
|
||||
// Allow empty JSON bodies on POSTs that don't take a body (archive, unarchive, stop, etc.).
|
||||
// Default Fastify parser throws FST_ERR_CTP_EMPTY_JSON_BODY on empty string.
|
||||
app.removeContentTypeParser(['application/json']);
|
||||
app.addContentTypeParser('application/json', { parseAs: 'string' }, (_req, body, done) => {
|
||||
const str = (body as string) ?? '';
|
||||
if (str.trim().length === 0) {
|
||||
done(null, {});
|
||||
return;
|
||||
}
|
||||
try {
|
||||
done(null, JSON.parse(str));
|
||||
} catch (err) {
|
||||
done(err as Error, undefined);
|
||||
}
|
||||
});
|
||||
|
||||
const sql = getSql(config);
|
||||
await applySchema(sql);
|
||||
app.log.info('database schema applied');
|
||||
|
||||
@@ -26,11 +26,37 @@ export function registerChatRoutes(
|
||||
reply.code(404);
|
||||
return { error: 'session not found' };
|
||||
}
|
||||
// Enriched list: computed per-chat fields via LATERAL joins.
|
||||
// `effective_context_tokens` = ctx_used (prompt tokens) on the most
|
||||
// recent complete assistant message — represents the current context
|
||||
// window consumption post-compact.
|
||||
const rows = await sql<Chat[]>`
|
||||
SELECT id, session_id, name, status, created_at, updated_at
|
||||
FROM chats
|
||||
WHERE session_id = ${req.params.id}
|
||||
ORDER BY updated_at DESC
|
||||
SELECT
|
||||
c.id, c.session_id, c.name, c.status, c.created_at, c.updated_at,
|
||||
COALESCE(mc.cnt, 0)::int AS message_count,
|
||||
lp.preview AS last_message_preview,
|
||||
ec.tokens AS effective_context_tokens
|
||||
FROM chats c
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT COUNT(*) AS cnt FROM messages WHERE chat_id = c.id
|
||||
) mc ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT LEFT(BTRIM(REGEXP_REPLACE(content, E'[\\n\\r]+', ' ', 'g')), 80) AS preview
|
||||
FROM messages
|
||||
WHERE chat_id = c.id AND kind = 'message' AND content <> ''
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
) lp ON TRUE
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT ctx_used AS tokens
|
||||
FROM messages
|
||||
WHERE chat_id = c.id AND kind = 'message' AND role = 'assistant'
|
||||
AND status = 'complete' AND ctx_used IS NOT NULL
|
||||
ORDER BY created_at DESC
|
||||
LIMIT 1
|
||||
) ec ON TRUE
|
||||
WHERE c.session_id = ${req.params.id}
|
||||
ORDER BY c.updated_at DESC
|
||||
`;
|
||||
return rows;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ export async function maybeAutoNameChat(
|
||||
WHERE chat_id = ${chatId}
|
||||
AND role = 'assistant'
|
||||
AND status = 'complete'
|
||||
AND content <> ''
|
||||
`;
|
||||
if (counts[0]?.n !== 1) return;
|
||||
|
||||
@@ -80,6 +81,7 @@ export async function maybeAutoNameChat(
|
||||
WHERE chat_id = ${chatId}
|
||||
AND role = 'assistant'
|
||||
AND status = 'complete'
|
||||
AND content <> ''
|
||||
ORDER BY created_at ASC
|
||||
LIMIT 1
|
||||
`;
|
||||
|
||||
@@ -33,6 +33,10 @@ export interface Chat {
|
||||
status: ChatStatus;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
// Populated by GET /api/sessions/:id/chats only.
|
||||
message_count?: number;
|
||||
last_message_preview?: string | null;
|
||||
effective_context_tokens?: number | null;
|
||||
}
|
||||
|
||||
// KEEP IN SYNC: apps/server/src/schema.sql messages_role_chk / messages_status_chk
|
||||
|
||||
Reference in New Issue
Block a user