@hiai-gg/docsmint 0.4.2 → 0.4.4

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.
@@ -198633,6 +198633,13 @@ var JOB_IDS = {
198633
198633
  init_names();
198634
198634
  var ACTIVE_STATUSES = ["pending", "processing", "retrying"];
198635
198635
  var postgresRunStore = {
198636
+ async isCancelled(input) {
198637
+ return withTenant({ userId: input.ownerId, role: "user", workspaceId: input.workspaceId }, async (tx) => {
198638
+ const boundary = input.workspaceId ? eq(documentPipelineRuns.workspaceId, input.workspaceId) : and(isNull(documentPipelineRuns.workspaceId), eq(documentPipelineRuns.ownerId, input.ownerId));
198639
+ const [run] = await tx.select({ status: documentPipelineRuns.status }).from(documentPipelineRuns).where(and(eq(documentPipelineRuns.generationId, input.generationId), boundary)).limit(1);
198640
+ return run?.status === "cancelled";
198641
+ });
198642
+ },
198636
198643
  async findOrCreate(input) {
198637
198644
  const ownerBoundary = input.workspaceId ? eq(documents.workspaceId, input.workspaceId) : and(isNull(documents.workspaceId), eq(documents.ownerId, input.ownerId));
198638
198645
  const runBoundary = input.workspaceId ? eq(documentPipelineRuns.workspaceId, input.workspaceId) : and(isNull(documentPipelineRuns.workspaceId), eq(documentPipelineRuns.ownerId, input.ownerId));
@@ -198691,11 +198698,24 @@ async function enqueueDocumentPipeline(input, dependencies) {
198691
198698
  requestedAt: requestedAt.toISOString(),
198692
198699
  source: parsed.source
198693
198700
  };
198694
- await deps.prepareQueue.add("prepare", job2, {
198701
+ const queued = await deps.prepareQueue.add("prepare", job2, {
198695
198702
  ...DEFAULT_JOB_OPTIONS,
198696
198703
  jobId: JOB_IDS.prepare(parsed.documentId, run.generationId, parsed.workspaceId),
198697
198704
  priority: SOURCE_PRIORITY[parsed.source]
198698
198705
  });
198706
+ if (await deps.runs.isCancelled({
198707
+ ownerId: parsed.ownerId,
198708
+ generationId: run.generationId,
198709
+ workspaceId: parsed.workspaceId
198710
+ })) {
198711
+ try {
198712
+ await queued.remove();
198713
+ } catch (error53) {
198714
+ const message2 = error53 instanceof Error ? error53.message.toLowerCase() : "";
198715
+ if (!message2.includes("locked") && !message2.includes("active") && !message2.includes("not found"))
198716
+ throw error53;
198717
+ }
198718
+ }
198699
198719
  }
198700
198720
  return { generationId: run.generationId, deduplicated: !created };
198701
198721
  }
@@ -212786,6 +212806,9 @@ function profileId(profile) {
212786
212806
  }
212787
212807
  async function activateEmbeddingGeneration(documentId, generationId, expectedChunks, profile) {
212788
212808
  await withTenant(WORKER_TENANT, async (tx) => {
212809
+ const run = await tx.select({ status: documentPipelineRuns.status }).from(documentPipelineRuns).where(eq(documentPipelineRuns.generationId, generationId)).limit(1).for("update");
212810
+ if (run[0]?.status === "cancelled")
212811
+ throw new Error("pipeline_cancelled");
212789
212812
  const documentRows = await tx.select({ pending: documents.pendingEmbeddingGeneration }).from(documents).where(eq(documents.id, documentId)).limit(1);
212790
212813
  if (documentRows[0]?.pending !== generationId) {
212791
212814
  throw new Error("generation_not_pending");
@@ -212823,6 +212846,18 @@ async function activateEmbeddingGeneration(documentId, generationId, expectedChu
212823
212846
  // ../../backend/src/queue/adapters.ts
212824
212847
  init_config();
212825
212848
 
212849
+ // ../../backend/src/lib/graph/delete-document-state.ts
212850
+ async function deleteDocumentGraphState(documentId) {
212851
+ const sql6 = await getGraphDb();
212852
+ if (!sql6)
212853
+ return;
212854
+ const literal2 = JSON.stringify(documentId);
212855
+ await sql6.begin(async (tx) => {
212856
+ await tx.unsafe("SET LOCAL search_path = ag_catalog, public");
212857
+ await tx.unsafe(`SELECT * FROM cypher('docs_graph', $$ MATCH (d:Document {id: ${literal2}}) DETACH DELETE d RETURN 1 $$) AS (deleted agtype)`);
212858
+ });
212859
+ }
212860
+
212826
212861
  // ../../backend/src/lib/graph/extract-entities.ts
212827
212862
  init_zod();
212828
212863
  init_config();
@@ -213297,7 +213332,7 @@ async function setStageStatus(generationId, stage, status2, errorCode) {
213297
213332
  ...stagePatch(stage, status2),
213298
213333
  ...errorCode ? { errorCode } : {},
213299
213334
  updatedAt: new Date
213300
- }).where(eq(documentPipelineRuns.generationId, generationId)));
213335
+ }).where(and(eq(documentPipelineRuns.generationId, generationId), ne(documentPipelineRuns.status, "cancelled"))));
213301
213336
  }
213302
213337
  async function markRunStale(generationId, stage, errorCode) {
213303
213338
  await withTenant(admin, (tx) => tx.update(documentPipelineRuns).set({
@@ -213305,12 +213340,15 @@ async function markRunStale(generationId, stage, errorCode) {
213305
213340
  status: "failed",
213306
213341
  errorCode,
213307
213342
  updatedAt: new Date
213308
- }).where(eq(documentPipelineRuns.generationId, generationId)));
213343
+ }).where(and(eq(documentPipelineRuns.generationId, generationId), ne(documentPipelineRuns.status, "cancelled"))));
213309
213344
  }
