fix(schedule): stop cancelled mutations

This commit is contained in:
pku-xht
2026-08-07 23:59:57 +08:00
committed by Tianyi Cui
parent c4d9e2edb6
commit fa466cf673
3 changed files with 112 additions and 5 deletions
+26 -4
View File
@@ -25,6 +25,7 @@ import type {
ScheduleCreateValue,
ScheduleDeleteValue,
ScheduleId as ScheduleIdType,
InternalScheduleError,
ScheduleListValue,
SchedulePersistenceOperation,
ScheduleToolError,
@@ -134,10 +135,27 @@ function present(title: string, kind: 'read' | 'other', rawInput?: unknown): Gen
}
/** Stable error for failures not safe to expose. */
function internalError(): ScheduleToolError {
function internalError(): InternalScheduleError {
return { code: 'internal_error', message: 'The schedule operation failed.' }
}
/** Placeholder the registry replaces with its canonical ABORTED result after body quiescence. */
function cancellationPlaceholder(signal: AbortSignal): InternalScheduleError | undefined {
return signal.aborted ? internalError() : undefined
}
/** Serialize one operation, stopping a body whose caller cancelled before its FIFO turn. */
function runCancellableScheduleTransaction<T>(
agent: Agent,
signal: AbortSignal,
task: () => Promise<T>,
): Promise<T | InternalScheduleError> {
return runScheduleTransaction(agent, async () => {
const cancelled = cancellationPlaceholder(signal)
return cancelled ?? task()
})
}
/** Stable durable-log failure. */
function corruptLogError(): ScheduleToolError {
return { code: 'corrupt_schedule_log', message: 'The session schedule log is corrupt.' }
@@ -256,7 +274,7 @@ export function registerScheduleTools(
if (exec.agent !== agent) return internalError()
const invalid = validateCreateArgs(args)
if (invalid !== undefined) return invalid
return runScheduleTransaction(agent, async () => {
return runCancellableScheduleTransaction(agent, exec.signal, async () => {
const uncertain = await preflight(rootCtx, agent, 'create')
if (uncertain !== undefined) return uncertain
notifyDurableChange()
@@ -269,6 +287,8 @@ export function registerScheduleTools(
} catch (error: unknown) {
return error instanceof ScheduleInputError ? inputError(error) : internalError()
}
const cancelledBeforeAppend = cancellationPlaceholder(exec.signal)
if (cancelledBeforeAppend !== undefined) return cancelledBeforeAppend
try {
agent.session.append('schedule/change', {
version: 1,
@@ -294,7 +314,7 @@ export function registerScheduleTools(
output: { schema: LIST_OUTPUT_SCHEMA, render: renderValue },
async execute(_args, exec): Promise<ScheduleListValue> {
if (exec.agent !== agent) return internalError()
return runScheduleTransaction(agent, async () => {
return runCancellableScheduleTransaction(agent, exec.signal, async () => {
const uncertain = await preflight(rootCtx, agent, 'list')
if (uncertain !== undefined) return uncertain
notifyDurableChange()
@@ -320,7 +340,7 @@ export function registerScheduleTools(
}
const id = ScheduleId(args.id)
if (exec.agent !== agent) return internalError()
return runScheduleTransaction(agent, async () => {
return runCancellableScheduleTransaction(agent, exec.signal, async () => {
const uncertain = await preflight(rootCtx, agent, 'delete', id)
if (uncertain !== undefined) return uncertain
notifyDurableChange()
@@ -329,6 +349,8 @@ export function registerScheduleTools(
if (!folded.active.some(record => record.id === id)) {
return { id, deleted: false, code: 'schedule_not_found' }
}
const cancelledBeforeAppend = cancellationPlaceholder(exec.signal)
if (cancelledBeforeAppend !== undefined) return cancelledBeforeAppend
try {
agent.session.append('schedule/change', { version: 1, operation: 'delete', id })
} catch {