@dcrays/dcgchat-test 0.3.31 → 0.3.33

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dcrays/dcgchat-test",
3
- "version": "0.3.31",
3
+ "version": "0.3.33",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
6
  "main": "index.ts",
package/src/channel.ts CHANGED
@@ -2,7 +2,7 @@ import type { ChannelPlugin, OpenClawConfig } from 'openclaw/plugin-sdk'
2
2
  import { DEFAULT_ACCOUNT_ID } from 'openclaw/plugin-sdk'
3
3
  import type { ResolvedDcgchatAccount, DcgchatConfig } from './types.js'
4
4
  import { ossUpload } from './request/oss.js'
5
- import { addSentMediaKey, getCronMessageId, getOpenClawConfig, hasSentMediaKey } from './utils/global.js'
5
+ import { addSentMediaKey, getCronMessageId, getInfoBySessionKey, getOpenClawConfig, hasSentMediaKey } from './utils/global.js'
6
6
  import { isWsOpen, mergeDefaultParams, mergeSessionParams, sendFinal, wsSendRaw } from './transport.js'
7
7
  import { dcgLogger, setLogger } from './utils/log.js'
8
8
  import { getOutboundMsgParams, getParamsMessage } from './utils/params.js'
@@ -147,7 +147,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
147
147
  })
148
148
  },
