@semiont/jobs 0.5.9 → 0.5.11
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 +64 -6
- package/dist/index.js +207 -55
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +368 -181
- package/dist/worker-main.js.map +1 -1
- package/package.json +8 -8
package/dist/worker-main.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { createTomlConfigLoader,
|
|
1
|
+
import { createTomlConfigLoader, didToAgent, baseUrl, busRequest, getPrimaryMediaType, textExtractionOf, assembleAnnotation, reconcileSelector, 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';
|
|
5
|
+
import { homedir, hostname } from 'os';
|
|
6
|
+
import { InMemorySessionStorage, setStoredSession, kbBackendUrl, SemiontClient, SemiontSession } from '@semiont/sdk';
|
|
7
|
+
import { HttpTransport, HttpContentTransport } from '@semiont/http-transport';
|
|
5
8
|
import { createInferenceClient } from '@semiont/inference';
|
|
6
9
|
import { createServer } from 'http';
|
|
7
10
|
import { existsSync, readFileSync } from 'fs';
|
|
8
|
-
import { homedir, hostname } from 'os';
|
|
9
11
|
import { join } from 'path';
|
|
10
|
-
import { InMemorySessionStorage, setStoredSession, kbBackendUrl, SemiontClient, SemiontSession } from '@semiont/sdk';
|
|
11
|
-
import { HttpTransport, HttpContentTransport } from '@semiont/http-transport';
|
|
12
12
|
import { createProcessLogger } from '@semiont/observability/process-logger';
|
|
13
13
|
|
|
14
14
|
var __create = Object.create;
|
|
@@ -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
|
|
|
@@ -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
|
|
|
@@ -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,
|
|
@@ -9945,7 +9940,13 @@ Example output:
|
|
|
9945
9940
|
function getLanguageName(locale) {
|
|
9946
9941
|
return getLocaleEnglishName(locale) || locale;
|
|
9947
9942
|
}
|
|
9948
|
-
|
|
9943
|
+
var RESOURCE_CONTENT_CAP = 4e3;
|
|
9944
|
+
var SEMANTIC_MATCH_LIMIT = 3;
|
|
9945
|
+
var SEMANTIC_MATCH_CHARS = 240;
|
|
9946
|
+
function idLabel(resourceId, annotationId) {
|
|
9947
|
+
return `[${resourceId}${annotationId ? `/${annotationId}` : ""}]`;
|
|
9948
|
+
}
|
|
9949
|
+
async function generateResourceFromTopic(topic, entityTypes, client, logger2, userPrompt, locale, context, temperature, maxTokens, sourceLanguage, outputMediaType = "text/markdown", task = "resource", structure, cite = false) {
|
|
9949
9950
|
logger2.debug("Generating resource from topic", {
|
|
9950
9951
|
topicPreview: topic.substring(0, 100),
|
|
9951
9952
|
entityTypes,
|
|
@@ -9954,7 +9955,10 @@ async function generateResourceFromTopic(topic, entityTypes, client, logger2, us
|
|
|
9954
9955
|
sourceLanguage,
|
|
9955
9956
|
hasContext: !!context,
|
|
9956
9957
|
temperature,
|
|
9957
|
-
maxTokens
|
|
9958
|
+
maxTokens,
|
|
9959
|
+
outputMediaType,
|
|
9960
|
+
task,
|
|
9961
|
+
structure
|
|
9958
9962
|
});
|
|
9959
9963
|
const finalTemperature = temperature ?? 0.7;
|
|
9960
9964
|
const finalMaxTokens = maxTokens ?? 500;
|
|
@@ -9965,83 +9969,146 @@ IMPORTANT: Write the entire resource in ${getLanguageName(locale)}.` : "";
|
|
|
9965
9969
|
|
|
9966
9970
|
The source resource and embedded context are in ${getLanguageName(sourceLanguage)}.` : "";
|
|
9967
9971
|
let annotationSection = "";
|
|
9972
|
+
let contextSection = "";
|
|
9973
|
+
let resourceSection = "";
|
|
9974
|
+
let graphSection = "";
|
|
9968
9975
|
if (context) {
|
|
9969
|
-
const
|
|
9970
|
-
|
|
9971
|
-
|
|
9972
|
-
|
|
9973
|
-
|
|
9974
|
-
|
|
9975
|
-
|
|
9976
|
-
|
|
9977
|
-
|
|
9978
|
-
|
|
9979
|
-
|
|
9980
|
-
|
|
9976
|
+
const { focus } = context;
|
|
9977
|
+
const mainResourceId = focus.kind === "annotation" ? focus.sourceResource["@id"] : focus.resource["@id"];
|
|
9978
|
+
const focalAnnotationId = focus.kind === "annotation" ? focus.annotation.id : void 0;
|
|
9979
|
+
if (focus.kind === "annotation") {
|
|
9980
|
+
const parts = [];
|
|
9981
|
+
parts.push(`- Annotation motivation: ${focus.annotation.motivation}`);
|
|
9982
|
+
parts.push(`- Source resource: ${focus.sourceResource.name} ${idLabel(mainResourceId)}`);
|
|
9983
|
+
const { motivation, body } = focus.annotation;
|
|
9984
|
+
if (motivation === "commenting" || motivation === "assessing") {
|
|
9985
|
+
const bodyItem = Array.isArray(body) ? body[0] : body;
|
|
9986
|
+
if (bodyItem && "value" in bodyItem && bodyItem.value) {
|
|
9987
|
+
const label = motivation === "commenting" ? "Comment" : "Assessment";
|
|
9988
|
+
parts.push(`- ${label}: ${bodyItem.value}`);
|
|
9989
|
+
}
|
|
9990
|
+
}
|
|
9991
|
+
annotationSection = `
|
|
9981
9992
|
|
|
9982
9993
|
Annotation context:
|
|
9983
9994
|
${parts.join("\n")}`;
|
|
9984
|
-
|
|
9985
|
-
|
|
9986
|
-
|
|
9987
|
-
const { before, selected, after } = context.sourceContext;
|
|
9988
|
-
contextSection = `
|
|
9995
|
+
if (focus.selected) {
|
|
9996
|
+
const { before, text, after } = focus.selected;
|
|
9997
|
+
contextSection = `
|
|
9989
9998
|
|
|
9990
9999
|
Source document context:
|
|
9991
10000
|
---
|
|
9992
10001
|
${before ? `...${before}` : ""}
|
|
9993
|
-
**[${
|
|
10002
|
+
**[${text}]**
|
|
9994
10003
|
${after ? `${after}...` : ""}
|
|
9995
10004
|
---
|
|
9996
10005
|
`;
|
|
9997
|
-
|
|
9998
|
-
|
|
9999
|
-
|
|
10000
|
-
|
|
10001
|
-
|
|
10002
|
-
|
|
10003
|
-
|
|
10004
|
-
|
|
10005
|
-
|
|
10006
|
-
|
|
10007
|
-
|
|
10008
|
-
|
|
10009
|
-
|
|
10010
|
-
|
|
10011
|
-
|
|
10012
|
-
|
|
10013
|
-
|
|
10014
|
-
|
|
10015
|
-
|
|
10016
|
-
|
|
10006
|
+
}
|
|
10007
|
+
} else {
|
|
10008
|
+
const parts = [`- Resource: ${focus.resource.name} ${idLabel(mainResourceId)}`];
|
|
10009
|
+
if (focus.summary) parts.push(`- Summary: ${focus.summary}`);
|
|
10010
|
+
if (focus.suggestedReferences && focus.suggestedReferences.length > 0) {
|
|
10011
|
+
parts.push(`- Suggested references: ${focus.suggestedReferences.join(", ")}`);
|
|
10012
|
+
}
|
|
10013
|
+
resourceSection = `
|
|
10014
|
+
|
|
10015
|
+
Resource context:
|
|
10016
|
+
${parts.join("\n")}`;
|
|
10017
|
+
if (focus.content?.main) {
|
|
10018
|
+
resourceSection += `
|
|
10019
|
+
|
|
10020
|
+
Resource content:
|
|
10021
|
+
---
|
|
10022
|
+
${focus.content.main.slice(0, RESOURCE_CONTENT_CAP)}
|
|
10023
|
+
---`;
|
|
10024
|
+
}
|
|
10025
|
+
const related = Object.entries(focus.content?.related ?? {});
|
|
10026
|
+
if (related.length > 0) {
|
|
10027
|
+
const blocks = related.map(([id, text]) => `[${id}]
|
|
10028
|
+
${text.slice(0, RESOURCE_CONTENT_CAP)}`).join("\n\n");
|
|
10029
|
+
resourceSection += `
|
|
10030
|
+
|
|
10031
|
+
Related resource content:
|
|
10032
|
+
---
|
|
10033
|
+
${blocks}
|
|
10034
|
+
---`;
|
|
10035
|
+
}
|
|
10017
10036
|
}
|
|
10018
|
-
if (
|
|
10019
|
-
|
|
10037
|
+
if (mainResourceId) {
|
|
10038
|
+
const views = deriveViews(context.graph, mainResourceId, focalAnnotationId);
|
|
10039
|
+
const parts = [];
|
|
10040
|
+
if (views.connections.length > 0) {
|
|
10041
|
+
const connList = views.connections.map((c) => `${c.resourceName}${c.entityTypes.length ? ` (${c.entityTypes.join(", ")})` : ""} ${idLabel(c.resourceId)}`).join(", ");
|
|
10042
|
+
parts.push(`- Connected resources: ${connList}`);
|
|
10043
|
+
}
|
|
10044
|
+
if (views.citedByCount > 0) {
|
|
10045
|
+
const citedNames = views.citedBy.map((c) => `${c.resourceName} ${idLabel(c.resourceId)}`).join(", ");
|
|
10046
|
+
parts.push(`- This resource is cited by ${views.citedByCount} other resource${views.citedByCount > 1 ? "s" : ""}${citedNames ? `: ${citedNames}` : ""}`);
|
|
10047
|
+
}
|
|
10048
|
+
if (views.siblingEntityTypes.length > 0) {
|
|
10049
|
+
parts.push(`- Related entity types in this document: ${views.siblingEntityTypes.join(", ")}`);
|
|
10050
|
+
}
|
|
10051
|
+
if (context.inferredRelationshipSummary) {
|
|
10052
|
+
parts.push(`- Relationship summary: ${context.inferredRelationshipSummary}`);
|
|
10053
|
+
}
|
|
10054
|
+
if (parts.length > 0) {
|
|
10055
|
+
graphSection = `
|
|
10020
10056
|
|
|
10021
10057
|
Knowledge graph context:
|
|
10022
10058
|
${parts.join("\n")}`;
|
|
10059
|
+
}
|
|
10023
10060
|
}
|
|
10024
10061
|
}
|
|
10025
10062
|
let semanticContextSection = "";
|
|
10026
10063
|
const similar = context?.semanticContext?.similar ?? [];
|
|
10027
10064
|
if (similar.length > 0) {
|
|
10028
|
-
const lines = [...similar].sort((a, b) => b.score - a.score).slice(0,
|
|
10065
|
+
const lines = [...similar].sort((a, b) => b.score - a.score).slice(0, SEMANTIC_MATCH_LIMIT).map((m) => `- ${idLabel(m.resourceId, m.annotationId)} (${m.score.toFixed(2)}) ${m.text.slice(0, SEMANTIC_MATCH_CHARS)}`);
|
|
10029
10066
|
semanticContextSection = `
|
|
10030
10067
|
|
|
10031
10068
|
Related passages from the knowledge base:
|
|
10032
10069
|
${lines.join("\n")}`;
|
|
10033
10070
|
}
|
|
10034
|
-
|
|
10035
|
-
|
|
10036
|
-
|
|
10037
|
-
|
|
10071
|
+
let leadLine;
|
|
10072
|
+
if (task === "resource") {
|
|
10073
|
+
leadLine = `Generate a concise, informative resource about "${topic}".`;
|
|
10074
|
+
} else if (task === "answer") {
|
|
10075
|
+
leadLine = `Answer the following question directly and concisely, grounded in the provided context: "${topic}"`;
|
|
10076
|
+
} else if (task === "summary") {
|
|
10077
|
+
leadLine = `Write a concise summary of "${topic}".`;
|
|
10078
|
+
} else {
|
|
10079
|
+
logger2.warn("Unknown task \u2014 using it verbatim as the framing instruction", { task });
|
|
10080
|
+
leadLine = `${task}
|
|
10081
|
+
Topic: "${topic}"`;
|
|
10082
|
+
}
|
|
10083
|
+
const isPlainText = outputMediaType === "text/plain";
|
|
10084
|
+
let structureRequirement = "";
|
|
10085
|
+
let titleRequirement = "";
|
|
10086
|
+
if (structure === "sections") {
|
|
10087
|
+
structureRequirement = isPlainText ? "\n- Organize the content into titled sections with well-structured paragraphs" : "\n- Organize the content into titled sections (## Section) with well-structured paragraphs";
|
|
10088
|
+
if (!isPlainText) {
|
|
10089
|
+
titleRequirement = "\n- Start with a clear heading (# Title)";
|
|
10090
|
+
}
|
|
10091
|
+
} else if (structure === "prose") {
|
|
10092
|
+
structureRequirement = "\n- Write flowing, well-structured paragraphs with no section headings";
|
|
10093
|
+
} else if (structure === "chat") {
|
|
10094
|
+
structureRequirement = "\n- Structure the content as a conversational chat transcript \u2014 a sequence of alternating, speaker-labeled turns (no section headings)";
|
|
10095
|
+
} else if (structure) {
|
|
10096
|
+
logger2.warn("Unknown structure \u2014 passing it through as freeform organization guidance", { structure });
|
|
10097
|
+
structureRequirement = `
|
|
10098
|
+
- Organize the output as: ${structure}`;
|
|
10099
|
+
}
|
|
10100
|
+
const citeRequirement = cite ? "\n- Ground every claim in the provided context. Immediately after each claim, cite its source by emitting [[<id>]], where <id> is an id shown in square brackets in the context above (for a passage labeled [abc], emit [[abc]]). Cite only ids that appear in the context." : "";
|
|
10101
|
+
const formatRequirements = isPlainText ? `- Write the response as plain text \u2014 no formatting markup (no #, *, backticks, headings, or links)
|
|
10102
|
+
- Begin with the title on its own first line` : `- Use markdown formatting
|
|
10103
|
+
- Write the response as markdown`;
|
|
10104
|
+
const prompt = `${leadLine}
|
|
10105
|
+
${userPrompt ? `Instruction: ${userPrompt}` : ""}
|
|
10106
|
+
${entityTypes.length > 0 ? `Focus on these entity types: ${entityTypes.join(", ")}.` : ""}${annotationSection}${contextSection}${resourceSection}${graphSection}${semanticContextSection}${sourceLanguageInstruction}${languageInstruction}
|
|
10038
10107
|
|
|
10039
10108
|
Requirements:
|
|
10040
|
-
-
|
|
10041
|
-
-
|
|
10042
|
-
|
|
10043
|
-
- Use markdown formatting
|
|
10044
|
-
- Write the response as markdown`;
|
|
10109
|
+
- Aim for approximately ${finalMaxTokens} tokens of content
|
|
10110
|
+
- Be factual and informative${structureRequirement}${titleRequirement}${citeRequirement}
|
|
10111
|
+
${formatRequirements}`;
|
|
10045
10112
|
const parseResponse = (response2) => {
|
|
10046
10113
|
let content = response2.trim();
|
|
10047
10114
|
if (content.startsWith("```markdown") || content.startsWith("```md")) {
|
|
@@ -10079,6 +10146,67 @@ Requirements:
|
|
|
10079
10146
|
});
|
|
10080
10147
|
return result;
|
|
10081
10148
|
}
|
|
10149
|
+
|
|
10150
|
+
// src/workers/generation/citation-resolver.ts
|
|
10151
|
+
var CITATION_TOKEN = /\[\[([^\s[\]/]+)(?:\/([^\s[\]/]+))?\]\]/g;
|
|
10152
|
+
function collectContextResourceIds(context) {
|
|
10153
|
+
const ids = /* @__PURE__ */ new Set();
|
|
10154
|
+
if (!context) return ids;
|
|
10155
|
+
const { focus } = context;
|
|
10156
|
+
ids.add(focus.kind === "annotation" ? focus.sourceResource["@id"] : focus.resource["@id"]);
|
|
10157
|
+
for (const node of context.graph.nodes) {
|
|
10158
|
+
if (node.type === "resource") ids.add(node.id);
|
|
10159
|
+
}
|
|
10160
|
+
for (const m of context.semanticContext?.similar ?? []) ids.add(m.resourceId);
|
|
10161
|
+
if (focus.kind === "resource") {
|
|
10162
|
+
for (const id of Object.keys(focus.content?.related ?? {})) ids.add(id);
|
|
10163
|
+
}
|
|
10164
|
+
return ids;
|
|
10165
|
+
}
|
|
10166
|
+
function resolveCitationTokens(content, validResourceIds, logger2) {
|
|
10167
|
+
const citations = [];
|
|
10168
|
+
let clean = "";
|
|
10169
|
+
let last = 0;
|
|
10170
|
+
for (const match of content.matchAll(CITATION_TOKEN)) {
|
|
10171
|
+
const token = match[0];
|
|
10172
|
+
const citedResourceId = match[1];
|
|
10173
|
+
const annotationId = match[2];
|
|
10174
|
+
clean += content.slice(last, match.index).replace(/[ \t]+$/, "");
|
|
10175
|
+
last = match.index + token.length;
|
|
10176
|
+
if (!validResourceIds.has(citedResourceId)) {
|
|
10177
|
+
logger2.warn("Citation token references an id absent from the provided context \u2014 dropped", {
|
|
10178
|
+
resourceId: citedResourceId
|
|
10179
|
+
});
|
|
10180
|
+
continue;
|
|
10181
|
+
}
|
|
10182
|
+
const end = clean.length;
|
|
10183
|
+
let start = 0;
|
|
10184
|
+
for (let i = end - 2; i >= 0; i--) {
|
|
10185
|
+
const ch = clean[i];
|
|
10186
|
+
if (ch === "." || ch === "!" || ch === "?" || ch === "\n") {
|
|
10187
|
+
start = i + 1;
|
|
10188
|
+
break;
|
|
10189
|
+
}
|
|
10190
|
+
}
|
|
10191
|
+
while (start < end && /\s/.test(clean[start])) start++;
|
|
10192
|
+
const exact = clean.slice(start, end);
|
|
10193
|
+
if (exact.length === 0) {
|
|
10194
|
+
logger2.warn("Citation token has no preceding claim text \u2014 dropped", {
|
|
10195
|
+
resourceId: citedResourceId
|
|
10196
|
+
});
|
|
10197
|
+
continue;
|
|
10198
|
+
}
|
|
10199
|
+
citations.push({
|
|
10200
|
+
resourceId: citedResourceId,
|
|
10201
|
+
...annotationId ? { annotationId } : {},
|
|
10202
|
+
start,
|
|
10203
|
+
end,
|
|
10204
|
+
exact
|
|
10205
|
+
});
|
|
10206
|
+
}
|
|
10207
|
+
clean += content.slice(last);
|
|
10208
|
+
return { content: clean, citations };
|
|
10209
|
+
}
|
|
10082
10210
|
function toMatch(r) {
|
|
10083
10211
|
return {
|
|
10084
10212
|
exact: r.exact,
|
|
@@ -10360,6 +10488,13 @@ async function processTagJob(content, inferenceClient, params, userId, generator
|
|
|
10360
10488
|
};
|
|
10361
10489
|
}
|
|
10362
10490
|
async function processGenerationJob(inferenceClient, params, onProgress, logger2) {
|
|
10491
|
+
const GENERATABLE_MEDIA_TYPES = ["text/markdown", "text/plain"];
|
|
10492
|
+
const outputMediaType = params.outputMediaType ?? "text/markdown";
|
|
10493
|
+
if (!GENERATABLE_MEDIA_TYPES.includes(outputMediaType)) {
|
|
10494
|
+
throw new Error(
|
|
10495
|
+
`Unsupported outputMediaType for generation: ${outputMediaType}. Generation produces ${GENERATABLE_MEDIA_TYPES.join(" or ")}.`
|
|
10496
|
+
);
|
|
10497
|
+
}
|
|
10363
10498
|
onProgress(20, "Fetching context...", "fetching");
|
|
10364
10499
|
const title = params.title ?? "Untitled";
|
|
10365
10500
|
const entityTypes = (params.entityTypes ?? []).map(String);
|
|
@@ -10374,13 +10509,25 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger2
|
|
|
10374
10509
|
params.context,
|
|
10375
10510
|
params.temperature,
|
|
10376
10511
|
params.maxTokens,
|
|
10377
|
-
params.sourceLanguage
|
|
10512
|
+
params.sourceLanguage,
|
|
10513
|
+
outputMediaType,
|
|
10514
|
+
params.task,
|
|
10515
|
+
params.structure,
|
|
10516
|
+
params.cite
|
|
10378
10517
|
);
|
|
10518
|
+
let content = generated.content;
|
|
10519
|
+
let citations = [];
|
|
10520
|
+
if (params.cite === true) {
|
|
10521
|
+
const resolved = resolveCitationTokens(content, collectContextResourceIds(params.context), logger2);
|
|
10522
|
+
content = resolved.content;
|
|
10523
|
+
citations = resolved.citations;
|
|
10524
|
+
}
|
|
10379
10525
|
onProgress(85, "Creating resource...", "creating");
|
|
10380
10526
|
return {
|
|
10381
|
-
content
|
|
10527
|
+
content,
|
|
10382
10528
|
title: generated.title ?? title,
|
|
10383
|
-
format:
|
|
10529
|
+
format: outputMediaType,
|
|
10530
|
+
citations,
|
|
10384
10531
|
result: {
|
|
10385
10532
|
resourceId: "",
|
|
10386
10533
|
resourceName: generated.title ?? title
|
|
@@ -10600,6 +10747,34 @@ async function handleJobInner(adapter, config, job) {
|
|
|
10600
10747
|
...genParams.entityTypes && genParams.entityTypes.length > 0 ? { entityTypes: genParams.entityTypes } : {},
|
|
10601
10748
|
generator
|
|
10602
10749
|
});
|
|
10750
|
+
if (!genParams.referenceId) {
|
|
10751
|
+
const { annotation: provenanceRef } = assembleAnnotation(
|
|
10752
|
+
{
|
|
10753
|
+
motivation: "linking",
|
|
10754
|
+
target: { source: String(resourceId) },
|
|
10755
|
+
body: { type: "SpecificResource", source: String(newResourceId), purpose: "linking" }
|
|
10756
|
+
},
|
|
10757
|
+
generator
|
|
10758
|
+
);
|
|
10759
|
+
await emitEvent(session, "mark:create", { annotation: provenanceRef, userId, resourceId });
|
|
10760
|
+
}
|
|
10761
|
+
for (const citation of genResult.citations) {
|
|
10762
|
+
const { annotation: citationRef } = assembleAnnotation(
|
|
10763
|
+
{
|
|
10764
|
+
motivation: "linking",
|
|
10765
|
+
target: {
|
|
10766
|
+
source: String(newResourceId),
|
|
10767
|
+
selector: [
|
|
10768
|
+
{ type: "TextPositionSelector", start: citation.start, end: citation.end },
|
|
10769
|
+
{ type: "TextQuoteSelector", exact: citation.exact }
|
|
10770
|
+
]
|
|
10771
|
+
},
|
|
10772
|
+
body: { type: "SpecificResource", source: citation.resourceId, purpose: "linking" }
|
|
10773
|
+
},
|
|
10774
|
+
generator
|
|
10775
|
+
);
|
|
10776
|
+
await emitEvent(session, "mark:create", { annotation: citationRef, userId, resourceId: newResourceId });
|
|
10777
|
+
}
|
|
10603
10778
|
await emitEvent(session, "job:complete", {
|
|
10604
10779
|
...lifecycleBase,
|
|
10605
10780
|
result: { resourceId: newResourceId, resourceName: genResult.title }
|
|
@@ -10610,75 +10785,8 @@ async function handleJobInner(adapter, config, job) {
|
|
|
10610
10785
|
}
|
|
10611
10786
|
}
|
|
10612
10787
|
|
|
10613
|
-
// src/worker-
|
|
10614
|
-
var
|
|
10615
|
-
var ALL_JOB_TYPES = [
|
|
10616
|
-
"reference-annotation",
|
|
10617
|
-
"generation",
|
|
10618
|
-
"highlight-annotation",
|
|
10619
|
-
"assessment-annotation",
|
|
10620
|
-
"comment-annotation",
|
|
10621
|
-
"tag-annotation"
|
|
10622
|
-
];
|
|
10623
|
-
var configPath = join(homedir(), ".semiontconfig");
|
|
10624
|
-
var tomlReader = {
|
|
10625
|
-
readIfExists: (p) => existsSync(p) ? readFileSync(p, "utf-8") : null
|
|
10626
|
-
};
|
|
10627
|
-
var envConfig = createTomlConfigLoader(
|
|
10628
|
-
tomlReader,
|
|
10629
|
-
configPath,
|
|
10630
|
-
process.env
|
|
10631
|
-
)(null, "local");
|
|
10632
|
-
var workerInferenceMap = envConfig._metadata?.workers;
|
|
10633
|
-
if (!workerInferenceMap || Object.keys(workerInferenceMap).length === 0) {
|
|
10634
|
-
throw new Error(
|
|
10635
|
-
'No worker inference config found in ~/.semiontconfig. Add at least [environments.<env>.workers.default.inference] with type = "..." and model = "...".'
|
|
10636
|
-
);
|
|
10637
|
-
}
|
|
10638
|
-
function resolveWorker(jobType) {
|
|
10639
|
-
const specific = workerInferenceMap[jobType];
|
|
10640
|
-
if (specific) return specific;
|
|
10641
|
-
const def = workerInferenceMap["default"];
|
|
10642
|
-
if (def) return def;
|
|
10643
|
-
throw new Error(
|
|
10644
|
-
`No inference config for worker '${jobType}' and no workers.default in ~/.semiontconfig.`
|
|
10645
|
-
);
|
|
10646
|
-
}
|
|
10647
|
-
var backendPublicURL = envConfig.services?.backend?.publicURL;
|
|
10648
|
-
if (!backendPublicURL) {
|
|
10649
|
-
throw new Error("services.backend.publicURL is required in ~/.semiontconfig");
|
|
10650
|
-
}
|
|
10651
|
-
var backendBaseUrl = backendPublicURL;
|
|
10652
|
-
var workerSecret = process.env.SEMIONT_WORKER_SECRET ?? "";
|
|
10653
|
-
var healthPort = 9090;
|
|
10654
|
-
var logger = createProcessLogger("worker");
|
|
10655
|
-
function clientKey(w) {
|
|
10656
|
-
return [w.type, w.model, w.apiKey ?? "", w.endpoint ?? "", w.baseURL ?? ""].join("|");
|
|
10657
|
-
}
|
|
10658
|
-
function toClientConfig(w) {
|
|
10659
|
-
return {
|
|
10660
|
-
type: w.type,
|
|
10661
|
-
model: w.model,
|
|
10662
|
-
...w.endpoint && { endpoint: w.endpoint },
|
|
10663
|
-
...w.baseURL && { baseURL: w.baseURL },
|
|
10664
|
-
...w.apiKey && { apiKey: w.apiKey }
|
|
10665
|
-
};
|
|
10666
|
-
}
|
|
10667
|
-
var groups = /* @__PURE__ */ new Map();
|
|
10668
|
-
for (const jobType of ALL_JOB_TYPES) {
|
|
10669
|
-
const inference = resolveWorker(jobType);
|
|
10670
|
-
const key = clientKey(inference);
|
|
10671
|
-
let group = groups.get(key);
|
|
10672
|
-
if (!group) {
|
|
10673
|
-
group = {
|
|
10674
|
-
inference,
|
|
10675
|
-
jobTypes: [],
|
|
10676
|
-
client: createInferenceClient(toClientConfig(inference), logger)
|
|
10677
|
-
};
|
|
10678
|
-
groups.set(key, group);
|
|
10679
|
-
}
|
|
10680
|
-
group.jobTypes.push(jobType);
|
|
10681
|
-
}
|
|
10788
|
+
// src/worker-runtime.ts
|
|
10789
|
+
var import_rxjs2 = __toESM(require_cjs());
|
|
10682
10790
|
function parseBackendUrl(url) {
|
|
10683
10791
|
const parsed = new URL(url);
|
|
10684
10792
|
const protocol = parsed.protocol.replace(":", "") === "https" ? "https" : "http";
|
|
@@ -10686,29 +10794,32 @@ function parseBackendUrl(url) {
|
|
|
10686
10794
|
const port = parsed.port ? Number(parsed.port) : protocol === "https" ? 443 : 80;
|
|
10687
10795
|
return { protocol, host, port };
|
|
10688
10796
|
}
|
|
10689
|
-
async function authenticateAgent(
|
|
10690
|
-
|
|
10797
|
+
async function authenticateAgent(opts) {
|
|
10798
|
+
const { backendBaseUrl: backendBaseUrl2, workerSecret: workerSecret2, provider, model } = opts;
|
|
10799
|
+
if (!workerSecret2) {
|
|
10691
10800
|
throw new Error("SEMIONT_WORKER_SECRET is required to authenticate worker agents");
|
|
10692
10801
|
}
|
|
10693
|
-
const response = await fetch(`${
|
|
10802
|
+
const response = await fetch(`${backendBaseUrl2}/api/tokens/agent`, {
|
|
10694
10803
|
method: "POST",
|
|
10695
10804
|
headers: { "Content-Type": "application/json" },
|
|
10696
|
-
body: JSON.stringify({ secret:
|
|
10805
|
+
body: JSON.stringify({ secret: workerSecret2, provider, model })
|
|
10697
10806
|
});
|
|
10698
10807
|
if (!response.ok) {
|
|
10699
10808
|
throw new Error(`Agent authentication failed for ${provider}:${model}: ${response.status} ${response.statusText}`);
|
|
10700
10809
|
}
|
|
10701
10810
|
return await response.json();
|
|
10702
10811
|
}
|
|
10703
|
-
async function startAgentWorker(
|
|
10812
|
+
async function startAgentWorker(opts) {
|
|
10813
|
+
const { group, backendBaseUrl: backendBaseUrl2, workerSecret: workerSecret2, logger: logger2 } = opts;
|
|
10704
10814
|
const { inference } = group;
|
|
10705
|
-
const { protocol, host, port } = parseBackendUrl(
|
|
10706
|
-
const { token: initialToken, did } = await authenticateAgent(
|
|
10707
|
-
|
|
10708
|
-
|
|
10815
|
+
const { protocol, host, port } = parseBackendUrl(backendBaseUrl2);
|
|
10816
|
+
const { token: initialToken, did } = await authenticateAgent({
|
|
10817
|
+
backendBaseUrl: backendBaseUrl2,
|
|
10818
|
+
workerSecret: workerSecret2,
|
|
10709
10819
|
provider: inference.type,
|
|
10710
10820
|
model: inference.model
|
|
10711
10821
|
});
|
|
10822
|
+
const generator = didToAgent(did);
|
|
10712
10823
|
const kbId = `agent-${inference.type}-${inference.model}-${hostname()}`;
|
|
10713
10824
|
const endpoint = { kind: "http", host, port, protocol };
|
|
10714
10825
|
const kb = {
|
|
@@ -10719,7 +10830,7 @@ async function startAgentWorker(group) {
|
|
|
10719
10830
|
};
|
|
10720
10831
|
const storage = new InMemorySessionStorage();
|
|
10721
10832
|
setStoredSession(storage, kbId, { access: initialToken, refresh: "" });
|
|
10722
|
-
const token$ = new
|
|
10833
|
+
const token$ = new import_rxjs2.BehaviorSubject(null);
|
|
10723
10834
|
let session;
|
|
10724
10835
|
const transport = new HttpTransport({
|
|
10725
10836
|
baseUrl: baseUrl(kbBackendUrl(endpoint)),
|
|
@@ -10735,10 +10846,15 @@ async function startAgentWorker(group) {
|
|
|
10735
10846
|
token$,
|
|
10736
10847
|
refresh: async () => {
|
|
10737
10848
|
try {
|
|
10738
|
-
const { token } = await authenticateAgent(
|
|
10849
|
+
const { token } = await authenticateAgent({
|
|
10850
|
+
backendBaseUrl: backendBaseUrl2,
|
|
10851
|
+
workerSecret: workerSecret2,
|
|
10852
|
+
provider: inference.type,
|
|
10853
|
+
model: inference.model
|
|
10854
|
+
});
|
|
10739
10855
|
return token;
|
|
10740
10856
|
} catch (err) {
|
|
10741
|
-
|
|
10857
|
+
logger2.error("Agent token refresh failed", {
|
|
10742
10858
|
error: err instanceof Error ? err.message : String(err),
|
|
10743
10859
|
agent: did
|
|
10744
10860
|
});
|
|
@@ -10746,7 +10862,7 @@ async function startAgentWorker(group) {
|
|
|
10746
10862
|
}
|
|
10747
10863
|
},
|
|
10748
10864
|
onError: (err) => {
|
|
10749
|
-
|
|
10865
|
+
logger2.error("Session error", { code: err.code, message: err.message, agent: did });
|
|
10750
10866
|
}
|
|
10751
10867
|
});
|
|
10752
10868
|
await session.ready;
|
|
@@ -10755,9 +10871,9 @@ async function startAgentWorker(group) {
|
|
|
10755
10871
|
jobTypes: group.jobTypes,
|
|
10756
10872
|
inferenceClient: group.client,
|
|
10757
10873
|
generator,
|
|
10758
|
-
logger
|
|
10874
|
+
logger: logger2
|
|
10759
10875
|
});
|
|
10760
|
-
|
|
10876
|
+
logger2.info("Agent ready", {
|
|
10761
10877
|
did,
|
|
10762
10878
|
provider: inference.type,
|
|
10763
10879
|
model: inference.model,
|
|
@@ -10771,6 +10887,73 @@ async function startAgentWorker(group) {
|
|
|
10771
10887
|
}
|
|
10772
10888
|
};
|
|
10773
10889
|
}
|
|
10890
|
+
var ALL_JOB_TYPES = [
|
|
10891
|
+
"reference-annotation",
|
|
10892
|
+
"generation",
|
|
10893
|
+
"highlight-annotation",
|
|
10894
|
+
"assessment-annotation",
|
|
10895
|
+
"comment-annotation",
|
|
10896
|
+
"tag-annotation"
|
|
10897
|
+
];
|
|
10898
|
+
var configPath = join(homedir(), ".semiontconfig");
|
|
10899
|
+
var tomlReader = {
|
|
10900
|
+
readIfExists: (p) => existsSync(p) ? readFileSync(p, "utf-8") : null
|
|
10901
|
+
};
|
|
10902
|
+
var envConfig = createTomlConfigLoader(
|
|
10903
|
+
tomlReader,
|
|
10904
|
+
configPath,
|
|
10905
|
+
process.env
|
|
10906
|
+
)(null, "local");
|
|
10907
|
+
var workerInferenceMap = envConfig._metadata?.workers;
|
|
10908
|
+
if (!workerInferenceMap || Object.keys(workerInferenceMap).length === 0) {
|
|
10909
|
+
throw new Error(
|
|
10910
|
+
'No worker inference config found in ~/.semiontconfig. Add at least [environments.<env>.workers.default.inference] with type = "..." and model = "...".'
|
|
10911
|
+
);
|
|
10912
|
+
}
|
|
10913
|
+
function resolveWorker(jobType) {
|
|
10914
|
+
const specific = workerInferenceMap[jobType];
|
|
10915
|
+
if (specific) return specific;
|
|
10916
|
+
const def = workerInferenceMap["default"];
|
|
10917
|
+
if (def) return def;
|
|
10918
|
+
throw new Error(
|
|
10919
|
+
`No inference config for worker '${jobType}' and no workers.default in ~/.semiontconfig.`
|
|
10920
|
+
);
|
|
10921
|
+
}
|
|
10922
|
+
var backendPublicURL = envConfig.services?.backend?.publicURL;
|
|
10923
|
+
if (!backendPublicURL) {
|
|
10924
|
+
throw new Error("services.backend.publicURL is required in ~/.semiontconfig");
|
|
10925
|
+
}
|
|
10926
|
+
var backendBaseUrl = backendPublicURL;
|
|
10927
|
+
var workerSecret = process.env.SEMIONT_WORKER_SECRET ?? "";
|
|
10928
|
+
var healthPort = 9090;
|
|
10929
|
+
var logger = createProcessLogger("worker");
|
|
10930
|
+
function clientKey(w) {
|
|
10931
|
+
return [w.type, w.model, w.apiKey ?? "", w.endpoint ?? "", w.baseURL ?? ""].join("|");
|
|
10932
|
+
}
|
|
10933
|
+
function toClientConfig(w) {
|
|
10934
|
+
return {
|
|
10935
|
+
type: w.type,
|
|
10936
|
+
model: w.model,
|
|
10937
|
+
...w.endpoint && { endpoint: w.endpoint },
|
|
10938
|
+
...w.baseURL && { baseURL: w.baseURL },
|
|
10939
|
+
...w.apiKey && { apiKey: w.apiKey }
|
|
10940
|
+
};
|
|
10941
|
+
}
|
|
10942
|
+
var groups = /* @__PURE__ */ new Map();
|
|
10943
|
+
for (const jobType of ALL_JOB_TYPES) {
|
|
10944
|
+
const inference = resolveWorker(jobType);
|
|
10945
|
+
const key = clientKey(inference);
|
|
10946
|
+
let group = groups.get(key);
|
|
10947
|
+
if (!group) {
|
|
10948
|
+
group = {
|
|
10949
|
+
inference,
|
|
10950
|
+
jobTypes: [],
|
|
10951
|
+
client: createInferenceClient(toClientConfig(inference), logger)
|
|
10952
|
+
};
|
|
10953
|
+
groups.set(key, group);
|
|
10954
|
+
}
|
|
10955
|
+
group.jobTypes.push(jobType);
|
|
10956
|
+
}
|
|
10774
10957
|
async function main() {
|
|
10775
10958
|
const { initObservabilityNode } = await import('@semiont/observability/node');
|
|
10776
10959
|
initObservabilityNode({ serviceName: "semiont-worker" });
|
|
@@ -10782,7 +10965,11 @@ async function main() {
|
|
|
10782
10965
|
jobTypes: g.jobTypes
|
|
10783
10966
|
}))
|
|
10784
10967
|
});
|
|
10785
|
-
const workers = await Promise.all(
|
|
10968
|
+
const workers = await Promise.all(
|
|
10969
|
+
Array.from(groups.values()).map(
|
|
10970
|
+
(group) => startAgentWorker({ group, backendBaseUrl, workerSecret, logger })
|
|
10971
|
+
)
|
|
10972
|
+
);
|
|
10786
10973
|
const health = createServer((req, res) => {
|
|
10787
10974
|
if (req.url === "/health") {
|
|
10788
10975
|
res.writeHead(200, { "Content-Type": "application/json" });
|