@musnows/scriverse 0.7.13 → 0.8.1
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/README.en.md +4 -0
- package/README.md +5 -0
- package/dist/ai-chat-tab-limit.js +14 -0
- package/dist/ai-chat-tab-limit.js.map +1 -0
- package/dist/ai-protocol.js +10 -2
- package/dist/ai-protocol.js.map +1 -1
- package/dist/ai-retry.js +52 -0
- package/dist/ai-retry.js.map +1 -0
- package/dist/ai.js +547 -119
- package/dist/ai.js.map +1 -1
- package/dist/app.js +80 -22
- package/dist/app.js.map +1 -1
- package/dist/cli-contract.js +2 -1
- package/dist/cli-contract.js.map +1 -1
- package/dist/database.js +127 -2
- package/dist/database.js.map +1 -1
- package/dist/domain.js +1 -0
- package/dist/domain.js.map +1 -1
- package/dist/public/ai-chat-tabs.js +75 -0
- package/dist/public/ai-request-manager.js +32 -15
- package/dist/public/app.js +1305 -298
- package/dist/public/background-task-center.d.ts +9 -0
- package/dist/public/background-task-center.js +18 -0
- package/dist/public/chapter-search.d.ts +6 -0
- package/dist/public/chapter-search.js +23 -0
- package/dist/public/character-filters.d.ts +3 -1
- package/dist/public/character-filters.js +17 -2
- package/dist/public/character-version.js +1 -0
- package/dist/public/display-labels.d.ts +1 -0
- package/dist/public/display-labels.js +5 -1
- package/dist/public/index.html +67 -26
- package/dist/public/model-config.d.ts +3 -1
- package/dist/public/model-config.js +13 -0
- package/dist/public/relationship-filters.d.ts +5 -0
- package/dist/public/relationship-filters.js +31 -0
- package/dist/public/relationship-graph.js +289 -58
- package/dist/public/stream-typewriter.d.ts +1 -0
- package/dist/public/stream-typewriter.js +12 -0
- package/dist/public/styles.css +185 -41
- package/dist/public/work-permissions.d.ts +1 -1
- package/dist/public/work-permissions.js +13 -1
- package/dist/server-runtime.js +6 -0
- package/dist/server-runtime.js.map +1 -1
- package/dist/store.js +127 -44
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +34 -7
- package/dist/user-auth.js.map +1 -1
- package/dist/version.js +6 -1
- package/dist/version.js.map +1 -1
- package/dist/work-permissions.js +13 -2
- package/dist/work-permissions.js.map +1 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -9,8 +9,9 @@ import { rm } from "node:fs/promises";
|
|
|
9
9
|
import { tmpdir } from "node:os";
|
|
10
10
|
import { pipeline } from "node:stream/promises";
|
|
11
11
|
import { z, ZodError } from "zod";
|
|
12
|
-
import { AI_PROVIDER_PROTOCOLS } from "./ai-protocol.js";
|
|
12
|
+
import { AI_PROVIDER_PROTOCOLS, MAX_TOKENS_PARAMETERS } from "./ai-protocol.js";
|
|
13
13
|
import { aiConversationExportContentDisposition, exportAiConversationMarkdown } from "./ai-conversation-export.js";
|
|
14
|
+
import { DEFAULT_AI_CHAT_TAB_LIMIT } from "./ai-chat-tab-limit.js";
|
|
14
15
|
import { DEFAULT_AI_STREAM_IDLE_TIMEOUT_MS } from "./ai-stream-timeout.js";
|
|
15
16
|
import { AttachmentStorage } from "./attachment-storage.js";
|
|
16
17
|
import { AiManager } from "./ai.js";
|
|
@@ -20,12 +21,12 @@ import { CredentialVault } from "./credential-vault.js";
|
|
|
20
21
|
import { Database } from "./database.js";
|
|
21
22
|
import { assertSafeDocxArchive } from "./docx-security.js";
|
|
22
23
|
import { EPUB_MIME_TYPE, epubContentDisposition } from "./epub-export.js";
|
|
23
|
-
import { CREATABLE_ANALYSIS_TASK_TYPES, DRAFT_SETTING_MODULES, TASK_TYPES } from "./domain.js";
|
|
24
|
+
import { CHARACTER_GENDERS, CREATABLE_ANALYSIS_TASK_TYPES, DRAFT_SETTING_MODULES, TASK_TYPES } from "./domain.js";
|
|
24
25
|
import { AppError } from "./errors.js";
|
|
25
26
|
import { isOfficialGoogleVertexBaseUrl, parseGoogleServiceAccount } from "./google-vertex-auth.js";
|
|
26
27
|
import { HYBRID_SEARCH_TYPES, MAXIMUM_WORK_SEARCH_QUERY_LENGTH, readableHybridSearchTypes } from "./hybrid-search.js";
|
|
27
28
|
import { applyImportFileHints, parseNovelText } from "./parser.js";
|
|
28
|
-
import { aiConversationTaskTypes, attachmentPermissionModules, RECYCLE_BIN_RETENTION_DAYS, Store, versionedEntityTypes } from "./store.js";
|
|
29
|
+
import { aiConversationTaskTypes, attachmentPermissionModules, RECYCLE_BIN_RETENTION_DAYS, Store, versionedEntityTypes, WORK_AGENT_TOOL_IDS } from "./store.js";
|
|
29
30
|
import { paginated, parsePagination } from "./pagination.js";
|
|
30
31
|
import { normalizeUploadFileName } from "./utils.js";
|
|
31
32
|
import { assertSafeAiEndpoint, assertSafeS3Endpoint, createApiRateLimitMiddleware, createAuthenticationRateLimitMiddleware, createBasicAuthMiddleware, createCaptchaRateLimitMiddleware, createExpensiveApiRateLimitMiddleware, createSameOriginMiddleware, createSecurityHeadersMiddleware, createUploadRateLimitMiddleware, enforceCaseInsensitiveRouting, normalizeApiPath, resolveTrustProxySetting, verifySetupToken } from "./security.js";
|
|
@@ -39,10 +40,14 @@ import { S3BackupManager } from "./s3-backup.js";
|
|
|
39
40
|
import { APP_VERSION } from "./version.js";
|
|
40
41
|
import { ReleaseUpdateChecker } from "./release-update.js";
|
|
41
42
|
import { DEFAULT_IMAGE_UPLOAD_LIMITS, formatUploadLimit } from "./upload-limits.js";
|
|
42
|
-
import { canReadWorkModule, canWriteWorkModule, fullWorkModulePermissions, proseReplacementPermissionModules } from "./work-permissions.js";
|
|
43
|
+
import { canReadWorkModule, canWriteWorkModule, chapterAnnotationPermissionModule, fullWorkModulePermissions, proseReplacementPermissionModules } from "./work-permissions.js";
|
|
43
44
|
import { CollaborationPresence, editorPageKey, entityEditorPageKey, modulePageKey, presencePageKinds } from "./collaboration-presence.js";
|
|
44
45
|
import { PresenceStore } from "./presence-store.js";
|
|
45
46
|
import { analysisTaskReadModules, clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, relationshipAnalysisReadModules, setSessionCookie, UserAuthService } from "./user-auth.js";
|
|
47
|
+
const chapterAnnotationKinds = ["note", "todo"];
|
|
48
|
+
function readableChapterAnnotationKinds(permissions) {
|
|
49
|
+
return chapterAnnotationKinds.filter((kind) => canReadWorkModule(permissions, chapterAnnotationPermissionModule(kind)));
|
|
50
|
+
}
|
|
46
51
|
const nonEmpty = z.string().trim().min(1);
|
|
47
52
|
const identifier = z.string().trim().min(1).max(200);
|
|
48
53
|
const idempotencyKeySchema = z.string().trim().min(16).max(128)
|
|
@@ -109,6 +114,8 @@ const memberRoleValueSchema = z.enum(["editor", "settings-editor", "viewer"]);
|
|
|
109
114
|
const moduleAccessSchema = z.enum(["none", "read", "write"]);
|
|
110
115
|
const modulePermissionsSchema = z.object({
|
|
111
116
|
prose: moduleAccessSchema,
|
|
117
|
+
comments: moduleAccessSchema.optional(),
|
|
118
|
+
todos: moduleAccessSchema.optional(),
|
|
112
119
|
drafts: moduleAccessSchema.optional(),
|
|
113
120
|
settings: moduleAccessSchema,
|
|
114
121
|
characters: moduleAccessSchema,
|
|
@@ -123,6 +130,8 @@ const modulePermissionsSchema = z.object({
|
|
|
123
130
|
"ai-settings": moduleAccessSchema
|
|
124
131
|
}).strict().transform((permissions) => ({
|
|
125
132
|
...permissions,
|
|
133
|
+
comments: permissions.comments ?? permissions.prose,
|
|
134
|
+
todos: permissions.todos ?? permissions.prose,
|
|
126
135
|
drafts: permissions.drafts ?? (permissions.prose === "write" && permissions.settings === "write"
|
|
127
136
|
? "write"
|
|
128
137
|
: permissions.prose === "none" || permissions.settings === "none" ? "none" : "read")
|
|
@@ -189,7 +198,8 @@ const settingSchema = z.object({
|
|
|
189
198
|
const globalReplaceSchema = z.object({
|
|
190
199
|
find: z.string().min(1).max(500),
|
|
191
200
|
replacement: z.string().max(200_000),
|
|
192
|
-
scope: z.enum(["prose", "settings", "prose-and-settings"])
|
|
201
|
+
scope: z.enum(["prose", "settings", "prose-and-settings"]),
|
|
202
|
+
volumeId: identifier.nullable().optional()
|
|
193
203
|
}).strict();
|
|
194
204
|
const draftSchema = z.object({
|
|
195
205
|
draftType: z.enum(["prose", "setting"]),
|
|
@@ -200,6 +210,7 @@ const draftSchema = z.object({
|
|
|
200
210
|
}).strict();
|
|
201
211
|
const characterSchema = z.object({
|
|
202
212
|
name: nonEmpty.max(200),
|
|
213
|
+
gender: z.enum(CHARACTER_GENDERS).optional(),
|
|
203
214
|
isDead: z.boolean().optional(),
|
|
204
215
|
code: z.string().trim().max(200).optional(),
|
|
205
216
|
aliases: z.array(z.string().trim().min(1).max(200)).max(100).optional(),
|
|
@@ -344,6 +355,7 @@ const providerBaseSchema = z.object({
|
|
|
344
355
|
baseUrl: z.string().url().refine((value) => value.startsWith("http://") || value.startsWith("https://"), "接口地址必须使用 HTTP 或 HTTPS"),
|
|
345
356
|
apiKey: z.string().trim().min(1).max(50_000),
|
|
346
357
|
protocol: z.enum(AI_PROVIDER_PROTOCOLS).optional(),
|
|
358
|
+
maxTokensParameter: z.enum(MAX_TOKENS_PARAMETERS).optional(),
|
|
347
359
|
status: z.enum(["enabled", "disabled"]).optional(),
|
|
348
360
|
note: z.string().max(10_000).optional(),
|
|
349
361
|
concurrencyLimit: z.number().int().min(1).max(100).optional(),
|
|
@@ -396,6 +408,7 @@ const modelSchema = z.object({
|
|
|
396
408
|
outputNote: z.string().max(10_000).optional(),
|
|
397
409
|
preset: jsonObject.optional(),
|
|
398
410
|
thinkingEnabled: z.boolean().optional(),
|
|
411
|
+
thinkingEffort: z.enum(["default", "low", "medium", "high", "xhigh", "max"]).optional(),
|
|
399
412
|
multimodalEnabled: z.boolean().optional(),
|
|
400
413
|
imageToolDefault: z.boolean().optional(),
|
|
401
414
|
enabled: z.boolean().optional(),
|
|
@@ -536,11 +549,12 @@ const workAiSettingsSchema = z.object({
|
|
|
536
549
|
autoRunBatchLimit: z.number().int().min(1).max(200).optional(),
|
|
537
550
|
autoRunDailyTaskLimit: z.number().int().min(0).max(10_000).optional(),
|
|
538
551
|
autoRunFailureThreshold: z.number().int().min(1).max(10).optional(),
|
|
552
|
+
autoRunStabilityDelayMinutes: z.number().int().min(1).max(120).optional(),
|
|
539
553
|
bookSummaryContextPercent: z.number().int().min(1).max(90).optional(),
|
|
540
554
|
contextCompactThreshold: z.number().int().min(50).max(90).optional(),
|
|
541
555
|
agentToolCallLimit: z.number().int().min(5).optional(),
|
|
542
556
|
agentToolCallGlobalMultiplier: z.number().int().min(1).max(6).optional(),
|
|
543
|
-
agentTools: z.array(z.enum(
|
|
557
|
+
agentTools: z.array(z.enum(WORK_AGENT_TOOL_IDS)).max(WORK_AGENT_TOOL_IDS.length).optional(),
|
|
544
558
|
alwaysIncludeSettingInfo: z.boolean().optional(),
|
|
545
559
|
titleGenerationModelId: z.string().trim().max(200).optional(),
|
|
546
560
|
imageToolModelId: identifier.nullable().optional()
|
|
@@ -605,8 +619,8 @@ const relationshipAnalysisScopeSchema = z.object({
|
|
|
605
619
|
if (scope.volumeIds && new Set(scope.volumeIds).size !== scope.volumeIds.length) {
|
|
606
620
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["volumeIds"], message: "分卷不能重复选择" });
|
|
607
621
|
}
|
|
608
|
-
if (scope.includeAllSettings && scope.type !== "book") {
|
|
609
|
-
context.addIssue({ code: z.ZodIssueCode.custom, path: ["includeAllSettings"], message: "
|
|
622
|
+
if (scope.includeAllSettings && scope.type !== "book" && scope.type !== "chapter") {
|
|
623
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["includeAllSettings"], message: "包含所有设定仅支持全书或指定章节人物关系分析" });
|
|
610
624
|
}
|
|
611
625
|
if (scope.characterIds && new Set(scope.characterIds).size !== scope.characterIds.length) {
|
|
612
626
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["characterIds"], message: "被分析角色不能重复" });
|
|
@@ -926,12 +940,18 @@ function redactAiConversationMessage(item, permissions) {
|
|
|
926
940
|
if (!message)
|
|
927
941
|
return item;
|
|
928
942
|
if (permissions.prose !== "none") {
|
|
929
|
-
if (permissions.characters !== "none")
|
|
930
|
-
return item;
|
|
931
943
|
const metadata = recordValue(message.metadata);
|
|
932
|
-
if (!metadata
|
|
944
|
+
if (!metadata)
|
|
945
|
+
return item;
|
|
946
|
+
const readableMetadata = { ...metadata };
|
|
947
|
+
if (permissions.characters === "none")
|
|
948
|
+
delete readableMetadata.mentionCharacterIds;
|
|
949
|
+
if (permissions.races === "none")
|
|
950
|
+
delete readableMetadata.mentionRaceIds;
|
|
951
|
+
if (permissions.organizations === "none")
|
|
952
|
+
delete readableMetadata.mentionOrganizationIds;
|
|
953
|
+
if (Object.keys(readableMetadata).length === Object.keys(metadata).length)
|
|
933
954
|
return item;
|
|
934
|
-
const { mentionCharacterIds: _mentionCharacterIds, ...readableMetadata } = metadata;
|
|
935
955
|
return { ...message, metadata: readableMetadata };
|
|
936
956
|
}
|
|
937
957
|
return {
|
|
@@ -949,6 +969,13 @@ function redactAiConversation(record, permissions) {
|
|
|
949
969
|
const result = {
|
|
950
970
|
...scopedRecord
|
|
951
971
|
};
|
|
972
|
+
if (result.roleplayCharacter) {
|
|
973
|
+
result.agentTools = [
|
|
974
|
+
...(permissions.characters !== "none" ? ["recall_self"] : []),
|
|
975
|
+
...(permissions.characters !== "none" && permissions.relationships !== "none" ? ["recall_relationship"] : []),
|
|
976
|
+
"calculate_time"
|
|
977
|
+
];
|
|
978
|
+
}
|
|
952
979
|
if ((permissions.prose === "none" || permissions.characters === "none") && Array.isArray(result.messages)) {
|
|
953
980
|
result.messages = result.messages.map((item) => redactAiConversationMessage(item, permissions));
|
|
954
981
|
}
|
|
@@ -1007,6 +1034,7 @@ function redactVersionSnapshots(value, mapper) {
|
|
|
1007
1034
|
}
|
|
1008
1035
|
export function createRuntime(options) {
|
|
1009
1036
|
const uploadLimits = options.uploadLimits ?? DEFAULT_IMAGE_UPLOAD_LIMITS;
|
|
1037
|
+
const aiChatTabLimit = options.aiChatTabLimit ?? DEFAULT_AI_CHAT_TAB_LIMIT;
|
|
1010
1038
|
logger.info("runtime.initializing", {
|
|
1011
1039
|
databasePath: options.databasePath,
|
|
1012
1040
|
serveUi: options.serveUi ?? true,
|
|
@@ -1124,7 +1152,11 @@ export function createRuntime(options) {
|
|
|
1124
1152
|
read: requiredModules,
|
|
1125
1153
|
write: ["ai-analysis"]
|
|
1126
1154
|
}, false, actor?.allowAdminAccess ?? false);
|
|
1127
|
-
}, attachmentStorage, {
|
|
1155
|
+
}, attachmentStorage, {
|
|
1156
|
+
interactiveStreamIdleTimeoutMs: options.aiStreamIdleTimeoutMs ?? DEFAULT_AI_STREAM_IDLE_TIMEOUT_MS,
|
|
1157
|
+
retryPolicy: options.aiRetryPolicy,
|
|
1158
|
+
retrySleep: options.aiRetrySleep
|
|
1159
|
+
});
|
|
1128
1160
|
const app = express();
|
|
1129
1161
|
enforceCaseInsensitiveRouting(app);
|
|
1130
1162
|
const upload = multer({
|
|
@@ -1160,9 +1192,11 @@ export function createRuntime(options) {
|
|
|
1160
1192
|
status: "ok",
|
|
1161
1193
|
bootId,
|
|
1162
1194
|
version: APP_VERSION,
|
|
1195
|
+
versionLabel: options.betaVersionLabel ?? null,
|
|
1163
1196
|
protocol: "openai-chat-completions",
|
|
1164
1197
|
protocols: [...AI_PROVIDER_PROTOCOLS],
|
|
1165
1198
|
development: options.developmentServer === true,
|
|
1199
|
+
aiChatTabLimit,
|
|
1166
1200
|
uploadLimits
|
|
1167
1201
|
});
|
|
1168
1202
|
});
|
|
@@ -1589,12 +1623,23 @@ export function createRuntime(options) {
|
|
|
1589
1623
|
const pagination = parsePagination(request.query);
|
|
1590
1624
|
data(response, pagination ? store.listChapterInsightsPage(request.params.chapterId, pagination) : store.listChapterInsights(request.params.chapterId));
|
|
1591
1625
|
});
|
|
1592
|
-
app.get("/api/chapters/:chapterId/
|
|
1626
|
+
app.get("/api/chapters/:chapterId/annotation-counts", (request, response) => {
|
|
1627
|
+
const permissions = requestPermissions(request);
|
|
1628
|
+
data(response, store.listChapterAnnotationCounts(request.params.chapterId, readableChapterAnnotationKinds(permissions)));
|
|
1629
|
+
});
|
|
1630
|
+
app.get("/api/chapters/:chapterId/annotations", (request, response) => {
|
|
1631
|
+
const line = request.query.line === undefined
|
|
1632
|
+
? undefined
|
|
1633
|
+
: parse(z.coerce.number().int().positive().max(100_000), request.query.line);
|
|
1634
|
+
const permissions = requestPermissions(request);
|
|
1635
|
+
data(response, store.listChapterAnnotations(request.params.chapterId, readableChapterAnnotationKinds(permissions), line));
|
|
1636
|
+
});
|
|
1593
1637
|
app.get("/api/works/:workId/chapter-annotations", (request, response) => {
|
|
1594
1638
|
const pagination = parsePagination(request.query);
|
|
1639
|
+
const permissions = requestPermissions(request, request.params.workId);
|
|
1595
1640
|
data(response, pagination
|
|
1596
|
-
? store.listWorkChapterAnnotationsPage(request.params.workId, pagination)
|
|
1597
|
-
: store.listWorkChapterAnnotations(request.params.workId));
|
|
1641
|
+
? store.listWorkChapterAnnotationsPage(request.params.workId, pagination, readableChapterAnnotationKinds(permissions))
|
|
1642
|
+
: store.listWorkChapterAnnotations(request.params.workId, readableChapterAnnotationKinds(permissions)));
|
|
1598
1643
|
});
|
|
1599
1644
|
app.post("/api/chapters/:chapterId/annotations", (request, response) => {
|
|
1600
1645
|
const input = parse(z.object({
|
|
@@ -2173,9 +2218,16 @@ export function createRuntime(options) {
|
|
|
2173
2218
|
}
|
|
2174
2219
|
data(response, await ai.previewRelationshipSources(request.params.workId, input.scope, input.modelId));
|
|
2175
2220
|
});
|
|
2176
|
-
app.post("/api/works/:workId/tasks", (request, response) => {
|
|
2221
|
+
app.post("/api/works/:workId/tasks", async (request, response) => {
|
|
2177
2222
|
const input = parse(analysisTaskSchema, request.body);
|
|
2178
|
-
|
|
2223
|
+
const permissions = requestPermissions(request, request.params.workId);
|
|
2224
|
+
const deniedModules = analysisTaskReadModules(input.taskType, input.scope).filter((module) => permissions[module] === "none");
|
|
2225
|
+
if (deniedModules.length > 0) {
|
|
2226
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取创建分析任务所需资料模块的权限", {
|
|
2227
|
+
modules: deniedModules
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
data(response, redactTaskCharacterNames(await ai.createTask(request.params.workId, input), permissions), 201);
|
|
2179
2231
|
});
|
|
2180
2232
|
app.post("/api/works/:workId/tasks/auto-run", (request, response) => {
|
|
2181
2233
|
const permissions = requestPermissions(request, request.params.workId);
|
|
@@ -2223,7 +2275,7 @@ export function createRuntime(options) {
|
|
|
2223
2275
|
allowAdminAccess: request.authMethod !== "api-key"
|
|
2224
2276
|
} : undefined), requestPermissions(request)));
|
|
2225
2277
|
});
|
|
2226
|
-
app.post("/api/tasks/:taskId/rerun", (request, response) => {
|
|
2278
|
+
app.post("/api/tasks/:taskId/rerun", async (request, response) => {
|
|
2227
2279
|
const input = parse(z.object({ modelId: identifier.optional() }).strict(), request.body ?? {});
|
|
2228
2280
|
const task = store.getTask(request.params.taskId);
|
|
2229
2281
|
const permissions = requestPermissions(request, String(task.workId));
|
|
@@ -2233,7 +2285,7 @@ export function createRuntime(options) {
|
|
|
2233
2285
|
modules: deniedModules
|
|
2234
2286
|
});
|
|
2235
2287
|
}
|
|
2236
|
-
data(response, redactTaskCharacterNames(ai.rerunTask(request.params.taskId, input.modelId), requestPermissions(request)), 201);
|
|
2288
|
+
data(response, redactTaskCharacterNames(await ai.rerunTask(request.params.taskId, input.modelId), requestPermissions(request)), 201);
|
|
2237
2289
|
});
|
|
2238
2290
|
app.post("/api/tasks/:taskId/cancel", (request, response) => data(response, redactTaskCharacterNames(ai.cancelTask(request.params.taskId), requestPermissions(request))));
|
|
2239
2291
|
app.post("/api/tasks/:taskId/character-extraction/apply", (request, response) => {
|
|
@@ -2353,6 +2405,8 @@ export function createRuntime(options) {
|
|
|
2353
2405
|
else
|
|
2354
2406
|
ai.scheduleAutoRun(workId);
|
|
2355
2407
|
}
|
|
2408
|
+
if (input.autoRunStabilityDelayMinutes !== undefined)
|
|
2409
|
+
ai.rescheduleChapterAnalysisTasks(workId);
|
|
2356
2410
|
data(response, updated);
|
|
2357
2411
|
});
|
|
2358
2412
|
app.get("/api/works/:workId/ai-conversations", (request, response) => {
|
|
@@ -2680,6 +2734,8 @@ export function createRuntime(options) {
|
|
|
2680
2734
|
...(resolvedScope.characterIds ?? []),
|
|
2681
2735
|
...(resolvedScope.mentionCharacterIds ?? [])
|
|
2682
2736
|
])];
|
|
2737
|
+
const mentionRaceIds = [...new Set(resolvedScope.raceIds ?? [])];
|
|
2738
|
+
const mentionOrganizationIds = [...new Set(resolvedScope.organizationIds ?? [])];
|
|
2683
2739
|
const begun = store.beginAiConversationStreamRequest({
|
|
2684
2740
|
workId: request.params.workId,
|
|
2685
2741
|
conversationId,
|
|
@@ -2690,9 +2746,11 @@ export function createRuntime(options) {
|
|
|
2690
2746
|
content: input.instruction,
|
|
2691
2747
|
citations,
|
|
2692
2748
|
...(input.currentMessageId ? { existingMessageId: input.currentMessageId } : {}),
|
|
2693
|
-
...((modelId || mentionCharacterIds.length) ? { metadata: {
|
|
2749
|
+
...((modelId || mentionCharacterIds.length || mentionRaceIds.length || mentionOrganizationIds.length) ? { metadata: {
|
|
2694
2750
|
...(modelId ? { modelId } : {}),
|
|
2695
|
-
...(mentionCharacterIds.length ? { mentionCharacterIds } : {})
|
|
2751
|
+
...(mentionCharacterIds.length ? { mentionCharacterIds } : {}),
|
|
2752
|
+
...(mentionRaceIds.length ? { mentionRaceIds } : {}),
|
|
2753
|
+
...(mentionOrganizationIds.length ? { mentionOrganizationIds } : {})
|
|
2696
2754
|
} } : {})
|
|
2697
2755
|
}
|
|
2698
2756
|
});
|