Add page data delivery and publication guards
This commit is contained in:
+77
-19
@@ -11,6 +11,7 @@ import {
|
||||
persistSessionTranscriptMessages,
|
||||
} from './conversation-transcript-persist.mjs';
|
||||
import { ensureGooseUserMessageMetadata } from './goose-message.mjs';
|
||||
import { tryRecoverRunFromSessionDeliverables } from './agent-run-deliverable-check.mjs';
|
||||
|
||||
const DEFAULT_RUN_RETRY_DELAYS_MS = [1500, 5000, 15000];
|
||||
const TERMINAL_STATUSES = new Set(['succeeded', 'failed']);
|
||||
@@ -242,6 +243,7 @@ export function createAgentRunGateway({
|
||||
chatIntentRouter = null,
|
||||
sessionSnapshotService = null,
|
||||
conversationMemoryService = null,
|
||||
syncUserPagesOnSuccess = null,
|
||||
retryDelaysMs = DEFAULT_RUN_RETRY_DELAYS_MS,
|
||||
autoDispatch = envFlag(process.env.MEMIND_AGENT_RUN_AUTODISPATCH, true),
|
||||
maxConcurrentRuns = positiveInteger(
|
||||
@@ -389,6 +391,22 @@ export function createAgentRunGateway({
|
||||
return projectRun(await getRunById(runId));
|
||||
}
|
||||
|
||||
async function recoverRunFromDeliverables({ runId, userId, sessionId, err }) {
|
||||
const recovered = await tryRecoverRunFromSessionDeliverables({
|
||||
pool,
|
||||
userId,
|
||||
sessionId,
|
||||
error: err,
|
||||
});
|
||||
if (!recovered) return false;
|
||||
await appendEvent(runId, 'run_recovered_from_deliverables', {
|
||||
sessionId,
|
||||
deliverables: recovered.deliverables,
|
||||
originalError: recovered.originalError,
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
async function markRun(runId, status, fields = {}) {
|
||||
const updates = ['status = ?', 'updated_at = ?'];
|
||||
const values = [status, nowMs()];
|
||||
@@ -675,21 +693,33 @@ export function createAgentRunGateway({
|
||||
&& runOptions.toolMode === 'chat'
|
||||
&& typeof tkmindProxy.submitSessionReplyAndAwaitFinishForUser === 'function';
|
||||
if (awaitSessionFinish) {
|
||||
const finish = await tkmindProxy.submitSessionReplyAndAwaitFinishForUser(
|
||||
row.user_id,
|
||||
sessionId,
|
||||
row.request_id,
|
||||
ensureGooseUserMessageMetadata(userMessage),
|
||||
{
|
||||
toolMode: runOptions.toolMode,
|
||||
forceDeepReasoning: runOptions.forceDeepReasoning,
|
||||
timeoutMs: runTimeoutMs,
|
||||
},
|
||||
);
|
||||
await appendEvent(runId, 'session_finished', {
|
||||
sessionId,
|
||||
tokenState: finish.tokenState ?? null,
|
||||
});
|
||||
try {
|
||||
const finish = await tkmindProxy.submitSessionReplyAndAwaitFinishForUser(
|
||||
row.user_id,
|
||||
sessionId,
|
||||
row.request_id,
|
||||
ensureGooseUserMessageMetadata(userMessage),
|
||||
{
|
||||
toolMode: runOptions.toolMode,
|
||||
forceDeepReasoning: runOptions.forceDeepReasoning,
|
||||
timeoutMs: runTimeoutMs,
|
||||
},
|
||||
);
|
||||
await appendEvent(runId, 'session_finished', {
|
||||
sessionId,
|
||||
tokenState: finish.tokenState ?? null,
|
||||
});
|
||||
} catch (err) {
|
||||
if (await recoverRunFromDeliverables({
|
||||
runId,
|
||||
userId: row.user_id,
|
||||
sessionId,
|
||||
err,
|
||||
})) {
|
||||
return { sessionId };
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
} else {
|
||||
await tkmindProxy.submitSessionReplyForUser(
|
||||
row.user_id,
|
||||
@@ -705,6 +735,26 @@ export function createAgentRunGateway({
|
||||
return { sessionId };
|
||||
}
|
||||
|
||||
async function finalizeSuccessfulRun(runId, row, sessionId) {
|
||||
await markRun(runId, 'succeeded', {
|
||||
agent_session_id: sessionId,
|
||||
completed_at: nowMs(),
|
||||
error_message: null,
|
||||
});
|
||||
if (typeof syncUserPagesOnSuccess === 'function') {
|
||||
await syncUserPagesOnSuccess({
|
||||
userId: row.user_id,
|
||||
sessionId,
|
||||
runId,
|
||||
}).catch((err) => {
|
||||
console.warn(
|
||||
'[AgentRun] workspace page deliver failed:',
|
||||
err instanceof Error ? err.message : err,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function processRun(runId) {
|
||||
const row = await getRunById(runId);
|
||||
if (!row || TERMINAL_STATUSES.has(row.status)) return;
|
||||
@@ -721,11 +771,19 @@ export function createAgentRunGateway({
|
||||
|
||||
try {
|
||||
const { sessionId } = await runWithTimeout(runId, () => executeRun(row, runId));
|
||||
await markRun(runId, 'succeeded', {
|
||||
agent_session_id: sessionId,
|
||||
completed_at: nowMs(),
|
||||
});
|
||||
await finalizeSuccessfulRun(runId, row, sessionId);
|
||||
} catch (err) {
|
||||
const latest = await getRunById(runId);
|
||||
const recoverySessionId = latest?.agent_session_id ?? row.agent_session_id ?? null;
|
||||
if (await recoverRunFromDeliverables({
|
||||
runId,
|
||||
userId: row.user_id,
|
||||
sessionId: recoverySessionId,
|
||||
err,
|
||||
})) {
|
||||
await finalizeSuccessfulRun(runId, row, recoverySessionId);
|
||||
return;
|
||||
}
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const timedOut = err?.code === 'AGENT_RUN_TIMEOUT';
|
||||
if (timedOut) {
|
||||
|
||||
Reference in New Issue
Block a user