@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.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { JobId, components, UserId, UnitCursor, ResourceId, EntityType, JobReferenceAnnotationResult, GenerationJobParams, JobHighlightAnnotationResult, JobAssessmentAnnotationResult, JobCommentAnnotationResult, TagSchema, JobTagAnnotationResult, Annotation, Logger, SupportedMediaType, GatheredContext, BusRequestErrorCode, BusRequestPrimitive, EventMap } from '@semiont/core';
1
+ import { JobId, components, UserId, UnitCursor, ResourceId, EntityType, JobReferenceAnnotationResult, GenerationJobParams, JobHighlightAnnotationResult, JobAssessmentAnnotationResult, JobCommentAnnotationResult, TagSchema, JobTagAnnotationResult, Annotation, Logger, SupportedMediaType, GatheredContext, JobType as JobType$1, EventMap, BusRequestErrorCode, BusRequestPrimitive } from '@semiont/core';
2
2
  import { InferenceClient } from '@semiont/inference';
3
3
  import { Observable } from 'rxjs';
4
4
 
@@ -142,16 +142,6 @@ type TagDetectionParams = {
142
142
  /** Source-resource locale — see locale conventions above. */
143
143
  sourceLanguage?: string;
144
144
  };
145
- /**
146
- * Generation job result
147
- */
148
- interface GenerationResult {
149
- kind: 'generation';
150
- resourceId: ResourceId;
151
- resourceName: string;
152
- /** True when the model stopped at the maxTokens ceiling — the artifact is cut off, not complete (GENERATE-FROM-RESOURCE D6). */
153
- truncated: boolean;
154
- }
155
145
  /**
156
146
  * The progress a running job carries: the last its worker reported with
157
147
  * `job:report-progress`, or an empty object before the first report. One shape
@@ -216,7 +206,7 @@ type DetectionJob = Job<DetectionParams, JobReferenceAnnotationResult>;
216
206
  /** A generation job's params carry the resource the dispatcher derived from the context's focus. */
217
207
  type GenerationJob = Job<GenerationJobParams & {
218
208
  resourceId: ResourceId;
219
- }, GenerationResult>;
209
+ }, components['schemas']['JobGenerationResult']>;
220
210
  type HighlightDetectionJob = Job<HighlightDetectionParams, JobHighlightAnnotationResult>;
221
211
  type AssessmentDetectionJob = Job<AssessmentDetectionParams, JobAssessmentAnnotationResult>;
222
212
  type CommentDetectionJob = Job<CommentDetectionParams, JobCommentAnnotationResult>;
@@ -250,7 +240,7 @@ declare function isCancelledJob(job: AnyJob): job is CancelledJob<any>;
250
240
 
