or3-provider-sqlite 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ import { sql } from "kysely";
2
+ export async function up(db) {
3
+ await sql`
4
+ CREATE TABLE IF NOT EXISTS background_jobs (
5
+ id TEXT PRIMARY KEY,
6
+ user_id TEXT NOT NULL,
7
+ thread_id TEXT NOT NULL,
8
+ message_id TEXT NOT NULL,
9
+ model TEXT NOT NULL,
10
+ kind TEXT,
11
+ status TEXT NOT NULL,
12
+ content TEXT NOT NULL DEFAULT '',
13
+ chunks_received INTEGER NOT NULL DEFAULT 0,
14
+ started_at INTEGER NOT NULL,
15
+ last_activity_at INTEGER NOT NULL,
16
+ completed_at INTEGER,
17
+ error TEXT,
18
+ tool_calls_json TEXT,
19
+ workflow_state_json TEXT,
20
+ execution_json TEXT,
21
+ idempotency_key TEXT UNIQUE,
22
+ lease_owner TEXT,
23
+ lease_expires_at INTEGER,
24
+ attempts INTEGER NOT NULL DEFAULT 0
25
+ )
26
+ `.execute(db);
27
+ await sql`
28
+ CREATE INDEX IF NOT EXISTS background_jobs_active
29
+ ON background_jobs(status, last_activity_at)
30
+ `.execute(db);
31
+ await sql`
32
+ CREATE INDEX IF NOT EXISTS background_jobs_user_active
33
+ ON background_jobs(user_id, status)
34
+ `.execute(db);
35
+ await sql`
36
+ CREATE INDEX IF NOT EXISTS background_jobs_claim
37
+ ON background_jobs(status, lease_expires_at, started_at)
38
+ `.execute(db);
39
+ }
40
+ export async function down(db) {
41
+ await sql`DROP TABLE IF EXISTS background_jobs`.execute(db);
42
+ }
@@ -0,0 +1,7 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Durable admission cancellations. Creation and cancellation both check this
4
+ * table so a Stop that arrives before the job row commits cannot launch work.
5
+ */
6
+ export declare function up(db: Kysely<unknown>): Promise<void>;
7
+ export declare function down(db: Kysely<unknown>): Promise<void>;
@@ -0,0 +1,18 @@
1
+ import { sql } from "kysely";
2
+ export async function up(db) {
3
+ await sql`
4
+ CREATE TABLE IF NOT EXISTS background_admission_cancels (
5
+ user_id TEXT NOT NULL,
6
+ admission_id TEXT NOT NULL,
7
+ expires_at INTEGER NOT NULL,
8
+ PRIMARY KEY (user_id, admission_id)
9
+ )
10
+ `.execute(db);
11
+ await sql`
12
+ CREATE INDEX IF NOT EXISTS background_admission_cancels_expiry
13
+ ON background_admission_cancels(expires_at)
14
+ `.execute(db);
15
+ }
16
+ export async function down(db) {
17
+ await sql`DROP TABLE IF EXISTS background_admission_cancels`.execute(db);
18
+ }
@@ -0,0 +1,7 @@
1
+ import { type Kysely } from 'kysely';
2
+ /**
3
+ * Generation identity, durable history phase, and accumulated reasoning on
4
+ * background jobs. Reasoning is kept distinct from request reasoning config.
5
+ */
6
+ export declare function up(db: Kysely<unknown>): Promise<void>;
7
+ export declare function down(db: Kysely<unknown>): Promise<void>;
@@ -0,0 +1,25 @@
1
+ import { sql } from "kysely";
2
+ export async function up(db) {
3
+ await sql`
4
+ ALTER TABLE background_jobs
5
+ ADD COLUMN reasoning TEXT NOT NULL DEFAULT ''
6
+ `.execute(db);
7
+ await sql`
8
+ ALTER TABLE background_jobs
9
+ ADD COLUMN generation_id TEXT
10
+ `.execute(db);
11
+ await sql`
12
+ ALTER TABLE background_jobs
13
+ ADD COLUMN history_phase TEXT
14
+ `.execute(db);
15
+ await sql`
16
+ ALTER TABLE background_jobs
17
+ ADD COLUMN sync_provider_id TEXT
18
+ `.execute(db);
19
+ }
20
+ export async function down(db) {
21
+ await sql`ALTER TABLE background_jobs DROP COLUMN sync_provider_id`.execute(db);
22
+ await sql`ALTER TABLE background_jobs DROP COLUMN history_phase`.execute(db);
23
+ await sql`ALTER TABLE background_jobs DROP COLUMN generation_id`.execute(db);
24
+ await sql`ALTER TABLE background_jobs DROP COLUMN reasoning`.execute(db);
25
+ }
@@ -0,0 +1,4 @@
1
+ import { type Kysely } from 'kysely';
2
+ /** Durable replay receipts for canonical background-history transactions. */
3
+ export declare function up(db: Kysely<unknown>): Promise<void>;
4
+ export declare function down(db: Kysely<unknown>): Promise<void>;
@@ -0,0 +1,19 @@
1
+ import { sql } from "kysely";
2
+ export async function up(db) {
3
+ await sql`
4
+ CREATE TABLE background_generation_receipts (
5
+ id TEXT PRIMARY KEY,
6
+ workspace_id TEXT NOT NULL,
7
+ generation_id TEXT NOT NULL,
8
+ stage TEXT NOT NULL CHECK(stage IN ('admission', 'finalization')),
9
+ fingerprint TEXT NOT NULL,
10
+ outcome TEXT NOT NULL,
11
+ server_version INTEGER,
12
+ created_at INTEGER NOT NULL,
13
+ UNIQUE(workspace_id, generation_id, stage)
14
+ )
15
+ `.execute(db);
16
+ }
17
+ export async function down(db) {
18
+ await sql`DROP TABLE IF EXISTS background_generation_receipts`.execute(db);
19
+ }
@@ -188,6 +188,42 @@ export interface RateLimitsTable {
188
188
  window_started_at: number;
189
189
  expires_at: number;
190
190
  }
