@semiont/jobs 0.5.34 → 0.5.36
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 +130 -18
- package/dist/index.js +241 -108
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +281 -154
- package/dist/worker-main.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JobId, UserId, ResourceId, EntityType, JobReferenceAnnotationResult, GenerationJobParams, JobHighlightAnnotationResult, JobAssessmentAnnotationResult, JobCommentAnnotationResult, TagSchema, JobTagAnnotationResult, Logger, EventBus, components, Annotation, SupportedMediaType, GatheredContext } from '@semiont/core';
|
|
1
|
+
import { JobId, UserId, UnitCursor, ResourceId, EntityType, JobReferenceAnnotationResult, GenerationJobParams, JobHighlightAnnotationResult, JobAssessmentAnnotationResult, JobCommentAnnotationResult, TagSchema, JobTagAnnotationResult, Logger, EventBus, components, Annotation, SupportedMediaType, GatheredContext } from '@semiont/core';
|
|
2
2
|
import { SemiontState } from '@semiont/core/node';
|
|
3
3
|
import { InferenceClient } from '@semiont/inference';
|
|
4
4
|
|
|
@@ -47,6 +47,18 @@ interface JobMetadata {
|
|
|
47
47
|
* duplicated.
|
|
48
48
|
*/
|
|
49
49
|
completedUnits?: string[];
|
|
50
|
+
/**
|
|
51
|
+
* The finer grain `completedUnits` cannot express (CHUNK-GRAIN-RESUME P2):
|
|
52
|
+
* how far each UNFINISHED unit got, keyed by unit. Written per committed
|
|
53
|
+
* chunk, so a job that dies mid-unit resumes there rather than at the top —
|
|
54
|
+
* which for a one-unit job (every motivation job, and the 1958 document's
|
|
55
|
+
* single `Person` type) is the difference between resuming and restarting.
|
|
56
|
+
*
|
|
57
|
+
* A unit here is in progress, never complete; the two sets are disjoint by
|
|
58
|
+
* construction in `checkpointUnits`. Merged monotonically per unit, never
|
|
59
|
+
* unioned — see `mergeUnitCursors`.
|
|
60
|
+
*/
|
|
61
|
+
unitCursors?: Record<string, UnitCursor>;
|
|
50
62
|
}
|
|
51
63
|
/**
|
|
52
64
|
* Locale conventions for detection/generation params.
|
|
@@ -290,7 +302,7 @@ interface JobQueue {
|
|
|
290
302
|
* `failureClass` of 'deterministic' goes straight to `failed` with any
|
|
291
303
|
* budget remaining — a second identical attempt cannot succeed (P3).
|
|
292
304
|
*/
|
|
293
|
-
failJob(jobId: JobId, error: string, completedUnits?: string[], failureClass?: 'transient' | 'deterministic'): Promise<'retried' | 'failed' | null>;
|
|
305
|
+
failJob(jobId: JobId, error: string, completedUnits?: string[], failureClass?: 'transient' | 'deterministic', unitCursors?: Record<string, UnitCursor>): Promise<'retried' | 'failed' | null>;
|
|
294
306
|
/**
|
|
295
307
|
* Persist a running job's completed-unit checkpoint AT unit completion —
|
|
296
308
|
* not only when a job fails (JOB-RESTART-SAFETY P2). `failJob` carries the
|
|
@@ -300,8 +312,25 @@ interface JobQueue {
|
|
|
300
312
|
* file's metadata as each unit lands, unioned with any existing
|
|
301
313
|
* checkpoint, so recovery resumes rather than restarts. Unthrottled (a
|
|
302
314
|
* unit completion must never be dropped); a no-op for non-running jobs.
|
|
315
|
+
*
|
|
316
|
+
* `unitCursors` is the finer grain `completedUnits` cannot express
|
|
317
|
+
* (CHUNK-GRAIN-RESUME P2): how far an UNFINISHED unit got, so a job that
|
|
318
|
+
* dies mid-unit resumes there instead of at the top. It is written per
|
|
319
|
+
* committed chunk, not per unit.
|
|
320
|
+
*
|
|
321
|
+
* **The two merge differently, and the difference is the contract.**
|
|
322
|
+
* `completedUnits` is a set, so a union converges under concurrent snapshots
|
|
323
|
+
* — a set only grows. A cursor converges only if the merge is **monotone per
|
|
324
|
+
* unit**: a stale snapshot must never move one backward. `next` and `size`
|
|
325
|
+
* move TOGETHER as one observation; taking `size` from one snapshot and
|
|
326
|
+
* `next` from another would describe a chunk that never existed. A unit that
|
|
327
|
+
* reaches `completedUnits` drops its cursor, so "in progress with a cursor"
|
|
328
|
+
* and "complete" stay structurally exclusive rather than by convention.
|
|
329
|
+
*
|
|
330
|
+
* The rule belongs here rather than to any one driver because it is what
|
|
331
|
+
* makes a cursor safe to merge at all.
|
|
303
332
|
*/
|
|
304
|
-
checkpointUnits(jobId: JobId, completedUnits: string[]): Promise<void>;
|
|
333
|
+
checkpointUnits(jobId: JobId, completedUnits: string[], unitCursors?: Record<string, UnitCursor>): Promise<void>;
|
|
305
334
|
/** Write progress into a running job's file (throttled, best-effort). */
|
|
306
335
|
recordProgress(jobId: JobId, progress: Record<string, unknown>): Promise<void>;
|
|
307
336
|
/**
|
|
@@ -385,7 +414,7 @@ declare class FsJobQueue implements JobQueue {
|
|
|
385
414
|
* re-announced); after that it lands in `failed` with the error.
|
|
386
415
|
* Returns null (and changes nothing) if the job isn't running.
|
|
387
416
|
*/
|
|
388
|
-
failJob(jobId: JobId, error: string, completedUnits?: string[], failureClass?: 'transient' | 'deterministic'): Promise<'retried' | 'failed' | null>;
|
|
417
|
+
failJob(jobId: JobId, error: string, completedUnits?: string[], failureClass?: 'transient' | 'deterministic', unitCursors?: Record<string, UnitCursor>): Promise<'retried' | 'failed' | null>;
|
|
389
418
|
/**
|
|
390
419
|
* Persist a running job's completed-unit checkpoint at unit completion
|
|
391
420
|
* (JOB-RESTART-SAFETY P2). `failJob` writes this checkpoint on a clean
|
|
@@ -398,7 +427,7 @@ declare class FsJobQueue implements JobQueue {
|
|
|
398
427
|
* non-running jobs. Written directly, like `recordProgress`, so it also
|
|
399
428
|
* refreshes the mtime heartbeat.
|
|
400
429
|
*/
|
|
401
|
-
checkpointUnits(jobId: JobId, completedUnits: string[]): Promise<void>;
|
|
430
|
+
checkpointUnits(jobId: JobId, completedUnits: string[], unitCursors?: Record<string, UnitCursor>): Promise<void>;
|
|
402
431
|
/**
|
|
403
432
|
* Write progress into a running job's file. Throttled per job, and
|
|
404
433
|
* a no-op for jobs that aren't running. Beyond surfacing live
|
|
@@ -521,15 +550,40 @@ type Motivation = Annotation['motivation'];
|
|
|
521
550
|
interface ProcessorResult<R> {
|
|
522
551
|
result: R;
|
|
523
552
|
}
|
|
553
|
+
/**
|
|
554
|
+
* Where one unit stands once the chunk just handed over is durable
|
|
555
|
+
* (CHUNK-GRAIN-RESUME P2).
|
|
556
|
+
*
|
|
557
|
+
* The unit is named HERE rather than in the detection layer, which knows about
|
|
558
|
+
* chunks and nothing about jobs: for `reference-annotation` a unit is an entity
|
|
559
|
+
* type, for `tag-annotation` a category — both loop over several — and for the
|
|
560
|
+
* other three the job runs exactly one unit, its own motivation.
|
|
561
|
+
*/
|
|
562
|
+
interface UnitCheckpoint {
|
|
563
|
+
unit: string;
|
|
564
|
+
cursor: UnitCursor;
|
|
565
|
+
}
|
|
524
566
|
declare function processHighlightJob(content: string, inferenceClient: InferenceClient, params: HighlightDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress,
|
|
525
567
|
/** This chunk's novel annotations, awaited: the durability write. */
|
|
526
|
-
onChunkComplete: (annotations: Annotation[]) => Promise<void
|
|
568
|
+
onChunkComplete: (annotations: Annotation[], checkpoint: UnitCheckpoint) => Promise<void>,
|
|
569
|
+
/** Where earlier attempts left each unit (CHUNK-GRAIN-RESUME P3), keyed the
|
|
570
|
+
* same way the checkpoint is. A unit absent here starts at the top, which is
|
|
571
|
+
* every unit of a first attempt. */
|
|
572
|
+
resumeCursors?: Record<string, UnitCursor>): Promise<ProcessorResult<JobHighlightAnnotationResult>>;
|
|
527
573
|
declare function processCommentJob(content: string, inferenceClient: InferenceClient, params: CommentDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress,
|
|
528
574
|
/** This chunk's novel annotations, awaited: the durability write. */
|
|
529
|
-
onChunkComplete: (annotations: Annotation[]) => Promise<void
|
|
575
|
+
onChunkComplete: (annotations: Annotation[], checkpoint: UnitCheckpoint) => Promise<void>,
|
|
576
|
+
/** Where earlier attempts left each unit (CHUNK-GRAIN-RESUME P3), keyed the
|
|
577
|
+
* same way the checkpoint is. A unit absent here starts at the top, which is
|
|
578
|
+
* every unit of a first attempt. */
|
|
579
|
+
resumeCursors?: Record<string, UnitCursor>): Promise<ProcessorResult<JobCommentAnnotationResult>>;
|
|
530
580
|
declare function processAssessmentJob(content: string, inferenceClient: InferenceClient, params: AssessmentDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress,
|
|
531
581
|
/** This chunk's novel annotations, awaited: the durability write. */
|
|
532
|
-
onChunkComplete: (annotations: Annotation[]) => Promise<void
|
|
582
|
+
onChunkComplete: (annotations: Annotation[], checkpoint: UnitCheckpoint) => Promise<void>,
|
|
583
|
+
/** Where earlier attempts left each unit (CHUNK-GRAIN-RESUME P3), keyed the
|
|
584
|
+
* same way the checkpoint is. A unit absent here starts at the top, which is
|
|
585
|
+
* every unit of a first attempt. */
|
|
586
|
+
resumeCursors?: Record<string, UnitCursor>): Promise<ProcessorResult<JobAssessmentAnnotationResult>>;
|
|
533
587
|
/**
|
|
534
588
|
* Reference detection commits per UNIT — one entity type — through
|
|
535
589
|
* `onUnitComplete` (ABANDONED-INFERENCE P2, checkpointed resume): the
|
|
@@ -548,12 +602,20 @@ declare function processReferenceJob(content: string, inferenceClient: Inference
|
|
|
548
602
|
*/
|
|
549
603
|
onUnitComplete: (entityType: string) => Promise<void>, signal?: AbortSignal,
|
|
550
604
|
/** This chunk's novel annotations, awaited: the durability write. */
|
|
551
|
-
onChunkComplete?: (annotations: Annotation[]) => Promise<void
|
|
605
|
+
onChunkComplete?: (annotations: Annotation[], checkpoint: UnitCheckpoint) => Promise<void>,
|
|
606
|
+
/** Where earlier attempts left each entity-type unit (CHUNK-GRAIN-RESUME P3).
|
|
607
|
+
* A unit absent here starts at the top; units already COMPLETE never reach
|
|
608
|
+
* this function at all, the caller having filtered them out. */
|
|
609
|
+
resumeCursors?: Record<string, UnitCursor>): Promise<{
|
|
552
610
|
result: JobReferenceAnnotationResult;
|
|
553
611
|
}>;
|
|
554
612
|
declare function processTagJob(content: string, inferenceClient: InferenceClient, params: TagDetectionParams, buildAnnotation: BuildAnnotation, onProgress: OnProgress,
|
|
555
613
|
/** This chunk's novel annotations, awaited: the durability write. */
|
|
556
|
-
onChunkComplete: (annotations: Annotation[]) => Promise<void
|
|
614
|
+
onChunkComplete: (annotations: Annotation[], checkpoint: UnitCheckpoint) => Promise<void>,
|
|
615
|
+
/** Where earlier attempts left each CATEGORY (CHUNK-GRAIN-RESUME P3) — a tag
|
|
616
|
+
* job's units are its categories, not its motivation: each walks the whole
|
|
617
|
+
* document, so one shared cursor would skip text for all but one of them. */
|
|
618
|
+
resumeCursors?: Record<string, UnitCursor>): Promise<ProcessorResult<JobTagAnnotationResult>>;
|
|
557
619
|
declare function processGenerationJob(inferenceClient: InferenceClient, params: GenerationJobParams, onProgress: OnProgress, logger: Logger): Promise<{
|
|
558
620
|
content: Uint8Array;
|
|
559
621
|
title: string;
|
|
@@ -562,6 +624,44 @@ declare function processGenerationJob(inferenceClient: InferenceClient, params:
|
|
|
562
624
|
result: GenerationResult;
|
|
563
625
|
}>;
|
|
564
626
|
|
|
627
|
+
/**
|
|
628
|
+
* Detection budget derivation — pure window arithmetic over the inference
|
|
629
|
+
* provider's published limits. No hand-tuned chunk constants, no density or
|
|
630
|
+
* yield modeling: document content never enters this arithmetic. The guard
|
|
631
|
+
* for the pathological tail (a chunk whose annotation JSON still overflows
|
|
632
|
+
* the output budget) is `assertNotTruncated` below — invoked per chunk by
|
|
633
|
+
* the callers on every response, not a prediction here.
|
|
634
|
+
*
|
|
635
|
+
* Provider shapes (see `@semiont/inference` interface.ts):
|
|
636
|
+
* - Shared window (Ollama): the provider publishes
|
|
637
|
+
* `maxOutputTokens === contextTokens` — prompt and response share one
|
|
638
|
+
* `num_ctx`. What remains after the prompt scaffold is split
|
|
639
|
+
* input:output = 1:2 (annotation JSON echoes each span plus a fixed
|
|
640
|
+
* key/context envelope, so output needs the larger share). The 1:2 ratio
|
|
641
|
+
* is the plan's one allocation policy — doc-independent, tuned only on
|
|
642
|
+
* live evidence.
|
|
643
|
+
* - Separate ceilings (Anthropic): output takes its full ceiling (duration-
|
|
644
|
+
* capped below), and input follows the same 1:2 allocation — never more
|
|
645
|
+
* than half the output budget. Input does NOT get "the rest of the
|
|
646
|
+
* window": measured 2026-09-02, a window-sized chunk of entity-dense text
|
|
647
|
+
* demands more output than any budget holds, so the model grinds toward
|
|
648
|
+
* max_tokens for minutes (killed at the call bound as a "stall") or
|
|
649
|
+
* collapses to the degenerate []. Large documents chunk; that is the fix,
|
|
650
|
+
* not a cost.
|
|
651
|
+
*/
|
|
652
|
+
|
|
653
|
+
/** One chunk handed out by `runAdaptiveChunks`, with the cursor either side of
|
|
654
|
+
* it. `at`/`next` over `totalChars` is exact progress — and, once
|
|
655
|
+
* CHUNK-GRAIN-RESUME lands, the checkpoint identity a variable boundary forces
|
|
656
|
+
* (an ordinal cannot name a chunk whose size is decided while the job runs). */
|
|
657
|
+
/**
|
|
658
|
+
* The half of a `UnitCursor` the DETECTION layer can honestly report: where the
|
|
659
|
+
* walk stands and how it is cutting. The tallies belong to the processor, which
|
|
660
|
+
* owns unit identity and unit counts — this loop counts chunks, not annotations,
|
|
661
|
+
* and a zero it invented would be indistinguishable from a real one.
|
|
662
|
+
*/
|
|
663
|
+
type ChunkCursor = Pick<UnitCursor, 'next' | 'size'>;
|
|
664
|
+
|
|
565
665
|
/**
|
|
566
666
|
* Response parsers for annotation detection motivations
|
|
567
667
|
*
|
|
@@ -638,9 +738,12 @@ declare class AnnotationDetection {
|
|
|
638
738
|
* (source-resource locale). See `types.ts` "Locale conventions" for the
|
|
639
739
|
* full discussion.
|
|
640
740
|
*/
|
|
641
|
-
static detectComments(content: string, client: InferenceClient, instructions?: string, tone?: string, density?: number, language?: string, sourceLanguage?: string, onActivity?: (
|
|
741
|
+
static detectComments(content: string, client: InferenceClient, instructions?: string, tone?: string, density?: number, language?: string, sourceLanguage?: string, onActivity?: (consumedChars: number, totalChars: number) => void,
|
|
642
742
|
/** This chunk's matches, as the chunk completes. */
|
|
643
|
-
|
|
743
|
+
/** Where an earlier attempt left this unit (CHUNK-GRAIN-RESUME P3). */
|
|
744
|
+
resume?: UnitCursor,
|
|
745
|
+
/** This chunk's matches, as the chunk completes. Kept LAST. */
|
|
746
|
+
onChunkResults?: (matches: CommentMatch[], cursor: ChunkCursor) => Promise<void>): Promise<CommentMatch[]>;
|
|
644
747
|
/**
|
|
645
748
|
* Detect highlights in content.
|
|
646
749
|
*
|
|
@@ -648,9 +751,12 @@ declare class AnnotationDetection {
|
|
|
648
751
|
* applies, used in the prompt so the LLM analyzes non-English source
|
|
649
752
|
* correctly.
|
|
650
753
|
*/
|
|
651
|
-
static detectHighlights(content: string, client: InferenceClient, instructions?: string, density?: number, sourceLanguage?: string, onActivity?: (
|
|
754
|
+
static detectHighlights(content: string, client: InferenceClient, instructions?: string, density?: number, sourceLanguage?: string, onActivity?: (consumedChars: number, totalChars: number) => void,
|
|
652
755
|
/** This chunk's matches, as the chunk completes. */
|
|
653
|
-
|
|
756
|
+
/** Where an earlier attempt left this unit (CHUNK-GRAIN-RESUME P3). */
|
|
757
|
+
resume?: UnitCursor,
|
|
758
|
+
/** This chunk's matches, as the chunk completes. Kept LAST. */
|
|
759
|
+
onChunkResults?: (matches: HighlightMatch[], cursor: ChunkCursor) => Promise<void>): Promise<HighlightMatch[]>;
|
|
654
760
|
/**
|
|
655
761
|
* Detect assessments in content.
|
|
656
762
|
*
|
|
@@ -658,9 +764,12 @@ declare class AnnotationDetection {
|
|
|
658
764
|
* (annotation body locale). `sourceLanguage` is the locale of the content
|
|
659
765
|
* being analyzed (source-resource locale).
|
|
660
766
|
*/
|
|
661
|
-
static detectAssessments(content: string, client: InferenceClient, instructions?: string, tone?: string, density?: number, language?: string, sourceLanguage?: string, onActivity?: (
|
|
767
|
+
static detectAssessments(content: string, client: InferenceClient, instructions?: string, tone?: string, density?: number, language?: string, sourceLanguage?: string, onActivity?: (consumedChars: number, totalChars: number) => void,
|
|
662
768
|
/** This chunk's matches, as the chunk completes. */
|
|
663
|
-
|
|
769
|
+
/** Where an earlier attempt left this unit (CHUNK-GRAIN-RESUME P3). */
|
|
770
|
+
resume?: UnitCursor,
|
|
771
|
+
/** This chunk's matches, as the chunk completes. Kept LAST. */
|
|
772
|
+
onChunkResults?: (matches: AssessmentMatch[], cursor: ChunkCursor) => Promise<void>): Promise<AssessmentMatch[]>;
|
|
664
773
|
/**
|
|
665
774
|
* Detect tags in content for a specific category.
|
|
666
775
|
*
|
|
@@ -673,13 +782,16 @@ declare class AnnotationDetection {
|
|
|
673
782
|
* identifiers, not LLM-generated text — so it's consumed at the body-stamp
|
|
674
783
|
* site, not here.
|
|
675
784
|
*/
|
|
676
|
-
static detectTags(content: string, client: InferenceClient, schema: TagSchema, category: string, sourceLanguage?: string, onActivity?: (
|
|
785
|
+
static detectTags(content: string, client: InferenceClient, schema: TagSchema, category: string, sourceLanguage?: string, onActivity?: (consumedChars: number, totalChars: number) => void,
|
|
677
786
|
/**
|
|
678
787
|
* This chunk's matches, ANCHORED before they leave: `parse` here yields
|
|
679
788
|
* raw tags, so this path runs `validateTagOffsets` per chunk — a per-item
|
|
680
789
|
* anchor against the full document, so partitioning changes nothing.
|
|
681
790
|
*/
|
|
682
|
-
|
|
791
|
+
/** Where an earlier attempt left this unit (CHUNK-GRAIN-RESUME P3). */
|
|
792
|
+
resume?: UnitCursor,
|
|
793
|
+
/** This chunk's matches, as the chunk completes. Kept LAST. */
|
|
794
|
+
onChunkResults?: (matches: TagMatch[], cursor: ChunkCursor) => Promise<void>): Promise<TagMatch[]>;
|
|
683
795
|
}
|
|
684
796
|
|
|
685
797
|
/**
|