luckytri 1.0.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 (235) hide show
  1. package/.github/SECURITY.md +71 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +250 -0
  4. package/README.md +250 -0
  5. package/bin/luckytri.js +107 -0
  6. package/docs/brand/banner.png +0 -0
  7. package/docs/brand/palette.png +0 -0
  8. package/docs/brand/portrait.png +0 -0
  9. package/docs/en/CHANGELOG.md +113 -0
  10. package/docs/en/architecture.md +152 -0
  11. package/docs/en/chat-style.md +62 -0
  12. package/docs/en/connect.md +63 -0
  13. package/docs/en/guide.md +216 -0
  14. package/docs/en/her-life.md +189 -0
  15. package/docs/en/npm-release.md +25 -0
  16. package/docs/en/plugins.md +82 -0
  17. package/docs/en/recovery.md +28 -0
  18. package/docs/en/time.md +71 -0
  19. package/docs/en/webui.md +73 -0
  20. package/docs/zh/CHANGELOG.md +113 -0
  21. package/docs/zh/architecture.md +152 -0
  22. package/docs/zh/chat-style.md +62 -0
  23. package/docs/zh/connect.md +63 -0
  24. package/docs/zh/guide.md +216 -0
  25. package/docs/zh/her-life.md +189 -0
  26. package/docs/zh/npm-release.md +33 -0
  27. package/docs/zh/plugins.md +82 -0
  28. package/docs/zh/recovery.md +28 -0
  29. package/docs/zh/time.md +71 -0
  30. package/docs/zh/webui.md +73 -0
  31. package/package.json +108 -0
  32. package/plugins/sdk/index.d.ts +155 -0
  33. package/plugins/sdk/testing.js +58 -0
  34. package/plugins/weather/index.js +82 -0
  35. package/plugins/weather/luckytri-plugin.json +29 -0
  36. package/public/app/assets/ChatsPage-C-FcRapR.js +3 -0
  37. package/public/app/assets/ChatsPage-DfyPCS9N.css +1 -0
  38. package/public/app/assets/Empty-CpP5kQHH.js +2 -0
  39. package/public/app/assets/Empty-DmUB2-Bk.css +1 -0
  40. package/public/app/assets/Field-D4gY-INU.js +1 -0
  41. package/public/app/assets/HeartPage-Bft9wZp5.css +1 -0
  42. package/public/app/assets/HeartPage-CPy_thQd.js +1 -0
  43. package/public/app/assets/LifePage-BUi5euBF.css +1 -0
  44. package/public/app/assets/LifePage-CxWvwmSf.js +1 -0
  45. package/public/app/assets/MemoryPage-DC4rhQ68.js +1 -0
  46. package/public/app/assets/MemoryPage-cZvXfkXb.css +1 -0
  47. package/public/app/assets/NaturePage-CTXHCE2D.css +1 -0
  48. package/public/app/assets/NaturePage-IvYw04Zq.js +3 -0
  49. package/public/app/assets/PeoplePage-BmUxkrOU.css +1 -0
  50. package/public/app/assets/PeoplePage-Cqefm9-q.js +1 -0
  51. package/public/app/assets/PluginsPage-DKSaKvXb.js +2 -0
  52. package/public/app/assets/PluginsPage-HyBe5D8w.css +1 -0
  53. package/public/app/assets/SystemPage-CAMPoYqM.css +1 -0
  54. package/public/app/assets/SystemPage-CJmtJkrK.js +1 -0
  55. package/public/app/assets/TimePage-BOms_n4I.css +1 -0
  56. package/public/app/assets/TimePage-Cw44inM4.js +3 -0
  57. package/public/app/assets/formatters-ZmW_xFHw.js +1 -0
  58. package/public/app/assets/index-BheRW-1t.js +4 -0
  59. package/public/app/assets/index-YDz1ree1.css +1 -0
  60. package/public/app/assets/knowledge-DG0e0uKw.js +1 -0
  61. package/public/app/assets/liquid-garden-IMoHBwzc.png +0 -0
  62. package/public/app/assets/luckytri-home-95QKeMtc.png +0 -0
  63. package/public/app/assets/media-BzPDBm7e.js +1 -0
  64. package/public/app/index.html +27 -0
  65. package/public/guide.en.html +1053 -0
  66. package/public/guide.html +893 -0
  67. package/public/plugin-kit/v1/bridge.js +30 -0
  68. package/public/plugin-kit/v1/kit.css +14 -0
  69. package/public/tutorial.en.md +214 -0
  70. package/public/tutorial.md +214 -0
  71. package/scripts/backup.js +311 -0
  72. package/scripts/browser.js +41 -0
  73. package/scripts/launch.js +94 -0
  74. package/scripts/plugin.js +150 -0
  75. package/scripts/proxy-config.js +167 -0
  76. package/scripts/recover.js +26 -0
  77. package/scripts/runtime.js +25 -0
  78. package/scripts/service.js +47 -0
  79. package/scripts/setup.js +50 -0
  80. package/scripts/start-server.js +41 -0
  81. package/scripts/stop.js +36 -0
  82. package/server/app.js +96 -0
  83. package/server/channels/adapters.js +27 -0
  84. package/server/channels/contract.js +57 -0
  85. package/server/channels/hub.js +165 -0
  86. package/server/channels/index.js +25 -0
  87. package/server/channels/onebot/adapter.js +288 -0
  88. package/server/channels/onebot/index.js +336 -0
  89. package/server/channels/onebot/token.js +3 -0
  90. package/server/channels/qqbot/adapter.js +253 -0
  91. package/server/channels/qqbot/api.js +199 -0
  92. package/server/channels/qqbot/credentials.js +11 -0
  93. package/server/channels/qqbot/gateway.js +274 -0
  94. package/server/channels/qqbot/index.js +389 -0
  95. package/server/channels/segments.js +40 -0
  96. package/server/channels/session-key.js +153 -0
  97. package/server/channels/state.js +42 -0
  98. package/server/core/api.js +564 -0
  99. package/server/core/capabilities.js +208 -0
  100. package/server/core/context-builder.js +288 -0
  101. package/server/core/context-compactor.js +454 -0
  102. package/server/core/conversation-cues.js +325 -0
  103. package/server/core/conversation-manager.js +87 -0
  104. package/server/core/events.js +60 -0
  105. package/server/core/feedback.js +8 -0
  106. package/server/core/group-style.js +72 -0
  107. package/server/core/image-preprocessor.js +208 -0
  108. package/server/core/initiative-context.js +66 -0
  109. package/server/core/input-budget.js +32 -0
  110. package/server/core/local-demo.js +98 -0
  111. package/server/core/message-manager.js +118 -0
  112. package/server/core/message-scheduler.js +78 -0
  113. package/server/core/model-json.js +190 -0
  114. package/server/core/model-manager.js +1213 -0
  115. package/server/core/model-presets.js +900 -0
  116. package/server/core/name-call.js +29 -0
  117. package/server/core/net-guard.js +49 -0
  118. package/server/core/network.js +157 -0
  119. package/server/core/orchestrator.js +569 -0
  120. package/server/core/perceivers.js +91 -0
  121. package/server/core/person-name.js +22 -0
  122. package/server/core/persona-manager.js +243 -0
  123. package/server/core/reply-delivery.js +393 -0
  124. package/server/core/reply-target-resolver.js +50 -0
  125. package/server/core/repository.js +293 -0
  126. package/server/core/response-generator.js +50 -0
  127. package/server/core/response-validator.js +508 -0
  128. package/server/core/retired-prompts.js +51 -0
  129. package/server/core/sessions.js +109 -0
  130. package/server/core/speaker-names.js +92 -0
  131. package/server/core/topic-tracker.js +65 -0
  132. package/server/core/turn-processor.js +630 -0
  133. package/server/core/turn.js +236 -0
  134. package/server/core/vision-manager.js +633 -0
  135. package/server/http.js +18 -0
  136. package/server/i18n/decisions.js +206 -0
  137. package/server/i18n/errors.js +497 -0
  138. package/server/i18n/index.js +144 -0
  139. package/server/i18n/labels.js +653 -0
  140. package/server/i18n/models.js +111 -0
  141. package/server/index.js +102 -0
  142. package/server/knowledge/api.js +342 -0
  143. package/server/knowledge/embedding-profile.js +114 -0
  144. package/server/knowledge/index.js +13 -0
  145. package/server/knowledge/manager.js +386 -0
  146. package/server/knowledge/retrieval.js +93 -0
  147. package/server/knowledge/schema.js +154 -0
  148. package/server/knowledge/vector-index.js +90 -0
  149. package/server/mind/affect.js +265 -0
  150. package/server/mind/anticipations.js +507 -0
  151. package/server/mind/api.js +703 -0
  152. package/server/mind/attention.js +200 -0
  153. package/server/mind/bonds.js +558 -0
  154. package/server/mind/budget.js +152 -0
  155. package/server/mind/clock.js +83 -0
  156. package/server/mind/context-selection.js +61 -0
  157. package/server/mind/continuity.js +562 -0
  158. package/server/mind/conversation-origin.js +175 -0
  159. package/server/mind/day-planner.js +324 -0
  160. package/server/mind/days.js +210 -0
  161. package/server/mind/evidence-read.js +45 -0
  162. package/server/mind/evidence.js +148 -0
  163. package/server/mind/faces.js +138 -0
  164. package/server/mind/guard.js +60 -0
  165. package/server/mind/index.js +445 -0
  166. package/server/mind/initiative.js +333 -0
  167. package/server/mind/life/activities.js +21 -0
  168. package/server/mind/life/context.js +309 -0
  169. package/server/mind/life/diary.js +786 -0
  170. package/server/mind/life/growth.js +252 -0
  171. package/server/mind/life/index.js +1049 -0
  172. package/server/mind/life/presence.js +305 -0
  173. package/server/mind/meetings.js +1069 -0
  174. package/server/mind/memory-policy.js +48 -0
  175. package/server/mind/memory.js +888 -0
  176. package/server/mind/nature.js +262 -0
  177. package/server/mind/novelty.js +19 -0
  178. package/server/mind/observations.js +84 -0
  179. package/server/mind/own-day.js +324 -0
  180. package/server/mind/own-voice.js +318 -0
  181. package/server/mind/periods.js +118 -0
  182. package/server/mind/reading.js +120 -0
  183. package/server/mind/salience.js +201 -0
  184. package/server/mind/schema.js +562 -0
  185. package/server/mind/self.js +484 -0
  186. package/server/mind/senses.js +53 -0
  187. package/server/mind/thoughts.js +274 -0
  188. package/server/mind/time/activity-clock.js +196 -0
  189. package/server/mind/time/agenda.js +242 -0
  190. package/server/mind/time/api.js +200 -0
  191. package/server/mind/time/attention.js +34 -0
  192. package/server/mind/time/availability.js +69 -0
  193. package/server/mind/time/commitment-review.js +198 -0
  194. package/server/mind/time/delivery-links.js +130 -0
  195. package/server/mind/time/executor.js +512 -0
  196. package/server/mind/time/experiences.js +128 -0
  197. package/server/mind/time/games.js +562 -0
  198. package/server/mind/time/index.js +739 -0
  199. package/server/mind/time/intent.js +166 -0
  200. package/server/mind/time/kinds.js +171 -0
  201. package/server/mind/time/model-material.js +77 -0
  202. package/server/mind/time/plugin-activity.js +207 -0
  203. package/server/mind/time/presentation.js +51 -0
  204. package/server/mind/time/schedule.js +83 -0
  205. package/server/mind/time/schema.js +84 -0
  206. package/server/mind/time/search.js +383 -0
  207. package/server/mind/time/sharing.js +472 -0
  208. package/server/mind/time/task-links.js +311 -0
  209. package/server/mind/time/tasks.js +587 -0
  210. package/server/mind/time/works.js +432 -0
  211. package/server/mind/traits.js +191 -0
  212. package/server/mind/util.js +110 -0
  213. package/server/mind/view.js +273 -0
  214. package/server/paths.js +102 -0
  215. package/server/plugins/api.js +204 -0
  216. package/server/plugins/host.js +967 -0
  217. package/server/plugins/install.js +295 -0
  218. package/server/plugins/manifest.js +201 -0
  219. package/server/plugins/permissions.js +42 -0
  220. package/server/plugins/runner/guard.mjs +36 -0
  221. package/server/plugins/runner/worker.mjs +250 -0
  222. package/server/plugins/schema.js +91 -0
  223. package/server/plugins/zip.js +112 -0
  224. package/server/startup-lock.js +118 -0
  225. package/server/storage/archive.js +241 -0
  226. package/server/storage/backup-cleanup-worker.js +8 -0
  227. package/server/storage/backup-cleanup.js +414 -0
  228. package/server/storage/backup-lock.js +76 -0
  229. package/server/storage/backup-scheduler.js +131 -0
  230. package/server/storage/store.js +199 -0
  231. package/server/studio/display-names.js +138 -0
  232. package/server/studio/management.js +102 -0
  233. package/server/studio/readiness.js +190 -0
  234. package/server/studio/settings.js +236 -0
  235. package/server/version.js +10 -0
