@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 +1 -1
- package/src/channel.ts +23 -19
- package/src/cron.ts +21 -21
- package/src/gateway/index.ts +2 -2
- package/src/request/api.ts +1 -1
- package/src/transport.ts +3 -7
- package/src/utils/global.ts +5 -0
- package/src/utils/params.ts +1 -1
package/package.json
CHANGED
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) =>
|
|
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
|
-
|
|
166
|
-
if (!normalized) {
|
|
165
|
+
if (!to) {
|
|
167
166
|
return { ok: false, error: new Error('target is empty') }
|
|
168
167
|
}
|
|
169
|
-
return { ok: true, to:
|
|
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
|
-
|
|
177
|
-
const
|
|
178
|
-
const messageId = !!cronMsgId ? cronMsgId : isCron ? `${Date.now()}` : outboundCtx?.messageId
|
|
173
|
+
let messageId = ''
|
|
174
|
+
const to = normalizeSessionTarget(ctx.to)
|
|
179
175
|
if (isWsOpen()) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
const sessionId =
|
|
186
|
-
|
|
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,
|
|
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 =
|
|
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(
|
|
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,
|
|
57
|
+
const url = await ossUpload(jobPath, botToken ?? '', 0)
|
|
59
58
|
dcgLogger(`定时任务创建成功: ${url}`)
|
|
60
|
-
if (!
|
|
61
|
-
dcgLogger(`runCronJobsUpload: missing sessionKey
|
|
59
|
+
if (!sessionKey) {
|
|
60
|
+
dcgLogger(`runCronJobsUpload: missing sessionKey on msgCtx`, 'error')
|
|
62
61
|
return
|
|
63
62
|
}
|
|
64
|
-
|
|
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
|
-
|
|
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(
|
|
96
|
+
cronUploadFlushTimer = setTimeout(() => {
|
|
97
|
+
runCronJobsUpload(sessionKey)
|
|
98
|
+
}, CRON_UPLOAD_DEBOUNCE_MS)
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/**
|
package/src/gateway/index.ts
CHANGED
|
@@ -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)
|
package/src/request/api.ts
CHANGED
|
@@ -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,
|
|
182
|
-
const ctx =
|
|
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
|
-
|
|
198
|
-
session_id: ctx.sessionId,
|
|
199
|
-
message_id: Date.now().toString()
|
|
195
|
+
...params
|
|
200
196
|
}
|
|
201
197
|
})
|
|
202
198
|
)
|
package/src/utils/global.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/utils/params.ts
CHANGED
|
@@ -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?.[
|
|
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 ?? '',
|