251
241
  interface GenerationCitation {
252
242
  /** The cited source resource (validated present in the embedded context). */
253
- resourceId: string;
243
+ resourceId: ResourceId;
254
244
  /** The contributing annotation, when the cited excerpt was annotation-derived. */
255
245
  annotationId?: string;
256
246
  /** Claim span in the FINAL (token-stripped) content; substring(start, end) === exact. */
@@ -259,6 +249,17 @@ interface GenerationCitation {
259
249
  exact: string;
260
250
  }
261
251
 
252
+ /**
253
+ * Job Processors
254
+ *
255
+ * Pure functions that take content + inference client + params,
256
+ * report progress via callback, and return annotations + results.
257
+ *
258
+ * No EventBus, no queue, no side effects except calling inference.
259
+ * Driven by the remote worker process (worker-process.ts), which claims
260
+ * jobs over SSE and dispatches by jobType to these functions.
261
+ */
262
+
262
263
  /** A detected span — offsets into the extracted `.text`, plus optional context. */
263
264
  type SpanMatch = {
264
265
  exact: string;
@@ -378,7 +379,7 @@ declare function processGenerationJob(inferenceClient: InferenceClient, params:
378
379
  title: string;
379
380
  format: SupportedMediaType;
380
381
  citations: GenerationCitation[];
381
- result: GenerationResult;
382
+ truncated: boolean;
382
383
  }>;
383
384
 
384
385
  /**
@@ -628,12 +629,17 @@ declare function generateResourceFromTopic(topic: string, entityTypes: string[],
628
629
  * an in-process worker could pass a shim wrapping `client.bus`.
629
630
  */
630
631
 
632
+ /** The job a `job:claimed` reply carries, running under this worker: the spec's `JobRunning`. */
633
+ type ClaimedJob = EventMap['job:claimed']['response'];
634
+ /**
635
+ * The claimed job as the worker holds it: the fields of the claimed record the
636
+ * worker reads, each with the type the spec gives it there.
637
+ */
631
638
  interface ActiveJob {
632
- jobId: string;
633
- type: string;
634
- resourceId: string;
635
- userId: string;
636
- params: Record<string, unknown>;
639
+ jobId: JobId;
640
+ type: JobType$1;
641
+ resourceId: ResourceId;
642
+ params: ClaimedJob['params'];
637
643
  /**
638
644
  * Entity-type units earlier failed attempts fully emitted
639
645
  * (ABANDONED-INFERENCE P2 checkpointed resume) — carried on the claimed
@@ -671,9 +677,9 @@ interface JobClaimAdapterOptions {
671
677
  * A claim the dispatcher refused for a reason other than "nothing pending".
672
678
  *
673
679
  * `code` is the `BusRequestError` code the reply was promoted to, or `null`
674
- * when the failure was local — an unusable record, a thrown non-bus error —
675
- * never a manufactured bus code. `bus.none-pending` never appears here: it is
676
- * the quiet park, and emitting it would make an empty queue look like a fault.
680
+ * when the failure was local — a thrown non-bus error — never a manufactured
681
+ * bus code. `bus.none-pending` never appears here: it is the quiet park, and
682
+ * emitting it would make an empty queue look like a fault.
677
683
  */
678
684
  interface ClaimRefusal {
679
685
  code: BusRequestErrorCode | null;
@@ -819,4 +825,4 @@ declare const WORKER_CONSUMED_BROADCASTS: readonly ["job:queued", "job:cancel-re
819
825
  declare const WORKER_CHANNELS: readonly (keyof EventMap)[];
820
826
 
821
827
  export { AnnotationDetection, STALL_THRESHOLD_MS, WORKER_CHANNELS, WORKER_CONSUMED_BROADCASTS, createJobClaimAdapter, generateResourceFromTopic, isCancelledJob, isCompleteJob, isFailedJob, isPendingJob, isRunningJob, processAssessmentJob, processCommentJob, processGenerationJob, processHighlightJob, processReferenceJob, processTagJob };
822
- export type { ActiveJob, AnyJob, AssessmentDetectionJob, AssessmentDetectionParams, CancelledJob, ClaimRefusal, CommentDetectionJob, CommentDetectionParams, CompleteJob, DetectionJob, DetectionParams, FailedJob, GenerationJob, GenerationResult, HighlightDetectionJob, HighlightDetectionParams, JobClaimAdapter, JobClaimAdapterOptions, JobMetadata, JobStatus, JobType, OnProgress, PendingJob, ProcessorResult, RunningAnyJob, RunningJob, StoredProgress, TagDetectionJob, TagDetectionParams, WorkerVitals };
828
+ export type { ActiveJob, AnyJob, AssessmentDetectionJob, AssessmentDetectionParams, CancelledJob, ClaimRefusal, CommentDetectionJob, CommentDetectionParams, CompleteJob, DetectionJob, DetectionParams, FailedJob, GenerationJob, HighlightDetectionJob, HighlightDetectionParams, JobClaimAdapter, JobClaimAdapterOptions, JobMetadata, JobStatus, JobType, OnProgress, PendingJob, ProcessorResult, RunningAnyJob, RunningJob, StoredProgress, TagDetectionJob, TagDetectionParams, WorkerVitals };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { JOB_TYPES, replyChannelsFor, deriveViews, GENERATABLE_MEDIA_TYPES, estimateTokens, isObject, isString, reconcileSelector, getLocaleEnglishName, busRequest, BusRequestError, isArray, isNumber, cutChunk, chunkText } from '@semiont/core';
1
+ import { replyChannelsFor, deriveViews, GENERATABLE_MEDIA_TYPES, estimateTokens, isObject, isString, reconcileSelector, getLocaleEnglishName, isResourceId, busRequest, BusRequestError, cutChunk, chunkText } from '@semiont/core';
2
2
  import { withSpan, recordAnchorOutcome, recordDetectionCall } from '@semiont/observability';
3
3
  import { StructuredReadError } from '@semiont/inference';
4
4
  import { execFileSync } from 'child_process';
@@ -3764,9 +3764,9 @@ var require_mapOneOrManyArgs = __commonJS({
3764
3764
  Object.defineProperty(exports, "__esModule", { value: true });
3765
3765
  exports.mapOneOrManyArgs = void 0;
3766
3766
  var map_1 = require_map();
3767
- var isArray2 = Array.isArray;
3767
+ var isArray = Array.isArray;
3768
3768
  function callOrApply(fn, args) {
3769
- return isArray2(args) ? fn.apply(void 0, __spreadArray([], __read(args))) : fn(args);
3769
+ return isArray(args) ? fn.apply(void 0, __spreadArray([], __read(args))) : fn(args);
3770
3770
  }
3771
3771
  function mapOneOrManyArgs(fn) {
3772
3772
  return map_1.map(function(args) {
@@ -3911,14 +3911,14 @@ var require_argsArgArrayOrObject = __commonJS({
3911
3911
  "../../node_modules/rxjs/dist/cjs/internal/util/argsArgArrayOrObject.js"(exports) {
3912
3912
  Object.defineProperty(exports, "__esModule", { value: true });
3913
3913
  exports.argsArgArrayOrObject = void 0;
3914
- var isArray2 = Array.isArray;
3914
+ var isArray = Array.isArray;
3915
3915
  var getPrototypeOf = Object.getPrototypeOf;
3916
3916
  var objectProto = Object.prototype;
3917
3917
  var getKeys = Object.keys;
3918
3918
  function argsArgArrayOrObject(args) {
3919
3919
  if (args.length === 1) {
3920
3920
  var first_1 = args[0];
3921
- if (isArray2(first_1)) {
3921
+ if (isArray(first_1)) {
3922
3922
  return { args: first_1, keys: null };
3923
3923
  }
3924
3924
  if (isPOJO(first_1)) {
@@ -4666,9 +4666,9 @@ var require_argsOrArgArray = __commonJS({
4666
4666
  "../../node_modules/rxjs/dist/cjs/internal/util/argsOrArgArray.js"(exports) {
4667
4667
  Object.defineProperty(exports, "__esModule", { value: true });
4668
4668
  exports.argsOrArgArray = void 0;
4669
- var isArray2 = Array.isArray;
4669
+ var isArray = Array.isArray;
4670
4670
  function argsOrArgArray(args) {
4671
- return args.length === 1 && isArray2(args[0]) ? args[0] : args;
4671
+ return args.length === 1 && isArray(args[0]) ? args[0] : args;
4672
4672
  }
4673
4673
  exports.argsOrArgArray = argsOrArgArray;
4674
4674
  }
@@ -9203,7 +9203,8 @@ var require_cjs = __commonJS({
9203
9203
  } });
9204
9204
  }
9205
9205
  });
9206
- new Set(JOB_TYPES);
9206
+
9207
+ // src/types.ts
9207
9208
  function isPendingJob(job) {
9208
9209
  return job.status === "pending";
9209
9210
  }
@@ -10562,8 +10563,6 @@ function compileTypst(source) {
10562
10563
  rmSync(dir, { recursive: true, force: true });
10563
10564
  }
10564
10565
  }
10565
-
10566
- // src/workers/generation/citation-resolver.ts
10567
10566
  var CITATION_TOKEN = /\[\[([^\s[\]/]+)(?:\/([^\s[\]/]+))?\]\]/g;
10568
10567
  function collectContextResourceIds(context) {
10569
10568
  const ids = /* @__PURE__ */ new Set();
@@ -10589,7 +10588,7 @@ function resolveCitationTokens(content, validResourceIds, logger) {
10589
10588
  const annotationId = match[2];
10590
10589
  clean += content.slice(last, match.index).replace(/[ \t]+$/, "");
10591
10590
  last = match.index + token.length;
10592
- if (!validResourceIds.has(citedResourceId)) {
10591
+ if (!isResourceId(citedResourceId) || !validResourceIds.has(citedResourceId)) {
10593
10592
  logger.warn("Citation token references an id absent from the provided context \u2014 dropped", {
10594
10593
  resourceId: citedResourceId
10595
10594
  });
@@ -11091,12 +11090,7 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger)
11091
11090
  title,
11092
11091
  format: outputMediaType,
11093
11092
  citations: citations2,
11094
- result: {
11095
- kind: "generation",
11096
- resourceId: "",
11097
- resourceName: title,
11098
- truncated: generated2.truncated
11099
- }
11093
+ truncated: generated2.truncated
11100
11094
  };
11101
11095
  }
11102
11096
  onProgress(5, { code: "generating-resource" });
@@ -11132,30 +11126,12 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger)
11132
11126
  title,
11133
11127
  format: outputMediaType,
11134
11128
  citations,
11135
- result: {
11136
- kind: "generation",
11137
- resourceId: "",
11138
- resourceName: title,
11139
- truncated: generated.truncated
11140
- }
11129
+ truncated: generated.truncated
11141
11130
  };
11142
11131
  }
11143
11132
 
11144
11133
  // src/job-claim-adapter.ts
11145
11134
  var import_rxjs = __toESM(require_cjs());
11146
- function readUnitCursors(raw, completedUnits) {
11147
- if (!isObject(raw)) return {};
11148
- const done = new Set(completedUnits);
11149
- const cursors = {};
11150
- for (const [unit, value] of Object.entries(raw)) {
11151
- if (done.has(unit) || !isObject(value)) continue;
11152
- const { next, size, found, emitted } = value;
11153
- if (!isNumber(next) || !isNumber(size) || next < 0 || size < 1) continue;
11154
- if (!isNumber(found) || !isNumber(emitted) || found < 0 || emitted < 0) continue;
11155
- cursors[unit] = { next, size, found, emitted };
11156
- }
11157
- return cursors;
11158
- }
11159
11135
  function createJobClaimAdapter(options) {
11160
11136
  const { bus, jobTypes } = options;
11161
11137
  const activeJob$ = new import_rxjs.BehaviorSubject(null);
@@ -11174,9 +11150,9 @@ function createJobClaimAdapter(options) {
11174
11150
  let activeSince = null;
11175
11151
  const iso = (t) => t === null ? null : new Date(t).toISOString();
11176
11152
  const claimNext = async () => {
11177
- let record;
11153
+ let claimed;
11178
11154
  try {
11179
- record = await busRequest(bus, "job:claim", { types: jobTypes }, 1e4);
11155
+ claimed = await busRequest(bus, "job:claim", { types: jobTypes }, 1e4);
11180
11156
  } catch (error) {
11181
11157
  if (error instanceof BusRequestError) {
11182
11158
  if (error.code === "bus.none-pending") return { declined: true };
@@ -11184,25 +11160,19 @@ function createJobClaimAdapter(options) {
11184
11160
  }
11185
11161
  return { refused: { code: null, message: error instanceof Error ? error.message : String(error) } };
11186
11162
  }
11187
- if (!isString(record.metadata?.id) || !isString(record.metadata?.type)) {
11188
- return { refused: { code: null, message: "claimed record carries no job id or type" } };
11189
- }
11190
- const completedUnits = isArray(record.metadata?.completedUnits) ? record.metadata.completedUnits.filter(isString) : [];
11191
- const unitCursors = readUnitCursors(record.metadata?.unitCursors, completedUnits);
11192
- const params = record.params ?? {};
11163
+ const { metadata, params } = claimed;
11193
11164
  return {
11194
11165
  job: {
11195
- jobId: record.metadata.id,
11196
- type: record.metadata.type,
11197
- resourceId: isString(params.resourceId) ? params.resourceId : "",
11198
- userId: record.metadata?.userId ?? "",
11166
+ jobId: metadata.id,
11167
+ type: metadata.type,
11168
+ resourceId: params.resourceId,
11199
11169
  params,
11200
- completedUnits,
11201
- unitCursors,
11202
- // Absent or malformed metadata reads as "no budget left" — a worker
11203
- // that cannot see the budget must not claim a retry is coming.
11204
- retryCount: isNumber(record.metadata?.retryCount) ? record.metadata.retryCount : 0,
11205
- maxRetries: isNumber(record.metadata?.maxRetries) ? record.metadata.maxRetries : 0
11170
+ // Both appear on the record once an attempt has checkpointed, and a
11171
+ // finished unit has no cursor: the dispatcher drops it at the merge.
11172
+ completedUnits: metadata.completedUnits ?? [],
11173
+ unitCursors: metadata.unitCursors ?? {},
11174
+ retryCount: metadata.retryCount,
11175
+ maxRetries: metadata.maxRetries
11206
11176
  }
11207
11177
  };
11208
11178
  };