161 lines · 5.6 KB · TypeScript
RawDownload
/** * ProjectionTurnRepository - Projection repository interface for unified turn state. * * Owns persistence operations for pending starts, running/completed turn lifecycle, * and checkpoint metadata in a single projection table. * * @module ProjectionTurnRepository */import {  CheckpointRef,  IsoDateTime,  MessageId,  NonNegativeInt,  OrchestrationCheckpointFile,  OrchestrationCheckpointStatus,  ThreadId,  TurnId,} from "@t3tools/contracts";import { Option, Schema, ServiceMap } from "effect";import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; export const ProjectionTurnState = Schema.Literals([  "pending",  "running",  "interrupted",  "completed",  "error",]);export type ProjectionTurnState = typeof ProjectionTurnState.Type; export const ProjectionTurn = Schema.Struct({  threadId: ThreadId,  turnId: Schema.NullOr(TurnId),  pendingMessageId: Schema.NullOr(MessageId),  assistantMessageId: Schema.NullOr(MessageId),  state: ProjectionTurnState,  requestedAt: IsoDateTime,  startedAt: Schema.NullOr(IsoDateTime),  completedAt: Schema.NullOr(IsoDateTime),  checkpointTurnCount: Schema.NullOr(NonNegativeInt),  checkpointRef: Schema.NullOr(CheckpointRef),  checkpointStatus: Schema.NullOr(OrchestrationCheckpointStatus),  checkpointFiles: Schema.Array(OrchestrationCheckpointFile),});export type ProjectionTurn = typeof ProjectionTurn.Type; export const ProjectionTurnById = Schema.Struct({  threadId: ThreadId,  turnId: TurnId,  pendingMessageId: Schema.NullOr(MessageId),  assistantMessageId: Schema.NullOr(MessageId),  state: ProjectionTurnState,  requestedAt: IsoDateTime,  startedAt: Schema.NullOr(IsoDateTime),  completedAt: Schema.NullOr(IsoDateTime),  checkpointTurnCount: Schema.NullOr(NonNegativeInt),  checkpointRef: Schema.NullOr(CheckpointRef),  checkpointStatus: Schema.NullOr(OrchestrationCheckpointStatus),  checkpointFiles: Schema.Array(OrchestrationCheckpointFile),});export type ProjectionTurnById = typeof ProjectionTurnById.Type; export const ProjectionPendingTurnStart = Schema.Struct({  threadId: ThreadId,  messageId: MessageId,  requestedAt: IsoDateTime,});export type ProjectionPendingTurnStart = typeof ProjectionPendingTurnStart.Type; export const ListProjectionTurnsByThreadInput = Schema.Struct({  threadId: ThreadId,});export type ListProjectionTurnsByThreadInput = typeof ListProjectionTurnsByThreadInput.Type; export const GetProjectionTurnByTurnIdInput = Schema.Struct({  threadId: ThreadId,  turnId: TurnId,});export type GetProjectionTurnByTurnIdInput = typeof GetProjectionTurnByTurnIdInput.Type; export const GetProjectionPendingTurnStartInput = Schema.Struct({  threadId: ThreadId,});export type GetProjectionPendingTurnStartInput = typeof GetProjectionPendingTurnStartInput.Type; export const DeleteProjectionTurnsByThreadInput = Schema.Struct({  threadId: ThreadId,});export type DeleteProjectionTurnsByThreadInput = typeof DeleteProjectionTurnsByThreadInput.Type; export const ClearCheckpointTurnConflictInput = Schema.Struct({  threadId: ThreadId,  turnId: TurnId,  checkpointTurnCount: NonNegativeInt,});export type ClearCheckpointTurnConflictInput = typeof ClearCheckpointTurnConflictInput.Type; export interface ProjectionTurnRepositoryShape {  /**   * Inserts or updates the canonical row for a concrete `{threadId, turnId}` turn lifecycle state.   */  readonly upsertByTurnId: (    row: ProjectionTurnById,  ) => Effect.Effect<void, ProjectionRepositoryError>;   /**   * Replaces any existing pending-start placeholder rows for a thread with exactly one latest pending-start row.   */  readonly replacePendingTurnStart: (    row: ProjectionPendingTurnStart,  ) => Effect.Effect<void, ProjectionRepositoryError>;   /**   * Returns the newest pending-start placeholder for a thread; this is expected to be at most one row after replacement writes.   */  readonly getPendingTurnStartByThreadId: (    input: GetProjectionPendingTurnStartInput,  ) => Effect.Effect<Option.Option<ProjectionPendingTurnStart>, ProjectionRepositoryError>;   /**   * Deletes only pending-start placeholder rows (`turnId = null`) for a thread and leaves concrete turn rows untouched.   */  readonly deletePendingTurnStartByThreadId: (    input: GetProjectionPendingTurnStartInput,  ) => Effect.Effect<void, ProjectionRepositoryError>;   /**   * Lists all projection rows for a thread, including pending placeholders, with checkpoint rows ordered before non-checkpoint rows.   */  readonly listByThreadId: (    input: ListProjectionTurnsByThreadInput,  ) => Effect.Effect<ReadonlyArray<ProjectionTurn>, ProjectionRepositoryError>;   /**   * Looks up a concrete turn row by `{threadId, turnId}` and never returns pending placeholder rows.   */  readonly getByTurnId: (    input: GetProjectionTurnByTurnIdInput,  ) => Effect.Effect<Option.Option<ProjectionTurnById>, ProjectionRepositoryError>;   /**   * Clears checkpoint fields on conflicting rows that reuse the same checkpoint turn count in a thread, excluding the provided turn.   */  readonly clearCheckpointTurnConflict: (    input: ClearCheckpointTurnConflictInput,  ) => Effect.Effect<void, ProjectionRepositoryError>;   /**   * Hard-deletes all projection rows for a thread, including pending-start placeholders and checkpoint metadata rows.   */  readonly deleteByThreadId: (    input: DeleteProjectionTurnsByThreadInput,  ) => Effect.Effect<void, ProjectionRepositoryError>;} export class ProjectionTurnRepository extends ServiceMap.Service<  ProjectionTurnRepository,  ProjectionTurnRepositoryShape>()("t3/persistence/Services/ProjectionTurns/ProjectionTurnRepository") {}