@semiont/jobs 0.5.8 → 0.5.10
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 +26 -6
- package/dist/index.js +238 -231
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +291 -278
- package/dist/worker-main.js.map +1 -1
- package/package.json +8 -8
package/dist/worker-main.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createTomlConfigLoader, softwareToAgent, baseUrl, getPrimaryMediaType, textExtractionOf, reconcileSelector, didToAgent, getLocaleEnglishName } from '@semiont/core';
|
|
1
|
+
import { createTomlConfigLoader, softwareToAgent, baseUrl, busRequest, getPrimaryMediaType, textExtractionOf, assembleAnnotation, reconcileSelector, didToAgent, getLocaleEnglishName, isArray, isObject, isString, deriveViews } from '@semiont/core';
|
|
2
2
|
import { deriveStorageUri } from '@semiont/content';
|
|
3
3
|
import { withSpan, SpanKind, recordJobOutcome } from '@semiont/observability';
|
|
4
4
|
import { generateAnnotationId } from '@semiont/event-sourcing';
|
|
@@ -326,16 +326,16 @@ var require_timeoutProvider = __commonJS({
|
|
|
326
326
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
327
327
|
exports.timeoutProvider = void 0;
|
|
328
328
|
exports.timeoutProvider = {
|
|
329
|
-
setTimeout: function(handler,
|
|
329
|
+
setTimeout: function(handler, timeout) {
|
|
330
330
|
var args = [];
|
|
331
331
|
for (var _i = 2; _i < arguments.length; _i++) {
|
|
332
332
|
args[_i - 2] = arguments[_i];
|
|
333
333
|
}
|
|
334
334
|
var delegate = exports.timeoutProvider.delegate;
|
|
335
335
|
if (delegate === null || delegate === void 0 ? void 0 : delegate.setTimeout) {
|
|
336
|
-
return delegate.setTimeout.apply(delegate, __spreadArray([handler,
|
|
336
|
+
return delegate.setTimeout.apply(delegate, __spreadArray([handler, timeout], __read(args)));
|
|
337
337
|
}
|
|
338
|
-
return setTimeout.apply(void 0, __spreadArray([handler,
|
|
338
|
+
return setTimeout.apply(void 0, __spreadArray([handler, timeout], __read(args)));
|
|
339
339
|
},
|
|
340
340
|
clearTimeout: function(handle) {
|
|
341
341
|
var delegate = exports.timeoutProvider.delegate;
|
|
@@ -1659,16 +1659,16 @@ var require_intervalProvider = __commonJS({
|
|
|
1659
1659
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1660
1660
|
exports.intervalProvider = void 0;
|
|
1661
1661
|
exports.intervalProvider = {
|
|
1662
|
-
setInterval: function(handler,
|
|
1662
|
+
setInterval: function(handler, timeout) {
|
|
1663
1663
|
var args = [];
|
|
1664
1664
|
for (var _i = 2; _i < arguments.length; _i++) {
|
|
1665
1665
|
args[_i - 2] = arguments[_i];
|
|
1666
1666
|
}
|
|
1667
1667
|
var delegate = exports.intervalProvider.delegate;
|
|
1668
1668
|
if (delegate === null || delegate === void 0 ? void 0 : delegate.setInterval) {
|
|
1669
|
-
return delegate.setInterval.apply(delegate, __spreadArray([handler,
|
|
1669
|
+
return delegate.setInterval.apply(delegate, __spreadArray([handler, timeout], __read(args)));
|
|
1670
1670
|
}
|
|
1671
|
-
return setInterval.apply(void 0, __spreadArray([handler,
|
|
1671
|
+
return setInterval.apply(void 0, __spreadArray([handler, timeout], __read(args)));
|
|
1672
1672
|
},
|
|
1673
1673
|
clearInterval: function(handle) {
|
|
1674
1674
|
var delegate = exports.intervalProvider.delegate;
|
|
@@ -3566,7 +3566,7 @@ var require_firstValueFrom = __commonJS({
|
|
|
3566
3566
|
exports.firstValueFrom = void 0;
|
|
3567
3567
|
var EmptyError_1 = require_EmptyError();
|
|
3568
3568
|
var Subscriber_1 = require_Subscriber();
|
|
3569
|
-
function
|
|
3569
|
+
function firstValueFrom(source, config) {
|
|
3570
3570
|
var hasConfig = typeof config === "object";
|
|
3571
3571
|
return new Promise(function(resolve, reject) {
|
|
3572
3572
|
var subscriber = new Subscriber_1.SafeSubscriber({
|
|
@@ -3586,7 +3586,7 @@ var require_firstValueFrom = __commonJS({
|
|
|
3586
3586
|
source.subscribe(subscriber);
|
|
3587
3587
|
});
|
|
3588
3588
|
}
|
|
3589
|
-
exports.firstValueFrom =
|
|
3589
|
+
exports.firstValueFrom = firstValueFrom;
|
|
3590
3590
|
}
|
|
3591
3591
|
});
|
|
3592
3592
|
|
|
@@ -3673,7 +3673,7 @@ var require_timeout = __commonJS({
|
|
|
3673
3673
|
this.info = info;
|
|
3674
3674
|
};
|
|
3675
3675
|
});
|
|
3676
|
-
function
|
|
3676
|
+
function timeout(config, schedulerArg) {
|
|
3677
3677
|
var _a = isDate_1.isValidDate(config) ? { first: config } : typeof config === "number" ? { each: config } : config, first = _a.first, each = _a.each, _b = _a.with, _with = _b === void 0 ? timeoutErrorFactory : _b, _c = _a.scheduler, scheduler = _c === void 0 ? schedulerArg !== null && schedulerArg !== void 0 ? schedulerArg : async_1.asyncScheduler : _c, _d = _a.meta, meta = _d === void 0 ? null : _d;
|
|
3678
3678
|
if (first == null && each == null) {
|
|
3679
3679
|
throw new TypeError("No timeout provided.");
|
|
@@ -3711,7 +3711,7 @@ var require_timeout = __commonJS({
|
|
|
3711
3711
|
!seen && startTimer(first != null ? typeof first === "number" ? first : +first - scheduler.now() : each);
|
|
3712
3712
|
});
|
|
3713
3713
|
}
|
|
3714
|
-
exports.timeout =
|
|
3714
|
+
exports.timeout = timeout;
|
|
3715
3715
|
function timeoutErrorFactory(info) {
|
|
3716
3716
|
throw new exports.TimeoutError(info);
|
|
3717
3717
|
}
|
|
@@ -3725,7 +3725,7 @@ var require_map = __commonJS({
|
|
|
3725
3725
|
exports.map = void 0;
|
|
3726
3726
|
var lift_1 = require_lift();
|
|
3727
3727
|
var OperatorSubscriber_1 = require_OperatorSubscriber();
|
|
3728
|
-
function
|
|
3728
|
+
function map(project, thisArg) {
|
|
3729
3729
|
return lift_1.operate(function(source, subscriber) {
|
|
3730
3730
|
var index = 0;
|
|
3731
3731
|
source.subscribe(OperatorSubscriber_1.createOperatorSubscriber(subscriber, function(value) {
|
|
@@ -3733,7 +3733,7 @@ var require_map = __commonJS({
|
|
|
3733
3733
|
}));
|
|
3734
3734
|
});
|
|
3735
3735
|
}
|
|
3736
|
-
exports.map =
|
|
3736
|
+
exports.map = map;
|
|
3737
3737
|
}
|
|
3738
3738
|
});
|
|
3739
3739
|
|
|
@@ -3765,9 +3765,9 @@ var require_mapOneOrManyArgs = __commonJS({
|
|
|
3765
3765
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3766
3766
|
exports.mapOneOrManyArgs = void 0;
|
|
3767
3767
|
var map_1 = require_map();
|
|
3768
|
-
var
|
|
3768
|
+
var isArray2 = Array.isArray;
|
|
3769
3769
|
function callOrApply(fn, args) {
|
|
3770
|
-
return
|
|
3770
|
+
return isArray2(args) ? fn.apply(void 0, __spreadArray([], __read(args))) : fn(args);
|
|
3771
3771
|
}
|
|
3772
3772
|
function mapOneOrManyArgs(fn) {
|
|
3773
3773
|
return map_1.map(function(args) {
|
|
@@ -3912,14 +3912,14 @@ var require_argsArgArrayOrObject = __commonJS({
|
|
|
3912
3912
|
"../../node_modules/rxjs/dist/cjs/internal/util/argsArgArrayOrObject.js"(exports) {
|
|
3913
3913
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3914
3914
|
exports.argsArgArrayOrObject = void 0;
|
|
3915
|
-
var
|
|
3915
|
+
var isArray2 = Array.isArray;
|
|
3916
3916
|
var getPrototypeOf = Object.getPrototypeOf;
|
|
3917
3917
|
var objectProto = Object.prototype;
|
|
3918
3918
|
var getKeys = Object.keys;
|
|
3919
3919
|
function argsArgArrayOrObject(args) {
|
|
3920
3920
|
if (args.length === 1) {
|
|
3921
3921
|
var first_1 = args[0];
|
|
3922
|
-
if (
|
|
3922
|
+
if (isArray2(first_1)) {
|
|
3923
3923
|
return { args: first_1, keys: null };
|
|
3924
3924
|
}
|
|
3925
3925
|
if (isPOJO(first_1)) {
|
|
@@ -4633,7 +4633,7 @@ var require_merge = __commonJS({
|
|
|
4633
4633
|
var empty_1 = require_empty();
|
|
4634
4634
|
var args_1 = require_args();
|
|
4635
4635
|
var from_1 = require_from();
|
|
4636
|
-
function
|
|
4636
|
+
function merge() {
|
|
4637
4637
|
var args = [];
|
|
4638
4638
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
4639
4639
|
args[_i] = arguments[_i];
|
|
@@ -4643,7 +4643,7 @@ var require_merge = __commonJS({
|
|
|
4643
4643
|
var sources = args;
|
|
4644
4644
|
return !sources.length ? empty_1.EMPTY : sources.length === 1 ? innerFrom_1.innerFrom(sources[0]) : mergeAll_1.mergeAll(concurrent)(from_1.from(sources, scheduler));
|
|
4645
4645
|
}
|
|
4646
|
-
exports.merge =
|
|
4646
|
+
exports.merge = merge;
|
|
4647
4647
|
}
|
|
4648
4648
|
});
|
|
4649
4649
|
|
|
@@ -4667,9 +4667,9 @@ var require_argsOrArgArray = __commonJS({
|
|
|
4667
4667
|
"../../node_modules/rxjs/dist/cjs/internal/util/argsOrArgArray.js"(exports) {
|
|
4668
4668
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4669
4669
|
exports.argsOrArgArray = void 0;
|
|
4670
|
-
var
|
|
4670
|
+
var isArray2 = Array.isArray;
|
|
4671
4671
|
function argsOrArgArray(args) {
|
|
4672
|
-
return args.length === 1 &&
|
|
4672
|
+
return args.length === 1 && isArray2(args[0]) ? args[0] : args;
|
|
4673
4673
|
}
|
|
4674
4674
|
exports.argsOrArgArray = argsOrArgArray;
|
|
4675
4675
|
}
|
|
@@ -4750,7 +4750,7 @@ var require_filter = __commonJS({
|
|
|
4750
4750
|
exports.filter = void 0;
|
|
4751
4751
|
var lift_1 = require_lift();
|
|
4752
4752
|
var OperatorSubscriber_1 = require_OperatorSubscriber();
|
|
4753
|
-
function
|
|
4753
|
+
function filter(predicate, thisArg) {
|
|
4754
4754
|
return lift_1.operate(function(source, subscriber) {
|
|
4755
4755
|
var index = 0;
|
|
4756
4756
|
source.subscribe(OperatorSubscriber_1.createOperatorSubscriber(subscriber, function(value) {
|
|
@@ -4758,7 +4758,7 @@ var require_filter = __commonJS({
|
|
|
4758
4758
|
}));
|
|
4759
4759
|
});
|
|
4760
4760
|
}
|
|
4761
|
-
exports.filter =
|
|
4761
|
+
exports.filter = filter;
|
|
4762
4762
|
}
|
|
4763
4763
|
});
|
|
4764
4764
|
|
|
@@ -5885,7 +5885,7 @@ var require_take = __commonJS({
|
|
|
5885
5885
|
var empty_1 = require_empty();
|
|
5886
5886
|
var lift_1 = require_lift();
|
|
5887
5887
|
var OperatorSubscriber_1 = require_OperatorSubscriber();
|
|
5888
|
-
function
|
|
5888
|
+
function take(count) {
|
|
5889
5889
|
return count <= 0 ? function() {
|
|
5890
5890
|
return empty_1.EMPTY;
|
|
5891
5891
|
} : lift_1.operate(function(source, subscriber) {
|
|
@@ -5900,7 +5900,7 @@ var require_take = __commonJS({
|
|
|
5900
5900
|
}));
|
|
5901
5901
|
});
|
|
5902
5902
|
}
|
|
5903
|
-
exports.take =
|
|
5903
|
+
exports.take = take;
|
|
5904
5904
|
}
|
|
5905
5905
|
});
|
|
5906
5906
|
|
|
@@ -6692,7 +6692,7 @@ var require_merge2 = __commonJS({
|
|
|
6692
6692
|
var mergeAll_1 = require_mergeAll();
|
|
6693
6693
|
var args_1 = require_args();
|
|
6694
6694
|
var from_1 = require_from();
|
|
6695
|
-
function
|
|
6695
|
+
function merge() {
|
|
6696
6696
|
var args = [];
|
|
6697
6697
|
for (var _i = 0; _i < arguments.length; _i++) {
|
|
6698
6698
|
args[_i] = arguments[_i];
|
|
@@ -6703,7 +6703,7 @@ var require_merge2 = __commonJS({
|
|
|
6703
6703
|
mergeAll_1.mergeAll(concurrent)(from_1.from(__spreadArray([source], __read(args)), scheduler)).subscribe(subscriber);
|
|
6704
6704
|
});
|
|
6705
6705
|
}
|
|
6706
|
-
exports.merge =
|
|
6706
|
+
exports.merge = merge;
|
|
6707
6707
|
}
|
|
6708
6708
|
});
|
|
6709
6709
|
|
|
@@ -9207,9 +9207,19 @@ var require_cjs = __commonJS({
|
|
|
9207
9207
|
|
|
9208
9208
|
// src/job-claim-adapter.ts
|
|
9209
9209
|
var import_rxjs = __toESM(require_cjs());
|
|
9210
|
-
|
|
9210
|
+
function workerBusAsPrimitive(bus) {
|
|
9211
|
+
return {
|
|
9212
|
+
emit(channel, payload) {
|
|
9213
|
+
return bus.emit(channel, payload);
|
|
9214
|
+
},
|
|
9215
|
+
stream(channel) {
|
|
9216
|
+
return bus.on$(channel);
|
|
9217
|
+
}
|
|
9218
|
+
};
|
|
9219
|
+
}
|
|
9211
9220
|
function createJobClaimAdapter(options) {
|
|
9212
9221
|
const { bus, jobTypes } = options;
|
|
9222
|
+
const requestBus = workerBusAsPrimitive(bus);
|
|
9213
9223
|
const activeJob$ = new import_rxjs.BehaviorSubject(null);
|
|
9214
9224
|
const isProcessing$ = new import_rxjs.BehaviorSubject(false);
|
|
9215
9225
|
const jobsCompleted$ = new import_rxjs.BehaviorSubject(0);
|
|
@@ -9218,22 +9228,7 @@ function createJobClaimAdapter(options) {
|
|
|
9218
9228
|
let started = false;
|
|
9219
9229
|
const claimJob = async (assignment) => {
|
|
9220
9230
|
try {
|
|
9221
|
-
const
|
|
9222
|
-
const result$ = (0, import_rxjs2.merge)(
|
|
9223
|
-
bus.on$("job:claimed").pipe(
|
|
9224
|
-
(0, import_rxjs2.filter)((e) => e.correlationId === correlationId),
|
|
9225
|
-
(0, import_rxjs2.map)((e) => ({ ok: true, response: e.response }))
|
|
9226
|
-
),
|
|
9227
|
-
bus.on$("job:claim-failed").pipe(
|
|
9228
|
-
(0, import_rxjs2.filter)((e) => e.correlationId === correlationId),
|
|
9229
|
-
(0, import_rxjs2.map)(() => ({ ok: false }))
|
|
9230
|
-
)
|
|
9231
|
-
).pipe((0, import_rxjs2.take)(1), (0, import_rxjs2.timeout)(1e4));
|
|
9232
|
-
const resultPromise = (0, import_rxjs2.firstValueFrom)(result$);
|
|
9233
|
-
await bus.emit("job:claim", { correlationId, jobId: assignment.jobId });
|
|
9234
|
-
const result = await resultPromise;
|
|
9235
|
-
if (!result.ok) return null;
|
|
9236
|
-
const job = result.response;
|
|
9231
|
+
const job = await busRequest(requestBus, "job:claim", { jobId: assignment.jobId }, 1e4);
|
|
9237
9232
|
return {
|
|
9238
9233
|
jobId: assignment.jobId,
|
|
9239
9234
|
type: assignment.type,
|
|
@@ -9587,197 +9582,144 @@ Example format:
|
|
|
9587
9582
|
return prompt;
|
|
9588
9583
|
}
|
|
9589
9584
|
};
|
|
9590
|
-
function
|
|
9591
|
-
let
|
|
9592
|
-
if (cleaned.startsWith("```")) {
|
|
9593
|
-
cleaned = cleaned.replace(/^```(?:json)?\s*\n?/, "").replace(/\n?```\s*$/, "");
|
|
9594
|
-
}
|
|
9585
|
+
function parseJsonArray(response, motivation) {
|
|
9586
|
+
let parsed;
|
|
9595
9587
|
try {
|
|
9596
|
-
|
|
9597
|
-
|
|
9598
|
-
|
|
9599
|
-
|
|
9600
|
-
|
|
9601
|
-
|
|
9602
|
-
|
|
9603
|
-
|
|
9604
|
-
|
|
9605
|
-
const objects = [];
|
|
9606
|
-
let depth = 0;
|
|
9607
|
-
let objStart = -1;
|
|
9608
|
-
let inString = false;
|
|
9609
|
-
let escape = false;
|
|
9610
|
-
for (let i = 0; i < inner.length; i++) {
|
|
9611
|
-
const ch = inner[i];
|
|
9612
|
-
if (escape) {
|
|
9613
|
-
escape = false;
|
|
9614
|
-
continue;
|
|
9615
|
-
}
|
|
9616
|
-
if (ch === "\\") {
|
|
9617
|
-
escape = true;
|
|
9618
|
-
continue;
|
|
9619
|
-
}
|
|
9620
|
-
if (ch === '"') {
|
|
9621
|
-
inString = !inString;
|
|
9622
|
-
continue;
|
|
9623
|
-
}
|
|
9624
|
-
if (inString) continue;
|
|
9625
|
-
if (ch === "{") {
|
|
9626
|
-
if (depth === 0) objStart = i;
|
|
9627
|
-
depth++;
|
|
9628
|
-
} else if (ch === "}") {
|
|
9629
|
-
depth--;
|
|
9630
|
-
if (depth === 0 && objStart !== -1) {
|
|
9631
|
-
try {
|
|
9632
|
-
objects.push(JSON.parse(inner.slice(objStart, i + 1)));
|
|
9633
|
-
} catch {
|
|
9634
|
-
}
|
|
9635
|
-
objStart = -1;
|
|
9636
|
-
}
|
|
9637
|
-
}
|
|
9588
|
+
parsed = JSON.parse(response.trim());
|
|
9589
|
+
} catch (error) {
|
|
9590
|
+
console.error(`[MotivationParsers] Failed to parse AI ${motivation} response:`, error);
|
|
9591
|
+
console.error("Raw response:", response);
|
|
9592
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
9593
|
+
}
|
|
9594
|
+
if (!Array.isArray(parsed)) {
|
|
9595
|
+
console.error(`[MotivationParsers] Expected a JSON array for ${motivation} detection, got ${typeof parsed}:`, response);
|
|
9596
|
+
throw new Error(`Expected a JSON array for ${motivation} detection, got ${typeof parsed}`);
|
|
9638
9597
|
}
|
|
9639
|
-
return
|
|
9598
|
+
return parsed;
|
|
9640
9599
|
}
|
|
9641
9600
|
var MotivationParsers = class {
|
|
9642
9601
|
/**
|
|
9643
9602
|
* Parse and validate AI response for comment detection
|
|
9644
9603
|
*
|
|
9645
|
-
* @param response - Raw AI response
|
|
9604
|
+
* @param response - Raw AI response text (a JSON array)
|
|
9646
9605
|
* @param content - Original content to validate offsets against
|
|
9647
9606
|
* @returns Array of validated comment matches
|
|
9607
|
+
* @throws if the response is not a parseable JSON array
|
|
9648
9608
|
*/
|
|
9649
9609
|
static parseComments(response, content) {
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
9657
|
-
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
9664
|
-
|
|
9665
|
-
continue;
|
|
9666
|
-
}
|
|
9667
|
-
logAnchorMethod("comment", comment.exact, reconciled.anchorMethod);
|
|
9668
|
-
validatedComments.push({
|
|
9669
|
-
comment: comment.comment,
|
|
9670
|
-
exact: reconciled.exact,
|
|
9671
|
-
start: reconciled.start,
|
|
9672
|
-
end: reconciled.end,
|
|
9673
|
-
...reconciled.prefix !== void 0 ? { prefix: reconciled.prefix } : {},
|
|
9674
|
-
...reconciled.suffix !== void 0 ? { suffix: reconciled.suffix } : {}
|
|
9675
|
-
});
|
|
9610
|
+
const parsed = parseJsonArray(response, "comment");
|
|
9611
|
+
const valid = parsed.filter(
|
|
9612
|
+
(c) => isObject(c) && isString(c.exact) && isString(c.comment) && c.comment.trim().length > 0
|
|
9613
|
+
);
|
|
9614
|
+
console.log(`[MotivationParsers] Parsed ${valid.length} valid comments from ${parsed.length} total`);
|
|
9615
|
+
const validatedComments = [];
|
|
9616
|
+
for (const comment of valid) {
|
|
9617
|
+
const reconciled = reconcileSelector(content, {
|
|
9618
|
+
exact: comment.exact,
|
|
9619
|
+
...typeof comment.prefix === "string" ? { prefix: comment.prefix } : {},
|
|
9620
|
+
...typeof comment.suffix === "string" ? { suffix: comment.suffix } : {}
|
|
9621
|
+
});
|
|
9622
|
+
if (!reconciled) {
|
|
9623
|
+
console.warn(`[MotivationParsers] Dropped hallucinated comment "${comment.exact}"`);
|
|
9624
|
+
continue;
|
|
9676
9625
|
}
|
|
9677
|
-
|
|
9678
|
-
|
|
9679
|
-
|
|
9680
|
-
|
|
9626
|
+
logAnchorMethod("comment", comment.exact, reconciled.anchorMethod);
|
|
9627
|
+
validatedComments.push({
|
|
9628
|
+
comment: comment.comment,
|
|
9629
|
+
exact: reconciled.exact,
|
|
9630
|
+
start: reconciled.start,
|
|
9631
|
+
end: reconciled.end,
|
|
9632
|
+
...reconciled.prefix !== void 0 ? { prefix: reconciled.prefix } : {},
|
|
9633
|
+
...reconciled.suffix !== void 0 ? { suffix: reconciled.suffix } : {}
|
|
9634
|
+
});
|
|
9681
9635
|
}
|
|
9636
|
+
return validatedComments;
|
|
9682
9637
|
}
|
|
9683
9638
|
/**
|
|
9684
9639
|
* Parse and validate AI response for highlight detection
|
|
9685
9640
|
*
|
|
9686
|
-
* @param response - Raw AI response
|
|
9641
|
+
* @param response - Raw AI response text (a JSON array)
|
|
9687
9642
|
* @param content - Original content to validate offsets against
|
|
9688
9643
|
* @returns Array of validated highlight matches
|
|
9644
|
+
* @throws if the response is not a parseable JSON array
|
|
9689
9645
|
*/
|
|
9690
9646
|
static parseHighlights(response, content) {
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
|
|
9699
|
-
|
|
9700
|
-
|
|
9701
|
-
|
|
9702
|
-
|
|
9703
|
-
|
|
9704
|
-
|
|
9705
|
-
continue;
|
|
9706
|
-
}
|
|
9707
|
-
logAnchorMethod("highlight", highlight.exact, reconciled.anchorMethod);
|
|
9708
|
-
validatedHighlights.push({
|
|
9709
|
-
exact: reconciled.exact,
|
|
9710
|
-
start: reconciled.start,
|
|
9711
|
-
end: reconciled.end,
|
|
9712
|
-
...reconciled.prefix !== void 0 ? { prefix: reconciled.prefix } : {},
|
|
9713
|
-
...reconciled.suffix !== void 0 ? { suffix: reconciled.suffix } : {}
|
|
9714
|
-
});
|
|
9647
|
+
const parsed = parseJsonArray(response, "highlight");
|
|
9648
|
+
const highlights = parsed.filter(
|
|
9649
|
+
(h) => isObject(h) && isString(h.exact)
|
|
9650
|
+
);
|
|
9651
|
+
const validatedHighlights = [];
|
|
9652
|
+
for (const highlight of highlights) {
|
|
9653
|
+
const reconciled = reconcileSelector(content, {
|
|
9654
|
+
exact: highlight.exact,
|
|
9655
|
+
...typeof highlight.prefix === "string" ? { prefix: highlight.prefix } : {},
|
|
9656
|
+
...typeof highlight.suffix === "string" ? { suffix: highlight.suffix } : {}
|
|
9657
|
+
});
|
|
9658
|
+
if (!reconciled) {
|
|
9659
|
+
console.warn(`[MotivationParsers] Dropped hallucinated highlight "${highlight.exact}"`);
|
|
9660
|
+
continue;
|
|
9715
9661
|
}
|
|
9716
|
-
|
|
9717
|
-
|
|
9718
|
-
|
|
9719
|
-
|
|
9720
|
-
|
|
9662
|
+
logAnchorMethod("highlight", highlight.exact, reconciled.anchorMethod);
|
|
9663
|
+
validatedHighlights.push({
|
|
9664
|
+
exact: reconciled.exact,
|
|
9665
|
+
start: reconciled.start,
|
|
9666
|
+
end: reconciled.end,
|
|
9667
|
+
...reconciled.prefix !== void 0 ? { prefix: reconciled.prefix } : {},
|
|
9668
|
+
...reconciled.suffix !== void 0 ? { suffix: reconciled.suffix } : {}
|
|
9669
|
+
});
|
|
9721
9670
|
}
|
|
9671
|
+
return validatedHighlights;
|
|
9722
9672
|
}
|
|
9723
9673
|
/**
|
|
9724
9674
|
* Parse and validate AI response for assessment detection
|
|
9725
9675
|
*
|
|
9726
|
-
* @param response - Raw AI response
|
|
9676
|
+
* @param response - Raw AI response text (a JSON array)
|
|
9727
9677
|
* @param content - Original content to validate offsets against
|
|
9728
9678
|
* @returns Array of validated assessment matches
|
|
9679
|
+
* @throws if the response is not a parseable JSON array
|
|
9729
9680
|
*/
|
|
9730
9681
|
static parseAssessments(response, content) {
|
|
9731
|
-
|
|
9732
|
-
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
|
|
9737
|
-
|
|
9738
|
-
|
|
9739
|
-
|
|
9740
|
-
|
|
9741
|
-
|
|
9742
|
-
|
|
9743
|
-
|
|
9744
|
-
|
|
9745
|
-
continue;
|
|
9746
|
-
}
|
|
9747
|
-
logAnchorMethod("assessment", assessment.exact, reconciled.anchorMethod);
|
|
9748
|
-
validatedAssessments.push({
|
|
9749
|
-
assessment: assessment.assessment,
|
|
9750
|
-
exact: reconciled.exact,
|
|
9751
|
-
start: reconciled.start,
|
|
9752
|
-
end: reconciled.end,
|
|
9753
|
-
...reconciled.prefix !== void 0 ? { prefix: reconciled.prefix } : {},
|
|
9754
|
-
...reconciled.suffix !== void 0 ? { suffix: reconciled.suffix } : {}
|
|
9755
|
-
});
|
|
9682
|
+
const parsed = parseJsonArray(response, "assessment");
|
|
9683
|
+
const assessments = parsed.filter(
|
|
9684
|
+
(a) => isObject(a) && isString(a.exact) && isString(a.assessment)
|
|
9685
|
+
);
|
|
9686
|
+
const validatedAssessments = [];
|
|
9687
|
+
for (const assessment of assessments) {
|
|
9688
|
+
const reconciled = reconcileSelector(content, {
|
|
9689
|
+
exact: assessment.exact,
|
|
9690
|
+
...typeof assessment.prefix === "string" ? { prefix: assessment.prefix } : {},
|
|
9691
|
+
...typeof assessment.suffix === "string" ? { suffix: assessment.suffix } : {}
|
|
9692
|
+
});
|
|
9693
|
+
if (!reconciled) {
|
|
9694
|
+
console.warn(`[MotivationParsers] Dropped hallucinated assessment "${assessment.exact}"`);
|
|
9695
|
+
continue;
|
|
9756
9696
|
}
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9697
|
+
logAnchorMethod("assessment", assessment.exact, reconciled.anchorMethod);
|
|
9698
|
+
validatedAssessments.push({
|
|
9699
|
+
assessment: assessment.assessment,
|
|
9700
|
+
exact: reconciled.exact,
|
|
9701
|
+
start: reconciled.start,
|
|
9702
|
+
end: reconciled.end,
|
|
9703
|
+
...reconciled.prefix !== void 0 ? { prefix: reconciled.prefix } : {},
|
|
9704
|
+
...reconciled.suffix !== void 0 ? { suffix: reconciled.suffix } : {}
|
|
9705
|
+
});
|
|
9762
9706
|
}
|
|
9707
|
+
return validatedAssessments;
|
|
9763
9708
|
}
|
|
9764
9709
|
/**
|
|
9765
9710
|
* Parse the LLM's tag response into raw, pre-reconciliation tag inputs.
|
|
9766
9711
|
* Reconciliation happens in `validateTagOffsets`, which adds `start`/`end`
|
|
9767
9712
|
* by anchoring `exact` against the source content.
|
|
9713
|
+
*
|
|
9714
|
+
* @throws if the response is not a parseable JSON array
|
|
9768
9715
|
*/
|
|
9769
9716
|
static parseTags(response) {
|
|
9770
|
-
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
return valid;
|
|
9777
|
-
} catch (error) {
|
|
9778
|
-
console.error("[MotivationParsers] Failed to parse AI tag response:", error);
|
|
9779
|
-
return [];
|
|
9780
|
-
}
|
|
9717
|
+
const parsed = parseJsonArray(response, "tag");
|
|
9718
|
+
const valid = parsed.filter(
|
|
9719
|
+
(t) => isObject(t) && isString(t.exact) && t.exact.trim().length > 0
|
|
9720
|
+
);
|
|
9721
|
+
console.log(`[MotivationParsers] Parsed ${valid.length} valid tags from ${parsed.length} total`);
|
|
9722
|
+
return valid;
|
|
9781
9723
|
}
|
|
9782
9724
|
/**
|
|
9783
9725
|
* Anchor raw tag inputs against source content and add category.
|
|
@@ -9814,6 +9756,11 @@ function logAnchorMethod(motivation, exact, anchorMethod) {
|
|
|
9814
9756
|
}
|
|
9815
9757
|
|
|
9816
9758
|
// src/workers/annotation-detection.ts
|
|
9759
|
+
function assertNotTruncated(response, motivation) {
|
|
9760
|
+
if (response.stopReason === "max_tokens") {
|
|
9761
|
+
throw new Error(`${motivation} detection response truncated (max_tokens) \u2014 increase max_tokens or reduce resource size; failing the job rather than under-reporting annotations.`);
|
|
9762
|
+
}
|
|
9763
|
+
}
|
|
9817
9764
|
var AnnotationDetection = class {
|
|
9818
9765
|
/**
|
|
9819
9766
|
* Detect comments in content.
|
|
@@ -9825,8 +9772,9 @@ var AnnotationDetection = class {
|
|
|
9825
9772
|
*/
|
|
9826
9773
|
static async detectComments(content, client, instructions, tone, density, language, sourceLanguage) {
|
|
9827
9774
|
const prompt = MotivationPrompts.buildCommentPrompt(content, instructions, tone, density, language, sourceLanguage);
|
|
9828
|
-
const response = await client.
|
|
9829
|
-
|
|
9775
|
+
const response = await client.generateTextWithMetadata(prompt, 3e3, 0.4, { format: "json" });
|
|
9776
|
+
assertNotTruncated(response, "comment");
|
|
9777
|
+
return MotivationParsers.parseComments(response.text, content);
|
|
9830
9778
|
}
|
|
9831
9779
|
/**
|
|
9832
9780
|
* Detect highlights in content.
|
|
@@ -9837,8 +9785,9 @@ var AnnotationDetection = class {
|
|
|
9837
9785
|
*/
|
|
9838
9786
|
static async detectHighlights(content, client, instructions, density, sourceLanguage) {
|
|
9839
9787
|
const prompt = MotivationPrompts.buildHighlightPrompt(content, instructions, density, sourceLanguage);
|
|
9840
|
-
const response = await client.
|
|
9841
|
-
|
|
9788
|
+
const response = await client.generateTextWithMetadata(prompt, 2e3, 0.3, { format: "json" });
|
|
9789
|
+
assertNotTruncated(response, "highlight");
|
|
9790
|
+
return MotivationParsers.parseHighlights(response.text, content);
|
|
9842
9791
|
}
|
|
9843
9792
|
/**
|
|
9844
9793
|
* Detect assessments in content.
|
|
@@ -9849,8 +9798,9 @@ var AnnotationDetection = class {
|
|
|
9849
9798
|
*/
|
|
9850
9799
|
static async detectAssessments(content, client, instructions, tone, density, language, sourceLanguage) {
|
|
9851
9800
|
const prompt = MotivationPrompts.buildAssessmentPrompt(content, instructions, tone, density, language, sourceLanguage);
|
|
9852
|
-
const response = await client.
|
|
9853
|
-
|
|
9801
|
+
const response = await client.generateTextWithMetadata(prompt, 3e3, 0.3, { format: "json" });
|
|
9802
|
+
assertNotTruncated(response, "assessment");
|
|
9803
|
+
return MotivationParsers.parseAssessments(response.text, content);
|
|
9854
9804
|
}
|
|
9855
9805
|
/**
|
|
9856
9806
|
* Detect tags in content for a specific category.
|
|
@@ -9879,8 +9829,9 @@ var AnnotationDetection = class {
|
|
|
9879
9829
|
categoryInfo.examples,
|
|
9880
9830
|
sourceLanguage
|
|
9881
9831
|
);
|
|
9882
|
-
const response = await client.
|
|
9883
|
-
|
|
9832
|
+
const response = await client.generateTextWithMetadata(prompt, 4e3, 0.2, { format: "json" });
|
|
9833
|
+
assertNotTruncated(response, "tag");
|
|
9834
|
+
const parsedTags = MotivationParsers.parseTags(response.text);
|
|
9884
9835
|
return MotivationParsers.validateTagOffsets(parsedTags, content, category);
|
|
9885
9836
|
}
|
|
9886
9837
|
};
|
|
@@ -9949,41 +9900,47 @@ Example output:
|
|
|
9949
9900
|
{ format: "json" }
|
|
9950
9901
|
);
|
|
9951
9902
|
logger2.debug("Got entity extraction response", { responseLength: response.text.length });
|
|
9903
|
+
if (response.stopReason === "max_tokens") {
|
|
9904
|
+
const errorMsg = "Entity extraction response truncated (max_tokens) \u2014 increase max_tokens or reduce resource size; failing the job rather than dropping annotations.";
|
|
9905
|
+
logger2.error(errorMsg, { responseLength: response.text.length });
|
|
9906
|
+
throw new Error(errorMsg);
|
|
9907
|
+
}
|
|
9908
|
+
let entities;
|
|
9952
9909
|
try {
|
|
9953
|
-
|
|
9954
|
-
if (jsonStr.startsWith("```")) {
|
|
9955
|
-
jsonStr = jsonStr.replace(/^```(?:json)?\n?/, "").replace(/\n?```$/, "");
|
|
9956
|
-
}
|
|
9957
|
-
const entities = JSON.parse(jsonStr);
|
|
9958
|
-
logger2.debug("Parsed entities from AI response", { count: entities.length });
|
|
9959
|
-
if (response.stopReason === "max_tokens") {
|
|
9960
|
-
const errorMsg = `AI response truncated: Found ${entities.length} entities but response hit max_tokens limit. Increase max_tokens or reduce resource size.`;
|
|
9961
|
-
logger2.error(errorMsg);
|
|
9962
|
-
throw new Error(errorMsg);
|
|
9963
|
-
}
|
|
9964
|
-
return entities.filter((e) => {
|
|
9965
|
-
const ok = e && typeof e === "object" && typeof e.exact === "string" && typeof e.entityType === "string";
|
|
9966
|
-
if (!ok) {
|
|
9967
|
-
logger2.debug("Dropped malformed LLM entity", { entity: e });
|
|
9968
|
-
}
|
|
9969
|
-
return ok;
|
|
9970
|
-
}).map((entity) => ({
|
|
9971
|
-
exact: entity.exact,
|
|
9972
|
-
entityType: entity.entityType,
|
|
9973
|
-
...typeof entity.prefix === "string" ? { prefix: entity.prefix } : {},
|
|
9974
|
-
...typeof entity.suffix === "string" ? { suffix: entity.suffix } : {}
|
|
9975
|
-
}));
|
|
9910
|
+
entities = JSON.parse(response.text.trim());
|
|
9976
9911
|
} catch (error) {
|
|
9977
9912
|
logger2.error("Failed to parse entity extraction response", {
|
|
9978
|
-
error: error instanceof Error ? error.message : String(error)
|
|
9913
|
+
error: error instanceof Error ? error.message : String(error),
|
|
9914
|
+
response: response.text.slice(0, 500)
|
|
9915
|
+
});
|
|
9916
|
+
throw new Error("Failed to parse entity extraction response", {
|
|
9917
|
+
cause: error instanceof Error ? error : new Error(String(error))
|
|
9979
9918
|
});
|
|
9980
|
-
return [];
|
|
9981
9919
|
}
|
|
9920
|
+
if (!isArray(entities)) {
|
|
9921
|
+
logger2.error("Failed to parse entity extraction response: expected a JSON array", {
|
|
9922
|
+
response: response.text.slice(0, 500)
|
|
9923
|
+
});
|
|
9924
|
+
throw new Error("Failed to parse entity extraction response: expected a JSON array");
|
|
9925
|
+
}
|
|
9926
|
+
logger2.debug("Parsed entities from AI response", { count: entities.length });
|
|
9927
|
+
return entities.filter((e) => {
|
|
9928
|
+
const ok = isObject(e) && isString(e.exact) && isString(e.entityType);
|
|
9929
|
+
if (!ok) {
|
|
9930
|
+
logger2.debug("Dropped malformed LLM entity", { entity: e });
|
|
9931
|
+
}
|
|
9932
|
+
return ok;
|
|
9933
|
+
}).map((entity) => ({
|
|
9934
|
+
exact: entity.exact,
|
|
9935
|
+
entityType: entity.entityType,
|
|
9936
|
+
...isString(entity.prefix) ? { prefix: entity.prefix } : {},
|
|
9937
|
+
...isString(entity.suffix) ? { suffix: entity.suffix } : {}
|
|
9938
|
+
}));
|
|
9982
9939
|
}
|
|
9983
9940
|
function getLanguageName(locale) {
|
|
9984
9941
|
return getLocaleEnglishName(locale) || locale;
|
|
9985
9942
|
}
|
|
9986
|
-
async function generateResourceFromTopic(topic, entityTypes, client, logger2, userPrompt, locale, context, temperature, maxTokens, sourceLanguage) {
|
|
9943
|
+
async function generateResourceFromTopic(topic, entityTypes, client, logger2, userPrompt, locale, context, temperature, maxTokens, sourceLanguage, outputMediaType = "text/markdown") {
|
|
9987
9944
|
logger2.debug("Generating resource from topic", {
|
|
9988
9945
|
topicPreview: topic.substring(0, 100),
|
|
9989
9946
|
entityTypes,
|
|
@@ -10003,61 +9960,95 @@ IMPORTANT: Write the entire resource in ${getLanguageName(locale)}.` : "";
|
|
|
10003
9960
|
|
|
10004
9961
|
The source resource and embedded context are in ${getLanguageName(sourceLanguage)}.` : "";
|
|
10005
9962
|
let annotationSection = "";
|
|
9963
|
+
let contextSection = "";
|
|
9964
|
+
let resourceSection = "";
|
|
9965
|
+
let graphSection = "";
|
|
10006
9966
|
if (context) {
|
|
10007
|
-
const
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10017
|
-
|
|
10018
|
-
|
|
9967
|
+
const { focus } = context;
|
|
9968
|
+
const mainResourceId = focus.kind === "annotation" ? focus.sourceResource["@id"] : focus.resource["@id"];
|
|
9969
|
+
const focalAnnotationId = focus.kind === "annotation" ? focus.annotation.id : void 0;
|
|
9970
|
+
if (focus.kind === "annotation") {
|
|
9971
|
+
const parts = [];
|
|
9972
|
+
parts.push(`- Annotation motivation: ${focus.annotation.motivation}`);
|
|
9973
|
+
parts.push(`- Source resource: ${focus.sourceResource.name}`);
|
|
9974
|
+
const { motivation, body } = focus.annotation;
|
|
9975
|
+
if (motivation === "commenting" || motivation === "assessing") {
|
|
9976
|
+
const bodyItem = Array.isArray(body) ? body[0] : body;
|
|
9977
|
+
if (bodyItem && "value" in bodyItem && bodyItem.value) {
|
|
9978
|
+
const label = motivation === "commenting" ? "Comment" : "Assessment";
|
|
9979
|
+
parts.push(`- ${label}: ${bodyItem.value}`);
|
|
9980
|
+
}
|
|
9981
|
+
}
|
|
9982
|
+
annotationSection = `
|
|
10019
9983
|
|
|
10020
9984
|
Annotation context:
|
|
10021
9985
|
${parts.join("\n")}`;
|
|
10022
|
-
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
const { before, selected, after } = context.sourceContext;
|
|
10026
|
-
contextSection = `
|
|
9986
|
+
if (focus.selected) {
|
|
9987
|
+
const { before, text, after } = focus.selected;
|
|
9988
|
+
contextSection = `
|
|
10027
9989
|
|
|
10028
9990
|
Source document context:
|
|
10029
9991
|
---
|
|
10030
9992
|
${before ? `...${before}` : ""}
|
|
10031
|
-
**[${
|
|
9993
|
+
**[${text}]**
|
|
10032
9994
|
${after ? `${after}...` : ""}
|
|
10033
9995
|
---
|
|
10034
9996
|
`;
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10038
|
-
|
|
10039
|
-
|
|
10040
|
-
|
|
10041
|
-
|
|
10042
|
-
|
|
10043
|
-
|
|
10044
|
-
|
|
10045
|
-
|
|
10046
|
-
|
|
10047
|
-
|
|
10048
|
-
|
|
10049
|
-
|
|
10050
|
-
|
|
10051
|
-
|
|
10052
|
-
|
|
10053
|
-
|
|
10054
|
-
|
|
9997
|
+
}
|
|
9998
|
+
} else {
|
|
9999
|
+
const RESOURCE_CONTENT_CAP = 4e3;
|
|
10000
|
+
const parts = [`- Resource: ${focus.resource.name}`];
|
|
10001
|
+
if (focus.summary) parts.push(`- Summary: ${focus.summary}`);
|
|
10002
|
+
if (focus.suggestedReferences && focus.suggestedReferences.length > 0) {
|
|
10003
|
+
parts.push(`- Suggested references: ${focus.suggestedReferences.join(", ")}`);
|
|
10004
|
+
}
|
|
10005
|
+
resourceSection = `
|
|
10006
|
+
|
|
10007
|
+
Resource context:
|
|
10008
|
+
${parts.join("\n")}`;
|
|
10009
|
+
if (focus.content?.main) {
|
|
10010
|
+
resourceSection += `
|
|
10011
|
+
|
|
10012
|
+
Resource content:
|
|
10013
|
+
---
|
|
10014
|
+
${focus.content.main.slice(0, RESOURCE_CONTENT_CAP)}
|
|
10015
|
+
---`;
|
|
10016
|
+
}
|
|
10017
|
+
const related = Object.entries(focus.content?.related ?? {});
|
|
10018
|
+
if (related.length > 0) {
|
|
10019
|
+
const blocks = related.map(([id, text]) => `[${id}]
|
|
10020
|
+
${text.slice(0, RESOURCE_CONTENT_CAP)}`).join("\n\n");
|
|
10021
|
+
resourceSection += `
|
|
10022
|
+
|
|
10023
|
+
Related resource content:
|
|
10024
|
+
---
|
|
10025
|
+
${blocks}
|
|
10026
|
+
---`;
|
|
10027
|
+
}
|
|
10055
10028
|
}
|
|
10056
|
-
if (
|
|
10057
|
-
|
|
10029
|
+
if (mainResourceId) {
|
|
10030
|
+
const views = deriveViews(context.graph, mainResourceId, focalAnnotationId);
|
|
10031
|
+
const parts = [];
|
|
10032
|
+
if (views.connections.length > 0) {
|
|
10033
|
+
const connList = views.connections.map((c) => `${c.resourceName}${c.entityTypes.length ? ` (${c.entityTypes.join(", ")})` : ""}`).join(", ");
|
|
10034
|
+
parts.push(`- Connected resources: ${connList}`);
|
|
10035
|
+
}
|
|
10036
|
+
if (views.citedByCount > 0) {
|
|
10037
|
+
const citedNames = views.citedBy.map((c) => c.resourceName).join(", ");
|
|
10038
|
+
parts.push(`- This resource is cited by ${views.citedByCount} other resource${views.citedByCount > 1 ? "s" : ""}${citedNames ? `: ${citedNames}` : ""}`);
|
|
10039
|
+
}
|
|
10040
|
+
if (views.siblingEntityTypes.length > 0) {
|
|
10041
|
+
parts.push(`- Related entity types in this document: ${views.siblingEntityTypes.join(", ")}`);
|
|
10042
|
+
}
|
|
10043
|
+
if (context.inferredRelationshipSummary) {
|
|
10044
|
+
parts.push(`- Relationship summary: ${context.inferredRelationshipSummary}`);
|
|
10045
|
+
}
|
|
10046
|
+
if (parts.length > 0) {
|
|
10047
|
+
graphSection = `
|
|
10058
10048
|
|
|
10059
10049
|
Knowledge graph context:
|
|
10060
10050
|
${parts.join("\n")}`;
|
|
10051
|
+
}
|
|
10061
10052
|
}
|
|
10062
10053
|
}
|
|
10063
10054
|
let semanticContextSection = "";
|
|
@@ -10069,17 +10060,20 @@ ${parts.join("\n")}`;
|
|
|
10069
10060
|
Related passages from the knowledge base:
|
|
10070
10061
|
${lines.join("\n")}`;
|
|
10071
10062
|
}
|
|
10072
|
-
const
|
|
10063
|
+
const isPlainText = outputMediaType === "text/plain";
|
|
10064
|
+
const structureGuidance = !isPlainText && finalMaxTokens >= 1e3 ? "organized into titled sections (## Section) with well-structured paragraphs" : "organized into well-structured paragraphs";
|
|
10065
|
+
const formatRequirements = isPlainText ? `- Write the response as plain text \u2014 no formatting markup (no #, *, backticks, headings, or links)
|
|
10066
|
+
- Begin with the title on its own first line` : `- Start with a clear heading (# Title)
|
|
10067
|
+
- Use markdown formatting
|
|
10068
|
+
- Write the response as markdown`;
|
|
10073
10069
|
const prompt = `Generate a concise, informative resource about "${topic}".
|
|
10074
10070
|
${entityTypes.length > 0 ? `Focus on these entity types: ${entityTypes.join(", ")}.` : ""}
|
|
10075
|
-
${userPrompt ? `Additional context: ${userPrompt}` : ""}${annotationSection}${contextSection}${
|
|
10071
|
+
${userPrompt ? `Additional context: ${userPrompt}` : ""}${annotationSection}${contextSection}${resourceSection}${graphSection}${semanticContextSection}${sourceLanguageInstruction}${languageInstruction}
|
|
10076
10072
|
|
|
10077
10073
|
Requirements:
|
|
10078
|
-
- Start with a clear heading (# Title)
|
|
10079
10074
|
- Aim for approximately ${finalMaxTokens} tokens of content, ${structureGuidance}
|
|
10080
10075
|
- Be factual and informative
|
|
10081
|
-
|
|
10082
|
-
- Write the response as markdown`;
|
|
10076
|
+
${formatRequirements}`;
|
|
10083
10077
|
const parseResponse = (response2) => {
|
|
10084
10078
|
let content = response2.trim();
|
|
10085
10079
|
if (content.startsWith("```markdown") || content.startsWith("```md")) {
|
|
@@ -10398,6 +10392,13 @@ async function processTagJob(content, inferenceClient, params, userId, generator
|
|
|
10398
10392
|
};
|
|
10399
10393
|
}
|
|
10400
10394
|
async function processGenerationJob(inferenceClient, params, onProgress, logger2) {
|
|
10395
|
+
const GENERATABLE_MEDIA_TYPES = ["text/markdown", "text/plain"];
|
|
10396
|
+
const outputMediaType = params.outputMediaType ?? "text/markdown";
|
|
10397
|
+
if (!GENERATABLE_MEDIA_TYPES.includes(outputMediaType)) {
|
|
10398
|
+
throw new Error(
|
|
10399
|
+
`Unsupported outputMediaType for generation: ${outputMediaType}. Generation produces ${GENERATABLE_MEDIA_TYPES.join(" or ")}.`
|
|
10400
|
+
);
|
|
10401
|
+
}
|
|
10401
10402
|
onProgress(20, "Fetching context...", "fetching");
|
|
10402
10403
|
const title = params.title ?? "Untitled";
|
|
10403
10404
|
const entityTypes = (params.entityTypes ?? []).map(String);
|
|
@@ -10412,13 +10413,14 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger2
|
|
|
10412
10413
|
params.context,
|
|
10413
10414
|
params.temperature,
|
|
10414
10415
|
params.maxTokens,
|
|
10415
|
-
params.sourceLanguage
|
|
10416
|
+
params.sourceLanguage,
|
|
10417
|
+
outputMediaType
|
|
10416
10418
|
);
|
|
10417
10419
|
onProgress(85, "Creating resource...", "creating");
|
|
10418
10420
|
return {
|
|
10419
10421
|
content: generated.content,
|
|
10420
10422
|
title: generated.title ?? title,
|
|
10421
|
-
format:
|
|
10423
|
+
format: outputMediaType,
|
|
10422
10424
|
result: {
|
|
10423
10425
|
resourceId: "",
|
|
10424
10426
|
resourceName: generated.title ?? title
|
|
@@ -10638,6 +10640,17 @@ async function handleJobInner(adapter, config, job) {
|
|
|
10638
10640
|
...genParams.entityTypes && genParams.entityTypes.length > 0 ? { entityTypes: genParams.entityTypes } : {},
|
|
10639
10641
|
generator
|
|
10640
10642
|
});
|
|
10643
|
+
if (!genParams.referenceId) {
|
|
10644
|
+
const { annotation: provenanceRef } = assembleAnnotation(
|
|
10645
|
+
{
|
|
10646
|
+
motivation: "linking",
|
|
10647
|
+
target: { source: String(resourceId) },
|
|
10648
|
+
body: { type: "SpecificResource", source: String(newResourceId), purpose: "linking" }
|
|
10649
|
+
},
|
|
10650
|
+
generator
|
|
10651
|
+
);
|
|
10652
|
+
await emitEvent(session, "mark:create", { annotation: provenanceRef, userId, resourceId });
|
|
10653
|
+
}
|
|
10641
10654
|
await emitEvent(session, "job:complete", {
|
|
10642
10655
|
...lifecycleBase,
|
|
10643
10656
|
result: { resourceId: newResourceId, resourceName: genResult.title }
|
|
@@ -10649,7 +10662,7 @@ async function handleJobInner(adapter, config, job) {
|
|
|
10649
10662
|
}
|
|
10650
10663
|
|
|
10651
10664
|
// src/worker-main.ts
|
|
10652
|
-
var
|
|
10665
|
+
var import_rxjs2 = __toESM(require_cjs());
|
|
10653
10666
|
var ALL_JOB_TYPES = [
|
|
10654
10667
|
"reference-annotation",
|
|
10655
10668
|
"generation",
|
|
@@ -10757,7 +10770,7 @@ async function startAgentWorker(group) {
|
|
|
10757
10770
|
};
|
|
10758
10771
|
const storage = new InMemorySessionStorage();
|
|
10759
10772
|
setStoredSession(storage, kbId, { access: initialToken, refresh: "" });
|
|
10760
|
-
const token$ = new
|
|
10773
|
+
const token$ = new import_rxjs2.BehaviorSubject(null);
|
|
10761
10774
|
let session;
|
|
10762
10775
|
const transport = new HttpTransport({
|
|
10763
10776
|
baseUrl: baseUrl(kbBackendUrl(endpoint)),
|