batch4: chats-in-sessions, force-send, /compact, right-rail file browser
Session 1:N Chat data model with backfill. Workspace switches to client-side multi-tab pane management. Right-rail file browser with float-over viewer and click-drag line selection replaces FileBrowserPane. Adds /compact streaming summarizer (respects compact markers in context builder), force-send (cancels in-flight, persists partial as 'cancelled', awaits cancellation completion via deferred Promise + 5s timeout), message queue, stop generation, chat auto-rename, session archive/unarchive with Closed Sessions section on repo landing page. CHECK constraints on sessions.status, messages.role, messages.status with KEEP IN SYNC comments tying to MESSAGE_ROLES / MESSAGE_STATUSES const arrays. Deletes dead pane routes/hook and the api.panes.* client block. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,11 +21,11 @@ CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id, updated_
|
||||
CREATE TABLE IF NOT EXISTS messages (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
||||
role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'tool')),
|
||||
role TEXT NOT NULL,
|
||||
content TEXT NOT NULL DEFAULT '',
|
||||
tool_calls JSONB,
|
||||
tool_results JSONB,
|
||||
status TEXT NOT NULL DEFAULT 'complete' CHECK (status IN ('streaming', 'complete', 'failed')),
|
||||
status TEXT NOT NULL DEFAULT 'complete',
|
||||
last_seq INT NOT NULL DEFAULT 0,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
@@ -47,6 +47,8 @@ CREATE TABLE IF NOT EXISTS settings (
|
||||
|
||||
INSERT INTO settings (key, value) VALUES ('default_model', '"qwen3.6-35b-a3b-mxfp4"') ON CONFLICT (key) DO NOTHING;
|
||||
|
||||
-- DEPRECATED: client-side pane state as of v1.2-batch4. Table retained per
|
||||
-- additive schema rule; no writes. Drop in a future destructive migration.
|
||||
CREATE TABLE IF NOT EXISTS session_panes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
||||
@@ -66,3 +68,67 @@ FROM sessions s
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM session_panes p WHERE p.session_id = s.id
|
||||
);
|
||||
|
||||
-- v1.2: sessions.status (open | archived)
|
||||
ALTER TABLE sessions ADD COLUMN IF NOT EXISTS status TEXT NOT NULL DEFAULT 'open';
|
||||
|
||||
-- v1.2: chats table
|
||||
CREATE TABLE IF NOT EXISTS chats (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
session_id UUID NOT NULL REFERENCES sessions(id) ON DELETE CASCADE,
|
||||
name TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'open' CHECK (status IN ('open', 'closed')),
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp(),
|
||||
updated_at TIMESTAMPTZ NOT NULL DEFAULT clock_timestamp()
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_chats_session_status ON chats (session_id, status, updated_at DESC);
|
||||
|
||||
-- v1.2: messages.chat_id + messages.kind
|
||||
ALTER TABLE messages ADD COLUMN IF NOT EXISTS chat_id UUID REFERENCES chats(id) ON DELETE CASCADE;
|
||||
ALTER TABLE messages ADD COLUMN IF NOT EXISTS kind TEXT NOT NULL DEFAULT 'message';
|
||||
CREATE INDEX IF NOT EXISTS idx_messages_chat ON messages (chat_id, created_at);
|
||||
|
||||
-- Backfill: one chat per existing session that has none yet
|
||||
INSERT INTO chats (session_id, name, status, created_at, updated_at)
|
||||
SELECT s.id, s.name, 'open', s.created_at, s.updated_at
|
||||
FROM sessions s
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1 FROM chats c WHERE c.session_id = s.id
|
||||
);
|
||||
|
||||
-- Backfill: link orphaned messages to their session's first chat
|
||||
UPDATE messages SET chat_id = (
|
||||
SELECT c.id FROM chats c WHERE c.session_id = messages.session_id ORDER BY c.created_at ASC LIMIT 1
|
||||
)
|
||||
WHERE chat_id IS NULL;
|
||||
|
||||
-- Enforce NOT NULL on chat_id once all rows are backfilled
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1 FROM information_schema.columns
|
||||
WHERE table_name = 'messages' AND column_name = 'chat_id' AND is_nullable = 'YES'
|
||||
) AND NOT EXISTS (
|
||||
SELECT 1 FROM messages WHERE chat_id IS NULL
|
||||
) THEN
|
||||
ALTER TABLE messages ALTER COLUMN chat_id SET NOT NULL;
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- v1.2.1: CHECK constraints for sessions.status and messages (role, status)
|
||||
-- KEEP IN SYNC: apps/server/src/types/api.ts (MESSAGE_ROLES, MESSAGE_STATUSES, SessionStatus)
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'sessions_status_chk') THEN
|
||||
ALTER TABLE sessions ADD CONSTRAINT sessions_status_chk
|
||||
CHECK (status IN ('open', 'archived'));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'messages_role_chk') THEN
|
||||
ALTER TABLE messages ADD CONSTRAINT messages_role_chk
|
||||
CHECK (role IN ('user', 'assistant', 'system', 'tool'));
|
||||
END IF;
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'messages_status_chk') THEN
|
||||
ALTER TABLE messages ADD CONSTRAINT messages_status_chk
|
||||
CHECK (status IN ('streaming', 'complete', 'failed', 'cancelled'));
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
Reference in New Issue
Block a user