@semiont/jobs 0.6.8 → 0.6.9

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.
@@ -1,4 +1,4 @@
1
- import { JOB_TYPES, replyChannelsFor, createTomlConfigLoader, didToAgent, baseUrl, STARTUP_FETCH_RETRY, retryWithBackoff, serviceAccountToken, isTransientFetchError, isObject, isString, isNumber, RETRY_RULES, resourceId, getPrimaryMediaType, isGenerationJobParams, capabilitiesOf, assembleAnnotation, findClaimSpan, busRequest, BusRequestError, isArray, textSourceOf, yieldsGeometryOf, decodeRepresentation, GENERATABLE_MEDIA_TYPES, locate, createFragmentSelector, deriveViews, annotationId, estimateTokens, reconcileSelector, getLocaleEnglishName, cutChunk, chunkText } from '@semiont/core';
1
+ import { replyChannelsFor, createTomlConfigLoader, JOB_TYPES, didToAgent, baseUrl, STARTUP_FETCH_RETRY, retryWithBackoff, serviceAccountToken, isTransientFetchError, isObject, isString, isNumber, RETRY_RULES, getPrimaryMediaType, isGenerationJobParams, capabilitiesOf, assembleAnnotation, findClaimSpan, busRequest, BusRequestError, textSourceOf, yieldsGeometryOf, decodeRepresentation, GENERATABLE_MEDIA_TYPES, locate, createFragmentSelector, deriveViews, isResourceId, estimateTokens, reconcileSelector, getLocaleEnglishName, cutChunk, chunkText } from '@semiont/core';
2
2
  import { archivistContentReads, extractPdfTextLayer, withinByteBudget, MAX_PDF_BYTES } from '@semiont/content';
3
3
  import { withSpan, SpanKind, recordJobOutcome, recordAnchorOutcome, recordDetectionCall } from '@semiont/observability';
4
4
  import { createInferenceClient, answerLimitsRequests, StructuredReadError } from '@semiont/inference';
