@semiont/jobs 0.5.9 → 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 +16 -6
- package/dist/index.js +93 -48
- package/dist/index.js.map +1 -1
- package/dist/worker-main.js +139 -88
- package/dist/worker-main.js.map +1 -1
- package/package.json +8 -8
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { JobId, UserId, ResourceId, EntityType, AnnotationId,
|
|
1
|
+
import { JobId, UserId, ResourceId, EntityType, AnnotationId, GatheredContext, SupportedMediaType, TagSchema, Logger, EventBus, components } from '@semiont/core';
|
|
2
2
|
import { SemiontProject } from '@semiont/core/node';
|
|
3
3
|
import { InferenceClient } from '@semiont/inference';
|
|
4
4
|
|
|
@@ -74,10 +74,13 @@ interface DetectionParams {
|
|
|
74
74
|
* Generation job parameters
|
|
75
75
|
*/
|
|
76
76
|
interface GenerationParams {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
77
|
+
/**
|
|
78
|
+
* The unresolved reference an annotation-focus generation was triggered from.
|
|
79
|
+
* Absent for resource-focus generation (`yield.fromResource`). When present, the
|
|
80
|
+
* worker auto-binds the new resource to it; when absent, provenance is a minted
|
|
81
|
+
* source→derived reference annotation (Fork 2b).
|
|
82
|
+
*/
|
|
83
|
+
referenceId?: AnnotationId;
|
|
81
84
|
prompt?: string;
|
|
82
85
|
title?: string;
|
|
83
86
|
entityTypes?: EntityType[];
|
|
@@ -93,6 +96,13 @@ interface GenerationParams {
|
|
|
93
96
|
temperature?: number;
|
|
94
97
|
maxTokens?: number;
|
|
95
98
|
storageUri?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Requested media type of the generated resource's content. Default `text/markdown`.
|
|
101
|
+
* The generation worker produces `text/markdown` and `text/plain`; any other value
|
|
102
|
+
* fails the job (no silent fallback) — Semiont is multi-modal at the core, but
|
|
103
|
+
* generation coverage is text-only for now and the gap is surfaced, not hidden.
|
|
104
|
+
*/
|
|
105
|
+
outputMediaType?: SupportedMediaType;
|
|
96
106
|
}
|
|
97
107
|
/**
|
|
98
108
|
* Highlight detection job parameters
|
|
@@ -627,7 +637,7 @@ declare class AnnotationDetection {
|
|
|
627
637
|
* generate German content from an English source resource. See
|
|
628
638
|
* `types.ts` "Locale conventions" for the full discussion.
|
|
629
639
|
*/
|
|
630
|
-
declare function generateResourceFromTopic(topic: string, entityTypes: string[], client: InferenceClient, logger: Logger, userPrompt?: string, locale?: string, context?: GatheredContext, temperature?: number, maxTokens?: number, sourceLanguage?: string): Promise<{
|
|
640
|
+
declare function generateResourceFromTopic(topic: string, entityTypes: string[], client: InferenceClient, logger: Logger, userPrompt?: string, locale?: string, context?: GatheredContext, temperature?: number, maxTokens?: number, sourceLanguage?: string, outputMediaType?: SupportedMediaType): Promise<{
|
|
631
641
|
title: string;
|
|
632
642
|
content: string;
|
|
633
643
|
}>;
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { promises } from 'fs';
|
|
2
2
|
import * as path from 'path';
|
|
3
|
-
import { jobId, reconcileSelector, isObject, isString, getLocaleEnglishName, didToAgent, isArray } from '@semiont/core';
|
|
3
|
+
import { jobId, deriveViews, reconcileSelector, isObject, isString, getLocaleEnglishName, didToAgent, isArray } from '@semiont/core';
|
|
4
4
|
import { generateAnnotationId } from '@semiont/event-sourcing';
|
|
5
5
|
|
|
6
6
|
// src/fs-job-queue.ts
|
|
@@ -1068,7 +1068,7 @@ Example output:
|
|
|
1068
1068
|
function getLanguageName(locale) {
|
|
1069
1069
|
return getLocaleEnglishName(locale) || locale;
|
|
1070
1070
|
}
|
|
1071
|
-
async function generateResourceFromTopic(topic, entityTypes, client, logger, userPrompt, locale, context, temperature, maxTokens, sourceLanguage) {
|
|
1071
|
+
async function generateResourceFromTopic(topic, entityTypes, client, logger, userPrompt, locale, context, temperature, maxTokens, sourceLanguage, outputMediaType = "text/markdown") {
|
|
1072
1072
|
logger.debug("Generating resource from topic", {
|
|
1073
1073
|
topicPreview: topic.substring(0, 100),
|
|
1074
1074
|
entityTypes,
|
|
@@ -1088,61 +1088,95 @@ IMPORTANT: Write the entire resource in ${getLanguageName(locale)}.` : "";
|
|
|
1088
1088
|
|
|
1089
1089
|
The source resource and embedded context are in ${getLanguageName(sourceLanguage)}.` : "";
|
|
1090
1090
|
let annotationSection = "";
|
|
1091
|
+
let contextSection = "";
|
|
1092
|
+
let resourceSection = "";
|
|
1093
|
+
let graphSection = "";
|
|
1091
1094
|
if (context) {
|
|
1092
|
-
const
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1095
|
+
const { focus } = context;
|
|
1096
|
+
const mainResourceId = focus.kind === "annotation" ? focus.sourceResource["@id"] : focus.resource["@id"];
|
|
1097
|
+
const focalAnnotationId = focus.kind === "annotation" ? focus.annotation.id : void 0;
|
|
1098
|
+
if (focus.kind === "annotation") {
|
|
1099
|
+
const parts = [];
|
|
1100
|
+
parts.push(`- Annotation motivation: ${focus.annotation.motivation}`);
|
|
1101
|
+
parts.push(`- Source resource: ${focus.sourceResource.name}`);
|
|
1102
|
+
const { motivation, body } = focus.annotation;
|
|
1103
|
+
if (motivation === "commenting" || motivation === "assessing") {
|
|
1104
|
+
const bodyItem = Array.isArray(body) ? body[0] : body;
|
|
1105
|
+
if (bodyItem && "value" in bodyItem && bodyItem.value) {
|
|
1106
|
+
const label = motivation === "commenting" ? "Comment" : "Assessment";
|
|
1107
|
+
parts.push(`- ${label}: ${bodyItem.value}`);
|
|
1108
|
+
}
|
|
1101
1109
|
}
|
|
1102
|
-
|
|
1103
|
-
annotationSection = `
|
|
1110
|
+
annotationSection = `
|
|
1104
1111
|
|
|
1105
1112
|
Annotation context:
|
|
1106
1113
|
${parts.join("\n")}`;
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
const { before, selected, after } = context.sourceContext;
|
|
1111
|
-
contextSection = `
|
|
1114
|
+
if (focus.selected) {
|
|
1115
|
+
const { before, text, after } = focus.selected;
|
|
1116
|
+
contextSection = `
|
|
1112
1117
|
|
|
1113
1118
|
Source document context:
|
|
1114
1119
|
---
|
|
1115
1120
|
${before ? `...${before}` : ""}
|
|
1116
|
-
**[${
|
|
1121
|
+
**[${text}]**
|
|
1117
1122
|
${after ? `${after}...` : ""}
|
|
1118
1123
|
---
|
|
1119
1124
|
`;
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1125
|
+
}
|
|
1126
|
+
} else {
|
|
1127
|
+
const RESOURCE_CONTENT_CAP = 4e3;
|
|
1128
|
+
const parts = [`- Resource: ${focus.resource.name}`];
|
|
1129
|
+
if (focus.summary) parts.push(`- Summary: ${focus.summary}`);
|
|
1130
|
+
if (focus.suggestedReferences && focus.suggestedReferences.length > 0) {
|
|
1131
|
+
parts.push(`- Suggested references: ${focus.suggestedReferences.join(", ")}`);
|
|
1132
|
+
}
|
|
1133
|
+
resourceSection = `
|
|
1134
|
+
|
|
1135
|
+
Resource context:
|
|
1136
|
+
${parts.join("\n")}`;
|
|
1137
|
+
if (focus.content?.main) {
|
|
1138
|
+
resourceSection += `
|
|
1139
|
+
|
|
1140
|
+
Resource content:
|
|
1141
|
+
---
|
|
1142
|
+
${focus.content.main.slice(0, RESOURCE_CONTENT_CAP)}
|
|
1143
|
+
---`;
|
|
1144
|
+
}
|
|
1145
|
+
const related = Object.entries(focus.content?.related ?? {});
|
|
1146
|
+
if (related.length > 0) {
|
|
1147
|
+
const blocks = related.map(([id, text]) => `[${id}]
|
|
1148
|
+
${text.slice(0, RESOURCE_CONTENT_CAP)}`).join("\n\n");
|
|
1149
|
+
resourceSection += `
|
|
1150
|
+
|
|
1151
|
+
Related resource content:
|
|
1152
|
+
---
|
|
1153
|
+
${blocks}
|
|
1154
|
+
---`;
|
|
1155
|
+
}
|
|
1140
1156
|
}
|
|
1141
|
-
if (
|
|
1142
|
-
|
|
1157
|
+
if (mainResourceId) {
|
|
1158
|
+
const views = deriveViews(context.graph, mainResourceId, focalAnnotationId);
|
|
1159
|
+
const parts = [];
|
|
1160
|
+
if (views.connections.length > 0) {
|
|
1161
|
+
const connList = views.connections.map((c) => `${c.resourceName}${c.entityTypes.length ? ` (${c.entityTypes.join(", ")})` : ""}`).join(", ");
|
|
1162
|
+
parts.push(`- Connected resources: ${connList}`);
|
|
1163
|
+
}
|
|
1164
|
+
if (views.citedByCount > 0) {
|
|
1165
|
+
const citedNames = views.citedBy.map((c) => c.resourceName).join(", ");
|
|
1166
|
+
parts.push(`- This resource is cited by ${views.citedByCount} other resource${views.citedByCount > 1 ? "s" : ""}${citedNames ? `: ${citedNames}` : ""}`);
|
|
1167
|
+
}
|
|
1168
|
+
if (views.siblingEntityTypes.length > 0) {
|
|
1169
|
+
parts.push(`- Related entity types in this document: ${views.siblingEntityTypes.join(", ")}`);
|
|
1170
|
+
}
|
|
1171
|
+
if (context.inferredRelationshipSummary) {
|
|
1172
|
+
parts.push(`- Relationship summary: ${context.inferredRelationshipSummary}`);
|
|
1173
|
+
}
|
|
1174
|
+
if (parts.length > 0) {
|
|
1175
|
+
graphSection = `
|
|
1143
1176
|
|
|
1144
1177
|
Knowledge graph context:
|
|
1145
1178
|
${parts.join("\n")}`;
|
|
1179
|
+
}
|
|
1146
1180
|
}
|
|
1147
1181
|
}
|
|
1148
1182
|
let semanticContextSection = "";
|
|
@@ -1154,17 +1188,20 @@ ${parts.join("\n")}`;
|
|
|
1154
1188
|
Related passages from the knowledge base:
|
|
1155
1189
|
${lines.join("\n")}`;
|
|
1156
1190
|
}
|
|
1157
|
-
const
|
|
1191
|
+
const isPlainText = outputMediaType === "text/plain";
|
|
1192
|
+
const structureGuidance = !isPlainText && finalMaxTokens >= 1e3 ? "organized into titled sections (## Section) with well-structured paragraphs" : "organized into well-structured paragraphs";
|
|
1193
|
+
const formatRequirements = isPlainText ? `- Write the response as plain text \u2014 no formatting markup (no #, *, backticks, headings, or links)
|
|
1194
|
+
- Begin with the title on its own first line` : `- Start with a clear heading (# Title)
|
|
1195
|
+
- Use markdown formatting
|
|
1196
|
+
- Write the response as markdown`;
|
|
1158
1197
|
const prompt = `Generate a concise, informative resource about "${topic}".
|
|
1159
1198
|
${entityTypes.length > 0 ? `Focus on these entity types: ${entityTypes.join(", ")}.` : ""}
|
|
1160
|
-
${userPrompt ? `Additional context: ${userPrompt}` : ""}${annotationSection}${contextSection}${
|
|
1199
|
+
${userPrompt ? `Additional context: ${userPrompt}` : ""}${annotationSection}${contextSection}${resourceSection}${graphSection}${semanticContextSection}${sourceLanguageInstruction}${languageInstruction}
|
|
1161
1200
|
|
|
1162
1201
|
Requirements:
|
|
1163
|
-
- Start with a clear heading (# Title)
|
|
1164
1202
|
- Aim for approximately ${finalMaxTokens} tokens of content, ${structureGuidance}
|
|
1165
1203
|
- Be factual and informative
|
|
1166
|
-
|
|
1167
|
-
- Write the response as markdown`;
|
|
1204
|
+
${formatRequirements}`;
|
|
1168
1205
|
const parseResponse = (response2) => {
|
|
1169
1206
|
let content = response2.trim();
|
|
1170
1207
|
if (content.startsWith("```markdown") || content.startsWith("```md")) {
|
|
@@ -1483,6 +1520,13 @@ async function processTagJob(content, inferenceClient, params, userId, generator
|
|
|
1483
1520
|
};
|
|
1484
1521
|
}
|
|
1485
1522
|
async function processGenerationJob(inferenceClient, params, onProgress, logger) {
|
|
1523
|
+
const GENERATABLE_MEDIA_TYPES = ["text/markdown", "text/plain"];
|
|
1524
|
+
const outputMediaType = params.outputMediaType ?? "text/markdown";
|
|
1525
|
+
if (!GENERATABLE_MEDIA_TYPES.includes(outputMediaType)) {
|
|
1526
|
+
throw new Error(
|
|
1527
|
+
`Unsupported outputMediaType for generation: ${outputMediaType}. Generation produces ${GENERATABLE_MEDIA_TYPES.join(" or ")}.`
|
|
1528
|
+
);
|
|
1529
|
+
}
|
|
1486
1530
|
onProgress(20, "Fetching context...", "fetching");
|
|
1487
1531
|
const title = params.title ?? "Untitled";
|
|
1488
1532
|
const entityTypes = (params.entityTypes ?? []).map(String);
|
|
@@ -1497,13 +1541,14 @@ async function processGenerationJob(inferenceClient, params, onProgress, logger)
|
|
|
1497
1541
|
params.context,
|
|
1498
1542
|
params.temperature,
|
|
1499
1543
|
params.maxTokens,
|
|
1500
|
-
params.sourceLanguage
|
|
1544
|
+
params.sourceLanguage,
|
|
1545
|
+
outputMediaType
|
|
1501
1546
|
);
|
|
1502
1547
|
onProgress(85, "Creating resource...", "creating");
|
|
1503
1548
|
return {
|
|
1504
1549
|
content: generated.content,
|
|
1505
1550
|
title: generated.title ?? title,
|
|
1506
|
-
format:
|
|
1551
|
+
format: outputMediaType,
|
|
1507
1552
|
result: {
|
|
1508
1553
|
resourceId: "",
|
|
1509
1554
|
resourceName: generated.title ?? title
|