@musnows/scriverse 1.0.1 → 1.0.3
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.js +157 -21
- package/dist/ai.js.map +1 -1
- package/dist/app.js +70 -6
- package/dist/app.js.map +1 -1
- package/dist/database.js +24 -2
- package/dist/database.js.map +1 -1
- package/dist/im-orchestrator.js +73 -0
- package/dist/im-orchestrator.js.map +1 -1
- package/dist/public/ai-request-manager.js +10 -2
- package/dist/public/app.js +136 -23
- package/dist/public/index.html +2 -2
- package/dist/public/stream-typewriter.d.ts +1 -0
- package/dist/public/stream-typewriter.js +22 -3
- package/dist/public/styles.css +33 -0
- package/dist/public/text-count.d.ts +1 -0
- package/dist/public/text-count.js +7 -0
- package/dist/store.js +12 -5
- package/dist/store.js.map +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/app.js
CHANGED
|
@@ -504,6 +504,7 @@ const modelSchema = z.object({
|
|
|
504
504
|
});
|
|
505
505
|
const aiPromptSchema = z.object({
|
|
506
506
|
systemPrompt: z.string().max(100_000).optional(),
|
|
507
|
+
systemPromptOverride: z.boolean().optional(),
|
|
507
508
|
imageToolModelId: identifier.nullable().optional(),
|
|
508
509
|
streamIdleTimeoutSeconds: z.number().int().min(MIN_AI_STREAM_IDLE_TIMEOUT_SECONDS).max(MAX_AI_STREAM_IDLE_TIMEOUT_SECONDS).optional()
|
|
509
510
|
});
|
|
@@ -639,6 +640,7 @@ const aiProcessStepSchema = z.discriminatedUnion("type", [
|
|
|
639
640
|
]);
|
|
640
641
|
const workAiSettingsSchema = z.object({
|
|
641
642
|
systemPrompt: z.string().max(100_000).optional(),
|
|
643
|
+
systemPromptOverride: z.boolean().optional(),
|
|
642
644
|
dailyTokenQuota: z.number().int().min(1, "Token 额度必须设置大于 0").max(2_000_000_000).nullable().optional(),
|
|
643
645
|
monthlyTokenQuota: z.number().int().min(1, "Token 额度必须设置大于 0").max(2_000_000_000).nullable().optional(),
|
|
644
646
|
autoRunEnabled: z.boolean().optional(),
|
|
@@ -3566,7 +3568,7 @@ export function createRuntime(options) {
|
|
|
3566
3568
|
app.get("/api/works/:workId/ai/questions/:questionId", (request, response) => {
|
|
3567
3569
|
data(response, aiWritePlanManager.getQuestion(request.params.questionId, request.params.workId, planViewer()));
|
|
3568
3570
|
});
|
|
3569
|
-
const resumeQuestionWorkflow = async (questionId, workId, viewer) => {
|
|
3571
|
+
const resumeQuestionWorkflow = async (questionId, workId, viewer, stream = {}) => {
|
|
3570
3572
|
const continuation = aiWritePlanManager.claimQuestionContinuation(questionId, workId, viewer);
|
|
3571
3573
|
if (!continuation)
|
|
3572
3574
|
return;
|
|
@@ -3597,26 +3599,88 @@ export function createRuntime(options) {
|
|
|
3597
3599
|
: {}),
|
|
3598
3600
|
...(typeof continuation.round === "number" ? { round: continuation.round } : {}),
|
|
3599
3601
|
...(Array.isArray(continuation.toolMessages) ? { toolMessages: continuation.toolMessages } : {})
|
|
3600
|
-
});
|
|
3602
|
+
}, stream);
|
|
3601
3603
|
aiWritePlanManager.finishQuestionContinuation(questionId, { callId: resumed.callId ?? null, completed: true });
|
|
3604
|
+
return resumed;
|
|
3602
3605
|
}
|
|
3603
3606
|
catch (error) {
|
|
3604
3607
|
aiWritePlanManager.finishQuestionContinuation(questionId, { message: error instanceof Error ? error.message : "恢复失败" }, true);
|
|
3605
3608
|
throw error;
|
|
3606
3609
|
}
|
|
3607
3610
|
};
|
|
3611
|
+
const respondWithQuestionContinuation = async (request, response, viewer) => {
|
|
3612
|
+
const { questionId, workId } = request.params;
|
|
3613
|
+
if (!request.get("Accept")?.includes("text/event-stream")) {
|
|
3614
|
+
await resumeQuestionWorkflow(questionId, workId, viewer);
|
|
3615
|
+
data(response, aiWritePlanManager.getQuestion(questionId, workId, viewer));
|
|
3616
|
+
return;
|
|
3617
|
+
}
|
|
3618
|
+
const controller = new AbortController();
|
|
3619
|
+
response.status(200);
|
|
3620
|
+
response.setHeader("Content-Type", "text/event-stream; charset=utf-8");
|
|
3621
|
+
response.setHeader("Cache-Control", "no-cache, no-transform");
|
|
3622
|
+
response.setHeader("Connection", "keep-alive");
|
|
3623
|
+
response.setHeader("X-Accel-Buffering", "no");
|
|
3624
|
+
response.flushHeaders();
|
|
3625
|
+
const sendEvent = (event, payload) => {
|
|
3626
|
+
if (!response.writableEnded && !response.destroyed)
|
|
3627
|
+
response.write(`event: ${event}\ndata: ${JSON.stringify(payload)}\n\n`);
|
|
3628
|
+
};
|
|
3629
|
+
const heartbeat = setInterval(() => {
|
|
3630
|
+
if (!response.writableEnded && !response.destroyed)
|
|
3631
|
+
response.write(": heartbeat\n\n");
|
|
3632
|
+
}, aiStreamHeartbeatIntervalMs);
|
|
3633
|
+
heartbeat.unref();
|
|
3634
|
+
response.on("close", () => {
|
|
3635
|
+
clearInterval(heartbeat);
|
|
3636
|
+
if (!response.writableEnded)
|
|
3637
|
+
controller.abort(new Error("浏览器已中断流式请求"));
|
|
3638
|
+
});
|
|
3639
|
+
try {
|
|
3640
|
+
const resumed = await resumeQuestionWorkflow(questionId, workId, viewer, {
|
|
3641
|
+
signal: controller.signal,
|
|
3642
|
+
onStart: (message) => sendEvent("continuation", message),
|
|
3643
|
+
onDelta: (delta) => sendEvent("delta", { delta }),
|
|
3644
|
+
onToolCall: (toolCall, round) => sendEvent("tool_call", { ...toolCall, round }),
|
|
3645
|
+
onProcessStep: (step) => sendEvent("process_step", step),
|
|
3646
|
+
onContextCompacted: (event) => sendEvent("context_compacted", event)
|
|
3647
|
+
});
|
|
3648
|
+
const message = resumed?.conversationMessage;
|
|
3649
|
+
const metadata = message?.metadata;
|
|
3650
|
+
sendEvent("complete", {
|
|
3651
|
+
warningOnly: !resumed,
|
|
3652
|
+
model: resumed?.model,
|
|
3653
|
+
outputTokens: metadata?.outputTokens ?? resumed?.outputTokens,
|
|
3654
|
+
cacheHitPercent: metadata?.cacheHitPercent ?? resumed?.cacheHitPercent,
|
|
3655
|
+
processDurationMs: metadata?.processDurationMs ?? resumed?.processDurationMs,
|
|
3656
|
+
toolCalls: metadata?.toolCalls ?? resumed?.toolCalls,
|
|
3657
|
+
processSteps: metadata?.processSteps ?? resumed?.processSteps,
|
|
3658
|
+
contextUsage: resumed?.contextUsage,
|
|
3659
|
+
messageId: message?.id,
|
|
3660
|
+
messageCreatedAt: message?.createdAt,
|
|
3661
|
+
question: aiWritePlanManager.getQuestion(questionId, workId, viewer)
|
|
3662
|
+
});
|
|
3663
|
+
}
|
|
3664
|
+
catch (error) {
|
|
3665
|
+
if (!controller.signal.aborted)
|
|
3666
|
+
sendEvent("error", publicAiStreamError(error));
|
|
3667
|
+
}
|
|
3668
|
+
finally {
|
|
3669
|
+
clearInterval(heartbeat);
|
|
3670
|
+
if (!response.writableEnded && !response.destroyed)
|
|
3671
|
+
response.end();
|
|
3672
|
+
}
|
|
3673
|
+
};
|
|
3608
3674
|
app.post("/api/works/:workId/ai/questions/:questionId/answer", async (request, response) => {
|
|
3609
3675
|
const input = parse(answerAiUserQuestionSchema, request.body ?? {});
|
|
3610
3676
|
const viewer = planViewer();
|
|
3611
3677
|
aiWritePlanManager.answerQuestion(request.params.questionId, request.params.workId, viewer, input);
|
|
3612
|
-
await
|
|
3613
|
-
data(response, aiWritePlanManager.getQuestion(request.params.questionId, request.params.workId, viewer));
|
|
3678
|
+
await respondWithQuestionContinuation(request, response, viewer);
|
|
3614
3679
|
});
|
|
3615
3680
|
app.post("/api/works/:workId/ai/questions/:questionId/reject", async (request, response) => {
|
|
3616
3681
|
const viewer = planViewer();
|
|
3617
3682
|
aiWritePlanManager.rejectQuestion(request.params.questionId, request.params.workId, viewer);
|
|
3618
|
-
await
|
|
3619
|
-
data(response, aiWritePlanManager.getQuestion(request.params.questionId, request.params.workId, viewer));
|
|
3683
|
+
await respondWithQuestionContinuation(request, response, viewer);
|
|
3620
3684
|
});
|
|
3621
3685
|
app.get("/api/works/:workId/providers", (request, response) => {
|
|
3622
3686
|
store.getWork(request.params.workId);
|