213310
213345
  async function claimPendingBatches(job2, limit) {
213311
213346
  return withTenant({ ...admin, workspaceId: job2.workspaceId }, async (tx) => {
213312
- const [run] = await tx.select({ totalBatches: documentPipelineRuns.totalBatches }).from(documentPipelineRuns).where(eq(documentPipelineRuns.generationId, job2.generationId)).limit(1);
213313
- if (!run || limit < 1)
213347
+ const [run] = await tx.select({
213348
+ totalBatches: documentPipelineRuns.totalBatches,
213349
+ status: documentPipelineRuns.status
213350
+ }).from(documentPipelineRuns).where(eq(documentPipelineRuns.generationId, job2.generationId)).limit(1);
213351
+ if (!run || run.status === "cancelled" || limit < 1)
213314
213352
  return [];
213315
213353
  const candidates = await tx.select({
213316
213354
  batchIndex: documentPipelineBatches.batchIndex,
@@ -213340,8 +213378,24 @@ async function claimPendingBatches(job2, limit) {
213340
213378
  }
213341
213379
  function createPipelineStageDependencies(redisUrl) {
213342
213380
  const queue2 = (stage) => getPipelineQueue(stage, redisUrl);
213381
+ const enqueueIfActive = async (stage, name, data, options) => {
213382
+ if ((await getRun(data.generationId))?.status === "cancelled")
213383
+ return null;
213384
+ const queued = await queue2(stage).add(name, data, options);
213385
+ if ((await getRun(data.generationId))?.status !== "cancelled")
213386
+ return queued;
213387
+ try {
213388
+ await queued.remove();
213389
+ } catch (error53) {
213390
+ const message2 = error53 instanceof Error ? error53.message.toLowerCase() : "";
213391
+ if (!message2.includes("locked") && !message2.includes("active") && !message2.includes("not found"))
213392
+ throw error53;
213393
+ }
213394
+ return null;
213395
+ };
213343
213396
  return {
213344
213397
  prepare: {
213398
+ isCancelled: async (job2) => (await getRun(job2.generationId))?.status === "cancelled",
213345
213399
  claimPendingBatches,
213346
213400
  markStale: (job2, errorCode) => markRunStale(job2.generationId, "prepare", errorCode),
213347
213401
  async loadDocument({ documentId, ownerId, workspaceId }) {
@@ -213365,11 +213419,13 @@ function createPipelineStageDependencies(redisUrl) {
213365
213419
  if ((batches.at(-1)?.chunkEnd ?? 0) !== totalChunks) {
213366
213420
  return "stale";
213367
213421
  }
213368
- const [run] = await tx.select({ status: documentPipelineRuns.prepareStatus }).from(documentPipelineRuns).where(and(eq(documentPipelineRuns.generationId, job2.generationId), tenantOwnerCondition(documentPipelineRuns.ownerId, documentPipelineRuns.workspaceId, jobTenant(job2)), eq(documentPipelineRuns.revision, job2.revision))).limit(1);
213422
+ const [run] = await tx.select({ status: documentPipelineRuns.prepareStatus }).from(documentPipelineRuns).where(and(eq(documentPipelineRuns.generationId, job2.generationId), tenantOwnerCondition(documentPipelineRuns.ownerId, documentPipelineRuns.workspaceId, jobTenant(job2)), eq(documentPipelineRuns.revision, job2.revision))).limit(1).for("update");
213369
213423
  if (!run)
213370
213424
  return "stale";
213371
213425
  if (run.status === "ready")
213372
213426
  return "duplicate";
213427
+ if (run.status === "cancelled")
213428
+ return "stale";
213373
213429
  await tx.update(documents).set({
213374
213430
  pendingEmbeddingGeneration: job2.generationId,
213375
213431
  embeddingStatus: "processing",
@@ -213391,12 +213447,15 @@ function createPipelineStageDependencies(redisUrl) {
213391
213447
  status: "processing",
213392
213448
  totalBatches: batches.length,
213393
213449
  updatedAt: new Date
213394
- }).where(eq(documentPipelineRuns.generationId, job2.generationId));
213450
+ }).where(and(eq(documentPipelineRuns.generationId, job2.generationId), ne(documentPipelineRuns.status, "cancelled")));
213395
213451
  return "prepared";
213396
213452
  });
213397
213453
  },
213398
213454
  async completeEmpty(job2) {
213399
213455
  await withTenant({ ...admin, workspaceId: job2.workspaceId }, async (tx) => {
213456
+ const [run] = await tx.select({ status: documentPipelineRuns.status }).from(documentPipelineRuns).where(and(eq(documentPipelineRuns.generationId, job2.generationId), eq(documentPipelineRuns.ownerId, job2.ownerId))).limit(1).for("update");
213457
+ if (!run || run.status === "cancelled")
213458
+ return;
213400
213459
  const activated = await tx.update(documents).set({
213401
213460
  activeEmbeddingGeneration: job2.generationId,
213402
213461
  pendingEmbeddingGeneration: null,
@@ -213416,16 +213475,17 @@ function createPipelineStageDependencies(redisUrl) {
213416
213475
  });
213417
213476
  },
213418
213477
  enqueueEmbed(data, options) {
213419
- return queue2("embed").add("embed", data, options);
213478
+ return enqueueIfActive("embed", "embed", data, options);
213420
213479
  },
213421
213480
  enqueueGraph(data, options) {
213422
- return queue2("graph").add("graph", data, options);
213481
+ return enqueueIfActive("graph", "graph", data, options);
213423
213482
  }
213424
213483
  },
213425
213484
  embed: {
213485
+ isCancelled: async (job2) => (await getRun(job2.generationId))?.status === "cancelled",
213426
213486
  claimPendingBatches,
213427
213487
  enqueueEmbed(data, options) {
213428
- return queue2("embed").add("embed", data, options);
213488
+ return enqueueIfActive("embed", "embed", data, options);
213429
213489
  },
213430
213490
  markStale: (job2, errorCode) => markRunStale(job2.generationId, "embed", errorCode),
213431
213491
  async loadDocument({ documentId, ownerId, generationId, workspaceId }) {
@@ -213449,8 +213509,9 @@ function createPipelineStageDependencies(redisUrl) {
213449
213509
  getEmbedding: (text4) => withProviderPermit(providerProfile(`embedding:${config3.EMBEDDING_MODEL ?? "default"}`), "embed", () => getEmbedding(text4)),
213450
213510
  async storeBatch({ job: job2, rows }) {
213451
213511
  return withTenant({ ...admin, workspaceId: job2.workspaceId }, async (tx) => {
213512
+ const [run] = await tx.select({ status: documentPipelineRuns.status }).from(documentPipelineRuns).where(eq(documentPipelineRuns.generationId, job2.generationId)).limit(1).for("update");
213452
213513
  const [batch] = await tx.select({ status: documentPipelineBatches.status }).from(documentPipelineBatches).where(and(eq(documentPipelineBatches.generationId, job2.generationId), eq(documentPipelineBatches.batchIndex, job2.batchIndex))).limit(1);
213453
- if (!batch)
213514
+ if (!batch || run?.status === "cancelled")
213454
213515
  return "stale";
213455
213516
  if (batch.status === "ready")
213456
213517
  return "duplicate";
@@ -213474,6 +213535,9 @@ function createPipelineStageDependencies(redisUrl) {
213474
213535
  },
213475
213536
  async completeBatch({ job: job2, profile }) {
213476
213537
  return withTenant(admin, async (tx) => {
213538
+ const [run] = await tx.select({ status: documentPipelineRuns.status }).from(documentPipelineRuns).where(and(eq(documentPipelineRuns.generationId, job2.generationId), eq(documentPipelineRuns.ownerId, job2.ownerId))).limit(1).for("update");
213539
+ if (!run || run.status === "cancelled")
213540
+ return { allBatchesComplete: false, totalChunks: 0 };
213477
213541
  await tx.update(documentPipelineBatches).set({
213478
213542
  status: "ready",
213479
213543
  embeddingProfile: profile.profile,
@@ -213489,7 +213553,7 @@ function createPipelineStageDependencies(redisUrl) {
213489
213553
  completedBatches: counts?.ready ?? 0,
213490
213554
  embedStatus: (counts?.ready ?? 0) === (counts?.total ?? -1) ? "ready" : "processing",
213491
213555
  updatedAt: new Date
213492
- }).where(eq(documentPipelineRuns.generationId, job2.generationId));
213556
+ }).where(and(eq(documentPipelineRuns.generationId, job2.generationId), ne(documentPipelineRuns.status, "cancelled")));
213493
213557
  return {
213494
213558
  allBatchesComplete: (counts?.total ?? 0) > 0 && counts?.ready === counts?.total,
213495
213559
  totalChunks: chunks?.total ?? 0
@@ -213501,10 +213565,11 @@ function createPipelineStageDependencies(redisUrl) {
213501
213565
  await setStageStatus(input.generationId, "embed", "ready");
213502
213566
  },
213503
213567
  enqueueGraph(data, options) {
213504
- return queue2("graph").add("graph", data, options);
213568
+ return enqueueIfActive("graph", "graph", data, options);
213505
213569
  }
213506
213570
  },
213507
213571
  graph: {
213572
+ isCancelled: async (job2) => (await getRun(job2.generationId))?.status === "cancelled",
213508
213573
  async getRun(job2) {
213509
213574
  const run = await getRun(job2.generationId);
213510
213575
  return run ? {
@@ -213524,10 +213589,15 @@ function createPipelineStageDependencies(redisUrl) {
213524
213589
  throw new Error("Pipeline document not found");
213525
213590
  await withProviderPermit(providerProfile(`graph:${config3.GRAPH_EXTRACT_MODEL ?? "default"}`), "graph", () => extractEntities(doc3.content ?? "", job2.documentId));
213526
213591
  },
213592
+ async compensateExtract(job2) {
213593
+ const owned = await withTenant({ ...admin, workspaceId: job2.workspaceId }, async (tx) => tx.select({ id: documents.id }).from(documents).where(and(eq(documents.id, job2.documentId), tenantOwnerCondition(documents.ownerId, documents.workspaceId, jobTenant(job2)))).limit(1));
213594
+ if (owned.length === 1)
213595
+ await deleteDocumentGraphState(job2.documentId);
213596
+ },
213527
213597
  setGraphStatus: (generationId, status2, errorCode) => setStageStatus(generationId, "graph", status2, errorCode),
213528
213598
  async enqueueSummarize(job2) {
213529
213599
  const data = { ...job2, stage: "summarize" };
213530
- await queue2("summarize").add("summarize", data, {
213600
+ await enqueueIfActive("summarize", "summarize", data, {
213531
213601
  ...DEFAULT_JOB_OPTIONS,
213532
213602
  jobId: JOB_IDS.summarize(job2.generationId, job2.workspaceId),
213533
213603
  priority: SOURCE_PRIORITY[job2.source]
@@ -213535,6 +213605,7 @@ function createPipelineStageDependencies(redisUrl) {
213535
213605
  }
213536
213606
  },
213537
213607
  summarize: {
213608
+ isCancelled: async (job2) => (await getRun(job2.generationId))?.status === "cancelled",
213538
213609
  async getRun(job2) {
213539
213610
  const run = await getRun(job2.generationId);
213540
213611
  return run ? {
@@ -213550,7 +213621,7 @@ function createPipelineStageDependencies(redisUrl) {
213550
213621
  setSummaryStatus: (generationId, status2, errorCode) => setStageStatus(generationId, "summarize", status2, errorCode),
213551
213622
  async enqueueFinalize(job2) {
213552
213623
  const data = { ...job2, stage: "finalize" };
213553
- await queue2("finalize").add("finalize", data, {
213624
+ await enqueueIfActive("finalize", "finalize", data, {
213554
213625
  ...DEFAULT_JOB_OPTIONS,
213555
213626
  jobId: JOB_IDS.finalize(job2.generationId, job2.workspaceId),
213556
213627
  priority: SOURCE_PRIORITY[job2.source]
@@ -213578,7 +213649,7 @@ function createPipelineStageDependencies(redisUrl) {
213578
213649
  ...errorCode ? { errorCode } : {},
213579
213650
  completedAt: new Date,
213580
213651
  updatedAt: new Date
213581
- }).where(eq(documentPipelineRuns.generationId, generationId)));
213652
+ }).where(and(eq(documentPipelineRuns.generationId, generationId), ne(documentPipelineRuns.status, "cancelled"))));
213582
213653
  }
213583
213654
  }
213584
213655
  };
@@ -213837,6 +213908,8 @@ init_esm();
213837
213908
  init_names();
213838
213909
  async function processEmbedJob(rawJob, deps) {
213839
213910
  const job2 = embedBatchJobSchema.parse(rawJob.data);
213911
+ if (await deps.isCancelled?.(job2))
213912
+ return { status: "cancelled", activated: false };
213840
213913
  const document2 = await deps.loadDocument(job2);
213841
213914
  if (!document2 || document2.revision !== job2.revision || document2.pendingGenerationId !== job2.generationId) {
213842
213915
  await deps.markStale(job2, "stale_revision");
@@ -213866,6 +213939,8 @@ ${document2.content}`);
213866
213939
  throw new Error("empty_batch");
213867
213940
  if (results.some(({ result }) => result.model !== first.model || result.profile !== first.profile || result.dimensions !== first.dimensions))
213868
213941
  throw new Error("mixed_embedding_profile");
213942
+ if (await deps.isCancelled?.(job2))
213943
+ return { status: "cancelled", activated: false };
213869
213944
  const stored = await deps.storeBatch({
213870
213945
  job: job2,
213871
213946
  rows: results.map(({ index: index2, chunk, result }) => ({
@@ -213889,9 +213964,13 @@ ${document2.content}`);
213889
213964
  profile: first.profile,
213890
213965
  dimensions: first.dimensions
213891
213966
  };
213967
+ if (await deps.isCancelled?.(job2))
213968
+ return { status: "cancelled", activated: false };
213892
213969
  const completion = await deps.completeBatch({ job: job2, profile });
213893
213970
  if (!completion.allBatchesComplete) {
213894
213971
  const next = await deps.claimPendingBatches(job2, 1);
213972
+ if (await deps.isCancelled?.(job2))
213973
+ return { status: "cancelled", activated: false };
213895
213974
  await Promise.all(next.map((data) => deps.enqueueEmbed(data, {
213896
213975
  ...DEFAULT_JOB_OPTIONS,
213897
213976
  jobId: JOB_IDS.embed(job2.generationId, data.batchIndex, job2.workspaceId),
@@ -213899,12 +213978,16 @@ ${document2.content}`);
213899
213978
  })));
213900
213979
  return { status: "stored", activated: false };
213901
213980
  }
213981
+ if (await deps.isCancelled?.(job2))
213982
+ return { status: "cancelled", activated: false };
213902
213983
  await deps.activateGeneration({
213903
213984
  documentId: job2.documentId,
213904
213985
  generationId: job2.generationId,
213905
213986
  totalChunks: completion.totalChunks,
213906
213987
  profile
213907
213988
  });
213989
+ if (await deps.isCancelled?.(job2))
213990
+ return { status: "cancelled", activated: false };
213908
213991
  await deps.enqueueGraph({ ...job2, stage: "graph" }, {
213909
213992
  ...DEFAULT_JOB_OPTIONS,
213910
213993
  jobId: JOB_IDS.graph(job2.generationId, job2.workspaceId),
@@ -213958,6 +214041,8 @@ function createFinalizeWorker(deps) {
213958
214041
  function createGraphWorker(deps) {
213959
214042
  return async function processGraphJob(input) {
213960
214043
  const job2 = graphJobSchema.parse(input);
214044
+ if (await deps.isCancelled?.(job2))
214045
+ return;
213961
214046
  const run = await deps.getRun(job2);
213962
214047
  if (!run)
213963
214048
  throw new Error("Pipeline run not found");
@@ -213969,18 +214054,33 @@ function createGraphWorker(deps) {
213969
214054
  return;
213970
214055
  }
213971
214056
  if (run.embedStatus !== "ready") {
214057
+ if (await deps.isCancelled?.(job2))
214058
+ return;
213972
214059
  await deps.setGraphStatus(job2.generationId, "skipped", "embedding_not_ready");
213973
- await deps.enqueueSummarize(job2);
214060
+ if (!await deps.isCancelled?.(job2))
214061
+ await deps.enqueueSummarize(job2);
213974
214062
  return;
213975
214063
  }
214064
+ if (await deps.isCancelled?.(job2))
214065
+ return;
213976
214066
  await deps.setGraphStatus(job2.generationId, "processing");
213977
214067
  try {
214068
+ if (await deps.isCancelled?.(job2))
214069
+ return;
213978
214070
  await deps.extract(job2);
214071
+ if (await deps.isCancelled?.(job2)) {
214072
+ await deps.compensateExtract?.(job2);
214073
+ return;
214074
+ }
213979
214075
  await deps.setGraphStatus(job2.generationId, "ready");
213980
- await deps.enqueueSummarize(job2);
214076
+ if (!await deps.isCancelled?.(job2))
214077
+ await deps.enqueueSummarize(job2);
213981
214078
  } catch (error53) {
214079
+ if (await deps.isCancelled?.(job2))
214080
+ throw error53;
213982
214081
  await deps.setGraphStatus(job2.generationId, "failed", error53 instanceof Error ? error53.name : "graph_failed");
213983
- await deps.enqueueSummarize(job2);
214082
+ if (!await deps.isCancelled?.(job2))
214083
+ await deps.enqueueSummarize(job2);
213984
214084
  throw error53;
213985
214085
  }
213986
214086
  };
@@ -213991,6 +214091,8 @@ init_esm();
213991
214091
  init_names();
213992
214092
  async function processPrepareJob(rawJob, deps, batchSize = DEFAULT_EMBED_CHUNKS_PER_JOB, maxActiveBatches = 2) {
213993
214093
  const job2 = prepareJobSchema.parse(rawJob.data);
214094
+ if (await deps.isCancelled?.(job2))
214095
+ return { status: "cancelled", batches: 0 };
213994
214096
  const document2 = await deps.loadDocument(job2);
213995
214097
  if (!document2 || document2.revision !== job2.revision) {
213996
214098
  await deps.markStale(job2, "stale_revision");
@@ -214004,6 +214106,8 @@ ${document2.content}`);
214004
214106
  chunkStart: batchIndex * batchSize,
214005
214107
  chunkEnd: Math.min(chunks.length, (batchIndex + 1) * batchSize)
214006
214108
  }));
214109
+ if (await deps.isCancelled?.(job2))
214110
+ return { status: "cancelled", batches: 0 };
214007
214111
  const state = await deps.prepareRun({
214008
214112
  job: job2,
214009
214113
  totalChunks: chunks.length,
@@ -214015,7 +214119,11 @@ ${document2.content}`);
214015
214119
  return { status: state, batches: batches.length };
214016
214120
  }
214017
214121
  if (batches.length === 0) {
214122
+ if (await deps.isCancelled?.(job2))
214123
+ return { status: "cancelled", batches: 0 };
214018
214124
  await deps.completeEmpty(job2);
214125
+ if (await deps.isCancelled?.(job2))
214126
+ return { status: "cancelled", batches: 0 };
214019
214127
  await deps.enqueueGraph({ ...job2, stage: "graph" }, {
214020
214128
  ...DEFAULT_JOB_OPTIONS,
214021
214129
  jobId: JOB_IDS.graph(job2.generationId, job2.workspaceId),
@@ -214024,6 +214132,8 @@ ${document2.content}`);
214024
214132
  return { status: "prepared", batches: 0 };
214025
214133
  }
214026
214134
  const initial = await deps.claimPendingBatches(job2, maxActiveBatches);
214135
+ if (await deps.isCancelled?.(job2))
214136
+ return { status: "cancelled", batches: batches.length };
214027
214137
  await Promise.all(initial.map((data) => deps.enqueueEmbed(data, {
214028
214138
  ...DEFAULT_JOB_OPTIONS,
214029
214139
  jobId: JOB_IDS.embed(job2.generationId, data.batchIndex, data.workspaceId),
@@ -214042,6 +214152,8 @@ function createPrepareWorker(redisUrl, deps, options = {}) {
214042
214152
  function createSummarizeWorker(deps) {
214043
214153
  return async function processSummarizeJob(input) {
214044
214154
  const job2 = summarizeJobSchema.parse(input);
214155
+ if (await deps.isCancelled?.(job2))
214156
+ return;
214045
214157
  const run = await deps.getRun(job2);
214046
214158
  if (!run)
214047
214159
  throw new Error("Pipeline run not found");
@@ -214053,19 +214165,31 @@ function createSummarizeWorker(deps) {
214053
214165
  return;
214054
214166
  }
214055
214167
  if (!deps.enabled()) {
214168
+ if (await deps.isCancelled?.(job2))
214169
+ return;
214056
214170
  await deps.setSummaryStatus(job2.generationId, "skipped");
214057
- await deps.enqueueFinalize(job2);
214171
+ if (!await deps.isCancelled?.(job2))
214172
+ await deps.enqueueFinalize(job2);
214058
214173
  return;
214059
214174
  }
214175
+ if (await deps.isCancelled?.(job2))
214176
+ return;
214060
214177
  await deps.setSummaryStatus(job2.generationId, "processing");
214061
214178
  try {
214179
+ if (await deps.isCancelled?.(job2))
214180
+ return;
214062
214181
  await deps.summarize(job2);
214182
+ if (await deps.isCancelled?.(job2))
214183
+ return;
214063
214184
  await deps.setSummaryStatus(job2.generationId, "ready");
214064
214185
  } catch (error53) {
214186
+ if (await deps.isCancelled?.(job2))
214187
+ return;
214065
214188
  await deps.setSummaryStatus(job2.generationId, "failed", error53 instanceof Error ? error53.name : "summary_failed");
214066
214189
  throw error53;
214067
214190
  }
214068
- await deps.enqueueFinalize(job2);
214191
+ if (!await deps.isCancelled?.(job2))
214192
+ await deps.enqueueFinalize(job2);
214069
214193
  };
214070
214194
  }
214071
214195
 
@@ -214237,7 +214361,7 @@ var swaggerConfig = {
214237
214361
  documentation: {
214238
214362
  info: {
214239
214363
  title: "DocsMint API",
214240
- version: "0.4.2",
214364
+ version: "0.4.4",
214241
214365
  description: "Self-hosted AI-first documentation platform. Full-text + semantic search, version history, sharing, and folder organization.",
214242
214366
  contact: { name: "HiAi-gg", url: "https://github.com/HiAi-gg/docsmint" },
214243
214367
  license: {
@@ -0,0 +1,11 @@
1
+ export type AccountPipelineCancellation = Readonly<{
2
+ cancelActorPipeline(actorUserId: string, signal?: AbortSignal): Promise<{
3
+ runs: number;
4
+ jobs: number;
5
+ }>;
6
+ close(): Promise<void>;
7
+ }>;
8
+ export declare function createAccountPipelineCancellation(options: {
9
+ redisUrl: string;
10
+ databaseUrl: string;
11
+ }): AccountPipelineCancellation;