dsh-qqchat 0.2.5 → 0.2.7

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.
@@ -3,7 +3,7 @@ import { createRequire } from 'node:module'
3
3
  import type { Context } from '@deepseek-ai/cordis'
4
4
  import { installModelSelection } from '@deepseek-ai/dsh-agent'
5
5
  import type { AgentHandle, AgentOptions, AgentSetup, ModelSelectionRef } from '@deepseek-ai/dsh-agent'
6
- import { resolveSessionPreset } from '@deepseek-ai/dsh-agent-presets'
6
+ import { agentPresetProjectionDefinition } from '@deepseek-ai/dsh-agent-presets'
7
7
  import { createUserMessage } from '@deepseek-ai/dsh-llm'
8
8
  import type { ContentBlock } from '@deepseek-ai/dsh-llm'
9
9
  import type { CommandInvocation, CommandRuntime, CommandResult } from '@deepseek-ai/dsh-commands'
@@ -41,12 +41,15 @@ interface SessionPersistenceService { inspect(id: SessionId): Promise<{ meta: Se
41
41
  interface SessionTitleService { get(session: Session): unknown; rename(session: Session, title: string): unknown }
42
42
  interface WorkspaceRegistryService {
43
43
  archivedSessionIds: readonly string[]
44
+ resolveByPath(path: string): Promise<{ attachSession(sessionId: import('@deepseek-ai/dsh-session').SessionId): Promise<void> } | undefined>
44
45
  }
45
46
  interface Composition { presetId?: string; setup?: AgentSetup }
46
47
  interface ActiveActor { chatType: ChatType; senderId: string }
47
48
 
48
49
  export function resolveQQSessionPreset(header: Session['header'], events: readonly SessionEvent[]): string | undefined {
49
- return resolveSessionPreset({ header, events })
50
+ let current = agentPresetProjectionDefinition.init(header)
51
+ for (const event of events) current = agentPresetProjectionDefinition.apply(current, event)
52
+ return current || undefined
50
53
  }
51
54
 
52
55
  const MEDIA_TOOL_NAMES = new Set(['qqchat_describe_image', 'qqchat_read_file', 'qqchat_media_info'])
@@ -65,6 +68,7 @@ export class DshQQBridge {
65
68
  private readonly activeMediaReadable = new Map<string, boolean>()
66
69
  private readonly memorySnapshots = new Map<string, MemorySnapshotState>()
67
70
  private readonly disposeEvent: () => void
71
+ private readonly disposeAssistantStream: () => void
68
72
  private readonly disposeToolGate: () => void
69
73
  private readonly disposeCommands: () => void
70
74
  private readonly disposeImageTool: () => void
@@ -78,6 +82,10 @@ export class DshQQBridge {
78
82
  private readonly logger: LoggerLike = console,
79
83
  ) {
80
84
  this.disposeEvent = ctx.on('session/event', (session, event) => this.onSessionEvent(session, event))
85
+ this.disposeAssistantStream = ctx.on('agent/assistant-stream', ({ agent, frame }) => {
86
+ if (frame.type !== 'chunk' || frame.chunk.type !== 'text-delta' || !frame.chunk.text) return
87
+ this.pending.get(String(agent.id))?.onTextDelta?.(frame.chunk.text)
88
+ })
81
89
  this.disposeToolGate = ctx.on('tools/pre-execute', async (exec, next): Promise<PreToolDecision> => {
82
90
  const agent = exec.agent
83
91
  if (!agent) return next()
@@ -100,8 +108,19 @@ export class DshQQBridge {
100
108
  this.disposeCommands = this.registerCommands()
101
109
  }
102
110
 
111
+ async attachMappedSessionsToWorkspace(): Promise<void> {
112
+ const sessionIds = [
113
+ ...this.db.listGroups().map(row => row.dsh_session_id),
114
+ ...this.db.listDirectChats().map(row => row.dsh_session_id),
115
+ ]
116
+ for (const sessionId of sessionIds) {
117
+ if (sessionId) await this.attachToWorkspace(sessionId)
118
+ }
119
+ }
120
+
103
121
  async dispose(): Promise<void> {
104
122
  this.disposeEvent()
123
+ this.disposeAssistantStream()
105
124
  this.disposeToolGate()
106
125
  this.disposeImageTool()
107
126
  this.disposeMediaTools()
@@ -129,15 +148,6 @@ export class DshQQBridge {
129
148
  if (!existing && !createSession) return undefined
130
149
  const { agent, sessionId } = await this.ensureAgent(event.chatType, row)
131
150
  event.sessionId = sessionId
132
- if (event.isOwner) {
133
- // Keep owner messages as native user/message events even when they carry
134
- // images. DSH now owns the image projection: visual routes receive the
135
- // durable image block, while text-only routes receive its stable text
136
- // placeholder. Falling back to a display-only event here would discard
137
- // the owner's message semantics before DSH can apply that policy.
138
- this.appendOwnerMessageIfMissing(agent.session, event)
139
- return sessionId
140
- }
141
151
  this.appendDisplayIfMissing(agent.session, event)
142
152
  return sessionId
143
153
  }
@@ -235,12 +245,6 @@ export class DshQQBridge {
235
245
  if (text.trim()) pending.text = text
236
246
  return
237
247
  }
238
- if (event.type === 'assistant/chunk') {
239
- const pending = this.pending.get(id)
240
- const chunk = event.data.chunk
241
- if (pending?.onTextDelta && chunk.type === 'text-delta' && chunk.text) pending.onTextDelta(chunk.text)
242
- return
243
- }
244
248
  if (event.type === 'request/header') {
245
249
  const { config } = event.data.header
246
250
  if (config.provider && config.model) this.routes.set(id, { provider: config.provider, model: config.model })
@@ -271,7 +275,7 @@ export class DshQQBridge {
271
275
  }
272
276
 
273
277
  private restoreMemorySnapshot(session: Session): MemorySnapshotState | undefined {
274
- return restoreMemorySnapshotState(session.events as unknown as Parameters<typeof restoreMemorySnapshotState>[0], DSH_RUNTIME_CONTEXT_SOURCE)
278
+ return restoreMemorySnapshotState(session.snapshotEvents() as unknown as Parameters<typeof restoreMemorySnapshotState>[0], DSH_RUNTIME_CONTEXT_SOURCE)
275
279
  }
276
280
 
277
281
  private async ensureAgent(chatType: ChatType, row: GroupRow | MemberRow): Promise<{ agent: AgentHandle['agent']; sessionId: string }> {
@@ -292,6 +296,7 @@ export class DshQQBridge {
292
296
  if (live) {
293
297
  this.ensureSelection(live)
294
298
  this.ensureTitle(live.session, chatType, row)
299
+ await this.attachToWorkspace(sessionId)
295
300
  this.rememberRoute(chatType, row, live, sessionId)
296
301
  return { agent: live, sessionId }
297
302
  }
@@ -299,6 +304,7 @@ export class DshQQBridge {
299
304
  if (resumed) {
300
305
  this.ensureSelection(resumed.agent)
301
306
  this.ensureTitle(resumed.agent.session, chatType, row)
307
+ await this.attachToWorkspace(sessionId)
302
308
  this.rememberRoute(chatType, row, resumed.agent, sessionId)
303
309
  return { agent: resumed.agent, sessionId }
304
310
  }
@@ -317,6 +323,7 @@ export class DshQQBridge {
317
323
  this.handles.set(sessionId, handle)
318
324
  this.ensureSelection(handle.agent)
319
325
  this.db.setChatSession(chatType, Number(row.id), sessionId)
326
+ await this.attachToWorkspace(sessionId)
320
327
  this.ensureTitle(handle.agent.session, chatType, row)
321
328
  this.rememberRoute(chatType, row, handle.agent, sessionId)
322
329
  return { agent: handle.agent, sessionId }
@@ -327,6 +334,17 @@ export class DshQQBridge {
327
334
  return registry?.archivedSessionIds.includes(sessionId) ?? false
328
335
  }
329
336
 
337
+ private async attachToWorkspace(sessionId: string): Promise<void> {
338
+ const registry = (this.ctx as unknown as { workspaceRegistry?: WorkspaceRegistryService }).workspaceRegistry
339
+ if (!registry) return
340
+ try {
341
+ const workspace = await registry.resolveByPath(process.cwd())
342
+ await workspace?.attachSession(SessionId(sessionId))
343
+ } catch (error) {
344
+ this.logger.warn?.(`[dsh-qqchat] QQ session ${sessionId} 未能挂载到当前工作区: ${error instanceof Error ? error.message : String(error)}`)
345
+ }
346
+ }
347
+
330
348
  private rememberRoute(chatType: ChatType, row: GroupRow | MemberRow, agent: AgentHandle['agent'], sessionId: string): void {
331
349
  const provider = agent.options.provider || this.config.provider
332
350
  const model = agent.options.model || this.config.model
@@ -336,7 +354,7 @@ export class DshQQBridge {
336
354
  }
337
355
 
338
356
  private appendDisplayIfMissing(session: Session, event: QQChatDisplayEvent): void {
339
- if (session.events.some(item => item.type === 'qqchat/message' && item.data.messageId === event.messageId)) return
357
+ if (session.snapshotEvents().some(item => item.type === 'qqchat/message' && item.data.messageId === event.messageId)) return
340
358
  // Keep this on the public Session.append signature. Official DSH releases
341
359
  // do not yet expose the optional ignorable envelope marker; if an older
342
360
  // DSH cannot restore this plugin-only event, ensureAgent falls back to a
@@ -344,23 +362,6 @@ export class DshQQBridge {
344
362
  session.append('qqchat/message', displayEventPayload(event))
345
363
  }
346
364
 
347
- private appendOwnerMessageIfMissing(session: Session, event: QQChatDisplayEvent): void {
348
- if (session.events.some(item => {
349
- if (item.type !== 'user/message') return false
350
- const source = item.data.source as unknown as { messageId?: string }
351
- return source.messageId === event.messageId
352
- })) return
353
- session.append('user/message', createUserMessage({
354
- source: {
355
- kind: 'user', channel: 'qq', botId: 'qqchat', chatType: event.chatType,
356
- chatId: event.chatId, senderId: event.senderId,
357
- ...(event.senderName ? { senderName: event.senderName } : {}),
358
- messageId: event.messageId, mentioned: event.mentioned,
359
- },
360
- content: transcriptContent(event, this.db),
361
- }), { surfaceOp: 'append' })
362
- }
363
-
364
365
  private ensureTitle(session: Session, chatType: ChatType, row: GroupRow | MemberRow): void {
365
366
  try {
366
367
  const getService = (this.ctx as unknown as { get?: (name: string) => unknown }).get
@@ -521,7 +522,7 @@ export class DshQQBridge {
521
522
  const available = await presets.list()
522
523
  return { kind: 'success', text: available.length ? `可用 Agent Preset:\n${available.map(preset => `/qqpreset ${preset.id}`).join('\n')}` : '当前没有可用 Agent Preset。' }
523
524
  }
524
- if (agent.session.events.some(event => event.type === 'turn/start')) {
525
+ if (agent.session.snapshotEvents().some(event => event.type === 'turn/start')) {
525
526
  return { kind: 'error', text: '当前 Session 已经开始对话,DSH 不允许更换 Agent Preset。请先使用 /qqnew 开启新 Session。' }
526
527
  }
527
528
  try {
@@ -539,8 +540,9 @@ export class DshQQBridge {
539
540
 
540
541
  private statusCommand(agent: AgentHandle['agent']): CommandResult {
541
542
  const current = this.selection(agent)?.current
542
- const messages = agent.session.events.filter(event => event.type === 'user/message' || event.type === 'assistant/message').length
543
- const last = agent.session.events.at(-1)
543
+ const events = agent.session.snapshotEvents()
544
+ const messages = events.filter(event => event.type === 'user/message' || event.type === 'assistant/message').length
545
+ const last = events.at(-1)
544
546
  return {
545
547
  kind: 'success',
546
548
  text: ['📊 Session 状态', `Session:${String(agent.id)}`, `状态:${agent.status === 'running' ? '生成中' : '空闲'}`, `模型:${current ? `${current.provider}/${current.model}` : '未知'}`, `消息数:${messages}`, `最后事件:${last?.type || '无'}`].join('\n'),
@@ -604,36 +606,6 @@ export function qqMessageContent(text: string, attachments: readonly StoredAttac
604
606
  return content
605
607
  }
606
608
 
607
- function transcriptContent(event: QQChatDisplayEvent, db: QQChatDatabase): ContentBlock[] {
608
- const attachments = event.attachments || []
609
- const renderableImages = attachments.filter(attachment => attachment.kind === 'image' && db.attachmentById(attachment.id)?.imageRef)
610
- const imagePlaceholderLines = new Set(renderableImages.map(attachment => `[图片] ${attachment.filename}`))
611
- const quote = event.quote ? formatDisplayQuote(event) : ''
612
- const body = event.content.split('\n').filter(line => !imagePlaceholderLines.has(line)).join('\n').trim()
613
- const text = [quote, body].filter(Boolean).join('\n\n')
614
- const content: ContentBlock[] = [{ type: 'text', text }]
615
- for (const attachment of attachments) {
616
- const imageRef = attachment.kind === 'image' ? db.attachmentById(attachment.id)?.imageRef : undefined
617
- if (imageRef) {
618
- content.push({ type: 'image', attachment: imageRef })
619
- }
620
- }
621
- return content
622
- }
623
-
624
- function formatDisplayQuote(event: QQChatDisplayEvent): string {
625
- const quote = event.quote
626
- if (!quote) return ''
627
- return [
628
- '[引用消息]',
629
- quote.senderId ? `发送人ID=${quote.senderId}` : '',
630
- quote.senderName ? `显示名=${quote.senderName}` : '',
631
- quote.messageId ? `消息ID=${quote.messageId}` : '',
632
- `正文=${quote.text || '(空消息)'}`,
633
- quote.attachments.length ? `附件=${quote.attachments.map(attachment => `${attachment.kind || 'file'}:${attachment.filename}${attachment.attachmentId ? ` (attachment_id=${attachment.attachmentId})` : ''}`).join('、')}` : '',
634
- ].filter(Boolean).join('\n')
635
- }
636
-
637
609
  function displayEventPayload(event: QQChatDisplayEvent): QQChatDisplayEvent {
638
610
  const attachments = (event.attachments || []).map(attachment => ({
639
611
  id: String(attachment.id), kind: attachment.kind, filename: String(attachment.filename),
@@ -9,6 +9,7 @@ import type { QQApiClient } from '../gateway/api.js'
9
9
  import type { QQBindService } from '../gateway/auth.js'
10
10
  import { QQGateway } from '../gateway/gateway.js'
11
11
  import { renderQQMentionNames } from '../gateway/normalize.js'
12
+ import { qqCommandText } from '../commands/dispatch.js'
12
13
  import { QQMediaStore } from '../media/store.js'
13
14
  import type {
14
15
  AccountRow, ChatTargetRow, ChatType, GroupReceiveMode, GroupRow, MemberRow, QQAttachmentInput, QQChatConfig,
@@ -29,6 +30,7 @@ export class QQChatRuntime {
29
30
  ) {}
30
31
 
31
32
  async start(): Promise<void> {
33
+ await this.bridge.attachMappedSessionsToWorkspace()
32
34
  for (const account of this.db.enabledAccounts()) this.startGateway(account)
33
35
  this.outboxTimer = setInterval(() => void this.flushOutbox(), 3000)
34
36
  this.outboxTimer.unref?.()
@@ -51,9 +53,7 @@ export class QQChatRuntime {
51
53
  }
52
54
 
53
55
  settings(): QQChatRuntimeSettings {
54
- const settings = this.db.runtimeSettings(defaultRuntimeSettings(this.config))
55
- if (settings.directReplyFormat === 'compat') settings.directStreamingEnabled = false
56
- return settings
56
+ return this.db.runtimeSettings(defaultRuntimeSettings(this.config))
57
57
  }
58
58
 
59
59
  updateSettings(patch: QQChatRuntimeSettingsPatch): QQChatRuntimeSettings {
@@ -70,9 +70,7 @@ export class QQChatRuntime {
70
70
  if (patch.directReplyFormat !== undefined) {
71
71
  if (!isReplyFormat(patch.directReplyFormat)) throw new Error('无效的私聊消息兼容格式')
72
72
  this.db.setSetting('directReplyFormat', patch.directReplyFormat)
73
- if (patch.directReplyFormat === 'compat') this.db.setSetting('directStreamingEnabled', false)
74
73
  }
75
- if (patch.directStreamingEnabled !== undefined) this.db.setSetting('directStreamingEnabled', Boolean(patch.directStreamingEnabled))
76
74
  if (patch.groupMembersCanUseTools !== undefined) this.db.setSetting('groupMembersCanUseTools', Boolean(patch.groupMembersCanUseTools))
77
75
  if (patch.groupMembersCanReceiveMedia !== undefined) this.db.setSetting('groupMembersCanReceiveMedia', Boolean(patch.groupMembersCanReceiveMedia))
78
76
  if (patch.groupMembersCanReadMedia !== undefined) this.db.setSetting('groupMembersCanReadMedia', Boolean(patch.groupMembersCanReadMedia))
@@ -251,22 +249,21 @@ export class QQChatRuntime {
251
249
  }
252
250
  }
253
251
 
254
- if (!shouldReply) {
252
+ if (shouldRecordQQTranscript(shouldReply, message.text, message.mentioned)) {
255
253
  await this.bridge.recordTranscript(displayEvent, row, true)
254
+ }
255
+ if (!shouldReply) {
256
256
  return
257
257
  }
258
258
 
259
259
  try {
260
- // Keep the incoming QQ message visible in Web independently from the
261
- // notice-shaped message used to drive the Agent turn.
262
- await this.bridge.recordTranscript(displayEvent, row, true)
263
260
  const targetId = message.chatType === 'group' ? message.groupOpenid! : message.senderId
264
261
  const sendOptions = {
265
262
  group: message.chatType === 'group', messageId: message.messageId || null,
266
263
  format: message.chatType === 'group' ? settings.groupReplyFormat : settings.directReplyFormat,
267
264
  } as const
268
- const stream = message.chatType === 'c2c' && settings.directReplyFormat !== 'compat' && settings.directStreamingEnabled
269
- ? this.api.createPrivateTextStream(account, targetId, sendOptions)
265
+ const stream = message.chatType === 'c2c' && settings.directReplyFormat === 'markdown'
266
+ ? this.api.createPrivateTextStream(account, targetId, { messageId: sendOptions.messageId })
270
267
  : undefined
271
268
  const reply = await this.bridge.reply(message, group, member, storedAttachments, stream ? delta => stream.push(delta) : undefined, isOwner)
272
269
  if (stream) {
@@ -319,11 +316,15 @@ export class QQChatRuntime {
319
316
  }
320
317
 
321
318
  function isGroupReceiveMode(value: unknown): value is GroupReceiveMode { return value === 'auto' || value === 'mention' || value === 'silent' }
322
- function isReplyFormat(value: unknown): value is ReplyFormat { return value === 'smart' || value === 'markdown' || value === 'compat' }
319
+ function isReplyFormat(value: unknown): value is ReplyFormat { return value === 'markdown' || value === 'compat' }
323
320
  export function shouldReplyToGroup(mode: GroupReceiveMode, group: Pick<GroupRow, 'enabled' | 'read_enabled'>, mentioned: boolean): boolean {
324
321
  if (group.enabled !== 1 || group.read_enabled !== 1) return false
325
322
  return mode === 'auto' || (mode === 'mention' && mentioned)
326
323
  }
324
+ /** Record messages that do not enter the Agent turn, plus QQ commands handled outside Agent.followup. */
325
+ export function shouldRecordQQTranscript(shouldReply: boolean, text: string, mentioned: boolean): boolean {
326
+ return !shouldReply || qqCommandText(text, mentioned) !== undefined
327
+ }
327
328
  function shortId(value: string): string { return value.length > 10 ? `…${value.slice(-10)}` : value }
328
329
  function publicAttachments(attachments: StoredAttachmentSummary[]): StoredAttachmentSummary[] {
329
330
  return attachments.map(attachment => ({
package/src/storage/db.ts CHANGED
@@ -264,6 +264,9 @@ export class QQChatDatabase {
264
264
  error TEXT
265
265
  );
266
266
  `)
267
+ this.db.prepare("UPDATE plugin_settings SET value='\"markdown\"',updated_at=? WHERE key IN ('replyFormat','groupReplyFormat','directReplyFormat') AND value='\"smart\"'")
268
+ .run(now())
269
+ this.db.prepare("DELETE FROM plugin_settings WHERE key='directStreamingEnabled'").run()
267
270
  this.db.prepare("UPDATE reflection_tasks SET status='failed',updated_at=? WHERE status='running' AND updated_at<?")
268
271
  .run(now(), now() - REFLECTION_TASK_STALE_MS)
269
272
  const columns = new Set(many<{ name: string }>(this.db.prepare('PRAGMA table_info(group_members)').all()).map(column => column.name))
@@ -396,13 +399,16 @@ export class QQChatDatabase {
396
399
  }
397
400
 
398
401
  runtimeSettings(defaults: QQChatRuntimeSettings): QQChatRuntimeSettings {
402
+ const legacyReplyFormat = normalizeReplyFormat(
403
+ this.getSetting<unknown>('replyFormat', defaults.directReplyFormat),
404
+ defaults.directReplyFormat,
405
+ )
399
406
  return {
400
407
  memoryEnabled: this.getSetting('memoryEnabled', defaults.memoryEnabled),
401
408
  memoryMemberBatchEnabled: this.getSetting('memoryMemberBatchEnabled', defaults.memoryMemberBatchEnabled),
402
409
  groupReceiveMode: this.getSetting('groupReceiveMode', defaults.groupReceiveMode),
403
- groupReplyFormat: this.getSetting('groupReplyFormat', defaults.groupReplyFormat),
404
- directReplyFormat: this.getSetting('directReplyFormat', this.getSetting('replyFormat', defaults.directReplyFormat)),
405
- directStreamingEnabled: this.getSetting('directStreamingEnabled', defaults.directStreamingEnabled),
410
+ groupReplyFormat: normalizeReplyFormat(this.getSetting<unknown>('groupReplyFormat', defaults.groupReplyFormat), defaults.groupReplyFormat),
411
+ directReplyFormat: normalizeReplyFormat(this.getSetting<unknown>('directReplyFormat', legacyReplyFormat), legacyReplyFormat),
406
412
  groupMembersCanUseTools: this.getSetting('groupMembersCanUseTools', defaults.groupMembersCanUseTools),
407
413
  groupMembersCanReceiveMedia: this.getSetting('groupMembersCanReceiveMedia', defaults.groupMembersCanReceiveMedia),
408
414
  groupMembersCanReadMedia: this.getSetting('groupMembersCanReadMedia', defaults.groupMembersCanReadMedia),
@@ -828,3 +834,9 @@ export class QQChatDatabase {
828
834
  this.db.prepare('UPDATE outbox SET status=?,sent_at=?,error=? WHERE id=?').run(error ? 'failed' : 'sent', now(), error, id)
829
835
  }
830
836
  }
837
+
838
+ function normalizeReplyFormat(value: unknown, fallback: QQChatRuntimeSettings['directReplyFormat']): QQChatRuntimeSettings['directReplyFormat'] {
839
+ if (value === 'markdown' || value === 'compat') return value
840
+ // Older releases persisted the automatic “smart” mode. Its explicit replacement is Markdown.
841
+ return value === 'smart' ? 'markdown' : fallback
842
+ }
@@ -311,9 +311,8 @@ function asSettingsPatch(value: unknown): QQChatRuntimeSettingsPatch {
311
311
  if (record.groupReceiveMode === 'auto' || record.groupReceiveMode === 'mention' || record.groupReceiveMode === 'silent') {
312
312
  patch.groupReceiveMode = record.groupReceiveMode
313
313
  }
314
- if (record.groupReplyFormat === 'smart' || record.groupReplyFormat === 'markdown' || record.groupReplyFormat === 'compat') patch.groupReplyFormat = record.groupReplyFormat
315
- if (record.directReplyFormat === 'smart' || record.directReplyFormat === 'markdown' || record.directReplyFormat === 'compat') patch.directReplyFormat = record.directReplyFormat
316
- if (typeof record.directStreamingEnabled === 'boolean') patch.directStreamingEnabled = record.directStreamingEnabled
314
+ if (record.groupReplyFormat === 'markdown' || record.groupReplyFormat === 'compat') patch.groupReplyFormat = record.groupReplyFormat
315
+ if (record.directReplyFormat === 'markdown' || record.directReplyFormat === 'compat') patch.directReplyFormat = record.directReplyFormat
317
316
  if (typeof record.groupMembersCanUseTools === 'boolean') patch.groupMembersCanUseTools = record.groupMembersCanUseTools
318
317
  if (typeof record.groupMembersCanReceiveMedia === 'boolean') patch.groupMembersCanReceiveMedia = record.groupMembersCanReceiveMedia
319
318
  if (typeof record.groupMembersCanReadMedia === 'boolean') patch.groupMembersCanReadMedia = record.groupMembersCanReadMedia
package/src/types.ts CHANGED
@@ -16,7 +16,7 @@ export interface DailyEntry {
16
16
  date: string
17
17
  note: string
18
18
  }
19
- export type ReplyFormat = 'smart' | 'markdown' | 'compat'
19
+ export type ReplyFormat = 'markdown' | 'compat'
20
20
  export type GroupReceiveMode = 'auto' | 'mention' | 'silent'
21
21
  export type GatewayStatus = 'offline' | 'connecting' | 'online' | 'error'
22
22
  export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
@@ -65,7 +65,6 @@ export interface QQChatRuntimeSettings {
65
65
  groupReceiveMode: GroupReceiveMode
66
66
  groupReplyFormat: ReplyFormat
67
67
  directReplyFormat: ReplyFormat
68
- directStreamingEnabled: boolean
69
68
  groupMembersCanUseTools: boolean
70
69
  groupMembersCanReceiveMedia: boolean
71
70
  groupMembersCanReadMedia: boolean
@@ -78,7 +77,6 @@ export interface QQChatRuntimeSettingsPatch {
78
77
  groupReceiveMode?: GroupReceiveMode
79
78
  groupReplyFormat?: ReplyFormat
80
79
  directReplyFormat?: ReplyFormat
81
- directStreamingEnabled?: boolean
82
80
  groupMembersCanUseTools?: boolean
83
81
  groupMembersCanReceiveMedia?: boolean
84
82
  groupMembersCanReadMedia?: boolean