dsh-qqchat 0.2.4 → 0.2.6
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/README.en.md +5 -4
- package/README.md +3 -3
- package/client-src/plugin.cts +2 -2
- package/client-src/settings.cts +18 -1
- package/client-src/shared.cts +4 -4
- package/cordis.patch.yml +5 -0
- package/docs/ARCHITECTURE.en.md +1 -1
- package/docs/ARCHITECTURE.md +2 -1
- package/docs/DEVELOPMENT.md +3 -1
- package/docs/MEMORY.md +32 -4
- package/docs/MEMORY_CONTEXT.md +16 -0
- package/docs/README.md +2 -0
- package/docs/STREAMING.md +2 -2
- package/docs/prds/PRD-MEM-1-/347/276/244/350/256/260/345/277/206/344/270/216/347/276/244/345/217/213/350/256/260/345/277/206/347/255/226/347/225/245/350/260/203/346/225/264.md +396 -0
- package/docs/prds/README.md +62 -0
- package/lib/client.js +21 -4
- package/lib/config.js +3 -2
- package/lib/index.d.ts +2 -2
- package/lib/index.js +2 -3
- package/lib/session/agent-bridge.d.ts +3 -4
- package/lib/session/agent-bridge.js +40 -46
- package/lib/session/memory-snapshot.d.ts +4 -0
- package/lib/session/memory-snapshot.js +6 -2
- package/lib/session/runtime.js +15 -5
- package/lib/storage/db.d.ts +6 -1
- package/lib/storage/db.js +57 -0
- package/lib/storage/memory.d.ts +28 -2
- package/lib/storage/memory.js +375 -101
- package/lib/transport/rpc.js +2 -0
- package/lib/types.d.ts +26 -0
- package/package.json +24 -23
- package/prompts/group-compression.md +5 -0
- package/prompts/group-reflection.md +39 -0
- package/prompts/member-batch-reflection.md +39 -0
- package/prompts/member-compression.md +5 -0
- package/prompts/private-reflection.md +32 -0
- package/src/config.ts +3 -2
- package/src/index.ts +2 -3
- package/src/session/agent-bridge.ts +40 -47
- package/src/session/memory-snapshot.ts +6 -3
- package/src/session/runtime.ts +14 -4
- package/src/storage/db.ts +70 -0
- package/src/storage/memory.ts +343 -84
- package/src/transport/rpc.ts +1 -0
- package/src/types.ts +30 -0
package/README.en.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
<p>
|
|
8
8
|
<a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License"></a>
|
|
9
|
-
<img src="https://img.shields.io/badge/DSH-0.1.
|
|
10
|
-
<img src="https://img.shields.io/badge/QQChat-0.2.
|
|
9
|
+
<img src="https://img.shields.io/badge/DSH-0.1.6--alpha.1-6f42c1.svg" alt="DSH 0.1.6-alpha.1">
|
|
10
|
+
<img src="https://img.shields.io/badge/QQChat-0.2.6-2ea44f.svg" alt="QQChat 0.2.6">
|
|
11
11
|
<img src="https://img.shields.io/badge/TypeScript-5.x-3178c6.svg" alt="TypeScript">
|
|
12
12
|
</p>
|
|
13
13
|
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
|
|
19
19
|
<p><em>Chat in QQ, then view the complete Session, memory and tool activity in DSH Web.</em></p>
|
|
20
20
|
|
|
21
|
-
<p>This release is verified against DSH <code>0.1.
|
|
21
|
+
<p>This release is verified against DSH <code>0.1.6-alpha.1</code>. Install the plugin as-is; no DSH source patch or rebuild is required.</p>
|
|
22
22
|
|
|
23
23
|
`dsh-qqchat` is an official QQ Bot plugin for [DeepSeek Harness (DSH)](https://github.com/deepseek-ai/deepseek-harness). It maps QQ groups and direct chats to ordinary DSH Sessions and uses DSH's native Conversation, Agent, command and tool surfaces.
|
|
24
24
|
|
|
@@ -126,7 +126,8 @@ npx @deepseek-ai/dsh plugin --profile qqchat add @deepseek-ai/dsh-web-app dsh-qq
|
|
|
126
126
|
npx @deepseek-ai/dsh --profile qqchat
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
-
Git installs
|
|
129
|
+
Git installs use the committed `lib/` runtime artifacts, so they do not need to run
|
|
130
|
+
an install-time build. For local development:
|
|
130
131
|
|
|
131
132
|
```bash
|
|
132
133
|
git clone git@github.com:Coffeiz/dsh-qqchat.git
|
package/README.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
<p>
|
|
8
8
|
<a href="./LICENSE"><img src="https://img.shields.io/badge/License-MIT-blue.svg" alt="MIT License"></a>
|
|
9
|
-
<img src="https://img.shields.io/badge/DSH-0.1.
|
|
10
|
-
<img src="https://img.shields.io/badge/QQChat-0.2.
|
|
9
|
+
<img src="https://img.shields.io/badge/DSH-0.1.6--alpha.1-6f42c1.svg" alt="DSH 0.1.6-alpha.1">
|
|
10
|
+
<img src="https://img.shields.io/badge/QQChat-0.2.6-2ea44f.svg" alt="QQChat 0.2.6">
|
|
11
11
|
<img src="https://img.shields.io/badge/TypeScript-5.x-3178c6.svg" alt="TypeScript">
|
|
12
12
|
</p>
|
|
13
13
|
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
<p><em>dsh-qqchat 是 DeepSeek Harness(DSH)的 QQ Bot 插件,支持 QQ 群聊、私聊、会话隔离、记忆系统和 DSH 原生命令。</em></p>
|
|
21
21
|
|
|
22
|
-
<p>当前版本基于 DSH <code>0.1.
|
|
22
|
+
<p>当前版本基于 DSH <code>0.1.6-alpha.1</code> 验证,安装插件即可使用,无需修改或重新构建 DSH。</p>
|
|
23
23
|
|
|
24
24
|
> 本项目是一个 Vibe Coding 项目,代码质量和工程完整性可能需要改进。如果你发现问题或有更好的实现建议,欢迎提交 [Issue](https://github.com/Coffeiz/dsh-qqchat/issues) 或 [Pull Request](https://github.com/Coffeiz/dsh-qqchat/pulls)。
|
|
25
25
|
|
package/client-src/plugin.cts
CHANGED
|
@@ -3,12 +3,12 @@ import type { Ctx } from './shared.cjs'
|
|
|
3
3
|
import { QQSettings } from './settings.cjs'
|
|
4
4
|
import { QQSessionUtility, QQTranscriptNode, createQQMessageDefinition } from './workspace.cjs'
|
|
5
5
|
|
|
6
|
-
exports.inject = ['slots', 'connection', '
|
|
6
|
+
exports.inject = ['slots', 'connection', 'uiConversation'] as const
|
|
7
7
|
exports.apply = function apply(ctx: Ctx) {
|
|
8
8
|
setQQRpc(ctx.connection.rpc)
|
|
9
9
|
ctx.effect(installStyles, 'dsh-qqchat: client styles')
|
|
10
10
|
ctx.effect(installQQSettingsIcon, 'dsh-qqchat: QQ settings icon')
|
|
11
|
-
ctx.
|
|
11
|
+
ctx.uiConversation.events.register(createQQMessageDefinition())
|
|
12
12
|
|
|
13
13
|
ctx.slots.inject('settings.section', () => ctx.slots.register({ name: 'settings.section', id: 'qqchat', order: 35, label: () => 'QQ Chat', inject: () => ({ rpc: ctx.connection.rpc }) }, QQSettings))
|
|
14
14
|
ctx.slots.inject('conversation.chat.node', () => ctx.slots.register({ name: 'conversation.chat.node', key: 'qqchat-message' }, QQTranscriptNode))
|
package/client-src/settings.cts
CHANGED
|
@@ -25,6 +25,7 @@ export function QQSettings({ rpc }: { rpc: Rpc }) {
|
|
|
25
25
|
const [groupReplyMenuOpen, setGroupReplyMenuOpen] = useState(false)
|
|
26
26
|
const [directReplyMenuOpen, setDirectReplyMenuOpen] = useState(false)
|
|
27
27
|
const [ownerMenuOpen, setOwnerMenuOpen] = useState(false)
|
|
28
|
+
const [receiveHelpOpen, setReceiveHelpOpen] = useState(false)
|
|
28
29
|
|
|
29
30
|
const refresh = useCallback(async () => {
|
|
30
31
|
try {
|
|
@@ -168,11 +169,27 @@ export function QQSettings({ rpc }: { rpc: Rpc }) {
|
|
|
168
169
|
variant: settings.groupReceiveMode === mode ? 'primary' : 'outline',
|
|
169
170
|
onClick: () => void patch({ groupReceiveMode: mode }),
|
|
170
171
|
}, mode === 'auto' ? '自动回应' : mode === 'mention' ? '@回复' : '静默记录')))
|
|
172
|
+
const receiveHelp = h(Menu, {
|
|
173
|
+
open: receiveHelpOpen,
|
|
174
|
+
onClose: () => setReceiveHelpOpen(false),
|
|
175
|
+
onSelect: () => undefined,
|
|
176
|
+
portal: true,
|
|
177
|
+
align: 'end',
|
|
178
|
+
items: [
|
|
179
|
+
{ type: 'label', id: 'receive-help-title', text: '开启全量消息接收' },
|
|
180
|
+
{ type: 'label', id: 'receive-help-step-1', text: '1. 手机端 QQ 打开机器人所在的群' },
|
|
181
|
+
{ type: 'label', id: 'receive-help-step-2', text: '2. 点击机器人的头像进入资料页' },
|
|
182
|
+
{ type: 'label', id: 'receive-help-step-3', text: '3. 点击右上角「设置」' },
|
|
183
|
+
{ type: 'label', id: 'receive-help-step-4', text: '4. 打开「全量消息接收」' },
|
|
184
|
+
],
|
|
185
|
+
footer: [{ type: 'label', id: 'receive-help-note', text: '未开启时只能收到 @ 消息,非 @ 消息不会进入会话记录' }],
|
|
186
|
+
anchor: h(Button, { size: 'sm', variant: 'outline', onClick: () => setReceiveHelpOpen(!receiveHelpOpen) }, '设置方法'),
|
|
187
|
+
})
|
|
171
188
|
|
|
172
189
|
const receiveGroup = h('div', { className: 'qqSettingsGroup' },
|
|
173
190
|
h('h3', null, '消息接收'),
|
|
174
191
|
h('div', { className: 'qqSetting' },
|
|
175
|
-
h('div', null, h('div', { className: 'qqSettingTitle' }, '群聊接收方式'), h('div', { className: 'qqSettingHelp' }, '自动回应:每条群消息都会触发 Agent;@回复:所有消息都记录,但只有 @Bot 才唤醒 Agent;静默记录:只记录群聊与记忆,不主动回应。')),
|
|
192
|
+
h('div', null, h('div', { className: 'qqSettingTitle' }, '群聊接收方式'), h('div', { className: 'qqSettingHelp qqHelpRow' }, '自动回应:每条群消息都会触发 Agent;@回复:所有消息都记录,但只有 @Bot 才唤醒 Agent;静默记录:只记录群聊与记忆,不主动回应。', receiveHelp)),
|
|
176
193
|
h('div', { className: 'qqControl' }, receiveButtons)),
|
|
177
194
|
h('div', { className: 'qqSetting' },
|
|
178
195
|
h('div', null, h('div', { className: 'qqSettingTitle' }, '群聊消息兼容格式'), h('div', { className: 'qqSettingHelp' }, '仅控制发送到 QQ 群聊时使用的消息格式。')),
|
package/client-src/shared.cts
CHANGED
|
@@ -29,16 +29,16 @@ export interface SlotRegistry {
|
|
|
29
29
|
inject(name: string, fn: () => unknown): unknown
|
|
30
30
|
register<P>(options: Record<string, unknown>, component: import('react').ComponentType<P>): unknown
|
|
31
31
|
}
|
|
32
|
-
export interface
|
|
32
|
+
export interface UiConversation { events: { register(definition: Record<string, unknown>): unknown } }
|
|
33
33
|
export interface Ctx {
|
|
34
34
|
connection: { rpc: Rpc }
|
|
35
35
|
sessions: SessionsService
|
|
36
|
-
|
|
36
|
+
uiConversation: UiConversation
|
|
37
37
|
effect(fn: () => (() => void) | void, label: string): unknown
|
|
38
38
|
slots: SlotRegistry
|
|
39
39
|
}
|
|
40
40
|
export interface Account { id: number; appId: string; enabled: boolean; gatewayStatus: string; gatewayLastError?: string | null }
|
|
41
|
-
export interface Settings { memoryEnabled: boolean; groupReceiveMode: GroupReceiveMode; groupReplyFormat: ReplyFormat; directReplyFormat: ReplyFormat; directStreamingEnabled: boolean; groupMembersCanUseTools: boolean; groupMembersCanReceiveMedia: boolean; groupMembersCanReadMedia: boolean; ownerUserId: string }
|
|
41
|
+
export interface Settings { memoryEnabled: boolean; memoryMemberBatchEnabled: boolean; groupReceiveMode: GroupReceiveMode; groupReplyFormat: ReplyFormat; directReplyFormat: ReplyFormat; directStreamingEnabled: boolean; groupMembersCanUseTools: boolean; groupMembersCanReceiveMedia: boolean; groupMembersCanReadMedia: boolean; ownerUserId: string }
|
|
42
42
|
export interface KnownMember { id: number; platformUserId: string; displayName: string; lastSeenAt: number }
|
|
43
43
|
export interface ChatItem { chatType: ChatType; rowId: number; platformId: string; displayName: string; dshSessionId: string | null; lastMessageAt: number | null; messageCount: number }
|
|
44
44
|
export interface Memory { profile: string; summary: string; daily: string; memory: string; pattern: string }
|
|
@@ -118,7 +118,7 @@ const css = `
|
|
|
118
118
|
.qqWideModal{width:min(760px,calc(100vw - 48px));max-height:calc(100vh - 48px);min-height:0;overflow:hidden}.qqModalContent{min-height:0;overflow:auto}.qqModalContent .qqMemoryGrid{min-width:0}.qqModalContent .qqLog{overflow-wrap:anywhere;word-break:break-word}
|
|
119
119
|
`.concat('.qqQuoteSender{margin-top:4px;font-size:10px;color:var(--dsw-alias-label-secondary)}.qqMediaList{display:flex;flex-wrap:wrap;gap:6px;margin-top:7px}.qqMediaCard{display:flex;align-items:center;gap:6px;max-width:100%;padding:6px 8px;border:1px solid var(--dsw-alias-border-l1);border-radius:8px;background:var(--dsw-alias-bg-layer-1);font-size:11px}.qqMediaKind{color:var(--dsw-alias-brand-primary);font-weight:650}.qqMediaPreview{width:42px;height:42px;object-fit:cover;border-radius:6px}.qqMediaName{max-width:220px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.qqMediaSize,.qqMediaQuoted{color:var(--dsw-alias-label-secondary)}')
|
|
120
120
|
|
|
121
|
-
const qqThemeOverrides = '.qqTranscript.out .qqBubble{background:var(--dsw-
|
|
121
|
+
const qqThemeOverrides = '.qqBubble{background:var(--dsw-specific-bubble);color:var(--dsw-alias-label-primary)}.qqTranscript.out .qqBubble{background:var(--dsw-specific-bubble);color:var(--dsw-alias-label-primary)}'
|
|
122
122
|
|
|
123
123
|
export function installStyles(): () => void {
|
|
124
124
|
if (typeof document === 'undefined' || document.querySelector(`style[data-plugin-css="${STYLE_ID}"]`)) return () => {}
|
package/cordis.patch.yml
CHANGED
|
@@ -5,3 +5,8 @@
|
|
|
5
5
|
name: dsh-qqchat
|
|
6
6
|
config:
|
|
7
7
|
dataDir: !!js dshHomePath('plugins/dsh-qqchat')
|
|
8
|
+
|
|
9
|
+
# DSH 0.1.6's Connection RPC registry owns route lifetimes on the
|
|
10
|
+
# connection fiber, so that fiber must also receive the Web server service.
|
|
11
|
+
- id: connection
|
|
12
|
+
inject: [webRuntime, webServer]
|
package/docs/ARCHITECTURE.en.md
CHANGED
|
@@ -339,7 +339,7 @@ client-src/*.cts
|
|
|
339
339
|
tests/*.test.ts
|
|
340
340
|
```
|
|
341
341
|
|
|
342
|
-
The Host is built with `tsc`. The Client is compiled to temporary CJS and then wrapped by `scripts/wrap-client.mjs` as a DSH Client factory. `lib/` is generated output
|
|
342
|
+
The Host is built with `tsc`. The Client is compiled to temporary CJS and then wrapped by `scripts/wrap-client.mjs` as a DSH Client factory. `lib/` is generated release output committed with fixed revisions so DSH Store can find the runtime entry without executing third-party install scripts; source remains the implementation truth.
|
|
343
343
|
|
|
344
344
|
## Development and security documentation
|
|
345
345
|
|
package/docs/ARCHITECTURE.md
CHANGED
package/docs/DEVELOPMENT.md
CHANGED
|
@@ -60,7 +60,9 @@ client-src/*.cts -> 临时 CJS Client
|
|
|
60
60
|
临时 CJS -> lib/client.js DSH ModuleLoader factory
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
-
`lib/`
|
|
63
|
+
`lib/` 是由构建生成的发布产物,同时提交到仓库以支持 DSH Store 从固定 Commit
|
|
64
|
+
直接安装;修改源码后发布前必须重新构建并检查 `lib/` 的变更。临时 Client
|
|
65
|
+
构建目录仍是本地生成物,不提交。
|
|
64
66
|
|
|
65
67
|
## 启动 DSH Web
|
|
66
68
|
|
package/docs/MEMORY.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## 易读概述
|
|
4
4
|
|
|
5
|
-
QQChat 的 SQLite 是 QQ 世界事实来源,DSH Session 只保存 Agent 实际经历过的 turn 和展示事件。记忆反思从 SQLite 读取消息,再写回 group/member scope。
|
|
5
|
+
QQChat 的 SQLite 是 QQ 世界事实来源,DSH Session 只保存 Agent 实际经历过的 turn 和展示事件。记忆反思从 SQLite 读取消息,再写回 group/member scope。群记忆和群友批量记忆的后续调整见 [PRD-MEM-1](prds/PRD-MEM-1-群记忆与群友记忆策略调整.md)。
|
|
6
6
|
|
|
7
7
|
身份主键始终是 stable sender ID;昵称、群内称呼和历史昵称是展示或画像信息,不能替代身份主键。
|
|
8
8
|
|
|
@@ -45,12 +45,28 @@ QQChat 的 SQLite 是 QQ 世界事实来源,DSH Session 只保存 Agent 实际
|
|
|
45
45
|
|
|
46
46
|
默认配置:
|
|
47
47
|
|
|
48
|
-
-
|
|
49
|
-
-
|
|
48
|
+
- 群聊连续空闲 15 分钟后触发一次群反思
|
|
49
|
+
- 群反思不因固定消息条数立即触发;成员批量反思达到 50 条群消息时仍可提前触发
|
|
50
50
|
- 单次最多取 80 条未反思消息
|
|
51
51
|
|
|
52
|
+
当前已拆分群记忆与成员记忆:群反思只写 group scope;群友批量反思使用独立的成员游标,累计 50 条已落库群消息或空闲时触发,一次处理本批真实出现的多个成员。私聊反思使用独立的 `private-owner` 任务,并保留用户/Bot 消息方向。任务、游标和 snapshot 集成仍在持续完善。
|
|
53
|
+
|
|
54
|
+
成员批量反思可以通过运行时设置 `memoryMemberBatchEnabled` 灰度关闭;关闭只停止
|
|
55
|
+
新的群友批量调度,不删除已有成员记忆,也不影响群反思和私聊记忆。
|
|
56
|
+
|
|
52
57
|
群聊和私聊分别维护反思游标和模型路由。私聊首次没有成功 Agent 路由时不能凭空创建反思请求;需要先完成一次正常 Agent 回复。
|
|
53
58
|
|
|
59
|
+
反思任务统一使用以下 scope/task 契约:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
scope: group | member | private
|
|
63
|
+
task: group | member-batch | private-owner
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
群反思和群友批量反思共享群消息,但使用两条独立游标;私聊任务使用 member scope
|
|
67
|
+
和私聊自己的消息范围。旧数据库如果缺少成员批量游标或任务表,启动迁移会补齐
|
|
68
|
+
默认值,不会删除已有记忆或跳过未处理消息。
|
|
69
|
+
|
|
54
70
|
## 压缩策略
|
|
55
71
|
|
|
56
72
|
记忆如何进入 DSH Session 的生命周期、TTL 和 Session compact 处理,见[记忆系统上下文注入方案](./MEMORY_CONTEXT.md)。
|
|
@@ -60,7 +76,7 @@ QQChat 的 SQLite 是 QQ 世界事实来源,DSH Session 只保存 Agent 实际
|
|
|
60
76
|
| Scope | 触发条数 | 保留最近 | 压缩到 |
|
|
61
77
|
| --- | ---: | ---: | --- |
|
|
62
78
|
| member | 100 | 50 | `memory` |
|
|
63
|
-
| group |
|
|
79
|
+
| group | 200 | 100 | `memory` |
|
|
64
80
|
|
|
65
81
|
压缩模型最多使用 `memoryCompressionMaxTokens=15000`。压缩输入包含已有 memory、相关 profile/pattern 和待压缩 daily。
|
|
66
82
|
|
|
@@ -77,9 +93,21 @@ QQChat 的 SQLite 是 QQ 世界事实来源,DSH Session 只保存 Agent 实际
|
|
|
77
93
|
`@deepseek-ai/dsh-system-prompt` 来源标记。注入策略遵循“新 Session、TTL
|
|
78
94
|
过期、Session compact 后刷新”的生命周期规则,连续对话只刷新对应群或当前
|
|
79
95
|
成员的 TTL,不重复注入完整记忆。群持续活跃不会替潜水成员刷新成员 TTL。
|
|
96
|
+
每个记忆 scope 的直注入预算为 2000 个字符,daily 优先保留最新内容;超出
|
|
97
|
+
部分仍保存在 SQLite,不会因上下文裁剪而删除。
|
|
80
98
|
具体状态、hash、版本和失败处理见[记忆系统上下文注入方案](./MEMORY_CONTEXT.md)。
|
|
81
99
|
当前 QQ 消息仍作为正常 user prompt 进入 turn。
|
|
82
100
|
|
|
101
|
+
### 反思提示词策略
|
|
102
|
+
|
|
103
|
+
三类反思提示词分别对应不同的记忆主体,不共享一套模糊的“总结聊天”指令:
|
|
104
|
+
|
|
105
|
+
- **群组反思**只维护当前群的公开事实、规则、协作约定、群项目和群状态;不写成员个人资料,也不把昵称、引用、转述或推测当成群事实。
|
|
106
|
+
- **群友批量反思**先判断语义主体,再按真实 `senderId` 分配成员记忆;只允许本批实际发言且有明确个人事实的成员进入输出,群规、群项目和第三方属性留在群 scope。
|
|
107
|
+
- **私聊反思**使用消息 `direction` 作为事实边界:只有用户入站消息可以产生用户画像,BOT 出站消息只能作为上下文,不能反向证明用户的身份、偏好或经历。
|
|
108
|
+
|
|
109
|
+
三类提示词都要求增量输出、保留已有事实、使用绝对日期,并在主体不明确时宁可漏记;`profile`、`pattern`、`summary`、`daily` 和 `memory` 的字段职责分别受证据门槛约束。具体提示词实现位于 `src/storage/memory.ts`,压缩提示词则单独负责 `daily → memory` 沉淀,不参与成员主体判断。
|
|
110
|
+
|
|
83
111
|
群聊 Agent turn 注入:
|
|
84
112
|
|
|
85
113
|
```text
|
package/docs/MEMORY_CONTEXT.md
CHANGED
|
@@ -16,6 +16,22 @@ QQChat 的记忆属于 DSH Session 上下文的一部分,不脱离 Session 单
|
|
|
16
16
|
|
|
17
17
|
## 2. 记忆快照的范围
|
|
18
18
|
|
|
19
|
+
### 2.1 直注入预算
|
|
20
|
+
|
|
21
|
+
记忆快照遵循与咕咕一致的按 scope 限制策略,避免 profile、daily 或长期
|
|
22
|
+
memory 无限增长后挤占 DSH 对话上下文:
|
|
23
|
+
|
|
24
|
+
- 群级记忆字段合计最多直注入 2000 个字符;
|
|
25
|
+
- 当前发言成员的记忆字段合计最多直注入 2000 个字符;
|
|
26
|
+
- 私聊成员记忆字段合计最多直注入 2000 个字符;
|
|
27
|
+
- 近期沉淀优先保留末尾的最新内容;其他字段从开头保留;
|
|
28
|
+
- 被裁剪的内容仍保存在 SQLite 中,不会因为注入预算被删除;
|
|
29
|
+
- 预算只限制本轮 snapshot 文本,不改变 DSH Session 的历史或 compact 规则。
|
|
30
|
+
|
|
31
|
+
这里的 2000 是稳定、可预测的字符预算,不是模型输出 `maxTokens`。反思和
|
|
32
|
+
`daily → memory` 压缩仍分别使用 `memoryMaxTokens` 与
|
|
33
|
+
`memoryCompressionMaxTokens` 控制输出长度。
|
|
34
|
+
|
|
19
35
|
快照按照 Session 的聊天范围生成:
|
|
20
36
|
|
|
21
37
|
### 群聊 Session
|
package/docs/README.md
CHANGED
|
@@ -12,6 +12,8 @@ QQChat 是 DSH 的 out-of-tree QQ 官方 Bot 插件。文档按“如何开发
|
|
|
12
12
|
| [DEVELOPMENT.md](DEVELOPMENT.md) | 安装、构建、测试、启动和 UI 验证 |
|
|
13
13
|
| [MEMORY.md](MEMORY.md) | group/member scope、daily、memory、反思和压缩 |
|
|
14
14
|
| [MEMORY_CONTEXT.md](MEMORY_CONTEXT.md) | DSH Session 内的记忆快照、TTL、compact 刷新和注入生命周期 |
|
|
15
|
+
| [prds/README.md](prds/README.md) | PRD 撰写规范和产品需求文档导航 |
|
|
16
|
+
| [prds/PRD-MEM-1-群记忆与群友记忆策略调整.md](prds/PRD-MEM-1-群记忆与群友记忆策略调整.md) | 基于 Gugu 策略的群记忆、群友批量记忆和私聊记忆调整计划 |
|
|
15
17
|
| [MEDIA_AND_QUOTES.md](MEDIA_AND_QUOTES.md) | 媒体输入、引用消息、附件存储、安全和分阶段实现方案 |
|
|
16
18
|
| [QUOTES.md](QUOTES.md) | QQ 引用索引、引用回填、附件复用和 Web 展示实施方案 |
|
|
17
19
|
| [STREAMING.md](STREAMING.md) | QQ 私聊官方流式传输、队列、降级和故障复盘 |
|
package/docs/STREAMING.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
推荐采用以下结构:
|
|
12
12
|
|
|
13
13
|
```text
|
|
14
|
-
DSH assistant
|
|
14
|
+
DSH `agent/assistant-stream` 的 chunk frame
|
|
15
15
|
-> StreamingWriter
|
|
16
16
|
-> 累计完整文本
|
|
17
17
|
-> 节流定时器
|
|
@@ -118,7 +118,7 @@ interface StreamingWriterState {
|
|
|
118
118
|
|
|
119
119
|
### 2. 累计全文,不累计分片
|
|
120
120
|
|
|
121
|
-
DSH 的 `assistant
|
|
121
|
+
DSH 的 `agent/assistant-stream` chunk frame 通常携带增量文本:
|
|
122
122
|
|
|
123
123
|
```text
|
|
124
124
|
"你好"
|