@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.
Files changed (44) hide show
  1. package/README.en.md +4 -0
  2. package/README.md +5 -0
  3. package/dist/ai-chat-tab-limit.js +14 -0
  4. package/dist/ai-chat-tab-limit.js.map +1 -0
  5. package/dist/ai-protocol.js +10 -2
  6. package/dist/ai-protocol.js.map +1 -1
  7. package/dist/ai-retry.js +52 -0
  8. package/dist/ai-retry.js.map +1 -0
  9. package/dist/ai.js +525 -117
  10. package/dist/ai.js.map +1 -1
  11. package/dist/app.js +41 -12
  12. package/dist/app.js.map +1 -1
  13. package/dist/cli-contract.js +2 -1
  14. package/dist/cli-contract.js.map +1 -1
  15. package/dist/database.js +127 -2
  16. package/dist/database.js.map +1 -1
  17. package/dist/domain.js +1 -0
  18. package/dist/domain.js.map +1 -1
  19. package/dist/public/ai-chat-tabs.js +75 -0
  20. package/dist/public/ai-request-manager.js +32 -15
  21. package/dist/public/app.js +1151 -252
  22. package/dist/public/background-task-center.d.ts +9 -0
  23. package/dist/public/background-task-center.js +18 -0
  24. package/dist/public/chapter-search.d.ts +6 -0
  25. package/dist/public/chapter-search.js +23 -0
  26. package/dist/public/character-filters.d.ts +3 -1
  27. package/dist/public/character-filters.js +17 -2
  28. package/dist/public/character-version.js +1 -0
  29. package/dist/public/display-labels.d.ts +1 -0
  30. package/dist/public/display-labels.js +5 -1
  31. package/dist/public/index.html +66 -25
  32. package/dist/public/model-config.d.ts +3 -1
  33. package/dist/public/model-config.js +13 -0
  34. package/dist/public/relationship-filters.d.ts +5 -0
  35. package/dist/public/relationship-filters.js +31 -0
  36. package/dist/public/relationship-graph.js +289 -58
  37. package/dist/public/styles.css +170 -32
  38. package/dist/server-runtime.js +6 -0
  39. package/dist/server-runtime.js.map +1 -1
  40. package/dist/store.js +77 -34
  41. package/dist/store.js.map +1 -1
  42. package/dist/version.js +6 -1
  43. package/dist/version.js.map +1 -1
  44. package/package.json +1 -1
@@ -23,10 +23,13 @@ export function aiRequestTargetsState(request, current) {
23
23
 
24
24
  export function createAiRequestManager() {
25
25
  let generation = 0;
26
- let active = null;
26
+ const activeRequests = new Map();
27
+
28
+ const requestKey = (input) => normalizedId(input?.tabId) ?? "default";
27
29
 
28
30
  const snapshot = (input, controller, requestGeneration) => Object.freeze({
29
31
  generation: requestGeneration,
32
+ tabId: requestKey(input),
30
33
  workId: normalizedId(input.workId),
31
34
  conversationId: normalizedId(input.conversationId),
32
35
  userMessageId: normalizedId(input.userMessageId),
@@ -35,27 +38,36 @@ export function createAiRequestManager() {
35
38
 
36
39
  const isCurrent = (request) => Boolean(
37
40
  request
38
- && active
39
- && !active.controller.signal.aborted
40
- && active.snapshot.generation === request.generation
41
- && active.controller.signal === request.signal
41
+ && activeRequests.has(request.tabId)
42
+ && !activeRequests.get(request.tabId).controller.signal.aborted
43
+ && activeRequests.get(request.tabId).snapshot.generation === request.generation
44
+ && activeRequests.get(request.tabId).controller.signal === request.signal
42
45
  );
43
46
 
44
- const cancel = (reason = "AI 请求已取消") => {
45
- if (!active) return false;
46
- const current = active;
47
- active = null;
47
+ const cancel = (reason = "AI 请求已取消", tabId = "default") => {
48
+ const key = requestKey({ tabId });
49
+ const current = activeRequests.get(key);
50
+ if (!current) return false;
51
+ activeRequests.delete(key);
48
52
  current.controller.abort(createAiRequestAbortError(reason));
49
53
  return true;
50
54
  };
51
55
 
56
+ const cancelAll = (reason = "AI 请求已取消") => {
57
+ const requests = [...activeRequests.values()];
58
+ activeRequests.clear();
59
+ for (const current of requests) current.controller.abort(createAiRequestAbortError(reason));
60
+ return requests.length;
61
+ };
62
+
52
63
  const begin = (input) => {
53
- cancel("新的 AI 请求已开始");
64
+ const key = requestKey(input);
65
+ cancel("新的 AI 请求已开始", key);
54
66
  const controller = new AbortController();
55
67
  generation += 1;
56
68
  const request = snapshot(input, controller, generation);
57
69
  if (!request.workId) throw new Error("AI 请求必须绑定作品");
58
- active = { controller, snapshot: request };
70
+ activeRequests.set(key, { controller, snapshot: request });
59
71
  return request;
60
72
  };
61
73
 
@@ -73,18 +85,20 @@ export function createAiRequestManager() {
73
85
  if (request.userMessageId && userMessageId !== request.userMessageId) {
74
86
  throw new Error("AI 请求不能改绑到其他用户消息");
75
87
  }
88
+ const current = activeRequests.get(request.tabId);
76
89
  const next = snapshot({
90
+ tabId: request.tabId,
77
91
  workId: request.workId,
78
92
  conversationId,
79
93
  userMessageId
80
- }, active.controller, request.generation);
81
- active.snapshot = next;
94
+ }, current.controller, request.generation);
95
+ current.snapshot = next;
82
96
  return next;
83
97
  };
84
98
 
85
99
  const finish = (request) => {
86
100
  if (!isCurrent(request)) return false;
87
- active = null;
101
+ activeRequests.delete(request.tabId);
88
102
  return true;
89
103
  };
90
104
 
@@ -92,8 +106,11 @@ export function createAiRequestManager() {
92
106
  begin,
93
107
  bind,
94
108
  cancel,
109
+ cancelAll,
95
110
  finish,
96
- hasActive: () => active !== null,
111
+ hasActive: (tabId = null) => tabId === null
112
+ ? activeRequests.size > 0
113
+ : activeRequests.has(requestKey({ tabId })),
97
114
  isCurrent
98
115
  };
99
116
  }