Files
kandev/apps/web/lib/utils/task-pending-input.ts

54 lines
2.2 KiB
TypeScript

import type { TaskPendingAction } from "@/lib/types/http";
export type PendingInputFlags = { clarification: boolean; permission: boolean };
/**
* Session states where the session can request input from the user. Used to
* decide which sessions participate in the task-level pending-input
* aggregate — a COMPLETED/FAILED/CANCELLED session's stale message history
* must never light up a task-level clarification/permission indicator.
*/
export function isInputCapableSessionState(state: string): boolean {
return state === "RUNNING" || state === "WAITING_FOR_INPUT";
}
export type AggregatedPendingInput = PendingInputFlags & { hasUnloadedMessages: boolean };
/**
* Shared task-level pending-input aggregation: OR together the
* clarification/permission flags of every input-capable session, falling
* back to `taskPendingAction` when a session's messages are not loaded yet
* (or when there are no sessions at all) — the task-wide boot snapshot is the
* best available signal until the per-session messages arrive.
*
* `getSessionFlags` returns `undefined` for a session whose messages are not
* loaded, and the loaded `{ clarification, permission }` flags otherwise.
* Callers that need extra legacy fallback layers (e.g. a primary-session
* substate check) can inspect `hasUnloadedMessages` on the result and layer
* additional fallback on top.
*/
export function aggregateTaskPendingInput<S extends { state: string }>(
sessions: readonly S[],
getSessionFlags: (session: S) => PendingInputFlags | undefined,
taskPendingAction: TaskPendingAction | null | undefined,
): AggregatedPendingInput {
let clarification = false;
let permission = false;
let hasUnloadedMessages = false;
for (const session of sessions) {
if (!isInputCapableSessionState(session.state)) continue;
const flags = getSessionFlags(session);
if (flags === undefined) {
hasUnloadedMessages = true;
continue;
}
clarification ||= flags.clarification;
permission ||= flags.permission;
}
if (sessions.length === 0 || hasUnloadedMessages) {
clarification ||= taskPendingAction === "clarification";
permission ||= taskPendingAction === "permission";
}
return { clarification, permission, hasUnloadedMessages };
}