@musnows/scriverse 0.6.7 → 0.6.9

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/app.js CHANGED
@@ -31,6 +31,7 @@ import { createRequestLoggingMiddleware, sanitizeRequestPath } from "./http-logg
31
31
  import { accountReference, logger, sanitizeError } from "./logger.js";
32
32
  import { currentRequestActor, runWithRequestActor } from "./request-context.js";
33
33
  import { APP_VERSION } from "./version.js";
34
+ import { ReleaseUpdateChecker } from "./release-update.js";
34
35
  import { canReadWorkModule, canWriteWorkModule, fullWorkModulePermissions, proseReplacementPermissionModules } from "./work-permissions.js";
35
36
  import { CollaborationPresence, entityEditorPageKey, presencePageKinds } from "./collaboration-presence.js";
36
37
  import { analysisTaskReadModules, clearSessionCookie, createCliApiScopeMiddleware, createUserSessionMiddleware, createWorkAuthorizationMiddleware, relationshipAnalysisReadModules, setSessionCookie, UserAuthService } from "./user-auth.js";
@@ -352,11 +353,14 @@ const modelSchema = z.object({
352
353
  outputNote: z.string().max(10_000).optional(),
353
354
  preset: jsonObject.optional(),
354
355
  thinkingEnabled: z.boolean().optional(),
356
+ multimodalEnabled: z.boolean().optional(),
357
+ imageToolDefault: z.boolean().optional(),
355
358
  enabled: z.boolean().optional(),
356
359
  note: z.string().max(10_000).optional()
357
360
  });
358
361
  const aiPromptSchema = z.object({
359
- systemPrompt: z.string().max(100_000).optional()
362
+ systemPrompt: z.string().max(100_000).optional(),
363
+ imageToolModelId: identifier.nullable().optional()
360
364
  });
361
365
  const aiUsageQuerySchema = z.object({
362
366
  timezoneOffset: z.coerce.number().int().min(-840).max(840).default(0)
@@ -433,9 +437,10 @@ const workAiSettingsSchema = z.object({
433
437
  contextCompactThreshold: z.number().int().min(50).max(90).optional(),
434
438
  agentToolCallLimit: z.number().int().min(5).max(48).optional(),
435
439
  agentToolCallGlobalMultiplier: z.number().int().min(1).max(6).optional(),
436
- agentTools: z.array(z.enum(["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections", "search_drafts"])).max(6).optional(),
440
+ agentTools: z.array(z.enum(["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections", "search_drafts", "image"])).max(7).optional(),
437
441
  alwaysIncludeSettingInfo: z.boolean().optional(),
438
- titleGenerationModelId: z.string().trim().max(200).optional()
442
+ titleGenerationModelId: z.string().trim().max(200).optional(),
443
+ imageToolModelId: identifier.nullable().optional()
439
444
  }).strict();
440
445
  const contextSchema = z.object({
441
446
  type: z.enum(["none", "selection", "chapter", "volume", "book", "settings-catalog", "entities"]),
@@ -856,6 +861,11 @@ export function createRuntime(options) {
856
861
  return auth.workModulePermissions(request.authUser, resolvedWorkId, request.authMethod !== "api-key") ?? fullWorkModulePermissions();
857
862
  };
858
863
  const captcha = new ImageCaptchaService({ revealAnswer: options.revealCaptchaAnswer === true });
864
+ const releaseUpdateChecker = new ReleaseUpdateChecker(APP_VERSION, options.releaseFetchImpl ?? fetch, {
865
+ intervalMs: options.releaseCheckIntervalMs,
866
+ timeoutMs: options.releaseCheckTimeoutMs,
867
+ retries: options.releaseCheckRetries
868
+ });
859
869
  const ai = new AiManager(store, new CredentialVault(options.masterSecret), options.fetchImpl ?? fetch, options.security ? (url) => assertSafeAiEndpoint(url, options.security?.allowPrivateAiEndpoints) : undefined, (task, actor) => {
860
870
  const requiredModules = analysisTaskReadModules(task.taskType, task.scope);
861
871
  const creator = actor ? null : database.get("SELECT created_by_user_id FROM analysis_tasks WHERE id = ?", String(task.id));
@@ -869,7 +879,7 @@ export function createRuntime(options) {
869
879
  read: requiredModules,
870
880
  write: ["ai-analysis"]
871
881
  }, false, actor?.allowAdminAccess ?? false);
872
- });
882
+ }, attachmentStorage);
873
883
  const app = express();
874
884
  enforceCaseInsensitiveRouting(app);
875
885
  const upload = multer({
@@ -910,6 +920,9 @@ export function createRuntime(options) {
910
920
  development: options.developmentServer === true
911
921
  });
912
922
  });
