@musnows/scriverse 0.7.13 → 0.8.0
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 +525 -117
- package/dist/ai.js.map +1 -1
- package/dist/app.js +41 -12
- 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 +1151 -252
- 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 +66 -25
- 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/styles.css +170 -32
- package/dist/server-runtime.js +6 -0
- package/dist/server-runtime.js.map +1 -1
- package/dist/store.js +77 -34
- package/dist/store.js.map +1 -1
- package/dist/version.js +6 -1
- package/dist/version.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";
|
|
@@ -189,7 +190,8 @@ const settingSchema = z.object({
|
|
|
189
190
|
const globalReplaceSchema = z.object({
|
|
190
191
|
find: z.string().min(1).max(500),
|
|
191
192
|
replacement: z.string().max(200_000),
|
|
192
|
-
scope: z.enum(["prose", "settings", "prose-and-settings"])
|
|
193
|
+
scope: z.enum(["prose", "settings", "prose-and-settings"]),
|
|
194
|
+
volumeId: identifier.nullable().optional()
|
|
193
195
|
}).strict();
|
|
194
196
|
const draftSchema = z.object({
|
|
195
197
|
draftType: z.enum(["prose", "setting"]),
|
|
@@ -200,6 +202,7 @@ const draftSchema = z.object({
|
|
|
200
202
|
}).strict();
|
|
201
203
|
const characterSchema = z.object({
|
|
202
204
|
name: nonEmpty.max(200),
|
|
205
|
+
gender: z.enum(CHARACTER_GENDERS).optional(),
|
|
203
206
|
isDead: z.boolean().optional(),
|
|
204
207
|
code: z.string().trim().max(200).optional(),
|
|
205
208
|
aliases: z.array(z.string().trim().min(1).max(200)).max(100).optional(),
|
|
@@ -344,6 +347,7 @@ const providerBaseSchema = z.object({
|
|
|
344
347
|
baseUrl: z.string().url().refine((value) => value.startsWith("http://") || value.startsWith("https://"), "接口地址必须使用 HTTP 或 HTTPS"),
|
|
345
348
|
apiKey: z.string().trim().min(1).max(50_000),
|
|
346
349
|
protocol: z.enum(AI_PROVIDER_PROTOCOLS).optional(),
|
|
350
|
+
maxTokensParameter: z.enum(MAX_TOKENS_PARAMETERS).optional(),
|
|
347
351
|
status: z.enum(["enabled", "disabled"]).optional(),
|
|
348
352
|
note: z.string().max(10_000).optional(),
|
|
349
353
|
concurrencyLimit: z.number().int().min(1).max(100).optional(),
|
|
@@ -396,6 +400,7 @@ const modelSchema = z.object({
|
|
|
396
400
|
outputNote: z.string().max(10_000).optional(),
|
|
397
401
|
preset: jsonObject.optional(),
|
|
398
402
|
thinkingEnabled: z.boolean().optional(),
|
|
403
|
+
thinkingEffort: z.enum(["default", "low", "medium", "high", "xhigh", "max"]).optional(),
|
|
399
404
|
multimodalEnabled: z.boolean().optional(),
|
|
400
405
|
imageToolDefault: z.boolean().optional(),
|
|
401
406
|
enabled: z.boolean().optional(),
|
|
@@ -536,11 +541,12 @@ const workAiSettingsSchema = z.object({
|
|
|
536
541
|
autoRunBatchLimit: z.number().int().min(1).max(200).optional(),
|
|
537
542
|
autoRunDailyTaskLimit: z.number().int().min(0).max(10_000).optional(),
|
|
538
543
|
autoRunFailureThreshold: z.number().int().min(1).max(10).optional(),
|
|
544
|
+
autoRunStabilityDelayMinutes: z.number().int().min(1).max(120).optional(),
|
|
539
545
|
bookSummaryContextPercent: z.number().int().min(1).max(90).optional(),
|
|
540
546
|
contextCompactThreshold: z.number().int().min(50).max(90).optional(),
|
|
541
547
|
agentToolCallLimit: z.number().int().min(5).optional(),
|
|
542
548
|
agentToolCallGlobalMultiplier: z.number().int().min(1).max(6).optional(),
|
|
543
|
-
agentTools: z.array(z.enum(
|
|
549
|
+
agentTools: z.array(z.enum(WORK_AGENT_TOOL_IDS)).max(WORK_AGENT_TOOL_IDS.length).optional(),
|
|
544
550
|
alwaysIncludeSettingInfo: z.boolean().optional(),
|
|
545
551
|
titleGenerationModelId: z.string().trim().max(200).optional(),
|
|
546
552
|
imageToolModelId: identifier.nullable().optional()
|
|
@@ -605,8 +611,8 @@ const relationshipAnalysisScopeSchema = z.object({
|
|
|
605
611
|
if (scope.volumeIds && new Set(scope.volumeIds).size !== scope.volumeIds.length) {
|
|
606
612
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["volumeIds"], message: "分卷不能重复选择" });
|
|
607
613
|
}
|
|
608
|
-
if (scope.includeAllSettings && scope.type !== "book") {
|
|
609
|
-
context.addIssue({ code: z.ZodIssueCode.custom, path: ["includeAllSettings"], message: "
|
|
614
|
+
if (scope.includeAllSettings && scope.type !== "book" && scope.type !== "chapter") {
|
|
615
|
+
context.addIssue({ code: z.ZodIssueCode.custom, path: ["includeAllSettings"], message: "包含所有设定仅支持全书或指定章节人物关系分析" });
|
|
610
616
|
}
|
|
611
617
|
if (scope.characterIds && new Set(scope.characterIds).size !== scope.characterIds.length) {
|
|
612
618
|
context.addIssue({ code: z.ZodIssueCode.custom, path: ["characterIds"], message: "被分析角色不能重复" });
|
|
@@ -949,6 +955,13 @@ function redactAiConversation(record, permissions) {
|
|
|
949
955
|
const result = {
|
|
950
956
|
...scopedRecord
|
|
951
957
|
};
|
|
958
|
+
if (result.roleplayCharacter) {
|
|
959
|
+
result.agentTools = [
|
|
960
|
+
...(permissions.characters !== "none" ? ["recall_self"] : []),
|
|
961
|
+
...(permissions.characters !== "none" && permissions.relationships !== "none" ? ["recall_relationship"] : []),
|
|
962
|
+
"calculate_time"
|
|
963
|
+
];
|
|
964
|
+
}
|
|
952
965
|
if ((permissions.prose === "none" || permissions.characters === "none") && Array.isArray(result.messages)) {
|
|
953
966
|
result.messages = result.messages.map((item) => redactAiConversationMessage(item, permissions));
|
|
954
967
|
}
|
|
@@ -1007,6 +1020,7 @@ function redactVersionSnapshots(value, mapper) {
|
|
|
1007
1020
|
}
|
|
1008
1021
|
export function createRuntime(options) {
|
|
1009
1022
|
const uploadLimits = options.uploadLimits ?? DEFAULT_IMAGE_UPLOAD_LIMITS;
|
|
1023
|
+
const aiChatTabLimit = options.aiChatTabLimit ?? DEFAULT_AI_CHAT_TAB_LIMIT;
|
|
1010
1024
|
logger.info("runtime.initializing", {
|
|
1011
1025
|
databasePath: options.databasePath,
|
|
1012
1026
|
serveUi: options.serveUi ?? true,
|
|
@@ -1124,7 +1138,11 @@ export function createRuntime(options) {
|
|
|
1124
1138
|
read: requiredModules,
|
|
1125
1139
|
write: ["ai-analysis"]
|
|
1126
1140
|
}, false, actor?.allowAdminAccess ?? false);
|
|
1127
|
-
}, attachmentStorage, {
|
|
1141
|
+
}, attachmentStorage, {
|
|
1142
|
+
interactiveStreamIdleTimeoutMs: options.aiStreamIdleTimeoutMs ?? DEFAULT_AI_STREAM_IDLE_TIMEOUT_MS,
|
|
1143
|
+
retryPolicy: options.aiRetryPolicy,
|
|
1144
|
+
retrySleep: options.aiRetrySleep
|
|
1145
|
+
});
|
|
1128
1146
|
const app = express();
|
|
1129
1147
|
enforceCaseInsensitiveRouting(app);
|
|
1130
1148
|
const upload = multer({
|
|
@@ -1160,9 +1178,11 @@ export function createRuntime(options) {
|
|
|
1160
1178
|
status: "ok",
|
|
1161
1179
|
bootId,
|
|
1162
1180
|
version: APP_VERSION,
|
|
1181
|
+
versionLabel: options.betaVersionLabel ?? null,
|
|
1163
1182
|
protocol: "openai-chat-completions",
|
|
1164
1183
|
protocols: [...AI_PROVIDER_PROTOCOLS],
|
|
1165
1184
|
development: options.developmentServer === true,
|
|
1185
|
+
aiChatTabLimit,
|
|
1166
1186
|
uploadLimits
|
|
1167
1187
|
});
|
|
1168
1188
|
});
|
|
@@ -2173,9 +2193,16 @@ export function createRuntime(options) {
|
|
|
2173
2193
|
}
|
|
2174
2194
|
data(response, await ai.previewRelationshipSources(request.params.workId, input.scope, input.modelId));
|
|
2175
2195
|
});
|
|
2176
|
-
app.post("/api/works/:workId/tasks", (request, response) => {
|
|
2196
|
+
app.post("/api/works/:workId/tasks", async (request, response) => {
|
|
2177
2197
|
const input = parse(analysisTaskSchema, request.body);
|
|
2178
|
-
|
|
2198
|
+
const permissions = requestPermissions(request, request.params.workId);
|
|
2199
|
+
const deniedModules = analysisTaskReadModules(input.taskType, input.scope).filter((module) => permissions[module] === "none");
|
|
2200
|
+
if (deniedModules.length > 0) {
|
|
2201
|
+
throw new AppError(403, "WORK_MODULE_READ_DENIED", "你没有读取创建分析任务所需资料模块的权限", {
|
|
2202
|
+
modules: deniedModules
|
|
2203
|
+
});
|
|
2204
|
+
}
|
|
2205
|
+
data(response, redactTaskCharacterNames(await ai.createTask(request.params.workId, input), permissions), 201);
|
|
2179
2206
|
});
|
|
2180
2207
|
app.post("/api/works/:workId/tasks/auto-run", (request, response) => {
|
|
2181
2208
|
const permissions = requestPermissions(request, request.params.workId);
|
|
@@ -2223,7 +2250,7 @@ export function createRuntime(options) {
|
|
|
2223
2250
|
allowAdminAccess: request.authMethod !== "api-key"
|
|
2224
2251
|
} : undefined), requestPermissions(request)));
|
|
2225
2252
|
});
|
|
2226
|
-
app.post("/api/tasks/:taskId/rerun", (request, response) => {
|
|
2253
|
+
app.post("/api/tasks/:taskId/rerun", async (request, response) => {
|
|
2227
2254
|
const input = parse(z.object({ modelId: identifier.optional() }).strict(), request.body ?? {});
|
|
2228
2255
|
const task = store.getTask(request.params.taskId);
|
|
2229
2256
|
const permissions = requestPermissions(request, String(task.workId));
|
|
@@ -2233,7 +2260,7 @@ export function createRuntime(options) {
|
|
|
2233
2260
|
modules: deniedModules
|
|
2234
2261
|
});
|
|
2235
2262
|
}
|
|
2236
|
-
data(response, redactTaskCharacterNames(ai.rerunTask(request.params.taskId, input.modelId), requestPermissions(request)), 201);
|
|
2263
|
+
data(response, redactTaskCharacterNames(await ai.rerunTask(request.params.taskId, input.modelId), requestPermissions(request)), 201);
|
|
2237
2264
|
});
|
|
2238
2265
|
app.post("/api/tasks/:taskId/cancel", (request, response) => data(response, redactTaskCharacterNames(ai.cancelTask(request.params.taskId), requestPermissions(request))));
|
|
2239
2266
|
app.post("/api/tasks/:taskId/character-extraction/apply", (request, response) => {
|
|
@@ -2353,6 +2380,8 @@ export function createRuntime(options) {
|
|
|
2353
2380
|
else
|
|
2354
2381
|
ai.scheduleAutoRun(workId);
|
|
2355
2382
|
}
|
|
2383
|
+
if (input.autoRunStabilityDelayMinutes !== undefined)
|
|
2384
|
+
ai.rescheduleChapterAnalysisTasks(workId);
|
|
2356
2385
|
data(response, updated);
|
|
2357
2386
|
});
|
|
2358
2387
|
app.get("/api/works/:workId/ai-conversations", (request, response) => {
|