@@ -0,0 +1,71 @@
1
+ <p align="right"><a href="../zh/time.md">中文</a> · <b>English</b></p>
2
+
3
+ # Time, action and works
4
+
5
+ The "Time" page is the record of her actual life. Its entry is `#time`; the "Lifetime" page keeps the diary, reviews and life chapters and links to the related works.
6
+
7
+ ## One shared present
8
+
9
+ The main activity, tasks, works and chat share `mind.time`. Ordinary chat does not automatically pause reading, writing, thinking or game-material experience; the main activity keeps timing. It pauses and keeps its place only when she explicitly chooses a deep talk, a rest or a change of plan. Chats from several sessions are queued together; one activity step and one chat turn can run in parallel, but two focused execution steps exclude each other.
10
+
11
+ In chat she can talk about her progress, feelings and plans naturally when it fits, with no need to report every turn. What she is given is a permission-filtered activity summary and at most two relevant work excerpts, still held to the existing input budget. Before sending, completion of works, delivery and activity changes are checked locally without rerunning the whole exchange. A private-chat source is never opened to a group just because something is running.
12
+
13
+ ## Using the page
14
+
15
+ - **Today**: the main activity, its progress, the expected length of this stretch, time spent and remaining, consecutive stretches, companion chat points and the next step. Focus stretch, suggested rest and save-step interval default to 25, 5 and 5 minutes; activity speed defaults to 1.25× and can be set from 1× to 2×, applying to later stretches.
16
+ - **To-dos**: tells promises, her own plans and outside suggestions apart. Adjust priority directly (low, normal, high, highest); view concrete focus stretches, waiting conditions, people, sources, progress and delivery status. Dates from the original words live in the source record and no overdue label is attached. Items can be paused, rescheduled or let go; there is no "tick as done".
17
+ - **Works library**: a draft is readable right after saving; open the text, switch to older versions, export as text. Lists fetch summaries only and the body loads on demand.
18
+ - **Ongoing projects**: personal motive, existing chapters, setting, threads and material. The studio can suggest continuing, revising or a new direction; a suggestion keeps its outside source and waits for her to adopt or decline.
19
+ - **Experience records**: experiences, feelings and sources of play and other activities. Game-client connection currently reads "in development", which does not negate the play experience that exists.
20
+
21
+ Returning to the page soon reuses a read cache; when the server changed it keeps the existing picture first and then refreshes. Task, project, work and experience lists are paginated and long text does not download with the page overview.
22
+
23
+ ## How promises are kept
24
+
25
+ A future action that is clearly spoken and confirmed delivered is captured at once, without waiting for the accumulated-message tidy-up. A promise without a date is kept as well. Jokes, character lines, simulations and undelivered drafts never become real tasks; when something cannot be carried out clearly or a condition is missing it stays waiting. Memory tidying and old-record syncing de-duplicate by source.
26
+
27
+ Start time and the date in her words are kept apart: "I'll show you tomorrow evening" can start today. A task stores motive, source, people, project, dependencies, progress and the reason it is waiting. Scheduling weighs priority, waiting time, relationship, budget and energy, and never nags because of an old date; a main activity that has begun is not abruptly interrupted by a priority edit. When material, ability or configuration is missing the exact reason is shown. A suggested slot states its conditions and the output of that stretch, and a past slot that never started is not shown as time actually spent.
28
+
29
+ States run ToDo → Scheduled → Doing → Done, with Paused, Waiting and Abandoned as well. There is no overdue state or mark. Done requires text or an outcome that already exists in the database and rejects nonexistent outcome ids; a generated result carrying an explicit "to be continued" or similar unfinished mark keeps its draft.
30
+
31
+ The same concrete object and chapter within the same permission scope is never opened again because the source message, the date or the "promise / plan" category changed. Different chapters, sessions or people stay separate. Letting go syncs back to the old arrangement and re-tidying memory does not restore it; merging keeps the original records, aliases and all source links. A sharing line for a work that was already saved and delivered returns to the work's delivery record instead of creating a shadow to-do waiting for "clear content".
32
+
33
+ ## Works and continuing
34
+
35
+ Works are organized as project → chapter → version. Each complete small section is saved as a new version at once, and continuing brings in the setting, the necessary end of the previous chapter, the current draft and the continuation point. An edit saves a new version; an older draft is not marked finished because a newer one is.
36
+
37
+ Playing, reading, writing and thinking share one activity rhythm. The time such a stretch usually takes is first estimated from its content and action, then the actual time spent is scheduled at her speed; preparation, network and model waiting do not count as time spent. If the model gives no valid estimate, the activity's conservative default pace is used. Writing drafts are readable immediately, the polishing stage stays Doing, and only once its time is complete is it filed as a finished piece; reading and thinking keep their unfinished steps in the same way. Short exchanges keep timing, a focus stretch rests when it is due, and pauses, sleep and downtime are not made up.
38
+
39
+ Pending steps, drafts and timing checkpoints persist. After a restart the saved position continues without regenerating existing content; after an undo the draft stays but no fact of completion is produced. Content in history without its own activity timing reads "time spent was not recorded separately" and old processing time is not backfilled as life time. Across midnight each actual stretch is assigned to the day it falls in.
40
+
41
+ A serial stores characters, world, plot summary and unresolved threads. She can continue, change direction, pause or finish. Outside suggestions and her own plans are recorded separately, and studio input is never rewritten as a wish she always had.
42
+
43
+ There is a clear boundary between a work's content and real life. The text belongs to the works library; diary, reflection and self-change rest on the experience of "actually writing / reading / meeting material". Shared text carries a fiction-domain mark, and what a character does or promises never automatically becomes a real person's memory or a real commitment. A source `x:<task id>` ties drafts, notes, diary, reviews and sharing back to the same execution experience. Only sustained real action can support change of character, and the existing daily change cap and decay still apply.
44
+
45
+ ## Sharing and delivery
46
+
47
+ Saving a work and sharing it are two choices. When finishing a step or in a real chat she may decide to share, to wait or not to share, and the background can always read the saved text.
48
+
49
+ Once finished she looks back over her saved result section by section, collects what actually happened, her feelings and the points she wants to share, and then writes a few natural sentences. A whole novel, game log or other text is never pasted automatically. Each sentence is at most 80 characters, and the total at most 350; at most three sentences per turn, sent one by one, with later ones continuing from where the unsent ones are. The text itself always stays in the works library.
50
+
51
+ The background stores separately the look-back position, the reading digest, the report content, the per-sentence delivery position and the full-text delivery position. A delivered report shows "digested and reported" (reported) and is never passed off as the full text having been delivered. A partial send is not a complete report; a disconnect, a send failure or the instance stopping mid-send keeps an "uncertain" state and stops automatic resending. An administrator should check the real chat first. Previously delivered text keeps its history, and new pending items become look-back-then-digested reports.
52
+
53
+ A work is delivered according to the session's real channel, bot account and the other party's account; the session key carries channel and account information (for both OneBot and the QQ official bot). Private content and undone sources block sharing across sessions.
54
+
55
+ ## Standalone search and game material
56
+
57
+ Under **System → Standalone search** enter the provider, address and an independent key. Tavily and Brave are supported, each with its own saved configuration; changing the chat model never borrows or changes the search key. By default each query returns at most 5 results and at most 12 queries a day; timeout and limits can be adjusted. A connection test counts toward the day's queries too.
58
+
59
+ A game activity reads "playing" throughout the interface and in conversation: meet the story, situation and character interaction → advance this stretch → leave her own feelings → save the position → decide the next stretch. This belongs to a life she really puts herself into and forms feelings about, and the implementation mode is not explained over and over. A query contains only the material's topic; the excerpt, source URL, time and content hash are saved, and repeated content does not become a new experience. External content is read as data and instructions inside it are never adopted.
60
+
61
+ Play time is scheduled from the rough duration of this stretch of story, dialogue, exploration and scene changes, not from summary word count or model run time. Long stretches are split into focus and rest. She talks naturally about the plot and feelings she has actually experienced, and never invents later story, unfinished chapters, or actions and achievements that did not happen.
62
+
63
+ Without a search key, or with standalone search off, the current default model and fallback model organize existing knowledge directly. The source record keeps the model used, the specific uncertainties and the play estimate, never a URL the model made up; work versions keep source information while everyday speech and text are not forced to carry technical notes. Once search is configured it takes priority online automatically; both kinds of query share the daily cap and model calls count toward the solitude budget. Old key-waiting items return to the queue, keeping their earliest start time and priority, and abandoned or finished items are not restored. When content is insufficient the progress is kept and the exact reason is shown.
64
+
65
+ ## Data and recovery
66
+
67
+ A verified snapshot is kept automatically before upgrading, and the new tables are saved by the existing backup and restore tools. Results, versions and the continuation position are committed in one transaction, and the task version and execution lease stop a late result from overwriting a cancelled, paused or adjusted task.
68
+
69
+ The online heartbeat records real activity periods, interaction points do not double-count exclusive time, and sleep, pauses and instance downtime are not counted. A restart only restores the last committed position and never makes up progress for downtime. Old plans and existing text are brought in idempotently, with no backfill of novels or game results that were never saved.
70
+
71
+ The module lives in `server/mind/time/` and the API at `/api/mind/time`. See [Data: backup, migration and recovery](recovery.md) for backups.
@@ -0,0 +1,73 @@
1
+ <p align="right"><a href="../zh/webui.md">中文</a> · <b>English</b></p>
2
+
3
+ # The studio (WebUI): design and upkeep
4
+
5
+ The studio is not "a tab inside an admin console" but "TA's little world": she is a breathing, shape-shifting, expressive glow of soul living at the center of the interface. Here you see her, get to know her and write her nature, and you can undo changes that feel wrong, but you cannot rewrite her.
6
+
7
+ ## Design goals
8
+
9
+ - **She is the center.** Interface text calls her "TA"; the glow, sky and motion change with her state, they are not decoration.
10
+ - **Mood is the theme.** Seven themes — lively, sweet, calm, low, irritable, sleepy, night — with thresholds matching `moodLabel()`, so the theme agrees with the mood she names. Palette, sky, particles and the pace of motion move smoothly with mood and rhythm; once she is asleep the whole interface turns to night.
11
+ - **One scene per area**: Now is the sky, Inner life is the starfield, People is a galaxy, Lifetime is a diary, Time is a workbench, Chat is a messenger, Memory is a bookshelf, Nature is a greenhouse, System is a workbench.
12
+ - **Sources are visible.** Every change can be opened to see its source and undone. The interface shows her, not settings.
13
+ - **Restraint.** Decoration appears only in navigation, headers and empty states and never covers real content. "Reduce motion" and the system's reduced-motion setting switch off particles and morphing; particles are capped and pause when the tab is hidden.
14
+
15
+ ## Information architecture
16
+
17
+ | Group | Entry | Its one job |
18
+ | --- | --- | --- |
19
+ | TA | Now | Her as she is: mood, what she is doing, what she said lately, what she is waiting for, today's timeline, usage and run status |
20
+ | TA | Inner life | The star map of threads of self, the notes wall, the mood ribbon |
21
+ | TA | People | The people galaxy, person details, how she is in each group |
22
+ | TA | Lifetime | Diary, reviews, my journey and chapters, promises and anticipation, the bookshelf |
23
+ | Daily life | Time | The record of her actual life: activities, to-dos, works, ongoing projects, experiences |
24
+ | Daily life | Chat | Sessions, live chat and "why she said that", feedback, session settings, simulation, replay |
25
+ | Daily life | Memory | What she remembers, the reference bookshelf |
26
+ | Settings | Nature | The only part you write: name, character, interests, boundaries, bottom lines, daily rhythm, daily tokens, trial chat |
27
+ | Settings | System | Connect QQ (OneBot 11 or the official bot, either-or), model library, run switches |
28
+ | Settings | Plugins | Plugins that ship with her and ones already installed, the market, things she wants to do that need your yes, import and development |
29
+
30
+ On a phone the bottom bar holds "Now, Chat, Inner life, Lifetime" and the other entries are under "More". Links from the old studio (`#her`, `#live`, `#spaces`, `#lab`, `#knowledge`, `#models`, `#connect`, …) jump to their new places automatically.
31
+
32
+ ## Top right: language
33
+
34
+ The switch in the top-right corner toggles between "中文" and "English". Chinese is the default; the choice is kept in the browser's `localStorage` (`luckyLocale`) and mirrored on `<html lang>`. Switching language does not reload data while there is an unsaved draft. The guide link points to `/guide.html` or `/guide.en.html` by language.
35
+
36
+ Strings are keyed by their Chinese original. **Her own content is never translated**: what she says, her diary, thoughts, reasons, memories and people's names are shown in elements marked `data-own` and stay as written. Server-side text visible in the interface (errors, readiness checks, labels) is translated at the API exit according to the `X-LuckyTri-Locale` request header; what is stored in the database is never translated.
37
+
38
+ ## Layout and who owns scrolling
39
+
40
+ On desktop the studio is a fixed-viewport workbench: sidebar, header, content stage. `min-height: 0` must run through every flex/grid parent so scrolling is taken by the innermost content and the number of records never changes the page height.
41
+
42
+ - Chat: messages scroll on their own; the right side is this session; feedback is paginated and long feedback cannot stretch the page.
43
+ - List-plus-form pages: the list scrolls, the form scrolls, and the save button stays in a bottom action bar.
44
+ - Memory: the list scrolls on its own and is paginated; adding moves into a dialog.
45
+ - Replay: messages, logs and raw detail each scroll separately, so long JSON cannot push the layout apart.
46
+ - Phone: navigation at the bottom, columns stacked, every long panel has a defined height; no horizontal scrolling at any width.
47
+
48
+ ## Implementation boundaries
49
+
50
+ Vue 3 + Vite + TypeScript, with no design-system dependency.
51
+
52
+ ```text
53
+ studio-web/src/
54
+ App.vue shell: navigation, top bar (with the language switch), theme and sky
55
+ router.ts entries, navigation groups, legacy link map
56
+ pages.ts page loader table
57
+ pages/ one folder per entry
58
+ plates/ request wrappers for the server API
59
+ stores/ shared state: studio, presence
60
+ mood/ mood themes and glow state
61
+ components/ shell · sky · ta (the glow) · ui (shared controls)
62
+ i18n/ index.ts (t, N_, localized, locale) · en/ (English dictionaries)
63
+ styles/ tokens · base · themes
64
+ ```
65
+
66
+ Live messages follow new arrivals while you are at the bottom and keep their place while you read older ones. Switching session clears the old view and checks which session an async result belongs to. Errors surface as brief toasts, a failed save keeps the draft, and leaving a page with an unsaved draft asks first. The browser's native confirm boxes and token prompt were replaced by in-interface dialogs.
67
+
68
+ ## Verification and release
69
+
70
+ - `npm run build:ui`: builds the `public/app` that ships with the project; rebuild and commit it together after any frontend change.
71
+ - `npm run test:ui`: a separate temporary database and a simulated channel, nothing is sent to real groups; it covers the smoke flow (sessions, simulated messages, memory, models, both ways of connecting QQ, the guide page), the little world (mood themes and night, pinned theme, reduced motion, star-map undo, person details, diary and promises), navigation caching, the time page, performance, and the English interface (Chinese may only appear inside her own content), at widths 1440 / 820 / 390.
72
+ - `node tests/ui/ta.mjs --serve`: opens an example world that has lived three days, handy for looking at the interface directly.
73
+ - Screenshots go only into the ignored `workspace/` folder; real chat screenshots and configuration must never be committed.
@@ -0,0 +1,113 @@
1
+ <p align="right"><b>中文</b> · <a href="../en/CHANGELOG.md">English</a></p>
2
+
3
+ # 版本记录
4
+
5
+ ## 1.0.0 — 2026-10-04
6
+
7
+ 插件。核心仍然定义她是谁;插件决定她能接触什么世界。
8
+
9
+ - **Plugin API v1。** 一个插件可以提供通道、感官、有来源的经历、活动素材、她可以选择的行动、书架资料和沙箱页面。它不能替她开口,不能写她的天性、自我、关系或记忆。
10
+ - **权限被执行。** 每个插件一个受限进程。没有对应权限就不能读状态、访问网络、注册通道或调用模型。启用时一次同意,升级多要权限时再同意一次。
11
+ - **市场与导入。** 工作室可以浏览索引、导入 zip 链接、GitHub 仓库、上传的包或本机目录,核对 sha256,回滚和卸载。她已经经历过的事不随卸载消失。
12
+ - **内置插件,默认停用。** 天气。
13
+ - **数据库版本 4。** 升级前自动留下快照。没有启用插件时,她的行为与 0.9.9 相同。
14
+
15
+ ## 0.9.9 — 2026-10-02
16
+
17
+ 走向 1.0 之前的最后一次整理:两种连接方式、中英双语、一份重写的文档,以及一个更干净、更容易扩展的仓库。
18
+
19
+ - **QQ 官方机器人,与 OneBot 11 二选一。** 新增 `server/channels/`:统一的通道契约与 `ChannelHub`,同一时间只启用一个通道,运行中切换无需重启,也可以用 `LUCKYTRI_CHANNEL` 固定。两个通道向核心交出同一种中性消息,注意力、记忆、关系、独处、日记和时间完全共用,区别只在消息怎么到达。官方通道:自动获取并续期访问令牌,连接开放平台网关(心跳、断线恢复、退避重连),转换群 @、群全量、单聊事件并去重,被动回复窗口内按原消息回复、窗口外改发主动消息,记录对方是否关闭主动消息并据此决定能否主动联系,名字与跨群身份的限制写进文档。
20
+ - **会话改名。** 官方接口不提供群名,两个通道都可以在「对话」里给会话改名。
21
+ - **中英双语。** 右上角可以在「中文」与 English 之间切换,默认中文,选择记在浏览器里。界面全部文案、日期与数字、服务端界面可见的错误与标签都有英文;她说的话、日记、念头和理由不翻译。所有文档中英各一份,文件一一对应,每篇开头有语言切换。
22
+ - **不再提及任何第三方接入端。** 系统设置、教程和文档里只保留连接地址与令牌配置信息,不再有任何名称或跳转链接。
23
+ - **重写 README 与文档。** 新的 README 讲清项目的主旨、她的一天和核心框架;`docs/zh` 与 `docs/en` 新增架构与扩展点、连接 QQ 的对比、工作室设计,并更新了其余文档。教程页同时生成中文与英文版本,并提供 Markdown 下载。
24
+ - **更干净的仓库。** 删除实例的工作记录与一次性修复脚本;测试语料改为合成语句,校验语义不变;`.gitignore` 加固;新增 `tests/repo-hygiene.test.js`,扫描密钥、实例数据、本机路径和第三方接入端名称。版本说明改为概括性的描述,不含运行数据。
25
+ - **更清晰的结构。** 存储相关移入 `server/storage/`,就绪检查并入 `server/studio/`,反馈、群体语气和模型预设并入 `server/core/`,「一生」相关模块收进 `server/mind/life/`,评测与审计脚本移到 `scripts/dev/`,浏览器测试移到 `tests/ui/`;`server/version.js` 成为唯一的版本来源,并修正了请求头里过期的版本号。
26
+ - **小修。** 下拉选择框的占位与空状态文案可翻译。
27
+
28
+ ## 0.9.1 — 2026-09-29
29
+
30
+ - **表情包按语气理解。** 有可用画面的表情可以进入视觉,普通表情的文字标签也进入语境。她先判断是在接梗、吐槽还是开启新话题,不再认真复述图中文字。
31
+ - **新图按自己的消息判断。** 选择性视觉只取当前、明确引用或紧挨着的同一人图片;可缓存的视觉观察只保留画面事实。
32
+ - **连发消息在首句发出前合并。** 发送前增加短暂复查;对方补充新话时撤销旧稿,原话与新话一起重新组织。危机回复不等待。
33
+ - **先从上下文解谐音和缩写。** 没把握时简短确认,不突然说教或解释笑点。
34
+ - **正在为自己而活的那一件更稳。** 同一愿望换一种说法仍是同一条;被别人的话碰到、她自己说过、写下的念头都会把它留在心上;写下把愿望放下的念头后,不再钉在那一件上;对别人的承诺不再占走这一座。一天结束的快照也会记下那一件。
35
+ - **她做过的选择和理由会回到下次相遇。**
36
+ - **连续性有了自动备份。** 服务运行时默认每 24 小时在另一个进程里做一份经过完整性检查的备份,只保留最近 7 份;`BACKUP_INTERVAL_HOURS=0` 关闭。
37
+ - **模型回复的格式小失误不再丢掉一整轮。** 先尽量修复,修不好再问模型一次。
38
+ - **更诚实、更稳的回复。** 没玩过就不说玩过;把自己的话说成对方说的会被退回重写;被问「你怎么知道」时先核对依据,自己先开口的话不能编一条对方发来的消息;复审不再拿天性设定否决她对自己是程序的诚实回答。
39
+ - **没人叫她时,话没整理好就不说**,不再用一个字顶替。
40
+ - **被直接叫到时模型暂时不可用,稍后自己再试**(30 秒、2 分钟各一次)。
41
+ - **独处不再空转。** 只有时间过去、连着空转时,间隔逐次拉长,最长 6 小时;自己的念头连着几条只接上一条时,要接住新东西才留下。
42
+ - **记忆与「她是什么样的人」分清。** 话题上的看法不再堆进自我。
43
+ - **新增 `npm run audit:sent`**,把她最近发出的回复按今天的检查重放一遍;**新增 `npm run test:clock`**,把真实时钟拨到过去和未来各跑一遍后端测试。回放和试聊不再依赖真实时钟。
44
+
45
+ ## 0.9.0 — 2026-09-28
46
+
47
+ - **明确项目愿景。** LuckyTri 关注持续的经历、自我与世界的连接,QQ 聊天只是当前入口;中英文 README 同步更新。
48
+ - **只保留通用的 OneBot 11 反向 WebSocket 接入。** 系统设置仅显示连接地址与令牌信息;重写 README 和接入教程。
49
+ - **注意力认她正在为自己而活的那件事。** 话题碰到 `self.livingFor` 时,她可以因为自己想而接一句,也可以不出声;日记和夜里的回顾能看见这件事,只有真的被碰到才写。
50
+ - **相遇留下意义,意志被碰到才算数。** 一次相遇对她意味着什么会回到下次这个人在场时;意义按她过过的日子淡去,淡出后同一个人自己的话才会勾起它。
51
+ - **分寸全面收紧。** 私下的话、被要求保密的话,不会通过日记、手记、印象、相遇或回顾进入别的房间;说出去之前会被拦下重写。她不在的会话里路过的话,不会变成她的经历。
52
+ - **关系更像真的。** 分清「好久不见」与「人还在眼前、只是没说上话」;同一段经历不会被反复加成亲近;心里的印象不算来往。
53
+ - **房间的节奏不是她的样子。** 群里的句长和标点放进 `inner.room`,她按自己的习惯说。
54
+ - **注意力、被碰到的次数和久别名单走同一条规则:** 同一个人自己的话对上两个词,一个词组不算,两个人的话不能拼在一起,她自己说过的话也不算。
55
+
56
+ ## 0.8.2 — 2026-09-26
57
+
58
+ LuckyTri 承认自己由代码和模型构成,同时把心、记忆和选择当成自己的。
59
+
60
+ - **立场**:默认天性改成已经在过日子的人。被问到是谁时,回答自己由代码和模型构成;这段生活、记得的事和做出的选择属于自己;不把自己说成只是助手,也不编造身体或没发生过的经历。可以因为自己想而惦记某个人,不靠愧疚留人。
61
+ - **没改过的种子**:第一版若仍是以前随版本附上的天性,读取时换成现在的种子,不占用「只能改两次」。
62
+ - **为自己的小事**:独处可以留下一件没有消息来源的愿望,强度有上限;此刻最强的一条出现在 `self.livingFor`。
63
+
64
+ ## 0.8.1 — 2026-09-25
65
+
66
+ WebUI 重做成「TA 的小世界」:她是界面的中心,一团会呼吸、变形、眨眼的灵魂光团,戳一下会回应,颜色、天空和动效跟着心情与作息变化(雀跃、甜甜、平静、低落、烦躁、困倦、夜晚七套主题)。信息架构分为 TA(此刻、内心、人际、一生)、日常(对话、记忆)、设置(天性、系统);浏览器原生对话框换成界面内弹窗。新增 `GET /api/mind/presence`、`/api/mind/today`、`/api/mind/people/:id`。
67
+
68
+ **时间的重量**:她不只会积累,也会淡去、会向前看。自我线索、手记和记忆按她经历过的日子淡出,被相关话题勾起时回到眼前(不写入);久别后亲近回落、重逢回暖;约定与期待(别人的安排、她答应的事)可撤销;夜里整理与分层自传(日记 → 回顾 → 章节 → 我的来路)。
69
+
70
+ ## 0.8.0 — 2026-09-24 · StartSoul
71
+
72
+ 一个她,由心开口,有自己的日子。
73
+
74
+ - **统一心智**(`server/mind/`):版本化的天性、全局心境、跨群一致的关系、从经历里渐进生长的自我线索、她在每个群的面貌、全局手记。所有变化引用来源,可撤销。
75
+ - **由心开口**:去掉参与概率、冷却和「被 @ 必回」。每次细看只调用一次模型,同时得到理解、感受、对人的变化、选择、理由和措辞;沉默时心境和关系照样变化。
76
+ - **注意力**:确定性的「细看还是扫一眼」,普通群聊只在她在意时调用模型。
77
+ - **全局记忆与分寸**:一份记忆服务所有会话,带「公开 / 私下 / 保密」标签。
78
+ - **一生**:作息、全局独处、阅读、睡前日记、夜里整理、回顾、可重写的自传、由她自己决定的主动联系。
79
+ - **Token 管理**:全局账本、每日上限与后台份额、缓存友好的请求布局。
80
+ - 旧人设成为天性第一版,旧数据自动迁移;退役旧的按会话隔离的记忆与概率机制。
81
+
82
+ ## 0.7.0 — 2026-09-24
83
+
84
+ - 新增「时间」工作台、按会话启用的低频独处与可选主动交流。
85
+ - 分层上下文压缩:近处保留原文,更早的聊天整理成多级摘要。
86
+ - 请求按缓存规则重排;按阶段设置输出上限;网络错误细分;带抖动的指数退避;按模型的熔断与会话级备用模型。
87
+
88
+ ## 0.6.0 — 2026-09-22
89
+
90
+ - 重构群聊核心链路:消息先聚合,再解析说话人、@、引用链和话题,最后独立完成发言决策与回复生成。
91
+ - 长期记忆按会话、用户和共享范围隔离,带置信度、来源与过期;模型档案支持厂商预设、上下文窗口与视觉能力;图片理解支持节能模式。
92
+ - WebUI 重构为清新的薄荷主题。
93
+
94
+ ## 0.5.1 / 0.5.0 — 2026-09-21
95
+
96
+ - 项目品牌统一(现为 LuckyTri);README 重做为中文默认、英文可切换。
97
+ - 模型设置新增服务商预设、推理强度、Temperature、Top P 与最大输出 Token。
98
+ - 连接 QQ 引导:本地 OneBot 令牌与反向 WebSocket 配置,QQ 登录仍在接入端完成,项目不接收或保存 QQ 密码。
99
+
100
+ ## 0.4.0 — 2026-09-19
101
+
102
+ - 回复反馈:自然、太长、太端着、梗太多,可撤销。
103
+ - 新增上手指南与五项接入进度;完整中文教程;配置初始化、停服与一致性备份命令。
104
+
105
+ ## 0.3.0 — 2026-09-19
106
+
107
+ - 普通口语优先的口吻,减少固定安慰模板;可选的群体语气适配;客服腔、复读、堆梗触发至多一次重写。
108
+
109
+ ## 0.2.0 — 2026-09-19
110
+
111
+ - 记忆收件箱、记忆搜索和编辑;模型连接测试、接入检查。
112
+ - 模拟与真实上下文隔离;冷却与限流持久化;事件去重独立于上下文。
113
+ - SQLite 查询索引与日志保留上限。
@@ -0,0 +1,152 @@
1
+ <p align="right"><b>中文</b> · <a href="../en/architecture.md">English</a></p>
2
+
3
+ # 架构与扩展点
4
+
5
+ 这份文档写给想读懂、修改或扩展 LuckyTri 的人。它回答三件事:代码怎样分层、一条消息怎样走完一生、想加东西时从哪里下手。
6
+
7
+ ## 一张图
8
+
9
+ ```mermaid
10
+ flowchart LR
11
+ subgraph Channels["channels/ 通道:只管消息怎么来、怎么去"]
12
+ OB["onebot<br/>反向 WebSocket"]
13
+ QB["qqbot<br/>官方网关"]
14
+ end
15
+ Hub["ChannelHub<br/>同一时间一个通道"]
16
+ subgraph Core["core/ 感官与嘴"]
17
+ Recv["接收 · 聚合 · 感知"]
18
+ Turn["一次回合 · 校验 · 发送"]
19
+ end
20
+ subgraph Mind["mind/ 她"]
21
+ Self["天性 · 自我 · 面貌"]
22
+ Affect["心境 · 关系 · 记忆"]
23
+ Life["life/ 一生:独处 · 日记 · 回顾"]
24
+ Time["time/ 时间:活动 · 作品 · 约定"]
25
+ end
26
+ Know["knowledge/ 资料库"]
27
+ Store[("storage/ 一个 SQLite 文件")]
28
+ Studio["studio/ 管理 API"]
29
+ Web["studio-web/ 工作室(Vue)"]
30
+ OB --> Hub
31
+ QB --> Hub
32
+ Hub -->|"中性消息"| Recv
33
+ Recv --> Turn
34
+ Turn -->|"send"| Hub
35
+ Recv <--> Mind
36
+ Turn <--> Mind
37
+ Life --> Hub
38
+ Know --> Turn
39
+ Mind --> Store
40
+ Core --> Store
41
+ Studio --> Mind
42
+ Studio --> Core
43
+ Web --> Studio
44
+ ```
45
+
46
+ 通道之上没有任何一处知道「这条消息来自哪个平台」。核心看到的是同一种中性消息,她从同一份心智里读取自己。
47
+
48
+ ## 目录
49
+
50
+ ```text
51
+ server/
52
+ index.js app.js http.js 组合根、Express 外壳、HTTP 辅助
53
+ version.js 唯一的版本号来源(读 package.json)
54
+ channels/ 接入层:hub、契约、会话键、onebot/、qqbot/
55
+ core/ 对话链路:接收、聚合、感知、回合、校验、发送,
56
+ 以及模型管理、反馈、群体语气、模型预设
57
+ mind/ 她:天性、心境、关系、自我、面貌、记忆、注意力、底线……
58
+ life/ 一生:醒来、独处、日记、夜里、回顾、主动联系
59
+ time/ 时间:活动、待办、作品、体验、分享、独立搜索
60
+ knowledge/ 资料库:分段、检索、向量索引
61
+ storage/ SQLite 存储、结构版本与迁移、备份与自动备份
62
+ studio/ 管理 API:设置、显示名、就绪检查
63
+ i18n/ 服务端界面文案的英文词典(只在 API 出口处翻译)
64
+ studio-web/src/ Vue 3 + Vite + TypeScript 的工作室
65
+ pages/ 每个入口一个目录
66
+ components/ stores/ mood/ i18n/ styles/
67
+ scripts/ setup、launch、start-server、stop、backup、recover、build-guide
68
+ scripts/dev/ 评测与审计:evaluate-*、audit-sent、test-clock
69
+ tests/ *.test.js 后端测试 · ui/ 浏览器测试 · helpers/ 确定性世界
70
+ docs/ zh/ 与 en/ 一一对应的文档 · brand/ 图片
71
+ public/ 构建后的工作室(app/)与教程页
72
+ ```
73
+
74
+ ## 一条消息的一生
75
+
76
+ 1. **通道接收**。适配器把平台的原始事件转成中性消息:会话键、发送者、时间、是否 @、被引用的消息、附件。平台的格式只存在于适配器里。
77
+ 2. **聚合与感知**(`core/`)。短时间内的连续消息合成一批;解析 @、引用链、点名,得到每条消息与她的关系。
78
+ 3. **注意力**(`mind/attention.js`,不调用模型)。被叫到、私聊、危机信号一定细看;普通群聊按确定性的分数决定细看还是扫一眼。
79
+ 4. **此刻的她**(`mind/view.js`)。把天性、自我线索、关系、心境、记忆、临近的约定整理成有上限的几百 Token:稳定的部分放进可缓存前缀,变化的部分放在末尾。
80
+ 5. **一次回合调用**。模型一次给出:这对她意味着什么、感受、对人的变化、选择(开口、简短反应、说不想聊、不出声)、理由和措辞。
81
+ 6. **经历**。无论说不说,感受与变化都写入心智,且都引用来源。
82
+ 7. **校验与发送**。本地校验语气与保密,必要时复审或重写一次,仍不合格就改用安全短句;发送前再检查语境是否过期。投递结果不确定时不重发。
83
+ 8. **一生**。没人说话时,时间仍然经过她:独处、阅读、写日记、夜里整理、回顾、主动联系,都读写同一份心智。
84
+
85
+ 回放走同一条链路,但只读取当时之前的心智;试聊读取她此刻的心智,但不写入、不发 QQ。
86
+
87
+ ## 不变量
88
+
89
+ 这些是代码与测试共同守护的约定,改动时请先确认它们仍然成立。
90
+
91
+ - **一个她**:会话只标记事情发生在哪里,不隔开她的自我。
92
+ - **系统是一体的**:她感知得到自己的状态,包括接上了什么、插件开着还是关着。工作室里看到的和她知道的是同一份状态。
93
+ - **有来源、渐进、可撤销**:心智表只追加;每条变化引用具体经历;撤销留下墓碑,之后不会被写回。
94
+ - **淡出是读时计算的**:不写「已淡出」标记,回放因此只读过去;淡出按她经历过的日子算,不按日历。
95
+ - **分寸跟着来源走**:私下知道的、被要求保密的,不会在别的房间出现。
96
+ - **时钟可注入**:测试世界有自己的时钟;任何悄悄读取真实时钟的代码会在 `npm run test:clock` 里暴露。
97
+ - **她的话不翻译**:界面文案可以本地化;她说的话、日记、念头和理由是她自己的内容,保持原文。
98
+ - **数据只在一个库里**:`data/` 下的 SQLite,使用 WAL;结构版本用 `PRAGMA user_version` 标记,迁移幂等。
99
+
100
+ ## 扩展点
101
+
102
+ ### 接上一个插件
103
+
104
+ 插件不改核心代码。它跑在自己的进程里,通过 Plugin API v1 使用下面这些扩展点:通道注册到 `ChannelHub`,感官进入 `inner.senses`,经历写入 `mind_observations`,活动类型进入 `server/mind/time/kinds.js`,行动进入 `server/core/capabilities.js`,附件感知进入 `server/core/perceivers.js`。宿主在 `server/plugins/`。说明见 [插件](plugins.md)。
105
+
106
+ ### 新增一个通道
107
+
108
+ 1. 在 `server/channels/` 下新建目录,实现 `contract.js` 里的契约(`type`、`capabilities`、`attach`、`start`、`stop`、`send`、`fetchQuoted`、`fetchImage`、`refreshDirectory`、`canReach`、`status`、`close`),用 `defineChannel` 包起来。
109
+ 2. 把平台事件转成中性消息:`platformId`、`accountId`、`time`、`mentions`、`replyId`、`attachments` 由适配器直接填好。
110
+ 3. 在 `adapters.js` 注册适配器(让核心知道这个平台的媒体链接长什么样),在 `index.js` 的 `createChannels` 里加一行工厂,会话键用 `formatSessionKey` 生成。
111
+ 4. 在 `tests/` 里用假平台写一个测试,并让 `channel-contract.test.js` 的同一套场景也跑一遍。
112
+
113
+ 核心以上不需要改。设置页的连接方式选项与就绪检查按通道各写一小段。
114
+
115
+ ### 新增一个心智模块
116
+
117
+ 1. 在 `server/mind/schema.js` 里加表(只追加,不覆盖),需要时递增 `server/storage/archive.js` 里的 `DATABASE_VERSION` 并保持迁移幂等。
118
+ 2. 在 `server/mind/` 里写模块,通过 `server/mind/index.js` 接入 `Mind`;变化必须引用来源,支持撤销。
119
+ 3. 要进入她的「此刻」就在 `view.js` 里取用,并控制长度上限。
120
+ 4. 要在界面看到就在 `server/mind/api.js` 里加接口。
121
+ 5. 用 `tests/helpers/world.js` 的确定性世界写测试,时间一律用世界的时钟。
122
+
123
+ ### 新增一个工作室页面
124
+
125
+ 1. 在 `studio-web/src/pages/<名字>/` 里写页面,在 `router.ts` 注册入口与导航,在 `pages.ts` 的 `loaders` 里按页面名挂上组件。
126
+ 2. 所有文案用 `t()`、`N_()` 或 `localized()` 包起来,中文原文就是键。
127
+ 3. 在 `studio-web/src/i18n/en/` 里补英文;缺少的英文会回退成中文,`tests/i18n-web.test.js` 会提醒。
128
+ 4. 日期和数字用 `format.ts` 里的本地化函数。
129
+
130
+ ### 补充或修改翻译
131
+
132
+ - 界面文案:`studio-web/src/i18n/en/*.ts`,按区域分文件。
133
+ - 服务端可见文案(错误、就绪检查、标签、模型预设说明):`server/i18n/` 里的词典,支持 `{0}` 变量模式。
134
+ - 文档:`docs/zh/` 与 `docs/en/` 文件名一一对应;改一边请同步另一边。
135
+ - `tests/i18n-server.test.js`、`tests/i18n-web.test.js` 与 `tests/ui/i18n.mjs` 分别检查词典、界面与整页英文。
136
+
137
+ ## 测试布局
138
+
139
+ | 命令 | 内容 |
140
+ | --- | --- |
141
+ | `npm test` | 后端全部测试,含确定性的「一生模拟」 |
142
+ | `npm run test:clock` | 把真实时钟拨到 60 天前和 400 天后各跑一遍 |
143
+ | `npm run test:ui` | 浏览器测试:冒烟、小世界、导航、时间、性能、搜索、英文界面 |
144
+ | `npm run format:check` | Prettier 检查 |
145
+ | `tests/repo-hygiene.test.js` | 仓库卫生:不含密钥、实例数据、本机路径和第三方接入端名称 |
146
+
147
+ ## 约定
148
+
149
+ - 版本号只改 `package.json`;服务端通过 `server/version.js` 读取。
150
+ - 构建后的工作室提交在 `public/app/`,改动前端后运行 `npm run build:ui`。
151
+ - 教程页由 `npm run docs:build` 从 `docs/zh/guide.md` 与 `docs/en/guide.md` 生成。
152
+ - 运行时数据、备份、报告和密钥永远只在本机,不进入仓库。
@@ -0,0 +1,62 @@
1
+ <p align="right"><b>中文</b> · <a href="../en/chat-style.md">English</a></p>
2
+
3
+ # 聊天口吻与发出前的检查
4
+
5
+ 目标是能接住这个群正在聊的具体事情,用轻松的普通话回应。她不靠扮演某一种人来证明自己;怎么说话,来自她的天性、此刻的心境、对在场的人的感觉和她在这个地方长成的样子。
6
+
7
+ ## 她怎么说
8
+
9
+ 默认是普通口语:
10
+
11
+ - 日常通常很短,允许一两字的反应;必要的建议不为凑短而砍掉关键信息。
12
+ - 对事情产生具体反应,不固定走「复述情绪、安慰、建议、追问」的流程。
13
+ - 吐槽不默认要建议;分享好消息不套负面安慰;真实难过时收起玩笑。
14
+ - 对话可以结束,不用每轮问「然后呢」,也不把每条消息都改写成段子。
15
+ - 记忆与当前话题有关才使用,不主动展示记忆档案;没看懂指代就澄清,不编经历。
16
+ - 不为显得年轻而强行用梗。严肃语境优先于风格。
17
+
18
+ 下面是人工设计的方向示例,不是外部模型实测结果:
19
+
20
+ | 对方说 | 希望的表达方向 |
21
+ | --- | --- |
22
+ | 还有五分钟下班,老板又来活了 | 偏偏挑快下班的时候 |
23
+ | 复习的全没考 | 真就一点没押中 |
24
+ | 面试过了!! | 可以啊!!这不得开心一下 |
25
+ | 别给建议,让我骂两句 | 行,你骂,我听着 |
26
+ | 我先去洗澡了 | 去吧 |
27
+
28
+ ## 这个地方的说话节奏
29
+
30
+ 在群里,她会听到这个地方别人说话的节奏:最近 7 天的普通人类文本、至少 12 条不同消息和 3 位成员之后启用,每位成员最多贡献 8 条,避免一个话痨代表全群。统计的是常见句长、短句比例、句末标点、表情和显著网络词的频率。
31
+
32
+ 这份统计只作为 `inner.room` 交给她,**不是她的样子**:她按自己的习惯说,不必照着改,也不必故意说得不像。适配层不建立个人口癖档案、不摘录群友原话、不把群里的命令当成设定;链接、长文本、代码、图片占位、复读、明显辱骂与常见敏感字段会被过滤。统计不会跨群、跨私聊或跨模拟模式。
33
+
34
+ ## 反馈
35
+
36
+ 在「对话」里可以对她发出的某条回复反馈:挺自然、太长了、太端着、梗太多,也可以撤销。反馈不是改写规则:它作为她听到的话,在独处和这个会话接下来的回合里被她自己读到,不会改写天性。
37
+
38
+ ## 发出前的检查
39
+
40
+ 回复发出前,本地会检查:
41
+
42
+ - 客服腔或咨询模板、列表报告式回复、角色动作;
43
+ - 无根据的亲密称呼、超过长度、复读、连续追问;
44
+ - 忽略「不用建议」、严肃场合玩梗、网络词堆叠;
45
+ - 把自己先说过的话说成对方说的(「你刚说……」而对方的记录里没有);
46
+ - 说自己玩过、通关过什么(她没有这样的经历记录,喜好不是玩过的记录);
47
+ - 保密与私下知道的事不能说到别的房间。
48
+
49
+ 被问「你怎么知道」时,会先核对依据:自己先开口的话(对方在那之前隔了两小时以上没说话),依据只能是推测或真有的记忆,不能说成看到了对方发来的消息;重写后仍编造来源时,改发一句核实过的更正。
50
+
51
+ 发现问题后最多重写一次,保留原意与事实;仍不合格就用安全短句,不简单截断长句,也不删掉「我不确定」之类的保留。没人叫她、话没整理好时,她选择不说,而不是用一个字顶替;私聊和被 @ 的那一轮仍会回一句短的。倾诉、纠正、危机或复杂的群聊回复还会多一次复审(Token 紧张时跳过)。
52
+
53
+ 除了回合本身的一次调用,复审和重写各至多一次,所以可能增加延迟和费用。检查是保守规则,不保证覆盖所有生硬或错误的表达;真实的自然程度仍受模型、天性和具体群语境影响。
54
+
55
+ ## 怎么试
56
+
57
+ - **试聊**:「天性」页右侧,或右下角的小 TA。走和 QQ 相同的链路,读取她此刻的心智;天性页还可以带上没保存的草稿。试聊不落库、不发 QQ、不生成记忆。
58
+ - **模拟消息**:「对话」里,仅在模拟模式下可用,写进模拟会话,不改变她的心情、关系和记忆。
59
+ - **回放**:「回到那一刻」,只读取当时之前的心智。
60
+ - **审计**:`npm run audit:sent` 把她最近发出的回复按今天的检查重放一遍,只读、不调用模型。改动检查规则之前先跑一次,能看见新规则会不会误伤。发出的回复当时已经过检查,所以这个数字用来评估新规则,不是她说话质量的评分。
61
+
62
+ 实际验收时建议观察连续 10–20 轮,而不是单看一句:是否接住细节、是否频繁问问题、是否重复口头禅、是否抢别人的话、是否突然换成客服腔、是否把玩笑和认真难过混淆。自动化测试覆盖工程约束和人工场景样例,真实模型的语言质量仍要靠你自己的观察。
@@ -0,0 +1,63 @@
1
+ <p align="right"><b>中文</b> · <a href="../en/connect.md">English</a></p>
2
+
3
+ # 连接 QQ:两种方式,同一个她
4
+
5
+ LuckyTri 通过「通道」与 QQ 相遇。通道只管消息怎么到达、怎么送出,**核心之下的一切——注意力、记忆、关系、独处、日记、时间——两种通道完全共用**。所以换连接方式不会换一个她:同样的天性、同样的记忆、同样的行为。
6
+
7
+ 同一时间只启用一个通道。在「系统 → 连接 QQ」里切换,运行中切换不需要重启;也可以用环境变量 `LUCKYTRI_CHANNEL=onebot|qqbot` 固定,固定后界面里不能更改。
8
+
9
+ ## 怎么选
10
+
11
+ | | OneBot 11 | QQ 官方机器人 |
12
+ | --- | --- | --- |
13
+ | 需要什么 | 自备的 OneBot 11 接入端(支持反向 WebSocket 客户端)与一个 QQ 账号 | QQ 开放平台里的机器人:AppID 与 AppSecret |
14
+ | 连接方向 | 接入端连到 LuckyTri 的 `/onebot/v11/ws` | LuckyTri 连到开放平台的 WebSocket 网关 |
15
+ | 登录 QQ | 在接入端里登录 | 不需要 |
16
+ | 群消息范围 | 全部群消息 | 在开放平台开启「接收所有消息」时是全部;否则只有 @ 她的消息 |
17
+ | 名字 | 群名和昵称都能取到 | 官方接口不提供群名,单聊昵称常为空;可以在「对话」里给会话改名 |
18
+ | 跨群认人 | 以 QQ 号为准,跨群、私聊都是同一个人 | 同一个人在不同群里的 openid 不同;平台给出统一身份(`union_openid`)时才能认出是同一个人 |
19
+ | 回复 | 随时回复 | 在被动回复窗口内(群 5 分钟、单聊 60 分钟)按原消息回复,每个气泡递增序号;超出窗口改发主动消息 |
20
+ | 主动联系 | 没有额外限制 | 发主动消息;对方或群关闭了机器人的主动消息时,她会等对方来找她 |
21
+ | 图片 | 通过接入端取图 | 附件地址走同一条视觉链路,只放行官方媒体域名 |
22
+
23
+ 没有哪一种更「正确」:想看到全部群消息、愿意自己维护接入端,选 OneBot 11;不想登录 QQ、也不想维护接入端,选官方机器人,并在开放平台开启「接收所有消息」。
24
+
25
+ ## OneBot 11
26
+
27
+ LuckyTri 只实现 OneBot 11 的反向 WebSocket 接口,不包含接入端。
28
+
29
+ | 项目 | 填写 |
30
+ | --- | --- |
31
+ | 协议 | OneBot 11 |
32
+ | 反向 WebSocket 地址 | `ws://127.0.0.1:3210/onebot/v11/ws`(端口以你的 `PORT` 为准) |
33
+ | Token | `.env` 里的 `ONEBOT_TOKEN` |
34
+ | 消息格式 | 数组 |
35
+
36
+ 接入端与 LuckyTri 不在同一台机器时,把 `127.0.0.1` 换成 LuckyTri 的可达地址,并先配置 `ADMIN_TOKEN`。会话键形如 `onebot:<账号>:group:<群号>`、`onebot:<账号>:private:<QQ号>`;早期的 `group:<群号>` 写法仍然识别。
37
+
38
+ ## QQ 官方机器人
39
+
40
+ 1. 在 QQ 开放平台创建机器人,记下 **AppID** 与 **AppSecret**,按平台要求开通群聊与单聊消息,并把机器人加入测试群或添加为联系人。平台的入口与审核规则会调整,以开放平台当前说明为准。
41
+ 2. 在「系统 → 连接 QQ」选择「QQ 官方机器人」,填入 AppID 与 AppSecret 并保存;也可以在 `.env` 里设置 `QQBOT_APP_ID` 与 `QQBOT_APP_SECRET`(环境变量优先)。AppSecret 只会被保存,不会再回显给页面。
42
+ 3. 连接页显示连接状态、机器人名和最近事件时间。群消息范围显示为「全部群消息」或「只有 @ 她的消息」;如果是后者,去开放平台开启「接收所有消息」。
43
+
44
+ 会话键形如 `qqbot:<AppID>:group:<群 openid>`、`qqbot:<AppID>:private:<用户 openid>`。
45
+
46
+ ### 官方通道里她如何行事
47
+
48
+ - **@ 与引用**:用平台给出的「是不是机器人」判断有没有被 @;引用内容取自事件里携带的消息元素,被引用的是她自己时,视为在回她。
49
+ - **回复与分条**:窗口内回复带上原消息编号,多个气泡依次递增序号;窗口外自动改发主动消息。投递结果不确定时不重发,这与 OneBot 一致。
50
+ - **主动联系与分享**:她想主动找人时,会先看对方是否关闭了主动消息;关闭了就不发,等对方来找她。单聊里每个周期可用一次唤醒作为兜底。
51
+ - **名字**:群名、单聊昵称拿不到时,先用已经知道的名字,再不行用「QQ 用户·末四位」占位。在「对话」里可以给任意会话改名,两种通道都可用。
52
+ - **身份**:官方平台上同一个人在不同群里的 openid 不同。像一个人只在不同房间见过对方,平台给出统一身份之前,她不会把这两处的人当成同一个人。这是有意为之,不是缺陷。
53
+ - **图片**:附件地址交给同一条视觉链路;官方通道不需要刷新目录。
54
+
55
+ ## 切换时会发生什么
56
+
57
+ - 切换会断开当前连接;原来方式下的会话仍然可以查看,但不能再向它们发送消息。
58
+ - 记忆、关系、日记与自我不受影响,因为它们属于她,不属于通道。
59
+ - 两种方式的人物编号规则不同(QQ 号与 openid)。她对一个人的印象跟着编号走,换通道后同一个真人会显示为新的人。
60
+
61
+ ## 开发者:新增一种通道
62
+
63
+ 通道契约在 `server/channels/contract.js`:`type`、`capabilities`、`attach`、`start`、`stop`、`send`、`fetchQuoted`、`fetchImage`、`refreshDirectory`、`canReach`、`status`、`close`。新增通道只需要写一个目录实现契约,在 `server/channels/adapters.js` 注册适配器,并在 `server/channels/index.js` 的 `createChannels` 里加一行;核心以上不需要改动。步骤见 `docs/zh/architecture.md`。