backup current stable ejclaw state
This commit is contained in:
@@ -332,6 +332,38 @@ export function getRecentChatMessagesFromDatabase(
|
||||
return rows.map(normalizeMessageRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the seq of the earliest unanswered human message in this chat —
|
||||
* i.e. the first user message that came after the most recent bot reply.
|
||||
* Returns null if no such message exists (the user is "caught up").
|
||||
*
|
||||
* Used by restart-recovery to rewind the agent cursor before re-running an
|
||||
* interrupted turn from the message that initiated it.
|
||||
*/
|
||||
export function getEarliestUnansweredHumanSeqFromDatabase(
|
||||
database: Database,
|
||||
chatJid: string,
|
||||
): number | null {
|
||||
const lastBot = database
|
||||
.prepare(
|
||||
`SELECT MAX(seq) AS seq FROM messages
|
||||
WHERE chat_jid = ? AND is_bot_message = 1`,
|
||||
)
|
||||
.get(chatJid) as { seq: number | null } | undefined;
|
||||
const lastBotSeq = lastBot?.seq ?? 0;
|
||||
const row = database
|
||||
.prepare(
|
||||
`SELECT MIN(seq) AS seq FROM messages
|
||||
WHERE chat_jid = ?
|
||||
AND seq > ?
|
||||
AND is_bot_message = 0
|
||||
AND is_from_me = 0
|
||||
AND content != '' AND content IS NOT NULL`,
|
||||
)
|
||||
.get(chatJid, lastBotSeq) as { seq: number | null } | undefined;
|
||||
return row?.seq ?? null;
|
||||
}
|
||||
|
||||
export function getLastHumanMessageTimestampFromDatabase(
|
||||
database: Database,
|
||||
chatJid: string,
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { Database } from 'bun:sqlite';
|
||||
|
||||
import { logger } from '../logger.js';
|
||||
import { parseVisibleVerdict } from '../paired-verdict.js';
|
||||
import {
|
||||
parseReviewerVisibleVerdict,
|
||||
parseVisibleVerdict,
|
||||
} from '../paired-verdict.js';
|
||||
import { PairedRoomRole, PairedTurnOutput } from '../types.js';
|
||||
|
||||
const MAX_TURN_OUTPUT_CHARS = 50_000;
|
||||
@@ -38,7 +41,9 @@ export function insertPairedTurnOutputInDatabase(
|
||||
turnNumber,
|
||||
role,
|
||||
outputText.slice(0, MAX_TURN_OUTPUT_CHARS),
|
||||
parseVisibleVerdict(outputText),
|
||||
role === 'reviewer'
|
||||
? parseReviewerVisibleVerdict(outputText)
|
||||
: parseVisibleVerdict(outputText),
|
||||
createdAt ?? new Date().toISOString(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import {
|
||||
import {
|
||||
type ChatInfo,
|
||||
getAllChatsFromDatabase,
|
||||
getEarliestUnansweredHumanSeqFromDatabase,
|
||||
getLastHumanMessageContentFromDatabase,
|
||||
getLastHumanMessageSenderFromDatabase,
|
||||
getLastHumanMessageTimestampFromDatabase,
|
||||
@@ -36,6 +37,7 @@ import {
|
||||
createProducedWorkItemInDatabase,
|
||||
getOpenWorkItemForChatFromDatabase,
|
||||
getOpenWorkItemFromDatabase,
|
||||
getRecentDeliveredOwnerWorkItemsForChatFromDatabase,
|
||||
markWorkItemDeliveredInDatabase,
|
||||
markWorkItemDeliveryRetryInDatabase,
|
||||
} from './work-items.js';
|
||||
@@ -223,6 +225,10 @@ export function getLastHumanMessageTimestamp(chatJid: string): string | null {
|
||||
return getLastHumanMessageTimestampFromDatabase(requireDatabase(), chatJid);
|
||||
}
|
||||
|
||||
export function getEarliestUnansweredHumanSeq(chatJid: string): number | null {
|
||||
return getEarliestUnansweredHumanSeqFromDatabase(requireDatabase(), chatJid);
|
||||
}
|
||||
|
||||
export function getLastHumanMessageSender(chatJid: string): string | null {
|
||||
return getLastHumanMessageSenderFromDatabase(requireDatabase(), chatJid);
|
||||
}
|
||||
@@ -266,6 +272,17 @@ export function getOpenWorkItemForChat(
|
||||
);
|
||||
}
|
||||
|
||||
export function getRecentDeliveredOwnerWorkItemsForChat(
|
||||
chatJid: string,
|
||||
limit: number,
|
||||
): WorkItem[] {
|
||||
return getRecentDeliveredOwnerWorkItemsForChatFromDatabase(
|
||||
requireDatabase(),
|
||||
chatJid,
|
||||
limit,
|
||||
);
|
||||
}
|
||||
|
||||
export function createProducedWorkItem(
|
||||
input: CreateProducedWorkItemInput,
|
||||
): WorkItem {
|
||||
|
||||
@@ -199,6 +199,34 @@ export function getOpenWorkItemFromDatabase(
|
||||
return row ? hydrateWorkItemRow(row) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Recent delivered owner-side work items for a chat, newest last.
|
||||
* Used by single-mode prompt building to surface the bot's own prior
|
||||
* answers (which only live in work_items.result_payload) so a new turn
|
||||
* can reference what it previously said.
|
||||
*/
|
||||
export function getRecentDeliveredOwnerWorkItemsForChatFromDatabase(
|
||||
database: Database,
|
||||
chatJid: string,
|
||||
limit: number,
|
||||
): WorkItem[] {
|
||||
if (limit <= 0) {
|
||||
return [];
|
||||
}
|
||||
const rows = database
|
||||
.prepare(
|
||||
`SELECT *
|
||||
FROM work_items
|
||||
WHERE chat_jid = ?
|
||||
AND status = 'delivered'
|
||||
AND (delivery_role = 'owner' OR delivery_role IS NULL)
|
||||
ORDER BY id DESC
|
||||
LIMIT ?`,
|
||||
)
|
||||
.all(chatJid, limit) as StoredWorkItemRow[];
|
||||
return rows.map(hydrateWorkItemRow).reverse();
|
||||
}
|
||||
|
||||
export function getOpenWorkItemForChatFromDatabase(
|
||||
database: Database,
|
||||
chatJid: string,
|
||||
|
||||
Reference in New Issue
Block a user