@semiont/jobs 0.5.30 → 0.5.32
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.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +54 -52
- package/dist/worker-main.js.map +1 -1
- package/package.json +8 -8
package/dist/worker-main.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { replyChannelsFor, createTomlConfigLoader, didToAgent, baseUrl, STARTUP_FETCH_RETRY, retryWithBackoff, isTransientFetchError, isObject, isString, isNumber, busRequest, isArray, resourceId, getPrimaryMediaType, isGenerationJobParams, capabilitiesOf, assembleAnnotation, findClaimSpan,
|
|
2
|
-
import { archivistContentReads, extractPdfTextLayer,
|
|
1
|
+
import { replyChannelsFor, createTomlConfigLoader, didToAgent, baseUrl, STARTUP_FETCH_RETRY, retryWithBackoff, isTransientFetchError, isObject, isString, isNumber, busRequest, isArray, resourceId, getPrimaryMediaType, isGenerationJobParams, capabilitiesOf, assembleAnnotation, findClaimSpan, textSourceOf, yieldsGeometryOf, decodeRepresentation, GENERATABLE_MEDIA_TYPES, locate, createFragmentSelector, deriveViews, estimateTokens, chunkText, reconcileSelector, getLocaleEnglishName } from '@semiont/core';
|
|
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, StructuredReadError } from '@semiont/inference';
|
|
5
5
|
import { execFileSync } from 'child_process';
|
|
@@ -11216,28 +11216,43 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger2
|
|
|
11216
11216
|
}
|
|
11217
11217
|
|
|
11218
11218
|
// src/workers/detection/prepare-detection.ts
|
|
11219
|
-
async function prepareDetection(mediaType, content, resourceId, userId, generator,
|
|
11220
|
-
|
|
11221
|
-
if (
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11219
|
+
async function prepareDetection(mediaType, content, resourceId, userId, generator, consult) {
|
|
11220
|
+
if (textSourceOf(mediaType) === "none") return { declined: "no-extractor" };
|
|
11221
|
+
if (yieldsGeometryOf(mediaType)) {
|
|
11222
|
+
const answer = await consult(resourceId);
|
|
11223
|
+
switch (answer.kind) {
|
|
11224
|
+
case "extracted": {
|
|
11225
|
+
if (!answer.text.trim()) return { declined: "empty" };
|
|
11226
|
+
const anchored = { text: answer.text, items: answer.items ?? [] };
|
|
11227
|
+
return {
|
|
11228
|
+
text: answer.text,
|
|
11229
|
+
buildAnnotation: (motivation, match, body) => buildPdfAnnotation(anchored, resourceId, userId, generator, motivation, match, body)
|
|
11230
|
+
};
|
|
11231
|
+
}
|
|
11232
|
+
// The Smelter's own decline (encrypted, corrupt) — passed through by name.
|
|
11233
|
+
case "declined":
|
|
11234
|
+
return { declined: answer.declined };
|
|
11235
|
+
// Named absences: `not-yet` retries, the other two are terminal.
|
|
11236
|
+
case "not-yet":
|
|
11237
|
+
return { declined: "not-yet" };
|
|
11238
|
+
case "no-map":
|
|
11239
|
+
return { declined: "no-map" };
|
|
11240
|
+
case "unknown":
|
|
11241
|
+
return { declined: "unknown" };
|
|
11242
|
+
default: {
|
|
11243
|
+
const unhandled = answer;
|
|
11244
|
+
throw new DeterministicJobError(
|
|
11245
|
+
`Unhandled anchored-text answer for resource ${resourceId}: ${JSON.stringify(unhandled)}`
|
|
11246
|
+
);
|
|
11247
|
+
}
|
|
11248
|
+
}
|
|
11237
11249
|
}
|
|
11250
|
+
const { data } = await content.getBinary(resourceId);
|
|
11251
|
+
const text = decodeRepresentation(Buffer.from(data), mediaType);
|
|
11252
|
+
if (!text.trim()) return { declined: "empty" };
|
|
11238
11253
|
return {
|
|
11239
|
-
text
|
|
11240
|
-
buildAnnotation: (motivation, match, body) => buildTextAnnotation(
|
|
11254
|
+
text,
|
|
11255
|
+
buildAnnotation: (motivation, match, body) => buildTextAnnotation(text, resourceId, userId, generator, motivation, match, body)
|
|
11241
11256
|
};
|
|
11242
11257
|
}
|
|
11243
11258
|
function referenceIdOf(job) {
|
|
@@ -11372,13 +11387,19 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal)
|
|
|
11372
11387
|
const mediaType = getPrimaryMediaType(descriptor);
|
|
11373
11388
|
const source = await withSpan(
|
|
11374
11389
|
"detection:prepare",
|
|
11375
|
-
() => prepareDetection(mediaType ?? "", config.contentReads, resourceId$1, userId, generator,
|
|
11390
|
+
() => prepareDetection(mediaType ?? "", config.contentReads, resourceId$1, userId, generator, (rid) => session.client.browse.resourceAnchoredText(rid)),
|
|
11376
11391
|
{ attrs: { "resource.id": resourceId$1, "media.type": mediaType ?? "unknown" } }
|
|
11377
11392
|
);
|
|
11378
11393
|
if ("declined" in source) {
|
|
11394
|
+
if (source.declined === "not-yet") {
|
|
11395
|
+
throw new Error(`Anchored text not yet derived for resource ${resourceId$1} \u2014 Smelter has not settled; retrying`);
|
|
11396
|
+
}
|
|
11379
11397
|
if (source.declined === "no-extractor") {
|
|
11380
11398
|
throw new DeterministicJobError(`Cannot run ${jobType} on resource ${resourceId$1}: media type '${mediaType ?? "unknown"}' has no extractable text to analyze`);
|
|
11381
11399
|
}
|
|
11400
|
+
if (source.declined === "no-map" || source.declined === "unknown") {
|
|
11401
|
+
throw new DeterministicJobError(`Cannot run ${jobType} on resource ${resourceId$1}: anchored-text consult returned '${source.declined}'`);
|
|
11402
|
+
}
|
|
11382
11403
|
await emitEvent(session, "job:complete", {
|
|
11383
11404
|
...lifecycleBase,
|
|
11384
11405
|
result: {
|
|
@@ -11611,29 +11632,6 @@ async function handleJobInner(adapter, config, job, completedUnitsByJob, signal)
|
|
|
11611
11632
|
}
|
|
11612
11633
|
}
|
|
11613
11634
|
|
|
11614
|
-
// src/anchored-text-over-bus.ts
|
|
11615
|
-
function anchoredTextOverBus(client, logger2) {
|
|
11616
|
-
return {
|
|
11617
|
-
async read(key) {
|
|
11618
|
-
try {
|
|
11619
|
-
return await client.browse.anchoredTextByChecksum(key);
|
|
11620
|
-
} catch (error) {
|
|
11621
|
-
logger2?.debug("Anchored-text consult failed \u2014 treating as miss", {
|
|
11622
|
-
key,
|
|
11623
|
-
reason: error instanceof Error ? error.message : String(error)
|
|
11624
|
-
});
|
|
11625
|
-
return null;
|
|
11626
|
-
}
|
|
11627
|
-
},
|
|
11628
|
-
async write(key) {
|
|
11629
|
-
logger2?.debug("Anchored-text write skipped \u2014 the Smelter is the sole writer", { key });
|
|
11630
|
-
},
|
|
11631
|
-
async list() {
|
|
11632
|
-
return [];
|
|
11633
|
-
}
|
|
11634
|
-
};
|
|
11635
|
-
}
|
|
11636
|
-
|
|
11637
11635
|
// src/worker-runtime.ts
|
|
11638
11636
|
var import_rxjs2 = __toESM(require_cjs());
|
|
11639
11637
|
function buildHealthPayload(workers) {
|
|
@@ -11676,7 +11674,12 @@ function startStallWatchdog(opts) {
|
|
|
11676
11674
|
var WORKER_AWAITED_OPERATIONS = [
|
|
11677
11675
|
"job:claim",
|
|
11678
11676
|
"browse:resource-requested",
|
|
11679
|
-
|
|
11677
|
+
// Canonical geometry for a geometry-bearing detection: the consult behind
|
|
11678
|
+
// `ConsultAnchoredText` (SMELTER-OWNS-OCR P2). Its omission broke every
|
|
11679
|
+
// PDF detection job at the transport probe
|
|
11680
|
+
// (.plans/WORKER-ANCHORED-TEXT-CHANNEL.md); the census below now fails the
|
|
11681
|
+
// BUILD when this list and the declared awaits drift.
|
|
11682
|
+
"browse:anchored-text-requested",
|
|
11680
11683
|
// Durability acknowledgement for a unit's annotations (JOB-RESTART-SAFETY
|
|
11681
11684
|
// P6). The worker AWAITS this one — a unit may not advance until its
|
|
11682
11685
|
// annotations are in the event log — so its replies must be in the narrow
|
|
@@ -11788,11 +11791,10 @@ async function startAgentWorker(opts) {
|
|
|
11788
11791
|
jobTypes: group.jobTypes,
|
|
11789
11792
|
inferenceClient: group.client,
|
|
11790
11793
|
generator,
|
|
11791
|
-
//
|
|
11792
|
-
//
|
|
11793
|
-
//
|
|
11794
|
-
//
|
|
11795
|
-
anchoredTextStore: anchoredTextOverBus(client, logger2),
|
|
11794
|
+
// Byte reads for decode-path media only. A geometry-bearing type's text
|
|
11795
|
+
// never comes from bytes here — it is CONSULTED from the Smelter's
|
|
11796
|
+
// canonical anchored text over the bus (SMELTER-OWNS-OCR P2), and this
|
|
11797
|
+
// worker cannot derive even by mistake (READ-VS-EXTRACT P2).
|
|
11796
11798
|
contentReads: contentReads2,
|
|
11797
11799
|
logger: logger2
|
|
11798
11800
|
});
|