@@ -3766,9 +3766,9 @@ var require_mapOneOrManyArgs = __commonJS({
3766
3766
  Object.defineProperty(exports, "__esModule", { value: true });
3767
3767
  exports.mapOneOrManyArgs = void 0;
3768
3768
  var map_1 = require_map();
3769
- var isArray2 = Array.isArray;
3769
+ var isArray = Array.isArray;
3770
3770
  function callOrApply(fn, args) {
3771
- return isArray2(args) ? fn.apply(void 0, __spreadArray([], __read(args))) : fn(args);
3771
+ return isArray(args) ? fn.apply(void 0, __spreadArray([], __read(args))) : fn(args);
3772
3772
  }
3773
3773
  function mapOneOrManyArgs(fn) {
3774
3774
  return map_1.map(function(args) {
@@ -3913,14 +3913,14 @@ var require_argsArgArrayOrObject = __commonJS({
3913
3913
  "../../node_modules/rxjs/dist/cjs/internal/util/argsArgArrayOrObject.js"(exports) {
3914
3914
  Object.defineProperty(exports, "__esModule", { value: true });
3915
3915
  exports.argsArgArrayOrObject = void 0;
3916
- var isArray2 = Array.isArray;
3916
+ var isArray = Array.isArray;
3917
3917
  var getPrototypeOf = Object.getPrototypeOf;
3918
3918
  var objectProto = Object.prototype;
3919
3919
  var getKeys = Object.keys;
3920
3920
  function argsArgArrayOrObject(args) {
3921
3921
  if (args.length === 1) {
3922
3922
  var first_1 = args[0];
3923
- if (isArray2(first_1)) {
3923
+ if (isArray(first_1)) {
3924
3924
  return { args: first_1, keys: null };
3925
3925
  }
3926
3926
  if (isPOJO(first_1)) {
@@ -4668,9 +4668,9 @@ var require_argsOrArgArray = __commonJS({
4668
4668
  "../../node_modules/rxjs/dist/cjs/internal/util/argsOrArgArray.js"(exports) {
4669
4669
  Object.defineProperty(exports, "__esModule", { value: true });
4670
4670
  exports.argsOrArgArray = void 0;
4671
- var isArray2 = Array.isArray;
4671
+ var isArray = Array.isArray;
4672
4672
  function argsOrArgArray(args) {
4673
- return args.length === 1 && isArray2(args[0]) ? args[0] : args;
4673
+ return args.length === 1 && isArray(args[0]) ? args[0] : args;
4674
4674
  }
4675
4675
  exports.argsOrArgArray = argsOrArgArray;
4676
4676
  }
@@ -9208,19 +9208,6 @@ var require_cjs = __commonJS({
9208
9208
 
9209
9209
  // src/job-claim-adapter.ts
9210
9210
  var import_rxjs = __toESM(require_cjs());
9211
- function readUnitCursors(raw, completedUnits) {
9212
- if (!isObject(raw)) return {};
9213
- const done = new Set(completedUnits);
9214
- const cursors = {};
9215
- for (const [unit, value] of Object.entries(raw)) {
9216
- if (done.has(unit) || !isObject(value)) continue;
9217
- const { next, size, found, emitted } = value;
9218
- if (!isNumber(next) || !isNumber(size) || next < 0 || size < 1) continue;
9219
- if (!isNumber(found) || !isNumber(emitted) || found < 0 || emitted < 0) continue;
9220
- cursors[unit] = { next, size, found, emitted };
9221
- }
9222
- return cursors;
9223
- }
9224
9211
  function createJobClaimAdapter(options) {
9225
9212
  const { bus, jobTypes } = options;
9226
9213
  const activeJob$ = new import_rxjs.BehaviorSubject(null);
@@ -9239,9 +9226,9 @@ function createJobClaimAdapter(options) {
9239
9226
  let activeSince = null;
9240
9227
  const iso = (t) => t === null ? null : new Date(t).toISOString();
9241
9228
  const claimNext = async () => {
9242
- let record;
9229
+ let claimed;
9243
9230
  try {
9244
- record = await busRequest(bus, "job:claim", { types: jobTypes }, 1e4);
9231
+ claimed = await busRequest(bus, "job:claim", { types: jobTypes }, 1e4);
9245
9232
  } catch (error) {
9246
9233
  if (error instanceof BusRequestError) {
9247
9234
  if (error.code === "bus.none-pending") return { declined: true };
@@ -9249,25 +9236,19 @@ function createJobClaimAdapter(options) {
9249
9236
  }
9250
9237
  return { refused: { code: null, message: error instanceof Error ? error.message : String(error) } };
9251
9238
  }
9252
- if (!isString(record.metadata?.id) || !isString(record.metadata?.type)) {
9253
- return { refused: { code: null, message: "claimed record carries no job id or type" } };
9254
- }
9255
- const completedUnits = isArray(record.metadata?.completedUnits) ? record.metadata.completedUnits.filter(isString) : [];
9256
- const unitCursors = readUnitCursors(record.metadata?.unitCursors, completedUnits);
9257
- const params = record.params ?? {};
9239
+ const { metadata, params } = claimed;
9258
9240
  return {
9259
9241
  job: {
9260
- jobId: record.metadata.id,
9261
- type: record.metadata.type,
9262
- resourceId: isString(params.resourceId) ? params.resourceId : "",
9263
- userId: record.metadata?.userId ?? "",
9242
+ jobId: metadata.id,
9243
+ type: metadata.type,
9244
+ resourceId: params.resourceId,
9264
9245
  params,
9265
- completedUnits,
9266
- unitCursors,
9267
- // Absent or malformed metadata reads as "no budget left" — a worker
9268
- // that cannot see the budget must not claim a retry is coming.
9269
- retryCount: isNumber(record.metadata?.retryCount) ? record.metadata.retryCount : 0,
9270
- maxRetries: isNumber(record.metadata?.maxRetries) ? record.metadata.maxRetries : 0
9246
+ // Both appear on the record once an attempt has checkpointed, and a
9247
+ // finished unit has no cursor: the dispatcher drops it at the merge.
9248
+ completedUnits: metadata.completedUnits ?? [],
9249
+ unitCursors: metadata.unitCursors ?? {},
9250
+ retryCount: metadata.retryCount,
9251
+ maxRetries: metadata.maxRetries
9271
9252
  }
9272
9253
  };
9273
9254
  };
@@ -9384,10 +9365,8 @@ function createJobClaimAdapter(options) {
9384
9365
  function willRetryAfter(metadata, failureClass) {
9385
9366
  return failureClass !== "deterministic" && metadata.retryCount < metadata.maxRetries;
9386
9367
  }
9387
- var KNOWN_JOB_TYPES = new Set(JOB_TYPES);
9388
- function isJobType(value) {
9389
- return KNOWN_JOB_TYPES.has(value);
9390
- }
9368
+
9369
+ // src/types.ts
9391
9370
  function asJobParams(params) {
9392
9371
  if (typeof params.resourceId !== "string") {
9393
9372
  throw new Error("Job params are missing a resourceId");
@@ -10752,8 +10731,6 @@ function compileTypst(source) {
10752
10731
  rmSync(dir, { recursive: true, force: true });
10753
10732
  }
10754
10733
  }
10755
-
10756
- // src/workers/generation/citation-resolver.ts
10757
10734
  var CITATION_TOKEN = /\[\[([^\s[\]/]+)(?:\/([^\s[\]/]+))?\]\]/g;
10758
10735
  function collectContextResourceIds(context) {
10759
10736
  const ids = /* @__PURE__ */ new Set();
@@ -10779,7 +10756,7 @@ function resolveCitationTokens(content, validResourceIds, logger2) {
10779
10756
  const annotationId = match[2];
10780
10757
  clean += content.slice(last, match.index).replace(/[ \t]+$/, "");
10781
10758
  last = match.index + token.length;
10782
- if (!validResourceIds.has(citedResourceId)) {
10759
+ if (!isResourceId(citedResourceId) || !validResourceIds.has(citedResourceId)) {
10783
10760
  logger2.warn("Citation token references an id absent from the provided context \u2014 dropped", {
10784
10761
  resourceId: citedResourceId
10785
10762
  });
@@ -11373,12 +11350,7 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger2
11373
11350
  title,
11374
11351
  format: outputMediaType,
11375
11352
  citations: citations2,
11376
- result: {
11377
- kind: "generation",
11378
- resourceId: "",
11379
- resourceName: title,
11380
- truncated: generated2.truncated
11381
- }
11353
+ truncated: generated2.truncated
11382
11354
  };
11383
11355
  }
11384
11356
  onProgress(5, { code: "generating-resource" });
@@ -11414,12 +11386,7 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger2
11414
11386
  title,
11415
11387
  format: outputMediaType,
11416
11388
  citations,
11417
- result: {
11418
- kind: "generation",
11419
- resourceId: "",
11420
- resourceName: title,
11421
- truncated: generated.truncated
11422
- }
11389
+ truncated: generated.truncated
11423
11390
  };
11424
11391
  }
11425
11392
 
@@ -11503,11 +11470,11 @@ var CommitDurabilityError = class extends Error {
11503
11470
  durability;
11504
11471
  name = "CommitDurabilityError";
11505
11472
  };
11506
- async function probeDurability(session, resourceId$1, annotations) {
11473
+ async function probeDurability(session, resourceId, annotations) {
11507
11474
  const last = annotations[annotations.length - 1];
11508
11475
  if (!last) return "probe-unreachable";
11509
11476
  try {
11510
- await session.client.browse.annotation(resourceId(resourceId$1), annotationId(String(last.id))).fresh();
11477
+ await session.client.browse.annotation(resourceId, last.id).fresh();
11511
11478
  return "probe-confirmed";
11512
11479
  } catch (error) {
11513
11480
  const code = isObject(error) && isString(error.code) ? error.code : void 0;
@@ -11564,32 +11531,30 @@ function startWorkerProcess(config) {
11564
11531
  completedUnitsByJob.delete(job.jobId);
11565
11532
  unitCursorsByJob.delete(job.jobId);
11566
11533
  const failAnnotationId = referenceIdOf(job);
11567
- if (isJobType(job.type)) {
11568
- emitEvent(session, "job:fail", {
11569
- resourceId: job.resourceId,
11570
- jobId: job.jobId,
11571
- jobType: job.type,
11572
- ...failAnnotationId ? { annotationId: failAnnotationId } : {},
11573
- error: message,
11574
- ...completedUnits && completedUnits.length > 0 ? { completedUnits } : {},
11575
- // Where each unfinished unit got to. Absent rather than `{}` when
11576
- // nothing was reached: an empty object would claim units were
11577
- // tracked and none progressed.
11578
- ...unitCursors && Object.keys(unitCursors).length > 0 ? { unitCursors } : {},
11579
- ...failureClass !== void 0 ? { failureClass } : {},
11580
- // What the commit path OBSERVED about durability, when the failure
11581
- // came from a commit at all. Present only on that path: absent means
11582
- // the question never arose, never that durability was ruled out.
11583
- ...error instanceof CommitDurabilityError ? { durability: error.durability } : {},
11584
- // Whether this failure is the END, answered by the same predicate
11585
- // the queue applies at failJob (JOB-RESTART-SAFETY P5). Without
11586
- // it a client cannot tell a recovering run from a dead one: it
11587
- // sees job:fail either way and would end its stream on a job the
11588
- // queue is about to re-run.
11589
- willRetry: willRetryAfter(job, failureClass)
11590
- }).catch(() => {
11591
- });
11592
- }
11534
+ emitEvent(session, "job:fail", {
11535
+ resourceId: job.resourceId,
11536
+ jobId: job.jobId,
11537
+ jobType: job.type,
11538
+ ...failAnnotationId ? { annotationId: failAnnotationId } : {},
11539
+ error: message,
11540
+ ...completedUnits && completedUnits.length > 0 ? { completedUnits } : {},
11541
+ // Where each unfinished unit got to. Absent rather than `{}` when
11542
+ // nothing was reached: an empty object would claim units were
11543
+ // tracked and none progressed.
11544
+ ...unitCursors && Object.keys(unitCursors).length > 0 ? { unitCursors } : {},
11545
+ ...failureClass !== void 0 ? { failureClass } : {},
11546
+ // What the commit path OBSERVED about durability, when the failure
11547
+ // came from a commit at all. Present only on that path: absent means
11548
+ // the question never arose, never that durability was ruled out.
11549
+ ...error instanceof CommitDurabilityError ? { durability: error.durability } : {},
11550
+ // Whether this failure is the END, answered by the same predicate
11551
+ // the queue applies at failJob (JOB-RESTART-SAFETY P5). Without
11552
+ // it a client cannot tell a recovering run from a dead one: it
11553
+ // sees job:fail either way and would end its stream on a job the
11554
+ // queue is about to re-run.
11555
+ willRetry: willRetryAfter(job, failureClass)
11556
+ }).catch(() => {
11557
+ });
11593
11558
  adapter.failJob(job.jobId, message);
11594
11559
  }).finally(() => {
11595
11560
  if (activeCancel?.jobId === job.jobId) activeCancel = null;
@@ -11623,17 +11588,11 @@ async function handleJob(adapter, config, job, completedUnitsByJob = /* @__PURE_
11623
11588
  }
11624
11589
  async function handleJobInner(adapter, config, job, completedUnitsByJob, signal, unitCursorsByJob = /* @__PURE__ */ new Map()) {
11625
11590
  const { session, inferenceClient, generator } = config;
11626
- const { jobId } = job;
11627
- if (!isJobType(job.type)) {
11628
- adapter.failJob(jobId, `Unrecognized job type: ${job.type}`);
11629
- return;
11630
- }
11631
- const jobType = job.type;
11632
- const resourceId$1 = resourceId(job.resourceId);
11591
+ const { jobId, type: jobType, resourceId } = job;
11633
11592
  const annotationId = referenceIdOf(job);
11634
11593
  const attempt = job.retryCount + 1;
11635
11594
  const lifecycleBase = {
11636
- resourceId: resourceId$1,
11595
+ resourceId,
11637
11596
  jobId,
11638
11597
  jobType,
11639
11598
  attempt,
@@ -11652,22 +11611,22 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11652
11611
  }
11653
11612
  let ready = null;
11654
11613
  if (jobType !== "generation") {
11655
- const descriptor = await session.client.browse.resource(resourceId$1).fresh();
11614
+ const descriptor = await session.client.browse.resource(resourceId).fresh();
11656
11615
  const mediaType = getPrimaryMediaType(descriptor);
11657
11616
  const source = await withSpan(
11658
11617
  "detection:prepare",
11659
- () => prepareDetection(mediaType ?? "", config.contentReads, resourceId$1, generator, (rid) => session.client.browse.resourceAnchoredText(rid)),
11660
- { attrs: { "resource.id": resourceId$1, "media.type": mediaType ?? "unknown" } }
11618
+ () => prepareDetection(mediaType ?? "", config.contentReads, resourceId, generator, (rid) => session.client.browse.resourceAnchoredText(rid)),
11619
+ { attrs: { "resource.id": resourceId, "media.type": mediaType ?? "unknown" } }
11661
11620
  );
11662
11621
  if ("declined" in source) {
11663
11622
  if (source.declined === "not-yet") {
11664
- throw new Error(`Anchored text not yet derived for resource ${resourceId$1} \u2014 Smelter has not settled; retrying`);
11623
+ throw new Error(`Anchored text not yet derived for resource ${resourceId} \u2014 Smelter has not settled; retrying`);
11665
11624
  }
11666
11625
  if (source.declined === "no-extractor") {
11667
- throw new DeterministicJobError(`Cannot run ${jobType} on resource ${resourceId$1}: media type '${mediaType ?? "unknown"}' has no extractable text to analyze`);
11626
+ throw new DeterministicJobError(`Cannot run ${jobType} on resource ${resourceId}: media type '${mediaType ?? "unknown"}' has no extractable text to analyze`);
11668
11627
  }
11669
11628
  if (source.declined === "no-map" || source.declined === "unknown") {
11670
- throw new DeterministicJobError(`Cannot run ${jobType} on resource ${resourceId$1}: anchored-text consult returned '${source.declined}'`);
11629
+ throw new DeterministicJobError(`Cannot run ${jobType} on resource ${resourceId}: anchored-text consult returned '${source.declined}'`);
11671
11630
  }
11672
11631
  await emitEvent(session, "job:complete", {
11673
11632
  ...terminalBase(),
@@ -11698,7 +11657,7 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11698
11657
  };
11699
11658
  const unitCursors = /* @__PURE__ */ new Map();
11700
11659
  const commitChunk = async (annotations, checkpoint) => {
11701
- record(await commitAnnotations(session, String(resourceId$1), annotations, jobId));
11660
+ record(await commitAnnotations(session, resourceId, annotations, jobId));
11702
11661
  unitCursors.set(checkpoint.unit, checkpoint.cursor);
11703
11662
  unitCursorsByJob.set(job.jobId, Object.fromEntries(unitCursors));
11704
11663
  await emitEvent(session, "job:checkpoint", {
@@ -11859,7 +11818,7 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11859
11818
  file: Buffer.from(genResult.content),
11860
11819
  format: genResult.format,
11861
11820
  storageUri,
11862
- sourceResourceId: resourceId$1,
11821
+ sourceResourceId: resourceId,
11863
11822
  ...genReferenceId ? { sourceAnnotationId: genReferenceId } : {},
11864
11823
  ...genParams.prompt ? { generationPrompt: genParams.prompt } : {},
11865
11824
  ...genParams.language ? { language: genParams.language } : {},
@@ -11873,12 +11832,12 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11873
11832
  const { annotation: provenanceRef } = assembleAnnotation(
11874
11833
  {
11875
11834
  motivation: "linking",
11876
- target: { source: String(resourceId$1) },
11877
- body: { type: "SpecificResource", source: String(newResourceId), purpose: "linking" }
11835
+ target: { source: resourceId },
11836
+ body: { type: "SpecificResource", source: newResourceId, purpose: "linking" }
11878
11837
  },
11879
11838
  generator
11880
11839
  );
11881
- record(await commitAnnotations(session, String(resourceId$1), [provenanceRef], jobId));
11840
+ record(await commitAnnotations(session, resourceId, [provenanceRef], jobId));
11882
11841
  }
11883
11842
  const citationRefs = [];
11884
11843
  if (genResult.format === "application/pdf" && genResult.citations.length > 0) {
@@ -11903,7 +11862,7 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11903
11862
  }
11904
11863
  const citationRef = buildPdfAnnotation(
11905
11864
  layer,
11906
- resourceId(String(newResourceId)),
11865
+ newResourceId,
11907
11866
  generator,
11908
11867
  "linking",
11909
11868
  { exact: layer.text.slice(span.start, span.end), start: span.start, end: span.end },
@@ -11918,7 +11877,7 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11918
11877
  {
11919
11878
  motivation: "linking",
11920
11879
  target: {
11921
- source: String(newResourceId),
11880
+ source: newResourceId,
11922
11881
  selector: [
11923
11882
  { type: "TextPositionSelector", start: citation.start, end: citation.end },
11924
11883
  { type: "TextQuoteSelector", exact: citation.exact }
@@ -11931,10 +11890,10 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal,
11931
11890
  citationRefs.push(citationRef);
11932
11891
  }
11933
11892
  }
11934
- record(await commitAnnotations(session, String(newResourceId), citationRefs, jobId));
11893
+ record(await commitAnnotations(session, newResourceId, citationRefs, jobId));
11935
11894
  await emitEvent(session, "job:complete", {
11936
11895
  ...terminalBase(),
11937
- result: { kind: "generation", resourceId: newResourceId, resourceName: genResult.title, truncated: genResult.result.truncated }
11896
+ result: { kind: "generation", resourceId: newResourceId, resourceName: genResult.title, truncated: genResult.truncated }
11938
11897
  });
11939
11898
  adapter.completeJob();
11940
11899
  } else {