923
+ app.get("/api/update-check", async (_request, response) => {
924
+ data(response, await releaseUpdateChecker.check());
925
+ });
913
926
  if (options.security?.auth)
914
927
  app.use(createBasicAuthMiddleware(options.security.auth));
915
928
  app.use(createAuthenticationRateLimitMiddleware());
@@ -1885,7 +1898,12 @@ export function createRuntime(options) {
1885
1898
  data(response, pagination ? ai.listPlatformModelsPage(pagination) : ai.listPlatformModels());
1886
1899
  });
1887
1900
  app.get("/api/platform/ai/settings", (_request, response) => data(response, store.getPlatformAiSettings()));
1888
- app.patch("/api/platform/ai/settings", (request, response) => data(response, store.updatePlatformAiSettings(parse(aiPromptSchema, request.body))));
1901
+ app.patch("/api/platform/ai/settings", (request, response) => {
1902
+ const input = parse(aiPromptSchema, request.body);
1903
+ if (input.imageToolModelId)
1904
+ ai.assertImageToolModelAvailable(input.imageToolModelId);
1905
+ data(response, store.updatePlatformAiSettings(input));
1906
+ });
1889
1907
  app.get("/api/platform/ai/usage", (request, response) => {
1890
1908
  const query = parse(aiUsageQuerySchema, request.query);
1891
1909
  data(response, ai.getPlatformTokenUsage(query.timezoneOffset));
@@ -1924,6 +1942,8 @@ export function createRuntime(options) {
1924
1942
  const input = parse(workAiSettingsSchema, request.body);
1925
1943
  if (input.titleGenerationModelId)
1926
1944
  ai.assertModelAvailable(input.titleGenerationModelId);
1945
+ if (input.imageToolModelId)
1946
+ ai.assertImageToolModelAvailable(input.imageToolModelId);
1927
1947
  const before = store.getWorkAiSettings(workId);
1928
1948
  let updated = store.updateWorkAiSettings(workId, input);
1929
1949
  if (updated.autoRunEnabled) {
@@ -1951,8 +1971,11 @@ export function createRuntime(options) {
1951
1971
  });
1952
1972
  app.get("/api/ai-conversations/:conversationId", (request, response) => {
1953
1973
  const pagination = parsePagination(request.query);
1974
+ const focusMessageId = request.query.messageId === undefined
1975
+ ? undefined
1976
+ : parse(identifier, request.query.messageId);
1954
1977
  const conversation = pagination
1955
- ? store.getAiConversationPage(request.params.conversationId, pagination)
1978
+ ? store.getAiConversationPage(request.params.conversationId, pagination, focusMessageId)
1956
1979
  : store.getAiConversation(request.params.conversationId);
1957
1980
  const permissions = requestPermissions(request, String(conversation.workId));
1958
1981
  data(response, redactAiConversation(conversation, permissions));
@@ -2266,7 +2289,12 @@ export function createRuntime(options) {
2266
2289
  type: z.enum(HYBRID_SEARCH_TYPES).optional(),
2267
2290
  limit: z.coerce.number().int().min(1).max(100).optional()
2268
2291
  }).strict(), request.query);
2269
- data(response, await ai.searchWork(request.params.workId, query.q, { type: query.type, limit: query.limit }));
2292
+ const permissions = requestPermissions(request, request.params.workId);
2293
+ data(response, await ai.searchWork(request.params.workId, query.q, {
2294
+ type: query.type,
2295
+ limit: query.limit,
2296
+ includeAgentHistory: permissions["ai-chat"] !== "none"
2297
+ }));
2270
2298
  });
2271
2299
  app.get("/api/works/:workId/export", async (request, response) => {
2272
2300
  const format = parse(z.enum(["json", "txt", "markdown", "docx"]), request.query.format ?? "json");