Name sessions with the model and keep the rail list live
Sessions no longer take their title from the first message: once the first exchange is sent, the text model writes the title and summary, which the rail and sessions list show. The summary records how many messages it covers so a stale one is rewritten before it is carried into the next session. The sessions hook now reloads on live message and session events, so a session started by the first message, a rollover or another tab appears without a reload. New sessions are pushed as server:bot-session, both from the process that changed them and through the live relay.
This commit is contained in:
@@ -3,6 +3,7 @@ import { AppData } from "@/src/data/app-data";
|
||||
import { logError } from "@/src/functions/backend/logger";
|
||||
import grabConnectedUserIds from "@/src/websocket/(functions)/grab-connected-user-ids";
|
||||
import relayChangedBots from "./relay-changed-bots";
|
||||
import relayChangedSessions from "./relay-changed-sessions";
|
||||
import relayCreatedBots from "./relay-created-bots";
|
||||
import relayCreatedWorkspaces from "./relay-created-workspaces";
|
||||
import relayNewBotMessages from "./relay-new-bot-messages";
|
||||
@@ -32,6 +33,7 @@ export default async function liveRelay() {
|
||||
message_id: await latest("bot_messages"),
|
||||
update_id: await latest("bots_queue_updates"),
|
||||
bots_at: Date.now(),
|
||||
sessions_at: Date.now(),
|
||||
};
|
||||
|
||||
let running = false;
|
||||
@@ -58,6 +60,12 @@ export default async function liveRelay() {
|
||||
await relayCreatedWorkspaces({ since: bots_since, users });
|
||||
await relayChangedBots({ since: bots_since, users });
|
||||
cursor.bots_at = now;
|
||||
|
||||
await relayChangedSessions({
|
||||
since: cursor.sessions_at - AppData.LiveRelayPollMs,
|
||||
users,
|
||||
});
|
||||
cursor.sessions_at = now;
|
||||
} catch (error) {
|
||||
await logError({ title: `Live relay failed`, error }).catch(() => {});
|
||||
} finally {
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import BunSQLite from "@moduletrace/bun-sqlite";
|
||||
import type { BUN_SQLITE_COBBLE_BOT_SESSIONS } from "@/db/types/db";
|
||||
import type { BotSessionChangedData } from "@/src/types";
|
||||
import { sendToUser } from "@/src/websocket/(functions)/send-to-user";
|
||||
|
||||
type Params = {
|
||||
/**
|
||||
* Unix ms: sessions updated since then are pushed.
|
||||
*/
|
||||
since: number;
|
||||
users: Set<string>;
|
||||
};
|
||||
|
||||
/**
|
||||
* Pushes `server:bot-session` for every session created or changed since
|
||||
* `since` (named, reopened, marked read) to the connected user whose
|
||||
* conversation it's in. Pushes are idempotent, so overlapping windows only
|
||||
* repeat them.
|
||||
*/
|
||||
export default async function relayChangedSessions({ since, users }: Params) {
|
||||
if (!users.size) return;
|
||||
|
||||
const sessions =
|
||||
(
|
||||
await BunSQLite.sql<BUN_SQLITE_COBBLE_BOT_SESSIONS>({
|
||||
sql: `SELECT id, user_id, bot_id, workspace_id FROM bot_sessions WHERE updated_at > ?`,
|
||||
values: [since],
|
||||
})
|
||||
).payload || [];
|
||||
|
||||
for (const session of sessions) {
|
||||
if (!session.id || !session.user_id || !users.has(String(session.user_id))) continue;
|
||||
|
||||
const data: BotSessionChangedData = {
|
||||
session_id: Number(session.id),
|
||||
bot_id: Number(session.bot_id) || 0,
|
||||
workspace_id: session.workspace_id ? Number(session.workspace_id) : null,
|
||||
};
|
||||
|
||||
sendToUser({
|
||||
user_id: session.user_id,
|
||||
data: { event: "server:bot-session", data },
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
/**
|
||||
* How far the relay has read: the newest message and job step it pushed,
|
||||
* and when it last looked for changed bots.
|
||||
* and when it last looked for changed bots and sessions.
|
||||
*/
|
||||
export type LiveRelayCursor = {
|
||||
message_id: number;
|
||||
update_id: number;
|
||||
bots_at: number;
|
||||
sessions_at: number;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user