@roaming-ai/dsh-group-chat 0.2.1 → 0.3.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/README.md +3 -2
- package/lib/client.js +986 -298
- package/lib/client.js.map +1 -1
- package/lib/index.js +524 -52
- package/lib/types/client/components/Bubble.d.ts +6 -3
- package/lib/types/client/components/ChatPanel.d.ts +1 -0
- package/lib/types/client/components/ConstraintList.d.ts +11 -0
- package/lib/types/client/components/FailCard.d.ts +9 -0
- package/lib/types/client/components/Fold.d.ts +19 -0
- package/lib/types/client/components/HoverTip.d.ts +22 -0
- package/lib/types/client/components/MessageFlow.d.ts +1 -0
- package/lib/types/client/components/MsgActions.d.ts +14 -0
- package/lib/types/client/hooks/useComposer.d.ts +6 -1
- package/lib/types/client/lib/composer-draft.d.ts +17 -0
- package/lib/types/core/constraints.d.ts +61 -0
- package/lib/types/core/errors.d.ts +54 -0
- package/lib/types/core/types.d.ts +22 -0
- package/lib/types/host/api/actions.d.ts +1 -1
- package/lib/types/host/engine/conversation.d.ts +5 -3
- package/lib/types/host/engine/fold.d.ts +17 -0
- package/lib/types/host/engine/index.d.ts +1 -0
- package/lib/types/host/engine/retitle.d.ts +5 -5
- package/lib/types/host/service.d.ts +1 -1
- package/lib/types/host/state.d.ts +2 -0
- package/lib/types/index.d.ts +2 -0
- package/package.json +1 -1
- package/src/client/GroupChatPanel.tsx +18 -3
- package/src/client/components/AsidePanel.tsx +10 -8
- package/src/client/components/Bubble.tsx +45 -18
- package/src/client/components/ChatPanel.tsx +17 -12
- package/src/client/components/Composer.tsx +26 -20
- package/src/client/components/ConstraintList.tsx +69 -0
- package/src/client/components/FailCard.tsx +49 -0
- package/src/client/components/Fold.tsx +72 -0
- package/src/client/components/HoverTip.tsx +134 -0
- package/src/client/components/MessageFlow.tsx +77 -54
- package/src/client/components/MsgActions.tsx +85 -0
- package/src/client/components/NavPanel.tsx +6 -1
- package/src/client/components/ThinkRow.tsx +7 -3
- package/src/client/components/ToolRow.tsx +7 -3
- package/src/client/hooks/useComposer.ts +40 -3
- package/src/client/hooks/useGroupChatState.ts +5 -4
- package/src/client/lib/composer-draft.ts +47 -0
- package/src/client/lib/styles.ts +74 -13
- package/src/client/react-dom-shim.d.ts +2 -0
- package/src/core/constraints.ts +210 -0
- package/src/core/errors.ts +184 -0
- package/src/core/json.ts +1 -0
- package/src/core/types.ts +28 -3
- package/src/host/api/actions.ts +35 -1
- package/src/host/broadcast.ts +3 -3
- package/src/host/engine/conversation.ts +103 -38
- package/src/host/engine/fold.ts +114 -0
- package/src/host/engine/index.ts +1 -0
- package/src/host/engine/retitle.ts +16 -11
- package/src/host/persistence/persistence.ts +18 -1
- package/src/host/service.ts +1 -1
- package/src/host/state.ts +5 -4
- package/src/index.ts +2 -0
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { existsSync } from 'node:fs'
|
|
8
|
+
import { repairFailedMessage } from '../../core/errors.ts'
|
|
8
9
|
import { messageJson, roleJson } from '../../core/json.ts'
|
|
10
|
+
import { sanitizeConstraints } from '../../core/constraints.ts'
|
|
9
11
|
import { asNumber, migrateTier } from '../../core/types.ts'
|
|
10
12
|
import type { GroupRecord, MessageRecord, RoleRecord, SessionRecord } from '../../core/types.ts'
|
|
11
13
|
import { emptyGroup, LedgerDocument, scanGroupIds, scanSessionIds, STORE_DIR, Store } from './store.ts'
|
|
@@ -17,6 +19,8 @@ interface SessionDocument {
|
|
|
17
19
|
topic?: string
|
|
18
20
|
namePinned?: boolean
|
|
19
21
|
topicPinned?: boolean
|
|
22
|
+
constraints?: unknown
|
|
23
|
+
constraintsUpToSeq?: number
|
|
20
24
|
createdAt?: number
|
|
21
25
|
messages?: Partial<MessageRecord>[]
|
|
22
26
|
}
|
|
@@ -74,6 +78,8 @@ export function createPersistence(core: HostState): Persistence {
|
|
|
74
78
|
topic: s.topic,
|
|
75
79
|
...(s.namePinned ? { namePinned: true } : {}),
|
|
76
80
|
...(s.topicPinned ? { topicPinned: true } : {}),
|
|
81
|
+
...(s.constraints && s.constraints.length ? { constraints: s.constraints } : {}),
|
|
82
|
+
...(typeof s.constraintsUpToSeq === 'number' && s.constraintsUpToSeq > 0 ? { constraintsUpToSeq: s.constraintsUpToSeq } : {}),
|
|
77
83
|
createdAt: s.createdAt,
|
|
78
84
|
messages: s.messageIds.map((mid) => core.messages.get(mid)).filter(Boolean).map((m) => messageJson(m)).filter(Boolean),
|
|
79
85
|
})
|
|
@@ -178,6 +184,9 @@ export function createPersistence(core: HostState): Persistence {
|
|
|
178
184
|
if (typeof doc.topic === 'string') sess.topic = doc.topic
|
|
179
185
|
if (doc.namePinned === true) sess.namePinned = true
|
|
180
186
|
if (doc.topicPinned === true) sess.topicPinned = true
|
|
187
|
+
const constraints = sanitizeConstraints(doc.constraints)
|
|
188
|
+
if (constraints.length) sess.constraints = constraints
|
|
189
|
+
if (typeof doc.constraintsUpToSeq === 'number' && doc.constraintsUpToSeq > 0) sess.constraintsUpToSeq = doc.constraintsUpToSeq
|
|
181
190
|
if (typeof doc.createdAt === 'number') sess.createdAt = doc.createdAt
|
|
182
191
|
let fallbackSeq = 0
|
|
183
192
|
for (const m of (Array.isArray(doc.messages) ? doc.messages : [])) {
|
|
@@ -194,11 +203,19 @@ export function createPersistence(core: HostState): Persistence {
|
|
|
194
203
|
thinkingSummary: m.thinkingSummary !== undefined ? String(m.thinkingSummary) : undefined,
|
|
195
204
|
model: m.model,
|
|
196
205
|
error: m.error,
|
|
206
|
+
failedRoleId: typeof m.failedRoleId === 'string' && m.failedRoleId ? m.failedRoleId : undefined,
|
|
197
207
|
toolCalls: Array.isArray(m.toolCalls) ? m.toolCalls : undefined,
|
|
198
208
|
ts: typeof m.ts === 'number' ? m.ts : Date.now(),
|
|
199
209
|
})
|
|
200
210
|
sess.messageIds.push(m.id)
|
|
201
211
|
}
|
|
212
|
+
const groupRoles = g.roleIds.map((rid) => core.roles.get(rid)).filter((r): r is RoleRecord => Boolean(r))
|
|
213
|
+
let repaired = false
|
|
214
|
+
for (const mid of sess.messageIds) {
|
|
215
|
+
const rec = core.messages.get(mid)
|
|
216
|
+
if (rec && repairFailedMessage(rec, groupRoles)) repaired = true
|
|
217
|
+
}
|
|
218
|
+
if (repaired) schedulePersist({ session: sid })
|
|
202
219
|
}
|
|
203
220
|
core.sessions.set(sid, sess)
|
|
204
221
|
g.sessionIds.push(sid)
|
|
@@ -274,7 +291,7 @@ export function createPersistence(core: HostState): Persistence {
|
|
|
274
291
|
if (core.groups.size === 0) {
|
|
275
292
|
const g: GroupRecord = { id: core.nid('grp'), name: '默认群组', workspaceDir: '', permissionTier: 'view_only', roleIds: [], sessionIds: [] }
|
|
276
293
|
core.groups.set(g.id, g)
|
|
277
|
-
const sess = core.newSession(g.id
|
|
294
|
+
const sess = core.newSession(g.id)
|
|
278
295
|
g.sessionIds.push(sess.id)
|
|
279
296
|
autoSessions.push(sess.id)
|
|
280
297
|
}
|
package/src/host/service.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* persistence/ 持久化(store 文件原语 + 脏标记合并落盘 + 启动恢复)
|
|
7
7
|
* materials/ 资料读取与路径解析 + 目录浏览器
|
|
8
8
|
* tools/ 工具执行(沙箱 + 确认闸门)
|
|
9
|
-
* engine/ 对话引擎(conversation:speak/runLoop;retitle
|
|
9
|
+
* engine/ 对话引擎(conversation:speak/runLoop;retitle:标题整理;fold:窗口外约束)
|
|
10
10
|
* api/ HTTP 传输(http 护栏 + routes 路由)与动作分发(actions)
|
|
11
11
|
* @module dsh-group-chat/host/service
|
|
12
12
|
*/
|
package/src/host/state.ts
CHANGED
|
@@ -28,6 +28,9 @@ declare module '@deepseek-ai/cordis' {
|
|
|
28
28
|
/** 角色标识色板(新增角色依序取色)。 */
|
|
29
29
|
export const PALETTE = ['#5b8def', '#22a06b', '#e8912d', '#c678dd', '#e05661', '#56b6c2', '#98c379', '#d19a66']
|
|
30
30
|
|
|
31
|
+
/** 新建会话默认名称(自动标题只在仍为此占位名时生成一次)。 */
|
|
32
|
+
export const DEFAULT_SESSION_NAME = '新会话'
|
|
33
|
+
|
|
31
34
|
/** 宿主服务共享状态容器(见模块注释;可变原始值一律经 core.* 访问)。 */
|
|
32
35
|
export interface HostState {
|
|
33
36
|
ctx: Context
|
|
@@ -60,19 +63,17 @@ export function createHostState(ctx: Context): HostState {
|
|
|
60
63
|
sessions: new Map(),
|
|
61
64
|
roles: new Map(),
|
|
62
65
|
messages: new Map(),
|
|
63
|
-
run: { running: false, sessionId: null, currentRoleId: null, partial: '', partialReasoning: '', stopping: false, queue: [], pendingConfirm: null, confirmSignal: null, childProc: null, finished: null },
|
|
66
|
+
run: { running: false, sessionId: null, currentRoleId: null, partial: '', partialReasoning: '', stopping: false, queue: [], pendingConfirm: null, confirmSignal: null, childProc: null, finished: null, replaceMessageId: null },
|
|
64
67
|
store: null,
|
|
65
68
|
revision: 1,
|
|
66
69
|
idSeq: 1,
|
|
67
70
|
nid: (p: string): string => p + '-' + (core.idSeq++),
|
|
68
71
|
lastCreated: null,
|
|
69
72
|
newSession: (groupId: string, name?: string): SessionRecord => {
|
|
70
|
-
let n = 0
|
|
71
|
-
for (const s of core.sessions.values()) if (s.groupId === groupId) n++
|
|
72
73
|
const s: SessionRecord = {
|
|
73
74
|
id: randomUUID(),
|
|
74
75
|
groupId,
|
|
75
|
-
name: name ||
|
|
76
|
+
name: name || DEFAULT_SESSION_NAME,
|
|
76
77
|
topic: '',
|
|
77
78
|
messageIds: [],
|
|
78
79
|
createdAt: Date.now(),
|
package/src/index.ts
CHANGED
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* 数据模型:Group 1..N Session,消息挂在会话上;角色与工作区目录挂在群组上
|
|
11
11
|
* - 群组与会话的增删改;群组/会话检索由客户端在快照上过滤
|
|
12
12
|
* - 角色发言经 `llm` 服务流式生成,按角色绑定的 provider/model 路由
|
|
13
|
+
* - 整次 runLoop 结束后后台折叠被 40 条窗口挤出的消息为会话级约束备忘
|
|
14
|
+
* (engine/fold.ts;立刻 idle、fire-and-forget,不产生消息)
|
|
13
15
|
* - 群组工作区目录经 `fs` 服务读取(根下一层文本文件,最多 20 个),
|
|
14
16
|
* 以「共享资料」块注入每个角色的 system 提示词;无独立笔记/文件清单
|
|
15
17
|
* - 经 `webServer` 暴露 HTTP API:
|