backup current stable ejclaw state

This commit is contained in:
Codex
2026-05-27 10:53:05 +09:00
parent 646bc34372
commit 1509108e04
57 changed files with 7127 additions and 154 deletions

View File

@@ -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,

View File

@@ -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(),
);
}

View File

@@ -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 {

View File

@@ -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,