@musnows/scriverse 0.6.0 → 0.6.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/dist/app.js CHANGED
@@ -103,7 +103,7 @@ const presenceHeartbeatSchema = z.object({
103
103
  page: z.discriminatedUnion("kind", [
104
104
  z.object({ kind: z.literal(presencePageKinds[0]) }).strict(),
105
105
  z.object({ kind: z.literal(presencePageKinds[1]), resourceId: identifier }).strict(),
106
- z.object({ kind: z.literal(presencePageKinds[2]), module: z.enum(["drafts", "settings", "characters", "races", "organizations", "timeline", "relationships", "outlines", "reviews", "tasks", "ai-settings"]) }).strict(),
106
+ z.object({ kind: z.literal(presencePageKinds[2]), module: z.enum(["drafts", "settings", "characters", "races", "organizations", "timeline", "comments", "relationships", "outlines", "reviews", "tasks", "ai-settings"]) }).strict(),
107
107
  z.object({ kind: z.literal(presencePageKinds[3]), module: z.enum(["setting", "character", "race", "organization", "relationship"]), resourceId: identifier.optional() }).strict(),
108
108
  z.object({ kind: z.literal(presencePageKinds[4]) }).strict()
109
109
  ])
@@ -300,7 +300,7 @@ const modelSchema = z.object({
300
300
  modelId: nonEmpty.max(300),
301
301
  purposes: optionalStrings,
302
302
  contextNote: z.string().max(10_000).optional(),
303
- contextWindow: z.number().int().min(1_024).max(2_000_000).optional(),
303
+ contextWindow: z.number().int().min(32_768, "模型上下文不能低于 32768 Token").max(2_000_000).optional(),
304
304
  outputNote: z.string().max(10_000).optional(),
305
305
  preset: jsonObject.optional(),
306
306
  thinkingEnabled: z.boolean().optional(),
@@ -322,6 +322,7 @@ const platformPageSizesSchema = z.object({
322
322
  timeline: z.number().int().min(10).max(100).optional(),
323
323
  outlines: z.number().int().min(10).max(100).optional(),
324
324
  relationships: z.number().int().min(10).max(100).optional(),
325
+ comments: z.number().int().min(10).max(100).optional(),
325
326
  reviews: z.number().int().min(10).max(100).optional(),
326
327
  analysisTasks: z.number().int().min(10).max(100).optional(),
327
328
  fileVersions: z.number().int().min(10).max(100).optional()
@@ -361,6 +362,15 @@ const aiProcessStepSchema = z.discriminatedUnion("type", [
361
362
  round: z.number().int().min(1).max(20),
362
363
  toolCall: aiToolCallResultSchema,
363
364
  createdAt: z.string().datetime({ offset: true })
365
+ }).strict(),
366
+ z.object({
367
+ id: z.string().min(1).max(300),
368
+ type: z.literal("context_compaction"),
369
+ round: z.number().int().min(1).max(20),
370
+ sourceMessageCount: z.number().int().min(1).max(100),
371
+ sourceChars: z.number().int().min(1).max(10_000_000),
372
+ summaryChars: z.number().int().min(1).max(1_000_000),
373
+ createdAt: z.string().datetime({ offset: true })
364
374
  }).strict()
365
375
  ]);
366
376
  const workAiSettingsSchema = z.object({
@@ -1049,6 +1059,12 @@ export function createRuntime(options) {
1049
1059
  data(response, pagination ? store.listChapterInsightsPage(request.params.chapterId, pagination) : store.listChapterInsights(request.params.chapterId));
1050
1060
  });
1051
1061
  app.get("/api/chapters/:chapterId/annotations", (request, response) => data(response, store.listChapterAnnotations(request.params.chapterId)));
1062
+ app.get("/api/works/:workId/chapter-annotations", (request, response) => {
1063
+ const pagination = parsePagination(request.query);
1064
+ data(response, pagination
1065
+ ? store.listWorkChapterAnnotationsPage(request.params.workId, pagination)
1066
+ : store.listWorkChapterAnnotations(request.params.workId));
1067
+ });
1052
1068
  app.post("/api/chapters/:chapterId/annotations", (request, response) => {
1053
1069
  const input = parse(z.object({
1054
1070
  kind: z.enum(["note", "todo"]),
@@ -1683,8 +1699,11 @@ export function createRuntime(options) {
1683
1699
  data(response, updated);
1684
1700
  });
1685
1701
  app.get("/api/works/:workId/ai-conversations", (request, response) => {
1686
- const pagination = parsePagination(request.query);
1687
- data(response, pagination ? store.listAiConversationsPage(request.params.workId, pagination) : store.listAiConversations(request.params.workId));
1702
+ const pagination = parsePagination({
1703
+ page: request.query.page ?? "1",
1704
+ limit: request.query.limit ?? "20"
1705
+ }) ?? { page: 1, limit: 20, offset: 0 };
1706
+ data(response, store.listAiConversationsPage(request.params.workId, pagination));
1688
1707
  });
1689
1708
  app.post("/api/works/:workId/ai-conversations", (request, response) => {
1690
1709
  const input = parse(z.object({ title: z.string().max(200).optional() }), request.body ?? {});
@@ -1734,32 +1753,23 @@ export function createRuntime(options) {
1734
1753
  app.post("/api/ai-conversations/:conversationId/compact", async (request, response) => {
1735
1754
  const input = parse(z.object({ modelId: identifier.optional(), scope: contextSchema }), request.body);
1736
1755
  const conversation = store.getAiConversation(request.params.conversationId);
1737
- data(response, await ai.compactConversation({
1756
+ const compacted = await ai.compactConversation({
1738
1757
  conversationId: request.params.conversationId,
1739
1758
  workId: String(conversation.workId),
1740
1759
  modelId: input.modelId,
1741
1760
  scope: input.scope
1742
- }));
1743
- });
1744
- app.post("/api/works/:workId/ai-context-usage", (request, response) => {
1745
- const input = parse(z.object({
1746
- modelId: identifier.optional(),
1747
- taskType: z.enum(TASK_TYPES).default("chat"),
1748
- scope: contextSchema,
1749
- instruction: z.string().max(100_000).default(""),
1750
- citations: aiCitationsSchema.optional(),
1751
- conversationId: identifier.optional(),
1752
- currentMessageId: identifier.optional()
1753
- }), request.body ?? {});
1754
- data(response, ai.getContextUsage({
1755
- workId: request.params.workId,
1756
- modelId: input.modelId,
1757
- taskType: input.taskType,
1758
- scope: input.scope,
1759
- instruction: instructionWithCitations(input.instruction, input.citations ?? []),
1760
- conversationId: input.conversationId,
1761
- excludeConversationMessageId: input.currentMessageId
1762
- }));
1761
+ });
1762
+ data(response, {
1763
+ ...compacted,
1764
+ usage: ai.getContextUsage({
1765
+ workId: String(conversation.workId),
1766
+ taskType: "chat",
1767
+ instruction: "",
1768
+ conversationId: request.params.conversationId,
1769
+ modelId: input.modelId,
1770
+ scope: input.scope
1771
+ })
1772
+ });
1763
1773
  });
1764
1774
  app.get("/api/works/:workId/providers", (request, response) => {
1765
1775
  store.getWork(request.params.workId);
@@ -1861,6 +1871,40 @@ export function createRuntime(options) {
1861
1871
  };
1862
1872
  sendEvent("ready", { streaming: true });
1863
1873
  try {
1874
+ const conversation = input.conversationId
1875
+ ? store.getAiConversationSummary(input.conversationId)
1876
+ : store.createAiConversation(request.params.workId);
1877
+ if (String(conversation.workId) !== request.params.workId) {
1878
+ throw new AppError(400, "CONVERSATION_WORK_MISMATCH", "AI 对话不属于当前作品");
1879
+ }
1880
+ const conversationId = String(conversation.id);
1881
+ const prepared = await ai.prepareConversationContext({
1882
+ conversationId,
1883
+ workId: request.params.workId,
1884
+ modelId: input.modelId,
1885
+ scope: input.scope,
1886
+ instruction: instructionWithCitations(input.instruction, citations),
1887
+ excludeConversationMessageId: input.currentMessageId
1888
+ });
1889
+ sendEvent("context", {
1890
+ ...prepared,
1891
+ conversation: {
1892
+ ...store.getAiConversationSummary(conversationId),
1893
+ contextWarningPending: prepared.action === "warn"
1894
+ }
1895
+ });
1896
+ if (prepared.action === "warn")
1897
+ return;
1898
+ const userMessage = input.currentMessageId
1899
+ ? null
1900
+ : store.addAiConversationMessage(conversationId, {
1901
+ role: "user",
1902
+ content: input.instruction,
1903
+ citations
1904
+ });
1905
+ const currentMessageId = input.currentMessageId ?? String(userMessage?.id ?? "");
1906
+ if (userMessage)
1907
+ sendEvent("user_message", { message: userMessage });
1864
1908
  const suggestion = await ai.createStreamingChat({
1865
1909
  workId: request.params.workId,
1866
1910
  instruction: instructionWithCitations(input.instruction, citations),
@@ -1868,9 +1912,10 @@ export function createRuntime(options) {
1868
1912
  signal: controller.signal,
1869
1913
  onToolCall: (toolCall, round) => sendEvent("tool_call", { ...toolCall, round }),
1870
1914
  onProcessStep: (step) => sendEvent("process_step", step),
1871
- conversationId: input.conversationId,
1872
- excludeConversationMessageId: input.currentMessageId,
1873
- ...(input.currentMessageId ? { assistantMessageRequestId: `assistant:${input.currentMessageId}` } : {}),
1915
+ onContextCompacted: (event) => sendEvent("context_compacted", event),
1916
+ conversationId,
1917
+ excludeConversationMessageId: currentMessageId,
1918
+ ...(currentMessageId ? { assistantMessageRequestId: `assistant:${currentMessageId}` } : {}),
1874
1919
  ...(input.modelId ? { modelId: input.modelId } : {}),
1875
1920
  ...(input.parameters ? { parameters: input.parameters } : {})
1876
1921
  }, (delta) => sendEvent("delta", { delta }));
@@ -1884,6 +1929,8 @@ export function createRuntime(options) {
1884
1929
  chapterVersion: suggestion.chapterVersion,
1885
1930
  toolCalls: suggestion.toolCalls,
1886
1931
  processSteps: suggestion.processSteps,
1932
+ contextUsage: suggestion.contextUsage,
1933
+ conversationId,
1887
1934
  conversationTitle: suggestion.conversationTitle,
1888
1935
  messageId: typeof suggestion.conversationMessage === "object" && suggestion.conversationMessage !== null
1889
1936
  ? suggestion.conversationMessage.id
@@ -1903,7 +1950,11 @@ export function createRuntime(options) {
1903
1950
  message: error instanceof Error ? error.message : "AI 流式调用失败",
1904
1951
  ...(error instanceof AppError ? { status: error.status } : {}),
1905
1952
  ...(typeof details?.failure === "string" ? { failure: details.failure } : {}),
1906
- ...(typeof details?.callId === "string" ? { callId: details.callId } : {})
1953
+ ...(typeof details?.callId === "string" ? { callId: details.callId } : {}),
1954
+ ...(typeof details?.providerName === "string" ? { providerName: details.providerName } : {}),
1955
+ ...(typeof details?.providerId === "string" ? { providerId: details.providerId } : {}),
1956
+ ...(typeof details?.modelId === "string" ? { modelId: details.modelId } : {}),
1957
+ ...(typeof details?.modelRecordId === "string" ? { modelRecordId: details.modelRecordId } : {})
1907
1958
  });
1908
1959
  }
1909
1960
  }