@musnows/scriverse 0.5.12 → 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/ai-protocol.js +6 -1
- package/dist/ai-protocol.js.map +1 -1
- package/dist/ai-tool-results.js +177 -0
- package/dist/ai-tool-results.js.map +1 -0
- package/dist/ai.js +743 -138
- package/dist/ai.js.map +1 -1
- package/dist/app.js +94 -33
- package/dist/app.js.map +1 -1
- package/dist/cli-contract.js +5 -5
- package/dist/cli-core.js +8 -2
- package/dist/cli-core.js.map +1 -1
- package/dist/collaboration-presence.js +1 -0
- package/dist/collaboration-presence.js.map +1 -1
- package/dist/database.js +17 -0
- package/dist/database.js.map +1 -1
- package/dist/public/ai-context-meter.js +39 -0
- package/dist/public/app.js +619 -228
- package/dist/public/entity-version.js +2 -2
- package/dist/public/index.html +22 -11
- package/dist/public/model-config.d.ts +3 -0
- package/dist/public/model-config.js +14 -0
- package/dist/public/page-route.js +1 -0
- package/dist/public/styles.css +73 -14
- package/dist/public/work-permissions.d.ts +1 -1
- package/dist/public/work-permissions.js +1 -1
- package/dist/store.js +98 -13
- package/dist/store.js.map +1 -1
- package/dist/user-auth.js +4 -5
- package/dist/user-auth.js.map +1 -1
- package/dist/utils.js +1 -1
- package/dist/version.js +1 -1
- package/dist/version.js.map +1 -1
- package/dist/work-permissions.js +1 -1
- package/package.json +1 -1
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
|
])
|
|
@@ -293,15 +293,14 @@ const providerSchema = z.object({
|
|
|
293
293
|
status: z.enum(["enabled", "disabled"]).optional(),
|
|
294
294
|
note: z.string().max(10_000).optional(),
|
|
295
295
|
concurrencyLimit: z.number().int().min(1).max(100).optional(),
|
|
296
|
-
rpmLimit: z.number().int().min(1).max(10_000).optional()
|
|
297
|
-
maxTokens: z.number().int().min(1).max(32_768).optional()
|
|
296
|
+
rpmLimit: z.number().int().min(1).max(10_000).optional()
|
|
298
297
|
});
|
|
299
298
|
const modelSchema = z.object({
|
|
300
299
|
displayName: nonEmpty.max(200),
|
|
301
300
|
modelId: nonEmpty.max(300),
|
|
302
301
|
purposes: optionalStrings,
|
|
303
302
|
contextNote: z.string().max(10_000).optional(),
|
|
304
|
-
contextWindow: z.number().int().min(
|
|
303
|
+
contextWindow: z.number().int().min(32_768, "模型上下文不能低于 32768 Token").max(2_000_000).optional(),
|
|
305
304
|
outputNote: z.string().max(10_000).optional(),
|
|
306
305
|
preset: jsonObject.optional(),
|
|
307
306
|
thinkingEnabled: z.boolean().optional(),
|
|
@@ -323,6 +322,7 @@ const platformPageSizesSchema = z.object({
|
|
|
323
322
|
timeline: z.number().int().min(10).max(100).optional(),
|
|
324
323
|
outlines: z.number().int().min(10).max(100).optional(),
|
|
325
324
|
relationships: z.number().int().min(10).max(100).optional(),
|
|
325
|
+
comments: z.number().int().min(10).max(100).optional(),
|
|
326
326
|
reviews: z.number().int().min(10).max(100).optional(),
|
|
327
327
|
analysisTasks: z.number().int().min(10).max(100).optional(),
|
|
328
328
|
fileVersions: z.number().int().min(10).max(100).optional()
|
|
@@ -362,6 +362,15 @@ const aiProcessStepSchema = z.discriminatedUnion("type", [
|
|
|
362
362
|
round: z.number().int().min(1).max(20),
|
|
363
363
|
toolCall: aiToolCallResultSchema,
|
|
364
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 })
|
|
365
374
|
}).strict()
|
|
366
375
|
]);
|
|
367
376
|
const workAiSettingsSchema = z.object({
|
|
@@ -373,7 +382,8 @@ const workAiSettingsSchema = z.object({
|
|
|
373
382
|
autoRunFailureThreshold: z.number().int().min(1).max(10).optional(),
|
|
374
383
|
bookSummaryContextPercent: z.number().int().min(1).max(90).optional(),
|
|
375
384
|
contextCompactThreshold: z.number().int().min(50).max(90).optional(),
|
|
376
|
-
agentTools: z.array(z.enum(["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections", "search_drafts"])).max(6).optional()
|
|
385
|
+
agentTools: z.array(z.enum(["story_index", "read_chapters", "grep", "search_story_entities", "read_character_sections", "search_drafts"])).max(6).optional(),
|
|
386
|
+
titleGenerationModelId: z.string().trim().max(200).optional()
|
|
377
387
|
}).strict();
|
|
378
388
|
const contextSchema = z.object({
|
|
379
389
|
type: z.enum(["none", "selection", "chapter", "volume", "book", "entities"]),
|
|
@@ -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"]),
|
|
@@ -1670,6 +1686,8 @@ export function createRuntime(options) {
|
|
|
1670
1686
|
app.patch("/api/works/:workId/ai-settings", (request, response) => {
|
|
1671
1687
|
const workId = request.params.workId;
|
|
1672
1688
|
const input = parse(workAiSettingsSchema, request.body);
|
|
1689
|
+
if (input.titleGenerationModelId)
|
|
1690
|
+
ai.assertModelAvailable(input.titleGenerationModelId);
|
|
1673
1691
|
const before = store.getWorkAiSettings(workId);
|
|
1674
1692
|
let updated = store.updateWorkAiSettings(workId, input);
|
|
1675
1693
|
if (updated.autoRunEnabled) {
|
|
@@ -1681,8 +1699,11 @@ export function createRuntime(options) {
|
|
|
1681
1699
|
data(response, updated);
|
|
1682
1700
|
});
|
|
1683
1701
|
app.get("/api/works/:workId/ai-conversations", (request, response) => {
|
|
1684
|
-
const pagination = parsePagination(
|
|
1685
|
-
|
|
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));
|
|
1686
1707
|
});
|
|
1687
1708
|
app.post("/api/works/:workId/ai-conversations", (request, response) => {
|
|
1688
1709
|
const input = parse(z.object({ title: z.string().max(200).optional() }), request.body ?? {});
|
|
@@ -1732,32 +1753,23 @@ export function createRuntime(options) {
|
|
|
1732
1753
|
app.post("/api/ai-conversations/:conversationId/compact", async (request, response) => {
|
|
1733
1754
|
const input = parse(z.object({ modelId: identifier.optional(), scope: contextSchema }), request.body);
|
|
1734
1755
|
const conversation = store.getAiConversation(request.params.conversationId);
|
|
1735
|
-
|
|
1756
|
+
const compacted = await ai.compactConversation({
|
|
1736
1757
|
conversationId: request.params.conversationId,
|
|
1737
1758
|
workId: String(conversation.workId),
|
|
1738
1759
|
modelId: input.modelId,
|
|
1739
1760
|
scope: input.scope
|
|
1740
|
-
})
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
})
|
|
1752
|
-
data(response, ai.getContextUsage({
|
|
1753
|
-
workId: request.params.workId,
|
|
1754
|
-
modelId: input.modelId,
|
|
1755
|
-
taskType: input.taskType,
|
|
1756
|
-
scope: input.scope,
|
|
1757
|
-
instruction: instructionWithCitations(input.instruction, input.citations ?? []),
|
|
1758
|
-
conversationId: input.conversationId,
|
|
1759
|
-
excludeConversationMessageId: input.currentMessageId
|
|
1760
|
-
}));
|
|
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
|
+
});
|
|
1761
1773
|
});
|
|
1762
1774
|
app.get("/api/works/:workId/providers", (request, response) => {
|
|
1763
1775
|
store.getWork(request.params.workId);
|
|
@@ -1779,6 +1791,7 @@ export function createRuntime(options) {
|
|
|
1779
1791
|
data(response, pagination ? ai.listModelsPage(request.params.providerId, pagination) : ai.listModels(request.params.providerId));
|
|
1780
1792
|
});
|
|
1781
1793
|
app.post("/api/providers/:providerId/models", (request, response) => data(response, ai.createModel(request.params.providerId, parse(modelSchema, request.body)), 201));
|
|
1794
|
+
app.post("/api/models/:modelId/test", async (request, response) => data(response, await ai.testModel(request.params.modelId)));
|
|
1782
1795
|
app.get("/api/models/:modelId", (request, response) => data(response, ai.getModel(request.params.modelId)));
|
|
1783
1796
|
app.patch("/api/models/:modelId", (request, response) => data(response, ai.updateModel(request.params.modelId, parse(modelSchema.partial(), request.body))));
|
|
1784
1797
|
app.delete("/api/models/:modelId", (request, response) => {
|
|
@@ -1858,6 +1871,40 @@ export function createRuntime(options) {
|
|
|
1858
1871
|
};
|
|
1859
1872
|
sendEvent("ready", { streaming: true });
|
|
1860
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 });
|
|
1861
1908
|
const suggestion = await ai.createStreamingChat({
|
|
1862
1909
|
workId: request.params.workId,
|
|
1863
1910
|
instruction: instructionWithCitations(input.instruction, citations),
|
|
@@ -1865,9 +1912,10 @@ export function createRuntime(options) {
|
|
|
1865
1912
|
signal: controller.signal,
|
|
1866
1913
|
onToolCall: (toolCall, round) => sendEvent("tool_call", { ...toolCall, round }),
|
|
1867
1914
|
onProcessStep: (step) => sendEvent("process_step", step),
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1915
|
+
onContextCompacted: (event) => sendEvent("context_compacted", event),
|
|
1916
|
+
conversationId,
|
|
1917
|
+
excludeConversationMessageId: currentMessageId,
|
|
1918
|
+
...(currentMessageId ? { assistantMessageRequestId: `assistant:${currentMessageId}` } : {}),
|
|
1871
1919
|
...(input.modelId ? { modelId: input.modelId } : {}),
|
|
1872
1920
|
...(input.parameters ? { parameters: input.parameters } : {})
|
|
1873
1921
|
}, (delta) => sendEvent("delta", { delta }));
|
|
@@ -1881,6 +1929,9 @@ export function createRuntime(options) {
|
|
|
1881
1929
|
chapterVersion: suggestion.chapterVersion,
|
|
1882
1930
|
toolCalls: suggestion.toolCalls,
|
|
1883
1931
|
processSteps: suggestion.processSteps,
|
|
1932
|
+
contextUsage: suggestion.contextUsage,
|
|
1933
|
+
conversationId,
|
|
1934
|
+
conversationTitle: suggestion.conversationTitle,
|
|
1884
1935
|
messageId: typeof suggestion.conversationMessage === "object" && suggestion.conversationMessage !== null
|
|
1885
1936
|
? suggestion.conversationMessage.id
|
|
1886
1937
|
: undefined,
|
|
@@ -1891,9 +1942,19 @@ export function createRuntime(options) {
|
|
|
1891
1942
|
}
|
|
1892
1943
|
catch (error) {
|
|
1893
1944
|
if (!controller.signal.aborted) {
|
|
1945
|
+
const details = error instanceof AppError && error.details && typeof error.details === "object" && !Array.isArray(error.details)
|
|
1946
|
+
? error.details
|
|
1947
|
+
: null;
|
|
1894
1948
|
sendEvent("error", {
|
|
1895
1949
|
code: error instanceof AppError ? error.code : "AI_STREAM_FAILED",
|
|
1896
|
-
message: error instanceof Error ? error.message : "AI 流式调用失败"
|
|
1950
|
+
message: error instanceof Error ? error.message : "AI 流式调用失败",
|
|
1951
|
+
...(error instanceof AppError ? { status: error.status } : {}),
|
|
1952
|
+
...(typeof details?.failure === "string" ? { failure: details.failure } : {}),
|
|
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 } : {})
|
|
1897
1958
|
});
|
|
1898
1959
|
}
|
|
1899
1960
|
}
|