import { AgentSessionImportSource, ApprovalRequestId, ChatAttachment, CheckpointRef, IsoDateTime, MessageId, NonNegativeInt, OrchestrationCheckpointFile, OrchestrationProposedPlanId, OrchestrationReadModel, OrchestrationThreadSearchSource, OrchestrationShellSnapshot, OrchestrationThread, OrchestrationThreadDetailSnapshot, ProjectScript, ProjectIconOverride, TurnId, type OrchestrationCheckpointSummary, type OrchestrationLatestTurn, type OrchestrationMessage, type OrchestrationProjectShell, type OrchestrationProposedPlan, type OrchestrationProject, type OrchestrationSession, type OrchestrationThreadActivity, type OrchestrationThreadShell, ModelSelection, ProjectId, ThreadLinkedPullRequest, ThreadId, ThreadPullRequestSnapshot, ThreadPullRequestStack, type ThreadPullRequestLink,} from "@t3tools/contracts";import { legacyLinkedPullRequestOf } from "@t3tools/shared/threadPullRequests";import * as Arr from "effect/Array";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Result from "effect/Result";import * as Schema from "effect/Schema";import * as Struct from "effect/Struct";import * as SqlClient from "effect/unstable/sql/SqlClient";import * as SqlSchema from "effect/unstable/sql/SqlSchema"; import { isPersistenceError, toPersistenceDecodeError, toPersistenceSqlError, type ProjectionRepositoryError,} from "../../persistence/Errors.ts";import { ProjectionCheckpoint } from "../../persistence/Services/ProjectionCheckpoints.ts";import { ThreadBackgroundLivenessService } from "../ThreadBackgroundLiveness.ts";import { ThreadPlanProgressService } from "../ThreadPlanProgress.ts";import { ProjectionProject } from "../../persistence/Services/ProjectionProjects.ts";import { ProjectionState } from "../../persistence/Services/ProjectionState.ts";import { ProjectionThreadActivity } from "../../persistence/Services/ProjectionThreadActivities.ts";import { ProjectionThreadMessage } from "../../persistence/Services/ProjectionThreadMessages.ts";import { ProjectionThreadProposedPlan } from "../../persistence/Services/ProjectionThreadProposedPlans.ts";import { ProjectionThreadPullRequest } from "../../persistence/ProjectionThreadPullRequests.ts";import { ProjectionThreadSession } from "../../persistence/Services/ProjectionThreadSessions.ts";import { ProjectionThread } from "../../persistence/Services/ProjectionThreads.ts";import { decodeThreadDetailPageCursor, encodeThreadDetailPageCursor,} from "../threadDetailCursor.ts";import { projectActivityPayload } from "../ActivityPayloadProjection.ts";import * as RepositoryIdentityResolver from "../../project/RepositoryIdentityResolver.ts";import { ORCHESTRATION_PROJECTOR_NAMES } from "./ProjectionPipeline.ts";import { ProjectionSnapshotQuery, type ProjectionEventReplayStats, type ProjectionFullThreadDiffContext, type ProjectionSnapshotCounts, type ProjectionThreadCheckpointContext, type ProjectionThreadDetailQuery, type ProjectionSnapshotQueryShape,} from "../Services/ProjectionSnapshotQuery.ts"; const decodeReadModel = Schema.decodeUnknownEffect(OrchestrationReadModel);const decodeShellSnapshot = Schema.decodeUnknownEffect(OrchestrationShellSnapshot);const decodeThread = Schema.decodeUnknownEffect(OrchestrationThread);const decodeImportedTranscriptsPayload = Schema.decodeUnknownOption( Schema.fromJsonString( Schema.Struct({ importedTranscripts: Schema.Array(Schema.Unknown), }), ),);const decodeAgentSessionImportSource = Schema.decodeUnknownOption(AgentSessionImportSource);// Keep detail reads consistent with the in-memory projector's retained// activity window. Applying the limit in SQL avoids decoding an unbounded// payload_json set before the projector can enforce that invariant.const THREAD_DETAIL_ACTIVITY_LIMIT = 500;// Snapshot payloads are decoded and projected in small sequential batches so// one client read does not retain the raw payloads for the full activity window.const THREAD_DETAIL_ACTIVITY_PAYLOAD_BATCH_SIZE = 25;// SQLite trim defaults to spaces. Match the whitespace removed by String.trim.const MESSAGE_TRIM_WHITESPACE = "\t\n\v\f\r \u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff";const ProjectionProjectDbRowSchema = ProjectionProject.mapFields( Struct.assign({ defaultModelSelection: Schema.NullOr(Schema.fromJsonString(ModelSelection)), autoPull: Schema.Number, projectIcon: Schema.NullOr(Schema.fromJsonString(ProjectIconOverride)), scripts: Schema.fromJsonString(Schema.Array(ProjectScript)), }),);const ProjectionThreadMessageDbRowSchema = ProjectionThreadMessage.mapFields( Struct.assign({ isStreaming: Schema.Number, attachments: Schema.NullOr(Schema.fromJsonString(Schema.Array(ChatAttachment))), }),);const ProjectionTurnStartMessageDbRowSchema = ProjectionThreadMessageDbRowSchema.mapFields( Struct.assign({ hasOtherUserMessages: Schema.Number }),);const ProjectionThreadProposedPlanDbRowSchema = ProjectionThreadProposedPlan;const ProjectionThreadPullRequestDbRowSchema = ProjectionThreadPullRequest.mapFields( Struct.assign({ snapshot: Schema.NullOr(Schema.fromJsonString(ThreadPullRequestSnapshot)), stack: Schema.NullOr(Schema.fromJsonString(ThreadPullRequestStack)), }),);const ProjectionThreadDbRowSchema = ProjectionThread.mapFields( Struct.assign({ modelSelection: Schema.fromJsonString(ModelSelection), linkedPullRequest: Schema.NullOr(Schema.fromJsonString(ThreadLinkedPullRequest)), branchPullRequest: Schema.NullOr(Schema.fromJsonString(ThreadLinkedPullRequest)), }),);const ProjectionThreadActivityDbRowSchema = ProjectionThreadActivity.mapFields( Struct.assign({ payload: Schema.fromJsonString(Schema.Unknown), sequence: Schema.NullOr(NonNegativeInt), }),);const ProjectionThreadActivityIdRowSchema = Schema.Struct({ activityId: ProjectionThreadActivity.fields.activityId,});const ProjectionThreadSessionDbRowSchema = ProjectionThreadSession;const ProjectionThreadRuntimeContextDbRowSchema = Schema.Struct({ id: ThreadId, title: Schema.String, session: Schema.NullOr(ProjectionThreadSessionDbRowSchema),});const ProjectionCheckpointDbRowSchema = ProjectionCheckpoint.mapFields( Struct.assign({ files: Schema.fromJsonString(Schema.Array(OrchestrationCheckpointFile)), }),);const ProjectionLatestTurnDbRowSchema = Schema.Struct({ threadId: ProjectionThread.fields.threadId, turnId: TurnId, state: Schema.String, requestedAt: IsoDateTime, startedAt: Schema.NullOr(IsoDateTime), completedAt: Schema.NullOr(IsoDateTime), assistantMessageId: Schema.NullOr(MessageId), sourceProposedPlanThreadId: Schema.NullOr(ThreadId), sourceProposedPlanId: Schema.NullOr(OrchestrationProposedPlanId),});const ProjectionStateDbRowSchema = ProjectionState;const ProjectionCountsRowSchema = Schema.Struct({ projectCount: Schema.Number, threadCount: Schema.Number,});const EventReplayStatsInput = Schema.Struct({ fromSequenceExclusive: NonNegativeInt, toSequenceInclusive: NonNegativeInt,});const EventReplayStatsRowSchema = Schema.Struct({ eventCount: Schema.Number, payloadBytes: Schema.Number,});const ProjectionThreadSearchRequest = Schema.Struct({ pattern: Schema.String, limit: Schema.Int,});const ProjectionThreadSearchRow = Schema.Struct({ threadId: ThreadId, projectId: ProjectId, source: OrchestrationThreadSearchSource, matchText: Schema.String, messageCreatedAt: Schema.NullOr(IsoDateTime),});const WorkspaceRootLookupInput = Schema.Struct({ workspaceRoot: Schema.String,});const ProjectIdLookupInput = Schema.Struct({ projectId: ProjectId,});const ProjectionImportedAgentSessionSourcesRowSchema = Schema.Struct({ threadId: ThreadId, runtimePayload: Schema.Unknown,});const ThreadIdLookupInput = Schema.Struct({ threadId: ThreadId,});const TurnStartMessageLookupInput = Schema.Struct({ threadId: ThreadId, messageId: MessageId,});const ThreadActivityKindsLookupInput = Schema.Struct({ threadId: ThreadId, activityKinds: Schema.Array(Schema.String),});const ThreadActivityIdsLookupInput = Schema.Struct({ activityIds: Schema.Array(ProjectionThreadActivity.fields.activityId),});// Windowed reads order turns by the stable keyset (anchor, turn key), where// anchor is requested_at and turn key is// COALESCE(turn_id, ''). Both are event-derived, so cursors survive the// revert projector's row-id rewrite and full projection rebuilds.const ThreadTurnWindowLookupInput = Schema.Struct({ threadId: ThreadId, // Exclusive keyset upper bound. Sentinels "~"/"" mean unbounded ("~" sorts // after every ISO timestamp). beforeAnchorAt: Schema.String, beforeTurnKey: Schema.String, userTurnLimit: Schema.Number, maxRawTurns: Schema.Number,});const ProjectionTurnWindowRowSchema = Schema.Struct({ // The turn's timeline anchor, used to bound rows that have no turn linkage // (user messages and turnless activities) to the same page window. anchorAt: Schema.String, turnKey: Schema.String,});const ThreadTurnRangeLookupInput = Schema.Struct({ threadId: ThreadId, // Turn-linked rows are bounded by the keyset range [min, before) over // (anchor, turn key); turnless rows by the matching [minAnchorAt, // beforeAnchorAt) time range. Unbounded ends use sentinels: "" for the // lower bound, "~" (sorts after ISO dates) for the upper bound. minAnchorAt: Schema.String, minTurnKey: Schema.String, beforeAnchorAt: Schema.String, beforeTurnKey: Schema.String,});const ProjectionProjectLookupRowSchema = ProjectionProjectDbRowSchema;const ProjectionThreadIdLookupRowSchema = Schema.Struct({ threadId: ThreadId,});const ProjectionThreadCheckpointContextThreadRowSchema = Schema.Struct({ threadId: ThreadId, projectId: ProjectId, workspaceRoot: Schema.String, worktreePath: Schema.NullOr(Schema.String),});const FullThreadDiffContextLookupInput = Schema.Struct({ threadId: ThreadId, checkpointTurnCount: NonNegativeInt,});const ProjectionFullThreadDiffContextRowSchema = Schema.Struct({ threadId: ThreadId, projectId: ProjectId, workspaceRoot: Schema.String, worktreePath: Schema.NullOr(Schema.String), latestCheckpointTurnCount: Schema.NullOr(NonNegativeInt), toCheckpointRef: Schema.NullOr(CheckpointRef),}); const REQUIRED_SNAPSHOT_PROJECTORS = [ ORCHESTRATION_PROJECTOR_NAMES.projects, ORCHESTRATION_PROJECTOR_NAMES.threads, ORCHESTRATION_PROJECTOR_NAMES.threadMessages, ORCHESTRATION_PROJECTOR_NAMES.threadProposedPlans, ORCHESTRATION_PROJECTOR_NAMES.threadActivities, ORCHESTRATION_PROJECTOR_NAMES.threadSessions, ORCHESTRATION_PROJECTOR_NAMES.checkpoints,] as const; function maxIso(left: string | null, right: string): string { if (left === null) { return right; } return left > right ? left : right;} function escapeLikePattern(value: string): string { return value.replaceAll("!", "!!").replaceAll("%", "!%").replaceAll("_", "!_");} function foldAsciiCase(value: string): string { return value.replace(/[A-Z]/g, (character) => character.toLowerCase());} function buildSearchSnippet(text: string, query: string): string { const normalizedText = text.replace(/\s+/g, " ").trim(); if (normalizedText.length <= 240) { return normalizedText; } const normalizedQuery = foldAsciiCase(query.replace(/\s+/g, " ").trim()); const matchIndex = foldAsciiCase(normalizedText).indexOf(normalizedQuery); const bodyLength = 236; const idealStart = Math.max(0, matchIndex - 72); const start = Math.min(idealStart, normalizedText.length - bodyLength); const end = Math.min(normalizedText.length, start + bodyLength); return `${start > 0 ? "…" : ""}${normalizedText.slice(start, end)}${ end < normalizedText.length ? "…" : "" }`;} function computeSnapshotSequence( stateRows: ReadonlyArray<Schema.Schema.Type<typeof ProjectionStateDbRowSchema>>,): number { if (stateRows.length === 0) { return 0; } const sequenceByProjector = new Map( stateRows.map((row) => [row.projector, row.lastAppliedSequence] as const), ); let minSequence = Number.POSITIVE_INFINITY; for (const projector of REQUIRED_SNAPSHOT_PROJECTORS) { const sequence = sequenceByProjector.get(projector); if (sequence === undefined) { return 0; } if (sequence < minSequence) { minSequence = sequence; } } return Number.isFinite(minSequence) ? minSequence : 0;} function mapLatestTurn( row: Schema.Schema.Type<typeof ProjectionLatestTurnDbRowSchema>,): OrchestrationLatestTurn { return { turnId: row.turnId, state: row.state === "error" ? "error" : row.state === "interrupted" ? "interrupted" : row.state === "completed" ? "completed" : "running", requestedAt: row.requestedAt, startedAt: row.startedAt, completedAt: row.completedAt, assistantMessageId: row.assistantMessageId, ...(row.sourceProposedPlanThreadId !== null && row.sourceProposedPlanId !== null ? { sourceProposedPlan: { threadId: row.sourceProposedPlanThreadId, planId: row.sourceProposedPlanId, }, } : {}), };} function mapTitleRegeneration(row: Schema.Schema.Type<typeof ProjectionThreadDbRowSchema>) { return row.titleRegenerationRequestId != null && row.titleRegenerationStartedAt != null ? { requestId: row.titleRegenerationRequestId, startedAt: row.titleRegenerationStartedAt, } : null;} function mapSessionRow( row: Schema.Schema.Type<typeof ProjectionThreadSessionDbRowSchema>,): OrchestrationSession { return { threadId: row.threadId, status: row.status, providerName: row.providerName, ...(row.providerInstanceId !== null ? { providerInstanceId: row.providerInstanceId } : {}), runtimeMode: row.runtimeMode, activeTurnId: row.activeTurnId, lastError: row.lastError, updatedAt: row.updatedAt, };} function mapProjectShellRow( row: Schema.Schema.Type<typeof ProjectionProjectDbRowSchema>, repositoryIdentity: OrchestrationProject["repositoryIdentity"],): OrchestrationProjectShell { return { id: row.projectId, title: row.title, workspaceRoot: row.workspaceRoot, repositoryIdentity, defaultModelSelection: row.defaultModelSelection, defaultThreadEnvMode: row.defaultThreadEnvMode, autoPull: row.autoPull === 1, faviconPath: row.faviconPath ?? null, projectIcon: row.projectIcon ?? null, scripts: row.scripts, createdAt: row.createdAt, updatedAt: row.updatedAt, };} function mapProposedPlanRow( row: Schema.Schema.Type<typeof ProjectionThreadProposedPlanDbRowSchema>,): OrchestrationProposedPlan { return { id: row.planId, turnId: row.turnId, planMarkdown: row.planMarkdown, implementedAt: row.implementedAt, implementationThreadId: row.implementationThreadId, createdAt: row.createdAt, updatedAt: row.updatedAt, };} function mapPullRequestRow( row: Schema.Schema.Type<typeof ProjectionThreadPullRequestDbRowSchema>,): ThreadPullRequestLink { return { host: row.host, repository: row.repository, number: row.number, url: row.url, source: row.source, linkedAt: row.linkedAt, snapshot: row.snapshot, stack: row.stack, };} function groupPullRequestRowsByThread( rows: ReadonlyArray<Schema.Schema.Type<typeof ProjectionThreadPullRequestDbRowSchema>>,): Map<string, Array<ThreadPullRequestLink>> { const byThread = new Map<string, Array<ThreadPullRequestLink>>(); for (const row of rows) { const links = byThread.get(row.threadId) ?? []; links.push(mapPullRequestRow(row)); byThread.set(row.threadId, links); } return byThread;} /** * The link array plus the legacy single-link field derived from it, so clients * from before `pullRequests` keep seeing the thread's current pull request. */function mapThreadPullRequests( pullRequests: ReadonlyArray<ThreadPullRequestLink>, projectId: ProjectId, identity?: OrchestrationProject["repositoryIdentity"],): Pick<OrchestrationThread, "pullRequests" | "linkedPullRequest"> { const linkedPullRequest = legacyLinkedPullRequestOf(pullRequests, projectId, identity); return { pullRequests, ...(linkedPullRequest === null ? {} : { linkedPullRequest }), };} function mapThreadActivityRow( row: Schema.Schema.Type<typeof ProjectionThreadActivityDbRowSchema>,): OrchestrationThreadActivity { return { id: row.activityId, tone: row.tone, kind: row.kind, summary: row.summary, payload: row.payload, turnId: row.turnId, createdAt: row.createdAt, ...(row.sequence !== null ? { sequence: row.sequence } : {}), };} function toPersistenceSqlOrDecodeError(sqlOperation: string, decodeOperation: string) { return (cause: unknown): ProjectionRepositoryError => Schema.isSchemaError(cause) ? toPersistenceDecodeError(decodeOperation)(cause) : toPersistenceSqlError(sqlOperation)(cause);} const makeProjectionSnapshotQuery = Effect.gen(function* () { const threadBackgroundLiveness = yield* ThreadBackgroundLivenessService; const threadPlanProgress = yield* ThreadPlanProgressService; const sql = yield* SqlClient.SqlClient; const repositoryIdentityResolver = yield* RepositoryIdentityResolver.RepositoryIdentityResolver; const repositoryIdentityResolutionConcurrency = 4; const resolveRepositoryIdentitiesForProjects = Effect.fn( "ProjectionSnapshotQuery.resolveRepositoryIdentitiesForProjects", )(function* ( projectRows: ReadonlyArray<Schema.Schema.Type<typeof ProjectionProjectDbRowSchema>>, options?: { readonly includeDeleted?: boolean; }, ) { const filteredProjectRows = options?.includeDeleted === true ? projectRows : projectRows.filter((row) => row.deletedAt === null); const uniqueWorkspaceRoots = [...new Set(filteredProjectRows.map((row) => row.workspaceRoot))];Lines 1–500 of 3662. Load more
import { AgentSessionImportSource, ApprovalRequestId, ChatAttachment, CheckpointRef, IsoDateTime, MessageId, NonNegativeInt, OrchestrationCheckpointFile, OrchestrationProposedPlanId, OrchestrationReadModel, OrchestrationThreadSearchSource, OrchestrationShellSnapshot, OrchestrationThread, OrchestrationThreadDetailSnapshot, ProjectScript, ProjectIconOverride, TurnId, type OrchestrationCheckpointSummary, type OrchestrationLatestTurn, type OrchestrationMessage, type OrchestrationProjectShell, type OrchestrationProposedPlan, type OrchestrationProject, type OrchestrationSession, type OrchestrationThreadActivity, type OrchestrationThreadShell, ModelSelection, ProjectId, ThreadLinkedPullRequest, ThreadId, ThreadPullRequestSnapshot, ThreadPullRequestStack, type ThreadPullRequestLink, } from "@t3tools/contracts"; import { legacyLinkedPullRequestOf } from "@t3tools/shared/threadPullRequests"; import * as Arr from "effect/Array"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as Result from "effect/Result"; import * as Schema from "effect/Schema"; import * as Struct from "effect/Struct"; import * as SqlClient from "effect/unstable/sql/SqlClient"; import * as SqlSchema from "effect/unstable/sql/SqlSchema"; import { isPersistenceError, toPersistenceDecodeError, toPersistenceSqlError, type ProjectionRepositoryError, } from "../../persistence/Errors.ts"; import { ProjectionCheckpoint } from "../../persistence/Services/ProjectionCheckpoints.ts"; import { ThreadBackgroundLivenessService } from "../ThreadBackgroundLiveness.ts"; import { ThreadPlanProgressService } from "../ThreadPlanProgress.ts"; import { ProjectionProject } from "../../persistence/Services/ProjectionProjects.ts"; import { ProjectionState } from "../../persistence/Services/ProjectionState.ts"; import { ProjectionThreadActivity } from "../../persistence/Services/ProjectionThreadActivities.ts"; import { ProjectionThreadMessage } from "../../persistence/Services/ProjectionThreadMessages.ts"; import { ProjectionThreadProposedPlan } from "../../persistence/Services/ProjectionThreadProposedPlans.ts"; import { ProjectionThreadPullRequest } from "../../persistence/ProjectionThreadPullRequests.ts"; import { ProjectionThreadSession } from "../../persistence/Services/ProjectionThreadSessions.ts"; import { ProjectionThread } from "../../persistence/Services/ProjectionThreads.ts"; import { decodeThreadDetailPageCursor, encodeThreadDetailPageCursor, } from "../threadDetailCursor.ts"; import { projectActivityPayload } from "../ActivityPayloadProjection.ts"; import * as RepositoryIdentityResolver from "../../project/RepositoryIdentityResolver.ts"; import { ORCHESTRATION_PROJECTOR_NAMES } from "./ProjectionPipeline.ts"; import { ProjectionSnapshotQuery, type ProjectionEventReplayStats, type ProjectionFullThreadDiffContext, type ProjectionSnapshotCounts, type ProjectionThreadCheckpointContext, type ProjectionThreadDetailQuery, type ProjectionSnapshotQueryShape, } from "../Services/ProjectionSnapshotQuery.ts"; const decodeReadModel = Schema.decodeUnknownEffect(OrchestrationReadModel); const decodeShellSnapshot = Schema.decodeUnknownEffect(OrchestrationShellSnapshot); const decodeThread = Schema.decodeUnknownEffect(OrchestrationThread); const decodeImportedTranscriptsPayload = Schema.decodeUnknownOption( Schema.fromJsonString( Schema.Struct({ importedTranscripts: Schema.Array(Schema.Unknown), }), ), ); const decodeAgentSessionImportSource = Schema.decodeUnknownOption(AgentSessionImportSource); // Keep detail reads consistent with the in-memory projector's retained // activity window. Applying the limit in SQL avoids decoding an unbounded // payload_json set before the projector can enforce that invariant. const THREAD_DETAIL_ACTIVITY_LIMIT = 500; // Snapshot payloads are decoded and projected in small sequential batches so // one client read does not retain the raw payloads for the full activity window. const THREAD_DETAIL_ACTIVITY_PAYLOAD_BATCH_SIZE = 25; // SQLite trim defaults to spaces. Match the whitespace removed by String.trim. const MESSAGE_TRIM_WHITESPACE = "\t\n\v\f\r \u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u2028\u2029\u202f\u205f\u3000\ufeff"; const ProjectionProjectDbRowSchema = ProjectionProject.mapFields( Struct.assign({ defaultModelSelection: Schema.NullOr(Schema.fromJsonString(ModelSelection)), autoPull: Schema.Number, projectIcon: Schema.NullOr(Schema.fromJsonString(ProjectIconOverride)), scripts: Schema.fromJsonString(Schema.Array(ProjectScript)), }), ); const ProjectionThreadMessageDbRowSchema = ProjectionThreadMessage.mapFields( Struct.assign({ isStreaming: Schema.Number, attachments: Schema.NullOr(Schema.fromJsonString(Schema.Array(ChatAttachment))), }), ); const ProjectionTurnStartMessageDbRowSchema = ProjectionThreadMessageDbRowSchema.mapFields( Struct.assign({ hasOtherUserMessages: Schema.Number }), ); const ProjectionThreadProposedPlanDbRowSchema = ProjectionThreadProposedPlan; const ProjectionThreadPullRequestDbRowSchema = ProjectionThreadPullRequest.mapFields( Struct.assign({ snapshot: Schema.NullOr(Schema.fromJsonString(ThreadPullRequestSnapshot)), stack: Schema.NullOr(Schema.fromJsonString(ThreadPullRequestStack)), }), ); const ProjectionThreadDbRowSchema = ProjectionThread.mapFields( Struct.assign({ modelSelection: Schema.fromJsonString(ModelSelection), linkedPullRequest: Schema.NullOr(Schema.fromJsonString(ThreadLinkedPullRequest)), branchPullRequest: Schema.NullOr(Schema.fromJsonString(ThreadLinkedPullRequest)), }), ); const ProjectionThreadActivityDbRowSchema = ProjectionThreadActivity.mapFields( Struct.assign({ payload: Schema.fromJsonString(Schema.Unknown), sequence: Schema.NullOr(NonNegativeInt), }), ); const ProjectionThreadActivityIdRowSchema = Schema.Struct({ activityId: ProjectionThreadActivity.fields.activityId, }); const ProjectionThreadSessionDbRowSchema = ProjectionThreadSession; const ProjectionThreadRuntimeContextDbRowSchema = Schema.Struct({ id: ThreadId, title: Schema.String, session: Schema.NullOr(ProjectionThreadSessionDbRowSchema), }); const ProjectionCheckpointDbRowSchema = ProjectionCheckpoint.mapFields( Struct.assign({ files: Schema.fromJsonString(Schema.Array(OrchestrationCheckpointFile)), }), ); const ProjectionLatestTurnDbRowSchema = Schema.Struct({ threadId: ProjectionThread.fields.threadId, turnId: TurnId, state: Schema.String, requestedAt: IsoDateTime, startedAt: Schema.NullOr(IsoDateTime), completedAt: Schema.NullOr(IsoDateTime), assistantMessageId: Schema.NullOr(MessageId), sourceProposedPlanThreadId: Schema.NullOr(ThreadId), sourceProposedPlanId: Schema.NullOr(OrchestrationProposedPlanId), }); const ProjectionStateDbRowSchema = ProjectionState; const ProjectionCountsRowSchema = Schema.Struct({ projectCount: Schema.Number, threadCount: Schema.Number, }); const EventReplayStatsInput = Schema.Struct({ fromSequenceExclusive: NonNegativeInt, toSequenceInclusive: NonNegativeInt, }); const EventReplayStatsRowSchema = Schema.Struct({ eventCount: Schema.Number, payloadBytes: Schema.Number, }); const ProjectionThreadSearchRequest = Schema.Struct({ pattern: Schema.String, limit: Schema.Int, }); const ProjectionThreadSearchRow = Schema.Struct({ threadId: ThreadId, projectId: ProjectId, source: OrchestrationThreadSearchSource, matchText: Schema.String, messageCreatedAt: Schema.NullOr(IsoDateTime), }); const WorkspaceRootLookupInput = Schema.Struct({ workspaceRoot: Schema.String, }); const ProjectIdLookupInput = Schema.Struct({ projectId: ProjectId, }); const ProjectionImportedAgentSessionSourcesRowSchema = Schema.Struct({ threadId: ThreadId, runtimePayload: Schema.Unknown, }); const ThreadIdLookupInput = Schema.Struct({ threadId: ThreadId, }); const TurnStartMessageLookupInput = Schema.Struct({ threadId: ThreadId, messageId: MessageId, }); const ThreadActivityKindsLookupInput = Schema.Struct({ threadId: ThreadId, activityKinds: Schema.Array(Schema.String), }); const ThreadActivityIdsLookupInput = Schema.Struct({ activityIds: Schema.Array(ProjectionThreadActivity.fields.activityId), }); // Windowed reads order turns by the stable keyset (anchor, turn key), where // anchor is requested_at and turn key is // COALESCE(turn_id, ''). Both are event-derived, so cursors survive the // revert projector's row-id rewrite and full projection rebuilds. const ThreadTurnWindowLookupInput = Schema.Struct({ threadId: ThreadId, // Exclusive keyset upper bound. Sentinels "~"/"" mean unbounded ("~" sorts // after every ISO timestamp). beforeAnchorAt: Schema.String, beforeTurnKey: Schema.String, userTurnLimit: Schema.Number, maxRawTurns: Schema.Number, }); const ProjectionTurnWindowRowSchema = Schema.Struct({ // The turn's timeline anchor, used to bound rows that have no turn linkage // (user messages and turnless activities) to the same page window. anchorAt: Schema.String, turnKey: Schema.String, }); const ThreadTurnRangeLookupInput = Schema.Struct({ threadId: ThreadId, // Turn-linked rows are bounded by the keyset range [min, before) over // (anchor, turn key); turnless rows by the matching [minAnchorAt, // beforeAnchorAt) time range. Unbounded ends use sentinels: "" for the // lower bound, "~" (sorts after ISO dates) for the upper bound. minAnchorAt: Schema.String, minTurnKey: Schema.String, beforeAnchorAt: Schema.String, beforeTurnKey: Schema.String, }); const ProjectionProjectLookupRowSchema = ProjectionProjectDbRowSchema; const ProjectionThreadIdLookupRowSchema = Schema.Struct({ threadId: ThreadId, }); const ProjectionThreadCheckpointContextThreadRowSchema = Schema.Struct({ threadId: ThreadId, projectId: ProjectId, workspaceRoot: Schema.String, worktreePath: Schema.NullOr(Schema.String), }); const FullThreadDiffContextLookupInput = Schema.Struct({ threadId: ThreadId, checkpointTurnCount: NonNegativeInt, }); const ProjectionFullThreadDiffContextRowSchema = Schema.Struct({ threadId: ThreadId, projectId: ProjectId, workspaceRoot: Schema.String, worktreePath: Schema.NullOr(Schema.String), latestCheckpointTurnCount: Schema.NullOr(NonNegativeInt), toCheckpointRef: Schema.NullOr(CheckpointRef), }); const REQUIRED_SNAPSHOT_PROJECTORS = [ ORCHESTRATION_PROJECTOR_NAMES.projects, ORCHESTRATION_PROJECTOR_NAMES.threads, ORCHESTRATION_PROJECTOR_NAMES.threadMessages, ORCHESTRATION_PROJECTOR_NAMES.threadProposedPlans, ORCHESTRATION_PROJECTOR_NAMES.threadActivities, ORCHESTRATION_PROJECTOR_NAMES.threadSessions, ORCHESTRATION_PROJECTOR_NAMES.checkpoints, ] as const; function maxIso(left: string | null, right: string): string { if (left === null) { return right; } return left > right ? left : right; } function escapeLikePattern(value: string): string { return value.replaceAll("!", "!!").replaceAll("%", "!%").replaceAll("_", "!_"); } function foldAsciiCase(value: string): string { return value.replace(/[A-Z]/g, (character) => character.toLowerCase()); } function buildSearchSnippet(text: string, query: string): string { const normalizedText = text.replace(/\s+/g, " ").trim(); if (normalizedText.length <= 240) { return normalizedText; } const normalizedQuery = foldAsciiCase(query.replace(/\s+/g, " ").trim()); const matchIndex = foldAsciiCase(normalizedText).indexOf(normalizedQuery); const bodyLength = 236; const idealStart = Math.max(0, matchIndex - 72); const start = Math.min(idealStart, normalizedText.length - bodyLength); const end = Math.min(normalizedText.length, start + bodyLength); return `${start > 0 ? "…" : ""}${normalizedText.slice(start, end)}${ end < normalizedText.length ? "…" : "" }`; } function computeSnapshotSequence( stateRows: ReadonlyArray<Schema.Schema.Type<typeof ProjectionStateDbRowSchema>>, ): number { if (stateRows.length === 0) { return 0; } const sequenceByProjector = new Map( stateRows.map((row) => [row.projector, row.lastAppliedSequence] as const), ); let minSequence = Number.POSITIVE_INFINITY; for (const projector of REQUIRED_SNAPSHOT_PROJECTORS) { const sequence = sequenceByProjector.get(projector); if (sequence === undefined) { return 0; } if (sequence < minSequence) { minSequence = sequence; } } return Number.isFinite(minSequence) ? minSequence : 0; } function mapLatestTurn( row: Schema.Schema.Type<typeof ProjectionLatestTurnDbRowSchema>, ): OrchestrationLatestTurn { return { turnId: row.turnId, state: row.state === "error" ? "error" : row.state === "interrupted" ? "interrupted" : row.state === "completed" ? "completed" : "running", requestedAt: row.requestedAt, startedAt: row.startedAt, completedAt: row.completedAt, assistantMessageId: row.assistantMessageId, ...(row.sourceProposedPlanThreadId !== null && row.sourceProposedPlanId !== null ? { sourceProposedPlan: { threadId: row.sourceProposedPlanThreadId, planId: row.sourceProposedPlanId, }, } : {}), }; } function mapTitleRegeneration(row: Schema.Schema.Type<typeof ProjectionThreadDbRowSchema>) { return row.titleRegenerationRequestId != null && row.titleRegenerationStartedAt != null ? { requestId: row.titleRegenerationRequestId, startedAt: row.titleRegenerationStartedAt, } : null; } function mapSessionRow( row: Schema.Schema.Type<typeof ProjectionThreadSessionDbRowSchema>, ): OrchestrationSession { return { threadId: row.threadId, status: row.status, providerName: row.providerName, ...(row.providerInstanceId !== null ? { providerInstanceId: row.providerInstanceId } : {}), runtimeMode: row.runtimeMode, activeTurnId: row.activeTurnId, lastError: row.lastError, updatedAt: row.updatedAt, }; } function mapProjectShellRow( row: Schema.Schema.Type<typeof ProjectionProjectDbRowSchema>, repositoryIdentity: OrchestrationProject["repositoryIdentity"], ): OrchestrationProjectShell { return { id: row.projectId, title: row.title, workspaceRoot: row.workspaceRoot, repositoryIdentity, defaultModelSelection: row.defaultModelSelection, defaultThreadEnvMode: row.defaultThreadEnvMode, autoPull: row.autoPull === 1, faviconPath: row.faviconPath ?? null, projectIcon: row.projectIcon ?? null, scripts: row.scripts, createdAt: row.createdAt, updatedAt: row.updatedAt, }; } function mapProposedPlanRow( row: Schema.Schema.Type<typeof ProjectionThreadProposedPlanDbRowSchema>, ): OrchestrationProposedPlan { return { id: row.planId, turnId: row.turnId, planMarkdown: row.planMarkdown, implementedAt: row.implementedAt, implementationThreadId: row.implementationThreadId, createdAt: row.createdAt, updatedAt: row.updatedAt, }; } function mapPullRequestRow( row: Schema.Schema.Type<typeof ProjectionThreadPullRequestDbRowSchema>, ): ThreadPullRequestLink { return { host: row.host, repository: row.repository, number: row.number, url: row.url, source: row.source, linkedAt: row.linkedAt, snapshot: row.snapshot, stack: row.stack, }; } function groupPullRequestRowsByThread( rows: ReadonlyArray<Schema.Schema.Type<typeof ProjectionThreadPullRequestDbRowSchema>>, ): Map<string, Array<ThreadPullRequestLink>> { const byThread = new Map<string, Array<ThreadPullRequestLink>>(); for (const row of rows) { const links = byThread.get(row.threadId) ?? []; links.push(mapPullRequestRow(row)); byThread.set(row.threadId, links); } return byThread; } /** * The link array plus the legacy single-link field derived from it, so clients * from before `pullRequests` keep seeing the thread's current pull request. */ function mapThreadPullRequests( pullRequests: ReadonlyArray<ThreadPullRequestLink>, projectId: ProjectId, identity?: OrchestrationProject["repositoryIdentity"], ): Pick<OrchestrationThread, "pullRequests" | "linkedPullRequest"> { const linkedPullRequest = legacyLinkedPullRequestOf(pullRequests, projectId, identity); return { pullRequests, ...(linkedPullRequest === null ? {} : { linkedPullRequest }), }; } function mapThreadActivityRow( row: Schema.Schema.Type<typeof ProjectionThreadActivityDbRowSchema>, ): OrchestrationThreadActivity { return { id: row.activityId, tone: row.tone, kind: row.kind, summary: row.summary, payload: row.payload, turnId: row.turnId, createdAt: row.createdAt, ...(row.sequence !== null ? { sequence: row.sequence } : {}), }; } function toPersistenceSqlOrDecodeError(sqlOperation: string, decodeOperation: string) { return (cause: unknown): ProjectionRepositoryError => Schema.isSchemaError(cause) ? toPersistenceDecodeError(decodeOperation)(cause) : toPersistenceSqlError(sqlOperation)(cause); } const makeProjectionSnapshotQuery = Effect.gen(function* () { const threadBackgroundLiveness = yield* ThreadBackgroundLivenessService; const threadPlanProgress = yield* ThreadPlanProgressService; const sql = yield* SqlClient.SqlClient; const repositoryIdentityResolver = yield* RepositoryIdentityResolver.RepositoryIdentityResolver; const repositoryIdentityResolutionConcurrency = 4; const resolveRepositoryIdentitiesForProjects = Effect.fn( "ProjectionSnapshotQuery.resolveRepositoryIdentitiesForProjects", )(function* ( projectRows: ReadonlyArray<Schema.Schema.Type<typeof ProjectionProjectDbRowSchema>>, options?: { readonly includeDeleted?: boolean; }, ) { const filteredProjectRows = options?.includeDeleted === true ? projectRows : projectRows.filter((row) => row.deletedAt === null); const uniqueWorkspaceRoots = [...new Set(filteredProjectRows.map((row) => row.workspaceRoot))];