149
149
  messaging: {
150
- normalizeTarget: (raw) => normalizeSessionTarget(raw ?? '') || undefined,
150
+ normalizeTarget: (raw) => raw || undefined,
151
151
  targetResolver: {
152
152
  looksLikeId: (raw) => Boolean(raw?.trim()),
153
153
  hint: 'effectiveSessionKey(与 SessionKey 一致;勿填配置里的 WS userId)'
@@ -162,36 +162,40 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
162
162
  outbound: {
163
163
  deliveryMode: 'direct',
164
164
  resolveTarget: ({ to }) => {
165
- const normalized = normalizeSessionTarget(to ?? '')
166
- if (!normalized) {
165
+ if (!to) {
167
166
  return { ok: false, error: new Error('target is empty') }
168
167
  }
169
- return { ok: true, to: normalized }
168
+ return { ok: true, to: to }
170
169
  },
171
170
  textChunkLimit: 4000,
172
171
  sendText: async (ctx) => {
173
- const isCron = ctx.to.indexOf('dcg-cron:') >= 0
174
- const to = normalizeSessionTarget(ctx.to)
175
172
  dcgLogger(`channel sendText to ${ctx.to} `)
176
- const outboundCtx = getOutboundMsgParams(to)
177
- const cronMsgId = getCronMessageId(to)
178
- const messageId = !!cronMsgId ? cronMsgId : isCron ? `${Date.now()}` : outboundCtx?.messageId
173
+ let messageId = ''
174
+ const to = normalizeSessionTarget(ctx.to)
179
175
  if (isWsOpen()) {
180
- if (outboundCtx?.sessionId) {
181
- const newCtx = { ...outboundCtx, messageId }
182
- wsSendRaw(newCtx, { response: ctx.text, is_finish: -1, message_tags: { source: 'channel' } })
183
- } else {
184
- const sessionInfo = to.split(':')
185
- const sessionId = sessionInfo.at(-1) ?? ''
186
- const agentId = sessionInfo.at(-2) ?? ''
176
+ const isCron = ctx.to.indexOf('dcg-cron:') >= 0
177
+ const outboundCtx = getOutboundMsgParams(to)
178
+ const content: Record<string, unknown> = { response: ctx.text }
179
+ if (isCron) {
180
+ messageId = getCronMessageId(to) || `${Date.now()}`
181
+ const { sessionId, agentId } = getInfoBySessionKey(to)
182
+ content.is_finish = -1
183
+ content.message_tags = { source: 'cron' }
187
184
  const merged = mergeDefaultParams({
188
185
  agentId: agentId,
189
186
  sessionId: `${sessionId}`,
190
187
  messageId: messageId,
191
- is_finish: -1,
192
188
  real_mobook: !sessionId ? 1 : ''
193
189
  })
194
- wsSendRaw(merged, { response: ctx.text, message_tags: { source: 'channel' } })
190
+ wsSendRaw(merged, content)
191
+ } else {
192
+ if (outboundCtx?.sessionId) {
193
+ messageId = outboundCtx?.messageId || `${Date.now()}`
194
+ const newCtx = { ...outboundCtx, messageId }
195
+ wsSendRaw(newCtx, content)
196
+ } else {
197
+ dcgLogger(`channel sendText to ${ctx.to} -> sessionId not found`, 'error')
198
+ }
195
199
  }
196
200
  }
197
201
  return {
package/src/cron.ts CHANGED
@@ -6,7 +6,7 @@ import { getCronMessageId, getWorkspaceDir, getWsConnection, removeCronMessageId
6
6
  import { ossUpload } from './request/oss.js'
7
7
  import { dcgLogger } from './utils/log.js'
8
8
  import { sendMessageToGateway } from './gateway/socket.js'
9
- import { getEffectiveMsgParams } from './utils/params.js'
9
+ import { getEffectiveMsgParams, getParamsDefaults } from './utils/params.js'
10
10
 
11
11
  export function getCronJobsPath(): string {
12
12
  const workspaceDir = getWorkspaceDir()
@@ -45,23 +45,31 @@ function msgParamsToCtx(p: IMsgParams): IMsgParams | null {
45
45
  return p
46
46
  }
47
47
 
48
- const CRON_UPLOAD_DEBOUNCE_MS = 6600
48
+ const CRON_UPLOAD_DEBOUNCE_MS = 2400
49
49
 
50
- /** 待合并的上传上下文(短时间内多次调用只保留最后一次) */
51
- let pendingCronUploadCtx: IMsgParams | null = null
52
50
  let cronUploadFlushTimer: ReturnType<typeof setTimeout> | null = null
53
51
 
54
- async function runCronJobsUpload(msgCtx: IMsgParams): Promise<void> {
52
+ async function runCronJobsUpload(sessionKey: string): Promise<void> {
55
53
  const jobPath = getCronJobsPath()
54
+ const botToken = getParamsDefaults().botToken
56
55
  if (fs.existsSync(jobPath)) {
57
56
  try {
58
- const url = await ossUpload(jobPath, msgCtx.botToken ?? '', 0)
57
+ const url = await ossUpload(jobPath, botToken ?? '', 0)
59
58
  dcgLogger(`定时任务创建成功: ${url}`)
60
- if (!msgCtx.sessionKey) {
61
- dcgLogger(`runCronJobsUpload: missing sessionKey ${JSON.stringify(msgCtx)} on msgCtx`, 'error')
59
+ if (!sessionKey) {
60
+ dcgLogger(`runCronJobsUpload: missing sessionKey on msgCtx`, 'error')
62
61
  return
63
62
  }
64
- sendEventMessage(url, msgCtx.sessionKey)
63
+ const sessionInfo = sessionKey.split(':')
64
+ const sessionId = sessionInfo.at(-1) ?? ''
65
+ const agentId = sessionInfo.at(-2) ?? ''
66
+ const params = {
67
+ event_type: 'cron',
68
+ operation_type: 'install',
69
+ session_id: sessionId,
70
+ agent_id: agentId
71
+ }
72
+ sendEventMessage(url, params)
65
73
  } catch (error) {
66
74
  dcgLogger(`${jobPath} upload failed: ${error}`, 'error')
67
75
  }
@@ -70,14 +78,6 @@ async function runCronJobsUpload(msgCtx: IMsgParams): Promise<void> {
70
78
  }
71
79
  }
72
80
 
73
- function flushCronUploadQueue(): void {
74
- cronUploadFlushTimer = null
75
- const ctx = pendingCronUploadCtx
76
- pendingCronUploadCtx = null
77
- if (!ctx) return
78
- void runCronJobsUpload(ctx)
79
- }
80
-
81
81
  /**
82
82
  * 将 jobs.json 同步到 OSS 并推送事件。30s 内多次调用合并为一次上传;定时触发后清空待处理项,避免重复执行。
83
83
  * @param msgCtx 可选;省略时使用当前会话 getEffectiveMsgParams(sessionKey) 快照
@@ -85,17 +85,17 @@ function flushCronUploadQueue(): void {
85
85
  export function sendDcgchatCron(jobId: string): void {
86
86
  const jobPath = getCronJobsPath()
87
87
  const { sessionKey } = readCronJob(jobPath, jobId) || {}
88
- const ctx = msgParamsToCtx(getEffectiveMsgParams(sessionKey))
89
- if (!ctx) {
88
+ if (!sessionKey) {
90
89
  dcgLogger('sendDcgchatCron: no message context (missing token / params)', 'error')
91
90
  return
92
91
  }
93
92
  dcgLogger(`sessionKey: ${sessionKey}, jobId: ${jobId}`)
94
- pendingCronUploadCtx = ctx
95
93
  if (cronUploadFlushTimer !== null) {
96
94
  clearTimeout(cronUploadFlushTimer)
97
95
  }
98
- cronUploadFlushTimer = setTimeout(flushCronUploadQueue, CRON_UPLOAD_DEBOUNCE_MS)
96
+ cronUploadFlushTimer = setTimeout(() => {
97
+ runCronJobsUpload(sessionKey)
98
+ }, CRON_UPLOAD_DEBOUNCE_MS)
99
99
  }
100
100
 
101
101
  /**
@@ -363,10 +363,10 @@ export class GatewayConnection {
363
363
  if (msg.event === 'cron') {
364
364
  dcgLogger(`[Gateway] 收到事件: ${JSON.stringify(msg)}`)
365
365
  if (msg.payload?.action === 'added') {
366
- sendDcgchatCron()
366
+ sendDcgchatCron(msg.payload?.jobId)
367
367
  }
368
368
  if (msg.payload?.action === 'updated') {
369
- sendDcgchatCron()
369
+ sendDcgchatCron(msg.payload?.jobId as string)
370
370
  }
371
371
  if (msg.payload?.action === 'finished') {
372
372
  finishedDcgchatCron(msg.payload?.jobId as string)
@@ -40,7 +40,7 @@ export const queryUserTokenByBotToken = async (botToken: string): Promise<string
40
40
  const response = await post<{ botToken: string }, { token: string }>('/organization/queryUserTokenByBotToken', { botToken })
41
41
 
42
42
  if (!response || !response.data || !response.data.token) {
43
- dcgLogger('获取绑定的用户信息失败: ' + JSON.stringify(response), 'error')
43
+ dcgLogger('获取绑定的用户信息失败: token:' + botToken + '|' + JSON.stringify(response), 'error')
44
44
  return ''
45
45
  }
46
46
 
package/src/transport.ts CHANGED
@@ -178,8 +178,8 @@ export function sendError(errorMsg: string, ctx: IMsgParams): boolean {
178
178
  return wsSend(ctx, { response: `[错误] ${errorMsg}`, state: 'final' })
179
179
  }
180
180
 
181
- export function sendEventMessage(url: string, sessionKey: string) {
182
- const ctx = getEffectiveMsgParams(sessionKey)
181
+ export function sendEventMessage(url: string, params: Record<string, string> = {}) {
182
+ const ctx = getParamsDefaults()
183
183
  const ws = getWsConnection()
184
184
  if (isWsOpen()) {
185
185
  ws?.send(
@@ -187,16 +187,12 @@ export function sendEventMessage(url: string, sessionKey: string) {
187
187
  messageType: 'openclaw_bot_event',
188
188
  source: 'client',
189
189
  content: {
190
- event_type: 'cron',
191
- operation_type: 'install',
192
190
  bot_token: ctx.botToken,
193
191
  domain_id: ctx.domainId,
194
192
  app_id: ctx.appId,
195
193
  oss_url: url,
196
194
  bot_id: ctx.botId,
197
- agent_id: ctx.agentId,
198
- session_id: ctx.sessionId,
199
- message_id: Date.now().toString()
195
+ ...params
200
196
  }
201
197
  })
202
198
  )
@@ -143,3 +143,8 @@ export function getCronMessageId(sk: string): string {
143
143
  export function removeCronMessageId(sk: string) {
144
144
  cronMessageIdMap.delete(sk)
145
145
  }
146
+
147
+ export function getInfoBySessionKey(sk: string): { sessionId: string; agentId: string } {
148
+ const sessionInfo = sk.split(':')
149
+ return { sessionId: sessionInfo.at(-1) ?? '', agentId: sessionInfo.at(-2) ?? '' }
150
+ }
@@ -9,7 +9,7 @@ const paramsMessageMap = new Map<string, IMsgParams>()
9
9
 
10
10
  /** 从 OpenClaw 配置读取当前 channel 的基础参数(唯一来源,供 transport / resolve 等复用) */
11
11
  export function getParamsDefaults(): IMsgParams {
12
- const ch = (getOpenClawConfig()?.channels?.['dcgchat'] as DcgchatConfig | undefined) ?? {}
12
+ const ch = (getOpenClawConfig()?.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {}
13
13
  return {
14
14
  userId: Number(ch.userId ?? 0),
15
15
  botToken: ch.botToken ?? '',