- Bots get continue_in_new_session: the bot writes a title and summary, the session closes for good (read-only) and the new one opens with the summary as a "Carried over from the last session" message that links back to the old session. - Continue in new session (conversation menu, sessions modal) and the automatic rollover at the session length do the same; New session now starts a fresh, unlinked session. - Session length is an app setting in Settings > General. - ?session_id= opens a session; a carried-over one shows a bar linking to where the conversation went on instead of the composer. - The thread can open the previous session above the current one (shown only, never in the prompt), and replies get search_past_sessions and read_past_session. - Sessions are named from their opening messages, not their latest, and a carried summary is labelled as the earlier session's. Co-Authored-By: Claude Opus 5.5 <[email protected]>
111 lines
3.0 KiB
TypeScript
111 lines
3.0 KiB
TypeScript
import type {
|
|
BUN_SQLITE_COBBLE_BOT_MESSAGES,
|
|
BunSQLiteTables,
|
|
} from "@/db/types/db";
|
|
import BunSQLite from "@moduletrace/bun-sqlite";
|
|
import type { HarnessToolUse } from "@/src/harness/types";
|
|
|
|
type Params = {
|
|
bot_id: number;
|
|
/**
|
|
* The session it goes in, and that session's workspace.
|
|
*/
|
|
session_id: number;
|
|
workspace_id?: number | null;
|
|
text: string;
|
|
needs_you?: boolean;
|
|
/**
|
|
* Sent mid-reply (`send_message`): the reply is still being worked on.
|
|
*/
|
|
interim?: boolean;
|
|
/**
|
|
* Files the bot saved and sent with it (`media` ids): a PDF it made, a
|
|
* generated image, a document it wrote.
|
|
*/
|
|
media_ids?: number[];
|
|
/**
|
|
* Every tool call the run behind it made, told to the bot with this
|
|
* message in later turns (`botMessagesToHarness`).
|
|
*/
|
|
tool_log?: HarnessToolUse[];
|
|
/**
|
|
* Opens a session the conversation moved into
|
|
* (`carryOverBotSession`): the session it carries on from.
|
|
*/
|
|
carried_from_session_id?: number;
|
|
};
|
|
|
|
/**
|
|
* Appends a bot message to a session, marks the session unread and bumps
|
|
* its activity. Callers must check the bot and session first.
|
|
*/
|
|
export default async function insertBotMessage({
|
|
bot_id,
|
|
session_id,
|
|
workspace_id,
|
|
text,
|
|
needs_you,
|
|
interim,
|
|
media_ids = [],
|
|
tool_log,
|
|
carried_from_session_id,
|
|
}: Params): Promise<BUN_SQLITE_COBBLE_BOT_MESSAGES> {
|
|
const now = Date.now();
|
|
const needs_you_flag = needs_you ? 1 : 0;
|
|
const interim_flag = interim ? 1 : 0;
|
|
const tool_log_json = tool_log ? JSON.stringify(tool_log) : undefined;
|
|
|
|
const res = await BunSQLite.insert<
|
|
BUN_SQLITE_COBBLE_BOT_MESSAGES,
|
|
(typeof BunSQLiteTables)[number]
|
|
>({
|
|
table: "bot_messages",
|
|
data: [
|
|
{
|
|
bot_id,
|
|
session_id,
|
|
workspace_id: workspace_id || undefined,
|
|
author: "bot",
|
|
text,
|
|
needs_you: needs_you_flag,
|
|
interim: interim_flag,
|
|
tool_log: tool_log_json,
|
|
carried_from_session_id,
|
|
},
|
|
],
|
|
});
|
|
|
|
const id = res.postInsertReturn?.insertId;
|
|
|
|
if (!res.success || !id) {
|
|
throw new Error(`Failed to save message: ${res.msg}`);
|
|
}
|
|
|
|
for (const media_id of media_ids) {
|
|
await BunSQLite.sql({
|
|
sql: `INSERT INTO bot_message_media (created_at, updated_at, message_id, media_id) VALUES (?, ?, ?, ?)`,
|
|
values: [now, now, id, media_id],
|
|
}).catch(() => {});
|
|
}
|
|
|
|
await BunSQLite.sql({
|
|
sql: `UPDATE bot_sessions SET last_activity_at = ?, unread = 1 WHERE id = ?`,
|
|
values: [now, session_id],
|
|
});
|
|
|
|
return {
|
|
id,
|
|
bot_id,
|
|
session_id,
|
|
workspace_id: workspace_id || undefined,
|
|
author: "bot",
|
|
text,
|
|
needs_you: needs_you_flag,
|
|
interim: interim_flag,
|
|
tool_log: tool_log_json,
|
|
carried_from_session_id,
|
|
created_at: now,
|
|
updated_at: now,
|
|
};
|
|
}
|