@dcrays/dcgchat-test 0.3.25 → 0.3.26

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.25",
3
+ "version": "0.3.26",
4
4
  "type": "module",
5
5
  "description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
6
6
  "main": "index.ts",
package/src/channel.ts CHANGED
@@ -5,18 +5,18 @@ import { ossUpload } from './request/oss.js'
5
5
  import { addSentMediaKey, getCronMessageId, 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
- import { getEffectiveMsgParams, getCurrentSessionKey } from './utils/params.js'
8
+ import { getOutboundMsgParams } from './utils/params.js'
9
9
  import { startDcgchatGatewaySocket } from './gateway/socket.js'
10
10
 
11
11
  export type DcgchatMediaSendOptions = {
12
- /** 与 setParamsMessage / map 一致,用于 getEffectiveMsgParams */
12
+ /** 与 setParamsMessage / map 一致,用于 getOutboundMsgParams */
13
13
  sessionKey: string
14
14
  mediaUrl?: string
15
15
  text?: string
16
16
  }
17
17
 
18
18
  export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<void> {
19
- const msgCtx = getEffectiveMsgParams(opts.sessionKey)
19
+ const msgCtx = getOutboundMsgParams(opts.sessionKey ?? '')
20
20
  if (!isWsOpen()) {
21
21
  dcgLogger(`outbound media skipped -> ws not open: ${opts.mediaUrl ?? ''}`)
22
22
  return
@@ -147,7 +147,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
147
147
  const isCron = ctx.to.indexOf('dcg-cron:') >= 0
148
148
  const to = ctx.to.replace('dcg-cron:', '')
149
149
  dcgLogger(`channel sendText to ${ctx.to} `)
150
- const outboundCtx = getEffectiveMsgParams(to)
150
+ const outboundCtx = getOutboundMsgParams(to)
151
151
  const cronMsgId = getCronMessageId(to)
152
152
  const messageId = !!cronMsgId ? cronMsgId : isCron ? `${Date.now()}` : outboundCtx?.messageId
153
153
  if (isWsOpen()) {
@@ -176,7 +176,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
176
176
  },
177
177
  sendMedia: async (ctx) => {
178
178
  const to = ctx.to.replace('dcg-cron:', '')
179
- const msgCtx = getEffectiveMsgParams(to)
179
+ const msgCtx = getOutboundMsgParams(to)
180
180
  const cronMsgId = getCronMessageId(to)
181
181
  const isCron = ctx.to.indexOf('dcg-cron:') >= 0
182
182
  const messageId = !!cronMsgId ? cronMsgId : isCron ? `${Date.now()}` : msgCtx?.messageId
package/src/cron.ts CHANGED
@@ -2,18 +2,11 @@ import path from 'node:path'
2
2
  import fs from 'node:fs'
3
3
  import type { IMsgParams } from './types.js'
4
4
  import { isWsOpen, mergeDefaultParams, sendEventMessage, sendFinal } from './transport.js'
5
- import {
6
- getCronMessageId,
7
- getWorkspaceDir,
8
- getWsConnection,
9
- removeCronMessageId,
10
- setCronMessageId,
11
- setMsgStatus
12
- } from './utils/global.js'
5
+ import { getCronMessageId, getWorkspaceDir, getWsConnection, removeCronMessageId, setCronMessageId } from './utils/global.js'
13
6
  import { ossUpload } from './request/oss.js'
14
7
  import { dcgLogger } from './utils/log.js'
15
8
  import { sendMessageToGateway } from './gateway/socket.js'
16
- import { getCurrentSessionKey, getEffectiveMsgParams } from './utils/params.js'
9
+ import { getEffectiveMsgParams } from './utils/params.js'
17
10
 
18
11
  export function getCronJobsPath(): string {
19
12
  const workspaceDir = getWorkspaceDir()
@@ -89,12 +82,15 @@ function flushCronUploadQueue(): void {
89
82
  * 将 jobs.json 同步到 OSS 并推送事件。30s 内多次调用合并为一次上传;定时触发后清空待处理项,避免重复执行。
90
83
  * @param msgCtx 可选;省略时使用当前会话 getEffectiveMsgParams(sessionKey) 快照
91
84
  */
92
- export function sendDcgchatCron(): void {
93
- const ctx = msgParamsToCtx(getEffectiveMsgParams(getCurrentSessionKey() ?? ''))
85
+ export function sendDcgchatCron(jobId: string): void {
86
+ const jobPath = getCronJobsPath()
87
+ const { sessionKey } = readCronJob(jobPath, jobId) || {}
88
+ const ctx = msgParamsToCtx(getEffectiveMsgParams(sessionKey))
94
89
  if (!ctx) {
95
90
  dcgLogger('sendDcgchatCron: no message context (missing token / params)', 'error')
96
91
  return
97
92
  }
93
+ dcgLogger(`sessionKey: ${sessionKey}, jobId: ${jobId}`)
98
94
  pendingCronUploadCtx = ctx
99
95
  if (cronUploadFlushTimer !== null) {
100
96
  clearTimeout(cronUploadFlushTimer)
@@ -3,7 +3,7 @@ import axios from 'axios'
3
3
  import md5 from 'md5'
4
4
  import type { IResponse } from '../types.js'
5
5
  import { getUserTokenCache } from './userInfo.js'
6
- import { getCurrentSessionKey, getEffectiveMsgParams } from '../utils/params.js'
6
+ import { getEffectiveMsgParams } from '../utils/params.js'
7
7
  import { ENV } from '../utils/constant.js'
8
8
  import { dcgLogger } from '../utils/log.js'
9
9
 
@@ -39,9 +39,7 @@ function toCurl(config: {
39
39
  }): string {
40
40
  const base = config.baseURL ?? ''
41
41
  const path = config.url ?? ''
42
- const url = path.startsWith('http')
43
- ? path
44
- : `${base.replace(/\/$/, '')}/${path.replace(/^\//, '')}`
42
+ const url = path.startsWith('http') ? path : `${base.replace(/\/$/, '')}/${path.replace(/^\//, '')}`
45
43
  const method = (config.method ?? 'GET').toUpperCase()
46
44
  const headers = config.headers ?? {}
47
45
  const parts = ['curl', '-X', method, `'${url}'`]
@@ -82,9 +80,7 @@ export function getSignature(
82
80
  sortedKeys
83
81
  .map((key) => {
84
82
  const val = map[key as keyof typeof map]
85
- return val === undefined
86
- ? ''
87
- : `${key}${typeof val === 'object' ? JSON.stringify(val) : val}`
83
+ return val === undefined ? '' : `${key}${typeof val === 'object' ? JSON.stringify(val) : val}`
88
84
  })
89
85
  .join('') + signKey[ENV]
90
86
  // 4. MD5 加密并转大写
@@ -130,9 +126,7 @@ axiosInstance.interceptors.request.use(
130
126
  if (cachedToken) {
131
127
  config.headers = config.headers || {}
132
128
  config.headers.authorization = cachedToken
133
- dcgLogger(
134
- `[request] auto-injected userToken from cache for botToken=${botToken.slice(0, 10)}...`
135
- )
129
+ dcgLogger(`[request] auto-injected userToken from cache for botToken=${botToken.slice(0, 10)}...`)
136
130
  }
137
131
  }
138
132
 
@@ -172,7 +166,7 @@ export function post<T = Record<string, unknown>, R = unknown>(
172
166
  botToken?: string
173
167
  }
174
168
  ): Promise<IResponse<R>> {
175
- const params = getEffectiveMsgParams(getCurrentSessionKey() ?? '') || {}
169
+ const params = getEffectiveMsgParams() || { appId: 100 }
176
170
  const config: any = {
177
171
  method: 'POST',
178
172
  url,
package/src/tool.ts CHANGED
@@ -2,12 +2,9 @@ import type { OpenClawPluginApi } from 'openclaw/plugin-sdk'
2
2
  import { getMsgStatus } from './utils/global.js'
3
3
  import { dcgLogger } from './utils/log.js'
4
4
  import { sendFinal, sendText, wsSendRaw } from './transport.js'
5
- import { getCurrentSessionKey, getEffectiveMsgParams } from './utils/params.js'
6
- import { channelInfo, ENV } from './utils/constant.js'
5
+ import { getEffectiveMsgParams } from './utils/params.js'
7
6
  import { cronToolCall } from './cronToolCall.js'
8
7
 
9
- let toolCallId = ''
10
- let toolName = ''
11
8
  type PluginHookName =
12
9
  | 'before_model_resolve'
13
10
  | 'before_prompt_build'
@@ -56,13 +53,8 @@ const eventList = [
56
53
 
57
54
  function sendToolCallMessage(sk: string, text: string, toolCallId: string, isCover: number) {
58
55
  const params = getEffectiveMsgParams(sk)
59
- wsSendRaw(params, {
60
- is_finish: -1,
61
- tool_call_id: toolCallId,
62
- is_cover: isCover,
63
- thinking_content: text,
64
- response: ''
65
- })
56
+ const content = { is_finish: -1, tool_call_id: toolCallId, is_cover: isCover, thinking_content: text, response: '' }
57
+ wsSendRaw(params, content, false)
66
58
  }
67
59
 
68
60
  /**
package/src/transport.ts CHANGED
@@ -150,12 +150,13 @@ export function wsSend(ctx: IMsgParams, content: Record<string, unknown>): boole
150
150
  * 媒体 / channel 出站:content 保持嵌套对象(单次编码)。
151
151
  * `ctx` 须由调用方解析(如需合并覆盖可先 mergeSessionParams)。
152
152
  */
153
- export function wsSendRaw(ctx: IMsgParams, content: Record<string, unknown>): boolean {
153
+ export function wsSendRaw(ctx: IMsgParams, content: Record<string, unknown>, isLog = true): boolean {
154
154
  const ws = getWsConnection()
155
155
  if (isWsOpen()) {
156
156
  ws?.send(JSON.stringify(buildOpenclawBotChat(ctx, content, { mergeChannelDefaults: true })))
157
-
158
- dcgLogger('已发送:' + JSON.stringify(buildOpenclawBotChat(ctx, content, { mergeChannelDefaults: true })))
157
+ if (isLog) {
158
+ dcgLogger('已发送:' + JSON.stringify(buildOpenclawBotChat(ctx, content, { mergeChannelDefaults: true })))
159
+ }
159
160
  }
160
161
  return true
161
162
  }
@@ -195,7 +196,7 @@ export function sendEventMessage(url: string, sessionKey: string) {
195
196
  bot_id: ctx.botId,
196
197
  agent_id: ctx.agentId,
197
198
  session_id: ctx.sessionId,
198
- message_id: ctx.messageId || Date.now().toString()
199
+ message_id: Date.now().toString()
199
200
  }
200
201
  })
201
202
  )
@@ -7,12 +7,9 @@ import type { DcgchatConfig, IMsgParams } from '../types.js'
7
7
  */
8
8
  const paramsMessageMap = new Map<string, IMsgParams>()
9
9
 
10
- /** 最近一次 setParamsMessage 的 key,供不传参的 getEffectiveMsgParams() 使用 */
11
- let currentSessionKey: string | null = null
12
-
13
10
  /** 从 OpenClaw 配置读取当前 channel 的基础参数(唯一来源,供 transport / resolve 等复用) */
14
11
  export function getParamsDefaults(): IMsgParams {
15
- const ch = (getOpenClawConfig()?.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {}
12
+ const ch = (getOpenClawConfig()?.channels?.['dcgchat'] as DcgchatConfig | undefined) ?? {}
16
13
  return {
17
14
  userId: Number(ch.userId ?? 0),
18
15
  botToken: ch.botToken ?? '',
@@ -45,14 +42,25 @@ export function resolveParamsMessage(params: Partial<IMsgParams>): IMsgParams {
45
42
  * 统一取值入口:显式 sessionKey,或回落到当前会话;再与配置缺省 merge,保证字段完整。
46
43
  */
47
44
  export function getEffectiveMsgParams(sessionKey?: string): IMsgParams {
48
- const key = sessionKey ?? currentSessionKey
49
- const stored = key ? paramsMessageMap.get(key) : undefined
45
+ const stored = sessionKey ? paramsMessageMap.get(sessionKey) : undefined
50
46
  return stored ? resolveParamsMessage(stored) : getParamsDefaults()
51
47
  }
52
48
 
49
+ /**
50
+ * Agent `message` 工具常把 `target` 设为用户 ID(如 "150"),而 `setParamsMessage` 使用的 key 是
51
+ * `effectiveSessionKey`(如 `agent:main:mobook:direct:...`)。若按 preferredKey 查不到 map,
52
+ * 则回落到当前会话 `currentSessionKey`,避免拿到空 `messageId` / `sessionId` 导致无文件卡片、WS 上下文错误。
53
+ */
54
+ export function getOutboundMsgParams(preferredKey: string): IMsgParams {
55
+ const k = preferredKey?.trim()
56
+ if (k && paramsMessageMap.has(k)) {
57
+ return getEffectiveMsgParams(k)
58
+ }
59
+ return getEffectiveMsgParams()
60
+ }
61
+
53
62
  export function setParamsMessage(sessionKey: string, params: Partial<IMsgParams>) {
54
63
  if (!sessionKey) return
55
- currentSessionKey = sessionKey
56
64
  const previous = paramsMessageMap.get(sessionKey)
57
65
  const base = previous ? resolveParamsMessage(previous) : getParamsDefaults()
58
66
  paramsMessageMap.set(sessionKey, resolveParamsMessage({ ...base, ...params, sessionKey }))
@@ -61,7 +69,3 @@ export function setParamsMessage(sessionKey: string, params: Partial<IMsgParams>
61
69
  export function getParamsMessage(sessionKey: string): IMsgParams | undefined {
62
70
  return paramsMessageMap.get(sessionKey)
63
71
  }
64
-
65
- export function getCurrentSessionKey(): string | null {
66
- return currentSessionKey
67
- }