191
+ export interface BackgroundJobsTable {
192
+ id: string;
193
+ user_id: string;
194
+ thread_id: string;
195
+ message_id: string;
196
+ model: string;
197
+ kind: string | null;
198
+ status: 'streaming' | 'complete' | 'error' | 'aborted';
199
+ content: string;
200
+ reasoning: string;
201
+ generation_id: string | null;
202
+ history_phase: string | null;
203
+ sync_provider_id: string | null;
204
+ chunks_received: number;
205
+ started_at: number;
206
+ last_activity_at: number;
207
+ completed_at: number | null;
208
+ error: string | null;
209
+ tool_calls_json: string | null;
210
+ workflow_state_json: string | null;
211
+ execution_json: string | null;
212
+ idempotency_key: string | null;
213
+ lease_owner: string | null;
214
+ lease_expires_at: number | null;
215
+ attempts: number;
216
+ }
217
+ export interface BackgroundGenerationReceiptsTable {
218
+ id: string;
219
+ workspace_id: string;
220
+ generation_id: string;
221
+ stage: 'admission' | 'finalization';
222
+ fingerprint: string;
223
+ outcome: string;
224
+ server_version: number | null;
225
+ created_at: number;
226
+ }
191
227
  export interface AdminUsersTable {
192
228
  user_id: string;
193
229
  created_at: number;
@@ -216,6 +252,8 @@ export interface Or3SqliteDb {
216
252
  connect_device_authorizations: ConnectDeviceAuthorizationsTable;
217
253
  connect_environments: ConnectEnvironmentsTable;
218
254
  rate_limits: RateLimitsTable;
255
+ background_jobs: BackgroundJobsTable;
256
+ background_generation_receipts: BackgroundGenerationReceiptsTable;
219
257
  s_threads: SyncedEntityTable;
220
258
  s_messages: SyncedEntityTable;
221
259
  s_projects: SyncedEntityTable;
@@ -6,6 +6,7 @@ import { registerSyncGatewayAdapter } from "~~/server/sync/gateway/registry";
6
6
  import { registerWebhookStore } from "~~/server/utils/webhooks/store/registry";
7
7
  import { registerConnectStore } from "~~/server/connect/store/registry";
8
8
  import { registerRateLimitProvider } from "~~/server/utils/rate-limit/registry";
9
+ import { registerBackgroundJobProvider } from "~~/server/utils/background-jobs/registry";
9
10
  import { createSqliteAuthWorkspaceStore } from "../auth/sqlite-auth-workspace-store.js";
10
11
  import { createSqliteSyncGatewayAdapter } from "../sync/sqlite-sync-gateway-adapter.js";
11
12
  import { createSqliteWebhookStore } from "../webhooks/sqlite-webhook-store.js";
@@ -19,6 +20,7 @@ import { createSqliteConnectStore } from "../connect/sqlite-connect-store.js";
19
20
  import { getSqliteDriver, initializeSqliteDb } from "../db/kysely.js";
20
21
  import { runMigrations } from "../db/migrate.js";
21
22
  import { sqliteRateLimitProvider } from "../rate-limit/sqlite-provider.js";
23
+ import { sqliteBackgroundJobProvider } from "../background-jobs/sqlite-provider.js";
22
24
  import { useRuntimeConfig } from "#imports";
23
25
  const SQLITE_PROVIDER_ID = "sqlite";
24
26
  let d1RuntimeInitialization;
@@ -27,7 +29,8 @@ export default defineNitroPlugin(async (nitroApp) => {
27
29
  if (!config.auth?.enabled) return;
28
30
  const syncSelected = config.sync?.enabled === true && config.sync?.provider === SQLITE_PROVIDER_ID;
29
31
  const connectSelected = config.connect?.enabled === true && config.connect?.provider === SQLITE_PROVIDER_ID;
30
- if (!syncSelected && !connectSelected) return;
32
+ const backgroundJobsSelected = config.backgroundJobs?.enabled === true && config.backgroundJobs?.storageProvider === SQLITE_PROVIDER_ID;
33
+ if (!syncSelected && !connectSelected && !backgroundJobsSelected) return;
31
34
  const driver = getSqliteDriver();
32
35
  if (driver === "d1" && connectSelected) {
33
36
  throw new Error(
@@ -40,6 +43,10 @@ export default defineNitroPlugin(async (nitroApp) => {
40
43
  create: createSqliteAuthWorkspaceStore
41
44
  });
42
45
  registerRateLimitProvider(SQLITE_PROVIDER_ID, sqliteRateLimitProvider);
46
+ registerBackgroundJobProvider(
47
+ SQLITE_PROVIDER_ID,
48
+ sqliteBackgroundJobProvider
49
+ );
43
50
  if (syncSelected) {
44
51
  registerSyncGatewayAdapter({
45
52
  id: SQLITE_PROVIDER_ID,
@@ -11,3 +11,11 @@ export declare const SYNC_HISTORY_GC_POLICY: Readonly<{
11
11
  reason: "SQLite history GC is guarded by the verified snapshot-v1 retention contract.";
12
12
  }>;
13
13
  export declare function canRunSyncHistoryGc(): boolean;
14
+ export declare function computePullRetention(input: {
15
+ cursor: number;
16
+ oldestLogVersion: number | null;
17
+ highWatermark: number;
18
+ }): {
19
+ oldestRetainedVersion: number;
20
+ requiresSnapshot: boolean;
21
+ };
@@ -6,3 +6,10 @@ export const SYNC_HISTORY_GC_POLICY = Object.freeze({
6
6
  export function canRunSyncHistoryGc() {
7
7
  return SYNC_HISTORY_GC_POLICY.enabled && SYNC_HISTORY_GC_POLICY.snapshotBootstrapVerified;
8
8
  }
9
+ export function computePullRetention(input) {
10
+ const oldestRetainedVersion = input.oldestLogVersion ?? Math.max(0, input.highWatermark) + 1;
11
+ return {
12
+ oldestRetainedVersion,
13
+ requiresSnapshot: oldestRetainedVersion > 0 && input.cursor < Math.max(0, oldestRetainedVersion - 1)
14
+ };
15
+ }
@@ -7,14 +7,26 @@
7
7
  */
8
8
  import type { H3Event } from 'h3';
9
9
  import type { CanonicalStorageQueryRequest, CanonicalStorageQueryResponse, SyncGatewayAdapter, SyncMaintenanceState, UploadIntentConsumptionRequest, UploadIntentReservationRequest } from '~~/server/sync/gateway/types';
10
+ import type { AdmitChatGenerationResult, CanonicalGenerationSnapshot, CanonicalHistoryActor, ChatGenerationAdmissionEnvelope, FinalizeChatGenerationResult } from '~~/shared/chat/background-history';
10
11
  import type { PullRequest, PullResponse, PushBatch, PushResult, SnapshotRequest, SnapshotResponse } from '~~/shared/sync/types';
11
12
  export declare class SqliteSyncGatewayAdapter implements SyncGatewayAdapter {
12
13
  id: string;
13
- readonly capabilities: {
14
+ get capabilities(): {
14
15
  readonly snapshotBootstrap: "snapshot-v1";
15
16
  readonly historyRetention: "snapshot-v1";
17
+ readonly backgroundGenerationHistory?: undefined;
18
+ } | {
19
+ readonly snapshotBootstrap: "snapshot-v1";
20
+ readonly historyRetention: "snapshot-v1";
21
+ readonly backgroundGenerationHistory: "v1";
16
22
  };
17
23
  private get db();
24
+ private assertCanonicalActor;
25
+ admitChatGeneration(actor: CanonicalHistoryActor, input: ChatGenerationAdmissionEnvelope): Promise<AdmitChatGenerationResult>;
26
+ finalizeChatGeneration(actor: CanonicalHistoryActor, input: {
27
+ admission: ChatGenerationAdmissionEnvelope;
28
+ snapshot: CanonicalGenerationSnapshot;
29
+ }): Promise<FinalizeChatGenerationResult>;
18
30
  reserveUploadIntent(event: H3Event, input: UploadIntentReservationRequest): Promise<void>;
19
31
  consumeUploadIntent(event: H3Event, input: UploadIntentConsumptionRequest): Promise<void>;
20
32
  cancelUploadIntent(event: H3Event, input: {