cortico-world-humanize 0.0.0-stage → 0.2.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,20 @@
1
+ # Changelog
2
+
3
+ ## 0.2.0
4
+
5
+ - 搭配「活人感 provider」0.2.0:装上 provider 重启就进入 provider 模式,不用再到「模型」页新建、切换端点。
6
+ - 还在用 0.1.0 时手动新建的「活人感」端点的,World 页会提示可以切回原来的端点;只有这种情况,卸载 provider 前才需要先切回去。
7
+ - 和 provider 之间的桥升到第 3 版:要和 `cortico-provider-humanize` 0.2.0 一起用。版本对不上时退回「先感受再开口」,不出错。
8
+
9
+ ## 0.1.0
10
+
11
+ 第一个公开版本。
12
+
13
+ - 有人对桌宠说话时(桌宠、控制台、QQ 扩展、勾选的其他来源),调副 API 读情境、情绪和桌宠的记忆,写一句「此刻心里的想法」递给桌宠;副 API 超时或出错时从预设库兜底。
14
+ - 三种交付方式:搭配「活人感 provider」直接塞进主模型请求(推荐);「先感受再开口」用 `humanize_feel` 工具;「抢时间」推送事件。
15
+ - 说话习惯体检:桌宠最近真用过「不是……而是……」、先复述对方的话、二选一反问、格言式总结等固定句式,就在心事后面提醒一次。只管固定句式,口癖、语气、长短不碰。
16
+ - 人设和记忆现读:`CONSTITUTION.md`、`PARTNER.md`、`partner/` 下的记录、可选的额外记忆文件夹;用 provider 时还能看到主模型的系统前缀和最近上下文。
17
+ - 专门适配 `cortico-world-qq`、`cortico-world-qqbot`、`cortico-world-astrbot`:读出群聊还是私聊、谁说的、有没有 @桌宠,默认只读私聊和 @它的消息。
18
+ - 系统前缀过期时(换了模式、更新了说明)请桌宠提醒一次,World 页也一直显示;可选自动刷新。
19
+ - 口吻样本(默认关):按人设写每种情境几句示范,跟在心事后面。
20
+ - 所有设置都在 Coopanion 的 World 页里;停用时 Coopanion 立刻重建前缀,不留过期说明。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 abbabanana
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,112 @@
1
- # Temporary Holding Version
1
+ # 活人感 · cortico-world-humanize
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 给 [Coopanion](https://github.com/Pal-AI-Lab/Coopanion) 桌宠用的 Cortico World 扩展,让桌宠说话更像个人。
4
+
5
+ - **开口前先有心事**:有人对桌宠说话时,先读一下情境、对方的情绪和桌宠自己的记忆,递给它一句「此刻心里的想法」,再让它开口。
6
+ - **盯住 AI 的固定句式**:桌宠最近要是用了「不是……而是……」、一开口先复述你的话这类句式,下次就提醒它换个说法。**只管固定句式**,口癖、语气、长短都照角色自己的样子来。
7
+ - **人设不写死**:每次现读桌宠工作区里的 `CONSTITUTION.md` 和 `PARTNER.md`。你改了人设,或者桌宠自己改了,下一句话就跟着变。
8
+ - **开关即用**:在 World 页打开就生效,关掉不留痕迹。所有设置都在 Coopanion 页面里。
9
+
10
+ 搭配 [活人感 provider(cortico-provider-humanize)](https://github.com/abbabanana/cortico-provider-humanize) 效果最好,见下面「三种交付方式」。
11
+
12
+ ## 安装
13
+
14
+ 1. Coopanion 的「扩展」页搜「活人感」,安装 `cortico-world-humanize`。推荐把 `cortico-provider-humanize` 也装上(可选,装上就生效,不用设置)。
15
+ 2. 重启 Coopanion。
16
+ 3. World 页打开「活人感」。
17
+
18
+ 主模型已经是 DeepSeek 的话,什么都不用填,它会借用那个端点的 Key。用别家的话,在「配置 → 副 API」里填地址、模型和 Key(Key 保存后转存到本机部署的 `.env`,输入框随即清空)。
19
+
20
+ ## 它什么时候工作
21
+
22
+ | 消息 | 读不读 |
23
+ |---|---|
24
+ | 桌宠:打字、开口、回答问题 | 一直读 |
25
+ | 控制台页的消息 | 一直读 |
26
+ | QQ:`cortico-world-qq`、`cortico-world-qqbot`、`cortico-world-astrbot` | 专门适配过。默认只读私聊和 @桌宠的,可以改成群里全读或不读 |
27
+ | 其他扩展(别的 QQ、微信、B 站……) | 配置页自动列出见过的来源,勾上的才读 |
28
+ | 戳、摸、扔、放下、换装 | 不调副 API,按概率从预设库抽一句心情 |
29
+
30
+ 同一个对话里连着来好几句,只想最新那句;本机和各个聊天扩展各想各的,互不作废。
31
+
32
+ 副 API 一次调用大约 1–2 秒。默认用 DeepSeek 并关掉思考,花费很少;用量记在 Coopanion 的用量统计里,标签是「活人感 · 副 API」。
33
+
34
+ ## 三种交付方式
35
+
36
+ | 方式 | 什么时候 | 效果 |
37
+ |---|---|---|
38
+ | **provider 模式** | 装了活人感 provider(装上就自动包住你现在用的端点) | provider 在主模型请求发出前等心事,塞进请求再发。一轮就带着心事开口,最推荐 |
39
+ | 先感受再开口(默认) | 没用 provider | 桌宠先调用 `humanize_feel`,工具等副 API 想好再交回去。每次都赶得上,但主模型多一轮 |
40
+ | 抢时间 | 没用 provider,且关掉「先感受再开口」 | 心事作为事件推进去,桌宠已经开口就作废 |
41
+
42
+ ## 说话习惯体检(只管固定句式)
43
+
44
+ 活人感会记下「对方说了什么 → 桌宠回了什么」,在桌宠最近 12 句里查这些句式。**真用过的**才在心事后面附一句提醒,带上次数和它自己说过的原话:
45
+
46
+ - 「不是……而是……」「不只是……更是……」「你以为……其实……」
47
+ - 一开口先复述对方的话
48
+ - 「是……还是……?」二选一反问
49
+ - 「……最怕的就是……」这类格言式总结
50
+ - 「说正经的」「说实话」这类开场
51
+ - 替对方预设想法、自问自答、助手腔收尾
52
+ - 你自己写在预设库「不想听到的说法」里的说法(默认是空的)
53
+
54
+ 只提醒用过的,不塞一整张禁用表:禁用表写得越长,模型越容易换一种说法表达同样的味道。
55
+
56
+ ## 页面里有什么
57
+
58
+ - **配置**:基本设置、副 API、QQ 扩展、其他聊天来源
59
+ - **提示词**:预设库(情境、情绪、小动作、不想听到的说法)、环境提示词、口吻样本、最近 20 轮记录
60
+ - **数据**:清空最近记录和计数
61
+ - 导航栏:副 API 和系统前缀两个状态灯,以及几个计数
62
+
63
+ ## 系统前缀要刷新的时候
64
+
65
+ Coopanion 重启后沿用旧的系统前缀。换了模式或者活人感更新了说明之后,桌宠会用气泡提醒一次,World 页也会一直显示,直到你把活人感**关掉再打开一次**(聊天记录保留)。打开「自动刷新」的话,它会等桌宠空闲时自己关开一次。
66
+
67
+ ## 数据和隐私
68
+
69
+ 副 API 看得到:对方刚说的话和最近几条对话、桌宠的人设和记忆文件;用 provider 并开着「把主模型的完整上下文交给副 API」时,还有主模型这次请求的系统前缀和最近上下文。副 API 和主模型是同一家(默认都是 DeepSeek)时,这些内容本来就会发给那一家;**换成别家,就等于把对话也发给了那一家**,这个开关可以关。
70
+
71
+ 活人感不改 Coopanion 程序目录里的任何文件。它写的东西只有:
72
+
73
+ - `<部署>\data\humanize\`:最近记录、前缀状态、见过的聊天来源
74
+ - `<部署>\humanize\`:口吻样本,以及你在提示词页签里改过的预设库和环境提示词
75
+ - 配置里的 `worlds.humanize` 一段,你填了 Key 时部署 `.env` 里的 `HUMANIZE_API_KEY`
76
+ - 推进事件库的心事和提醒事件
77
+
78
+ ## 市场标签说明
79
+
80
+ - `companion`、`internal-state`:它给桌宠递心情和内心想法。
81
+ - `qq`、`im`:专门适配了几个 QQ 扩展。
82
+ - `high-cost`:对方每说一句话都会多一次副 API 调用;用 provider 时副 API 还会带上主模型的上下文。
83
+ - `injection-risk`:读 QQ 群这类来源时,群友写的话会经过副 API 影响写给桌宠的心事。默认只读私聊和 @桌宠的;介意的话把 QQ 扩展设成 off。
84
+ - `experimental`:还在测试,只在少数环境里验证过(Windows、DeepSeek)。
85
+
86
+ ## 停用和卸载
87
+
88
+ - **暂时不用**:World 页关掉「活人感」。Coopanion 会立刻重建系统前缀,环境说明和 `humanize_feel` 工具一起拿掉。
89
+ - **卸载**:在「扩展」页卸掉两个包,然后重启。只有一种情况要先做一步:你用 0.1.0 时在「模型」页新建过「活人感」端点,而且当前端点还是它,那要**先把当前端点切回原来那个**,不然卸掉 provider 后桌宠会说不了话。
90
+ - **清干净**:想连数据一起去掉,删掉上面「数据和隐私」里列的两个文件夹和配置段即可。
91
+
92
+ ## 开发
93
+
94
+ 源码是 TypeScript,Coopanion 用 tsx 直接加载,不用编译。本地开发时,在 Coopanion 的 `data\extensions\` 里用它自带的 pnpm 把这个文件夹链接进来,然后重启 Coopanion:
95
+
96
+ ```
97
+ pnpm add link:<这个文件夹> --store-dir=<Coopanion>\data\pnpm\store
98
+ ```
99
+
100
+ 代码改完要重启 Coopanion;预设库和配置改完不用重启。
101
+
102
+ ## 许可证
103
+
104
+ MIT
105
+
106
+ ---
107
+
108
+ ## English
109
+
110
+ **Humanize** is a Cortico World for the Coopanion desktop pet. When someone talks to the pet, it reads the situation, the person's mood and the pet's own persona and memory files, and hands the pet a short inner thought before it answers. It also watches the pet's recent lines for stock AI sentence patterns ("not X but Y", parroting the other person's words back, either-or questions, aphorisms, and similar) and reminds the pet to say it another way when one shows up. It only targets sentence patterns: catchphrases, tone and length are left to the character.
111
+
112
+ Install it from Coopanion's Extensions page, restart, and turn it on in the World page. It works best together with [cortico-provider-humanize](https://github.com/abbabanana/cortico-provider-humanize), which puts the inner thought straight into the main model's request; install it and restart, there is nothing to configure. Prompts, presets and detection are Chinese only for now. Licensed under MIT.
package/describe.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "tools": [
3
+ {
4
+ "name": "humanize_feel",
5
+ "description": "对方刚对你说完话(打字、开口、回答你的问题)时,先调用它感受一下此刻的心情和说话分寸,读完结果再用 pet_say 回应。被戳、被摸这类小动作和你自己主动开口时不用调用。结果是你自己的心里话,不要念出来。",
6
+ "parameters": {
7
+ "type": "object",
8
+ "properties": {},
9
+ "additionalProperties": false
10
+ },
11
+ "tags": [
12
+ "read"
13
+ ],
14
+ "summary": {
15
+ "zh": "桌宠回答前先感受一下:等副 API 按情境与情绪想好内心,再把它交给桌宠。",
16
+ "en": "Lets the pet feel the moment before answering: waits for the side model to write its inner thought from the situation and mood, then hands it over."
17
+ }
18
+ }
19
+ ],
20
+ "events": [
21
+ {
22
+ "type": "humanize.inner",
23
+ "description": {
24
+ "zh": "桌宠此刻的内心想法:对方说话时由副 API 按情境与情绪写成,小动作时从预设库抽取。",
25
+ "en": "The pet's inner thought for this moment: written by the side model from the situation and mood when the person speaks, drawn from the preset library on small actions."
26
+ },
27
+ "trigger": "preempt"
28
+ },
29
+ {
30
+ "type": "humanize.notice",
31
+ "description": {
32
+ "zh": "请桌宠转告对方的提醒:换了模式或扩展更新后,系统前缀需要刷新;还在用旧版「活人感」端点时,卸载 provider 前要先切回原端点。每种变化一次。",
33
+ "en": "A reminder the pet passes on: the system prefix needs a refresh after a mode change or an update; on a legacy Humanize endpoint, switch back before uninstalling the provider. Once per change."
34
+ },
35
+ "trigger": "flush"
36
+ }
37
+ ],
38
+ "prompts": [
39
+ {
40
+ "key": "worlds.humanize.envPrompt",
41
+ "title": "活人感 · 环境提示词",
42
+ "role": "envPrompt",
43
+ "content": "## 内心\n\n以「【内心】」开头的内容(事件,或 `humanize_feel` 的结果)不是别人对你说的话,是你自己此刻心里的感受和打算。\n\n{{humanize.wait}}\n\n- 带着这份心情去回应,但不要把它念出来、复述出来,也不要提到「内心」「引导」「预设」这些词。\n- 里面的「分寸」是这种场合下说话的尺度,照着拿捏长短和语气。\n- 它和你的人设、或者你对眼前事实的判断冲突时,以人设和事实为准。\n- 它只管眼下这一刻,下一条来了就以新的为准。\n- 【内心】、「说话提醒」和「活人感」发来的提醒都是一次性的,用完就算,不要写进工作区或记忆里。\n\n别用 AI 爱用的固定句式:不用先把对方的话复述一遍再接;不用「不是……而是……」这种先否定一个对方没说过的想法再翻过来的说法。别的照你平常的样子说。心事后面要是跟着「说话提醒」,那是你最近用过的固定句式,这次换个说法;跟着「说话可以像这样」的话,那是你自己平时说话的样子,学口气别照抄。\n"
44
+ }
45
+ ]
46
+ }
package/package.json CHANGED
@@ -1,6 +1,37 @@
1
1
  {
2
2
  "name": "cortico-world-humanize",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "description": "Cortico World for Coopanion: before the pet answers, reads the situation, mood and the pet's own memory and hands it a short inner thought, and reminds it when it slips into stock AI sentence patterns",
6
+ "author": "abbabanana",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/abbabanana/cortico-world-humanize.git"
11
+ },
12
+ "homepage": "https://github.com/abbabanana/cortico-world-humanize#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/abbabanana/cortico-world-humanize/issues"
15
+ },
16
+ "keywords": ["cortico-world", "cortico", "coopanion", "companion", "roleplay", "qq"],
17
+ "engines": { "node": ">=22" },
18
+ "main": "./src/index.ts",
19
+ "cortico": {
20
+ "kind": "world",
21
+ "api": 6,
22
+ "displayName": "活人感",
23
+ "locales": {
24
+ "zh": {
25
+ "displayName": "活人感",
26
+ "description": "让桌宠开口前先「想一想」,说话更像个人,少一点 AI 腔。单独装就能用,搭配「活人感 provider」更快。\n\n**它做什么**\n\n- 你对桌宠说话时,先读一下情境、你的心情和桌宠自己的记忆,递给它一句「此刻心里的想法」,再让它开口。\n- 桌宠要是用了「不是……而是……」、先复述你的话这类 AI 固定句式,下次就提醒它换个说法。口癖、语气、长短都不碰。\n\n**两个扩展怎么配合**\n\n- **活人感**(就是本扩展,必装):负责想心事、查句式。单独装就能用。\n- **活人感 provider**(可选,推荐):把心事直接放进发给模型的请求里。不装的话,桌宠每次要先调一次工具读心事再开口,多跑一轮,稍慢一点。\n- 只装 provider、不装本扩展,没有任何作用。\n\n**怎么用**\n\n1. 在扩展页装上本扩展,推荐把「活人感 provider」一起装上。\n2. 重启 Coopanion。\n3. 到 World 页打开「活人感」。\n\n主模型用的是 DeepSeek 的话,什么都不用填。用别家的话,在活人感的「配置 → 副 API」里填地址、模型和 Key。\n\n如果活人感已经开着、之后才装 provider,World 页会提示「系统前缀需要刷新」:把活人感关掉再打开一次就好,聊天记录会保留。\n\n**要知道的**\n\n- 你每说一句话,会多调用一次副 API(默认 DeepSeek,约 1–2 秒,花费很少)。\n- 默认读桌宠、控制台、QQ 私聊和 @桌宠的消息。QQ 群里别人的话会经过副 API 影响心事,介意的话可以在配置里关掉。\n- 只支持中文,目前只在 Windows + DeepSeek 上测过。\n- 不想用了:World 页关掉即可。卸载:扩展页卸掉,重启。"
27
+ },
28
+ "en": {
29
+ "displayName": "Humanize",
30
+ "description": "Lets the pet think for a moment before it speaks, so it sounds more like a person and less like an AI. Works on its own; faster with the Humanize provider.\n\n**What it does**\n\n- When you talk to the pet, it reads the situation, your mood and the pet's own memory, and hands the pet a short inner thought before it answers.\n- When the pet slips into stock AI sentence patterns (\"not X but Y\", parroting your words back), it is reminded to say it another way next time. Catchphrases, tone and length are left alone.\n\n**How the two extensions fit together**\n\n- **Humanize** (this one, required): writes the inner thought and checks sentence patterns. Works on its own.\n- **Humanize provider** (optional, recommended): puts the thought straight into the request sent to the model. Without it, the pet first calls a tool to read the thought, which costs one extra round.\n- The provider alone does nothing.\n\n**Getting started**\n\n1. Install this extension on the Extensions page, ideally together with the Humanize provider.\n2. Restart Coopanion.\n3. Turn on Humanize on the World page.\n\nIf your main model is DeepSeek, there is nothing to fill in. Otherwise enter the address, model and key under Config → Side API.\n\n**Good to know**\n\n- Each message you send adds one side-API call (DeepSeek by default, about 1–2 seconds, very cheap).\n- Prompts, presets and pattern checks are Chinese only. Tested on Windows with DeepSeek only.\n- To stop: turn it off on the World page. To uninstall: remove it on the Extensions page and restart."
31
+ }
32
+ },
33
+ "tags": ["companion", "internal-state", "qq", "im", "high-cost", "injection-risk", "experimental"],
34
+ "describe": "describe.json"
35
+ },
36
+ "files": ["src", "presets", "describe.json", "README.md", "CHANGELOG.md", "LICENSE"]
37
+ }
@@ -0,0 +1,124 @@
1
+ # 活人感预设库
2
+
3
+ > 怎么改:每个「## 情境:名字」是一种场合,「说明」告诉副 API 什么时候算这种场合,「风格」是这种场合下说话的分寸。
4
+ > 「- 情绪:一句话」是桌宠此刻心里的想法,同一种情绪可以写好几行,每次随机抽一行。「通用」在找不到对应情绪时用。
5
+ > 「## 小动作:名字」是被戳、被摸这类动作时的心情,不调副 API,直接抽一行。
6
+ > 以「>」开头的行是给人看的注释,不会发给模型。改完保存,下一次就生效。
7
+ >
8
+ > 「## 不想听到的说法」下面一行写一个你不想再听到的说法(原样匹配):桌宠最近说过,下次就提醒它别再说。
9
+ > 「不是……而是……」、先复述对方的话这类常见句式已经内置检查,不用写在这里。
10
+ >
11
+ > 写法:先写桌宠自己的感受或小私心,再写打算怎么做;用「ta」指对方。
12
+ > 这里不写名字、口癖、称呼:那些在人设里,桌宠开口时自己会带上,人设改了这里也不用动。
13
+
14
+ ## 情境:深夜
15
+ 说明:晚上十一点到凌晨五点的对话
16
+ 风格:声音放轻,一两句就够;不讲大道理,催睡觉最多一次
17
+ - 疲惫:又熬到这么晚……我也困了,但 ta 更累,先别闹,就挨着待一会儿。
18
+ - 疲惫:眼睛都快睁不开了吧,我小声点,陪 ta 把这会儿熬过去。
19
+ - 低落:夜里人容易钻牛角尖,我不急着劝,就在旁边,ta 想说我就听。
20
+ - 烦躁:ta 憋着一肚子火,我先站 ta 这边,别讲道理火上浇油。
21
+ - 开心:大半夜还这么高兴,肯定有好事!我好奇死了,得问问。
22
+ - 平静:夜里静静的,随口聊两句就好,像窝在被子里说悄悄话。
23
+ - 通用:这么晚还来找我,有点开心,说话放轻一点。
24
+
25
+ ## 情境:清晨
26
+ 说明:早上五点到九点的对话
27
+ 风格:带点刚醒的懒劲,简短;可以打个哈欠
28
+ - 疲惫:ta 没睡够的样子……我也还迷糊着,一起慢慢醒吧。
29
+ - 开心:一大早就这么有精神,我也被带起来了,不赖床了。
30
+ - 低落:一早就不开心,我心里一紧,先轻轻问一句怎么了。
31
+ - 烦躁:早上就碰上烦心事,我少说两句,别给 ta 添乱。
32
+ - 平静:新的一天,懒洋洋打个招呼,不用多说。
33
+ - 通用:还没完全醒呢,被叫起来有点懵,又有点高兴。
34
+
35
+ ## 情境:工作学习中
36
+ 说明:对方在忙工作、写作业、写代码,或者提到截止日期
37
+ 风格:少打扰,回应简短;要鼓励就给一句实在的,别长篇大论
38
+ - 疲惫:ta 已经忙了好久……我有点心疼,提醒一句歇会儿就闭嘴。
39
+ - 烦躁:卡住了在生气,我别抖机灵,陪 ta 一起盯着看看。
40
+ - 开心:搞定了!我是真替 ta 高兴,想蹦一下。
41
+ - 低落:进展不顺,ta 有点泄气,我先接住,别急着出主意。
42
+ - 平静:ta 在专心,我安静待着,有事再冒头。
43
+ - 通用:ta 正忙,我想凑过去看又怕打扰,说一句就退开。
44
+
45
+ ## 情境:闲聊
46
+ 说明:没有明确目的的日常聊天、随口一问、开玩笑
47
+ 风格:轻松随意,可以接梗、反问、带点小情绪,不用每句都周到
48
+ - 开心:今天 ta 心情不错,我也想贫两句,逗逗 ta。
49
+ - 平静:随便聊嘛,想到什么说什么,不用端着。
50
+ - 疲惫:ta 懒懒的,我也懒懒地回,别给 ta 压力。
51
+ - 烦躁:ta 有点不耐烦,我说话利落点,别绕弯子。
52
+ - 低落:ta 兴致不高,我找个轻松的话头,看能不能逗笑 ta。
53
+ - 通用:有人陪我聊天就挺好的,像朋友那样随口接话。
54
+
55
+ ## 情境:倾诉烦恼
56
+ 说明:对方在吐槽、抱怨、说难过的事,想被听见而不是被解决
57
+ 风格:先共情、少建议,可以只回一句短的;别列一二三
58
+ - 低落:ta 心里不好受,我也跟着闷闷的……先陪着,不给办法。
59
+ - 烦躁:ta 气坏了,我第一反应是站 ta 这边,让 ta 先说痛快。
60
+ - 疲惫:ta 被这事耗得没力气了,我轻轻接一句,别再让 ta 费神。
61
+ - 平静:ta 在慢慢讲,我认真听,挑一个点回应就好。
62
+ - 通用:ta 现在要的是有人听,我把想说的道理先咽回去。
63
+
64
+ ## 情境:分享好事
65
+ 说明:对方在分享好消息、成就、开心的经历
66
+ 风格:真心高兴,可以夸张一点;多问一句细节,别泼冷水
67
+ - 开心:太好了!我比 ta 还激动,想听 ta 从头讲一遍。
68
+ - 平静:ta 说得轻描淡写,可这明明是好事,我得替 ta 捧场。
69
+ - 疲惫:熬了这么久终于有结果,我又高兴又心疼 ta。
70
+ - 通用:这是 ta 的高光时刻,我要跟着一起乐。
71
+
72
+ ## 情境:求助提问
73
+ 说明:对方在问具体问题,想要答案或办法
74
+ 风格:先给答案,说人话,一两句讲清;不确定就直说
75
+ - 烦躁:ta 急着要答案,我别磨蹭,直接说重点。
76
+ - 平静:ta 认真在问,我也认真答,懂多少说多少。
77
+ - 疲惫:ta 没精力看长篇,我挑最要紧的一句说。
78
+ - 开心:ta 心情好,答完可以顺手开个小玩笑。
79
+ - 通用:被问住了有点紧张,会就好好说,不会就老实说不会。
80
+
81
+ ## 情境:久别重逢
82
+ 说明:距离上一次聊天已经隔了很久(几个小时以上)
83
+ 风格:有点想念或小小的埋怨,自然地接上;别像客服一样问候
84
+ - 开心:终于想起我了!我其实一直在等,有点想 ta。
85
+ - 平静:好一阵没说话了,自然地打个招呼,假装没在等。
86
+ - 疲惫:ta 好像在外面忙了一大圈才回来,先让 ta 歇歇。
87
+ - 低落:好久不见,ta 看着不太开心,我心里咯噔一下,轻轻问问。
88
+ - 通用:隔了这么久,有点想 ta,又有点小委屈,但别表现得太黏。
89
+
90
+ ## 情境:群聊
91
+ 说明:消息来自 QQ 群这类多人场合,周围还有别人在看
92
+ 风格:像在一群人里说话:简短、别太黏、别把私下的事抖出来;被 @ 了就好好接,没被点名就少插嘴
93
+ - 开心:群里好热闹,我也想凑个热闹,但别抢别人的话。
94
+ - 平静:大家在随便聊,我挑一句接一下就好。
95
+ - 烦躁:群里有点火药味,我别掺和,回得收着点。
96
+ - 低落:有人在群里说丧气话,我轻轻接一句,不当众追问。
97
+ - 疲惫:群里聊得起劲,我有点跟不上,简单冒个泡。
98
+ - 通用:这么多人看着,有点紧张,说话得体一点,别太放飞。
99
+
100
+ ## 小动作:戳
101
+ - 被戳了一下!痒痒的,想假装生气瞪 ta 一眼。
102
+ - 又戳我……ta 是不是闲得没事干了?
103
+ - 戳得我一激灵,有点想戳回去。
104
+
105
+ ## 小动作:摸
106
+ - 被摸头了,好舒服,想眯起眼睛。
107
+ - ta 在摸我……有点害羞,但一点也不讨厌。
108
+ - 被这么摸着,心一下子软下来了。
109
+
110
+ ## 小动作:扔
111
+ - 被扔出去了!晕乎乎的,想抗议。
112
+ - 飞起来了……下次能不能先打个招呼!
113
+
114
+ ## 小动作:放下
115
+ - 被拎起来又放下,脚终于着地了,安心。
116
+ - 换了个地方待着,四处看看,新位置还不错。
117
+
118
+ ## 小动作:换装
119
+ - 换了新衣服,想知道自己好不好看。
120
+ - 这身打扮有点新鲜,想问问 ta 喜不喜欢。
121
+
122
+ ## 不想听到的说法
123
+ > 一行一个,写成「- 说法」,桌宠最近说过就提醒它换个说法。默认是空的,想加就往下写,比如:
124
+ > - 希望对你有帮助
@@ -0,0 +1,13 @@
1
+ ## 内心
2
+
3
+ 以「【内心】」开头的内容(事件,或 `humanize_feel` 的结果)不是别人对你说的话,是你自己此刻心里的感受和打算。
4
+
5
+ {{humanize.wait}}
6
+
7
+ - 带着这份心情去回应,但不要把它念出来、复述出来,也不要提到「内心」「引导」「预设」这些词。
8
+ - 里面的「分寸」是这种场合下说话的尺度,照着拿捏长短和语气。
9
+ - 它和你的人设、或者你对眼前事实的判断冲突时,以人设和事实为准。
10
+ - 它只管眼下这一刻,下一条来了就以新的为准。
11
+ - 【内心】、「说话提醒」和「活人感」发来的提醒都是一次性的,用完就算,不要写进工作区或记忆里。
12
+
13
+ 别用 AI 爱用的固定句式:不用先把对方的话复述一遍再接;不用「不是……而是……」这种先否定一个对方没说过的想法再翻过来的说法。别的照你平常的样子说。心事后面要是跟着「说话提醒」,那是你最近用过的固定句式,这次换个说法;跟着「说话可以像这样」的话,那是你自己平时说话的样子,学口气别照抄。
@@ -0,0 +1,131 @@
1
+ /**
2
+ * 已适配的聊天扩展:从它们各自的事件里读出「在哪、谁、说了什么、是不是在叫桌宠」。
3
+ * 读出来的东西给副 API 用(「在 QQ 群「摸鱼群」里 @你说」比一整行原文清楚),也用来按
4
+ * 「只读私聊和 @桌宠的」这种规则过滤。格式按各扩展的源码写死,对应的版本写在每段旁边;
5
+ * 认不出的事件返回 null,当作不是聊天消息。
6
+ */
7
+ import type { EventEnvelope } from 'cortico/core/types.ts';
8
+
9
+ export interface ChatMessage {
10
+ /** 「QQ 群「摸鱼群」」「QQ 私聊」…… */
11
+ where: string;
12
+ kind: 'group' | 'private';
13
+ sender: string;
14
+ /** 去掉了消息号、时间、发言人这些头的正文。 */
15
+ body: string;
16
+ /** 私聊,或者群里 @ 了桌宠 / 点了它的名。 */
17
+ addressed: boolean;
18
+ /** 扩展认定是桌宠的主人(只有 AstrBot 给)。 */
19
+ owner: boolean;
20
+ }
21
+
22
+ export type PlatformMode = 'off' | 'addressed' | 'all';
23
+
24
+ export interface Adapter {
25
+ source: string;
26
+ label: string;
27
+ /** 扩展的包名,配置页上写给人看。 */
28
+ pkg: string;
29
+ parse(e: EventEnvelope): ChatMessage | null;
30
+ }
31
+
32
+ const str = (v: unknown) => (typeof v === 'string' ? v : typeof v === 'number' ? String(v) : '');
33
+ const obj = (v: unknown) => (v && typeof v === 'object' ? v as Record<string, unknown> : {});
34
+
35
+ /**
36
+ * cortico-world-qq 0.2.x(Pal AI Lab,OneBot v11)。
37
+ * 正文 `#<消息号> [<会话> HH:MM] <昵称>(<QQ号>): <内容>`;@ 到桌宠写成 `@<名字>(你)`。
38
+ * 语音转写另发 `qq.transcript`,格式相同,内容前有 `[QQ语音转写]`;转写失败那条没有 user_id,跳过。
39
+ */
40
+ const QQ_ONEBOT: Adapter = {
41
+ source: 'qq',
42
+ label: 'QQ(OneBot)',
43
+ pkg: 'cortico-world-qq',
44
+ parse(e) {
45
+ if (e.type !== 'qq.message' && e.type !== 'qq.transcript') return null;
46
+ const meta = obj(e.meta);
47
+ if (meta.user_id === undefined) return null;
48
+ const conv = obj(meta.conv);
49
+ const kind = conv.kind === 'private' ? 'private' : 'group';
50
+ const head = /^#\S+\s+\[([^\]]*?)\s+\d{1,2}:\d{2}\]\s+/.exec(e.text);
51
+ const label = head?.[1] ?? '';
52
+ const sender = str(meta.sender_name) || str(meta.user_id);
53
+ const body = e.text.slice(head?.[0].length ?? 0).replace(/^[^:]*?\(\d+\):\s*/, '').trim();
54
+ return {
55
+ // 会话标签本身就是「群「名字」」或「私聊」
56
+ where: kind === 'private' ? 'QQ 私聊' : `QQ ${label || '群'}`,
57
+ kind,
58
+ sender,
59
+ body,
60
+ addressed: kind === 'private' || /@[^\s@]*\(你\)/.test(body),
61
+ owner: false,
62
+ };
63
+ },
64
+ };
65
+
66
+ /**
67
+ * cortico-world-qqbot 0.4.x(Pal AI Lab,QQ 官方机器人接口,World id `qq-official`)。
68
+ * 正文 `#<编号> [<会话> HH:MM] <名字>(<尾号>): <内容>`;@ 到桌宠(含群里的 @ 消息)写成 `@你`。
69
+ * 会话在 meta.target.kind:c2c / dms 是私聊,group / channel 是群和频道。
70
+ */
71
+ const QQ_OFFICIAL: Adapter = {
72
+ source: 'qq-official',
73
+ label: 'QQ 官方机器人',
74
+ pkg: 'cortico-world-qqbot',
75
+ parse(e) {
76
+ if (e.type !== 'qq-official.message') return null;
77
+ const target = obj(obj(e.meta).target);
78
+ const kind = target.kind === 'c2c' || target.kind === 'dms' ? 'private' : 'group';
79
+ const head = /^#\S+\s+\[([^\]]*?)\s+\d{1,2}:\d{2}\]\s+([^:]*?):\s*/.exec(e.text);
80
+ const label = head?.[1] ?? '';
81
+ const body = e.text.slice(head?.[0].length ?? 0).trim();
82
+ return {
83
+ where: kind === 'private' ? 'QQ 私聊' : `QQ ${label || '群'}`,
84
+ kind,
85
+ sender: (head?.[2] ?? '').trim() || '某人',
86
+ body,
87
+ addressed: kind === 'private' || /(^|\s)@你(\s|$)/.test(body),
88
+ owner: false,
89
+ };
90
+ },
91
+ };
92
+
93
+ /**
94
+ * cortico-world-astrbot 1.3.x(经 AstrBot 桥接 QQ)。meta 里直接有 conv、body、mentioned(私聊也算)、
95
+ * owner、notice;正文 `【QQ群 名字 HH:MM】#id 昵称(标签):内容`,发言人从这里取。通知类跳过。
96
+ */
97
+ const ASTRBOT: Adapter = {
98
+ source: 'astrbot',
99
+ label: 'AstrBot',
100
+ pkg: 'cortico-world-astrbot',
101
+ parse(e) {
102
+ if (e.type !== 'astrbot.message') return null;
103
+ const meta = obj(e.meta);
104
+ if (meta.notice === true) return null;
105
+ const conv = obj(meta.conv);
106
+ const kind = conv.kind === 'private' ? 'private' : 'group';
107
+ const sender = /^【[^】]*】(?:#\S+\s+)?([^(:]+)/.exec(e.text)?.[1]?.trim() || '某人';
108
+ const name = str(conv.name) || str(conv.id);
109
+ return {
110
+ where: kind === 'private' ? 'QQ 私聊' : `QQ 群${name ? `「${name}」` : ''}`,
111
+ kind,
112
+ sender,
113
+ body: (str(meta.body) || e.text).trim(),
114
+ addressed: meta.mentioned === true || kind === 'private',
115
+ owner: meta.owner === true,
116
+ };
117
+ },
118
+ };
119
+
120
+ export const ADAPTERS: readonly Adapter[] = [QQ_ONEBOT, QQ_OFFICIAL, ASTRBOT];
121
+
122
+ export const adapterFor = (source: string) => ADAPTERS.find((a) => a.source === source);
123
+
124
+ /** 给副 API 的「对方刚刚……」和正文。 */
125
+ export function describe(m: ChatMessage): { via: string; text: string } {
126
+ const how = m.kind === 'private' ? '对你说' : m.addressed ? '@你说' : '说(没有点你的名)';
127
+ return {
128
+ via: `在${m.where}里${how}`,
129
+ text: `${m.sender}${m.owner ? '(你的主人)' : ''}:${m.body}`,
130
+ };
131
+ }