@dcrays/dcgchat-test 0.3.28 → 0.3.32
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/bot.ts +22 -2
- package/src/channel.ts +60 -19
- package/src/cron.ts +20 -18
- package/src/gateway/index.ts +2 -2
- package/src/request/api.ts +1 -1
- package/src/transport.ts +3 -7
- package/src/utils/params.ts +3 -3
package/package.json
CHANGED
package/src/bot.ts
CHANGED
|
@@ -166,7 +166,7 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
166
166
|
const effectiveAgentId = embeddedAgentId ?? route.agentId
|
|
167
167
|
const effectiveSessionKey = getSessionKey(msg.content, account.accountId)
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
const mergedParams = {
|
|
170
170
|
userId: msg._userId,
|
|
171
171
|
botToken: msg.content.bot_token,
|
|
172
172
|
sessionId: conversationId,
|
|
@@ -177,7 +177,14 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
177
177
|
agentId: msg.content.agent_id ?? '',
|
|
178
178
|
sessionKey: effectiveSessionKey,
|
|
179
179
|
real_mobook
|
|
180
|
-
}
|
|
180
|
+
}
|
|
181
|
+
setParamsMessage(effectiveSessionKey, mergedParams)
|
|
182
|
+
// 与 OpenClaw 会话投递里仍可能出现的 ctx.to=SenderId(userId)对齐,便于 getOutboundMsgParams 命中
|
|
183
|
+
dcgLogger(
|
|
184
|
+
`target normalize: rawTarget=${userId}, normalizedTarget=${effectiveSessionKey}, conversationId=${conversationId ?? ''}, messageId=${msg.content.message_id}`
|
|
185
|
+
)
|
|
186
|
+
setParamsMessage(userId, mergedParams)
|
|
187
|
+
dcgLogger(`target alias bound: aliasTarget=${userId} -> sessionKey=${effectiveSessionKey}`)
|
|
181
188
|
const outboundCtx = getEffectiveMsgParams(effectiveSessionKey)
|
|
182
189
|
const agentEntry =
|
|
183
190
|
effectiveAgentId && effectiveAgentId !== 'main' ? config.agents?.list?.find((a) => a.id === effectiveAgentId) : undefined
|
|
@@ -245,6 +252,9 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
245
252
|
OriginatingTo: effectiveSessionKey,
|
|
246
253
|
...mediaPayload
|
|
247
254
|
})
|
|
255
|
+
dcgLogger(
|
|
256
|
+
`inbound context target: rawTarget=${userId}, normalizedTarget=${effectiveSessionKey}, ctx.To=${String(ctxPayload.To ?? '')}, ctx.SessionKey=${String(ctxPayload.SessionKey ?? '')}, ctx.OriginatingTo=${String(ctxPayload.OriginatingTo ?? '')}`
|
|
257
|
+
)
|
|
248
258
|
|
|
249
259
|
const sentMediaKeys = new Set<string>()
|
|
250
260
|
const getMediaKey = (url: string) => url.split(/[\\/]/).pop() ?? url
|
|
@@ -438,11 +448,21 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
438
448
|
|
|
439
449
|
// Record session metadata
|
|
440
450
|
const storePath = core.channel.session.resolveStorePath(config.session?.store)
|
|
451
|
+
dcgLogger(
|
|
452
|
+
`record session route: rawTarget=${userId}, normalizedTarget=${effectiveSessionKey}, updateLastRoute.to=${effectiveSessionKey}, accountId=${route.accountId}`
|
|
453
|
+
)
|
|
441
454
|
core.channel.session
|
|
442
455
|
.recordInboundSession({
|
|
443
456
|
storePath,
|
|
444
457
|
sessionKey: effectiveSessionKey,
|
|
445
458
|
ctx: ctxPayload,
|
|
459
|
+
// 与 Telegram/Discord 等一致:写入 deliveryContext.to,否则投递可能回退为 From(userId),channel sendMedia 里 ctx.to 会变成数字 userId
|
|
460
|
+
updateLastRoute: {
|
|
461
|
+
sessionKey: effectiveSessionKey,
|
|
462
|
+
channel: "dcgchat-test",
|
|
463
|
+
to: effectiveSessionKey,
|
|
464
|
+
accountId: route.accountId
|
|
465
|
+
},
|
|
446
466
|
onRecordError: (err) => {
|
|
447
467
|
dcgLogger(` session record error: ${String(err)}`, 'error')
|
|
448
468
|
}
|
package/src/channel.ts
CHANGED
|
@@ -5,7 +5,7 @@ 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 { getOutboundMsgParams } from './utils/params.js'
|
|
8
|
+
import { getOutboundMsgParams, getParamsMessage } from './utils/params.js'
|
|
9
9
|
import { startDcgchatGatewaySocket } from './gateway/socket.js'
|
|
10
10
|
|
|
11
11
|
export type DcgchatMediaSendOptions = {
|
|
@@ -15,8 +15,15 @@ export type DcgchatMediaSendOptions = {
|
|
|
15
15
|
text?: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
function normalizeSessionTarget(rawTo: string): string {
|
|
19
|
+
const cleaned = rawTo.replace('dcg-cron:', '').trim()
|
|
20
|
+
if (!cleaned) return ''
|
|
21
|
+
return getParamsMessage(cleaned)?.sessionKey?.trim() || cleaned
|
|
22
|
+
}
|
|
23
|
+
|
|
18
24
|
export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<void> {
|
|
19
|
-
const
|
|
25
|
+
const sessionKey = normalizeSessionTarget(opts.sessionKey ?? '')
|
|
26
|
+
const msgCtx = getOutboundMsgParams(sessionKey)
|
|
20
27
|
if (!isWsOpen()) {
|
|
21
28
|
dcgLogger(`outbound media skipped -> ws not open: ${opts.mediaUrl ?? ''}`)
|
|
22
29
|
return
|
|
@@ -36,21 +43,20 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
|
|
|
36
43
|
|
|
37
44
|
try {
|
|
38
45
|
const botToken = msgCtx.botToken ?? getOpenClawConfig()?.channels?.["dcgchat-test"]?.botToken ?? ''
|
|
39
|
-
console.log('🚀 ~ sendDcgchatMedia ~ botToken:', botToken)
|
|
40
46
|
const url = opts.mediaUrl ? await ossUpload(opts.mediaUrl, botToken, 1) : ''
|
|
41
47
|
wsSendRaw(msgCtx, {
|
|
42
48
|
response: opts.text ?? '',
|
|
43
49
|
message_tags: { source: 'file' },
|
|
44
50
|
files: [{ url, name: fileName }]
|
|
45
51
|
})
|
|
46
|
-
dcgLogger(`dcgchat: sendMedia
|
|
52
|
+
dcgLogger(`dcgchat: sendMedia session=${sessionKey}, file=${fileName}`)
|
|
47
53
|
} catch (error) {
|
|
48
54
|
wsSendRaw(msgCtx, {
|
|
49
55
|
response: opts.text ?? '',
|
|
50
56
|
message_tags: { source: 'file' },
|
|
51
57
|
files: [{ url: opts.mediaUrl ?? '', name: fileName }]
|
|
52
58
|
})
|
|
53
|
-
dcgLogger(`dcgchat: error sendMedia
|
|
59
|
+
dcgLogger(`dcgchat: error sendMedia session=${sessionKey}: ${String(error)}`, 'error')
|
|
54
60
|
}
|
|
55
61
|
}
|
|
56
62
|
|
|
@@ -101,11 +107,17 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
101
107
|
enabled: { type: 'boolean' },
|
|
102
108
|
wsUrl: { type: 'string' },
|
|
103
109
|
botToken: { type: 'string' },
|
|
104
|
-
userId: { type: 'string' },
|
|
110
|
+
userId: { type: 'string', description: 'WebSocket 连接参数 _userId,与 message 工具的 target(effectiveSessionKey)无关' },
|
|
105
111
|
appId: { type: 'string' },
|
|
106
112
|
domainId: { type: 'string' },
|
|
107
113
|
capabilities: { type: 'array', items: { type: 'string' } }
|
|
108
114
|
}
|
|
115
|
+
},
|
|
116
|
+
uiHints: {
|
|
117
|
+
userId: {
|
|
118
|
+
label: 'WS 连接 _userId',
|
|
119
|
+
help: '仅用于拼接网关 WebSocket URL 的查询参数,不是 Agent 发消息时的 target。发消息请使用 effectiveSessionKey(与入站上下文 SessionKey 相同,格式如 agent:main:mobook:direct:…)。'
|
|
120
|
+
}
|
|
109
121
|
}
|
|
110
122
|
},
|
|
111
123
|
config: {
|
|
@@ -135,26 +147,44 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
135
147
|
})
|
|
136
148
|
},
|
|
137
149
|
messaging: {
|
|
138
|
-
normalizeTarget: (raw) => raw
|
|
150
|
+
normalizeTarget: (raw) => normalizeSessionTarget(raw ?? '') || undefined,
|
|
139
151
|
targetResolver: {
|
|
140
152
|
looksLikeId: (raw) => Boolean(raw?.trim()),
|
|
141
|
-
hint: 'userId'
|
|
153
|
+
hint: 'effectiveSessionKey(与 SessionKey 一致;勿填配置里的 WS userId)'
|
|
142
154
|
}
|
|
143
155
|
},
|
|
156
|
+
agentPrompt: {
|
|
157
|
+
messageToolHints: () => [
|
|
158
|
+
'书灵墨宝:message 工具的 target 必须填 effectiveSessionKey(与当前会话 SessionKey / OriginatingTo 相同),形如 agent:main:mobook:direct:<agent_id>:<session_id>;不要填 channels.dcgchat.userId 或纯数字 userId。',
|
|
159
|
+
'OpenClaw 自带的 target 字段说明里仍可能出现 “user id”,在本频道请忽略该字样,一律按 effectiveSessionKey 理解。'
|
|
160
|
+
]
|
|
161
|
+
},
|
|
144
162
|
outbound: {
|
|
145
163
|
deliveryMode: 'direct',
|
|
164
|
+
resolveTarget: ({ to }) => {
|
|
165
|
+
const normalized = normalizeSessionTarget(to ?? '')
|
|
166
|
+
if (!normalized) {
|
|
167
|
+
return { ok: false, error: new Error('target is empty') }
|
|
168
|
+
}
|
|
169
|
+
return { ok: true, to: normalized }
|
|
170
|
+
},
|
|
146
171
|
textChunkLimit: 4000,
|
|
147
172
|
sendText: async (ctx) => {
|
|
148
173
|
const isCron = ctx.to.indexOf('dcg-cron:') >= 0
|
|
149
|
-
const to = ctx.to
|
|
174
|
+
const to = normalizeSessionTarget(ctx.to)
|
|
150
175
|
dcgLogger(`channel sendText to ${ctx.to} `)
|
|
151
176
|
const outboundCtx = getOutboundMsgParams(to)
|
|
152
177
|
const cronMsgId = getCronMessageId(to)
|
|
153
178
|
const messageId = !!cronMsgId ? cronMsgId : isCron ? `${Date.now()}` : outboundCtx?.messageId
|
|
179
|
+
const content: Record<string, unknown> = { response: ctx.text }
|
|
180
|
+
if (isCron || !outboundCtx?.messageId) {
|
|
181
|
+
content.is_finish = -1
|
|
182
|
+
content.message_tags = { source: 'cron' }
|
|
183
|
+
}
|
|
154
184
|
if (isWsOpen()) {
|
|
155
185
|
if (outboundCtx?.sessionId) {
|
|
156
186
|
const newCtx = { ...outboundCtx, messageId }
|
|
157
|
-
wsSendRaw(newCtx,
|
|
187
|
+
wsSendRaw(newCtx, content)
|
|
158
188
|
} else {
|
|
159
189
|
const sessionInfo = to.split(':')
|
|
160
190
|
const sessionId = sessionInfo.at(-1) ?? ''
|
|
@@ -163,10 +193,9 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
163
193
|
agentId: agentId,
|
|
164
194
|
sessionId: `${sessionId}`,
|
|
165
195
|
messageId: messageId,
|
|
166
|
-
is_finish: -1,
|
|
167
196
|
real_mobook: !sessionId ? 1 : ''
|
|
168
197
|
})
|
|
169
|
-
wsSendRaw(merged,
|
|
198
|
+
wsSendRaw(merged, content)
|
|
170
199
|
}
|
|
171
200
|
}
|
|
172
201
|
return {
|
|
@@ -176,17 +205,29 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
176
205
|
}
|
|
177
206
|
},
|
|
178
207
|
sendMedia: async (ctx) => {
|
|
179
|
-
const to = ctx.to.replace('dcg-cron:', '')
|
|
180
|
-
const msgCtx = getOutboundMsgParams(to)
|
|
181
|
-
const cronMsgId = getCronMessageId(to)
|
|
182
208
|
const isCron = ctx.to.indexOf('dcg-cron:') >= 0
|
|
183
|
-
const
|
|
209
|
+
const to = normalizeSessionTarget(ctx.to)
|
|
210
|
+
const outboundCtx = getOutboundMsgParams(to)
|
|
211
|
+
const msgCtx = getParamsMessage(to) ?? outboundCtx
|
|
212
|
+
const cronMsgId = getCronMessageId(to)
|
|
213
|
+
const fallbackMessageId = `${Date.now()}`
|
|
214
|
+
const messageId = cronMsgId || (isCron ? fallbackMessageId : msgCtx?.messageId || fallbackMessageId)
|
|
215
|
+
|
|
216
|
+
if (!outboundCtx?.sessionId) {
|
|
217
|
+
dcgLogger(`channel sendMedia to ${ctx.to} -> sessionId not found`, 'error')
|
|
218
|
+
return {
|
|
219
|
+
channel: "dcgchat-test",
|
|
220
|
+
messageId,
|
|
221
|
+
chatId: to || ''
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
184
225
|
dcgLogger(`channel sendMedia to ${ctx.to}`)
|
|
185
|
-
await sendDcgchatMedia({ sessionKey: to
|
|
226
|
+
await sendDcgchatMedia({ sessionKey: to || '', mediaUrl: ctx.mediaUrl || '' })
|
|
186
227
|
return {
|
|
187
228
|
channel: "dcgchat-test",
|
|
188
|
-
messageId
|
|
189
|
-
chatId:
|
|
229
|
+
messageId,
|
|
230
|
+
chatId: to || ''
|
|
190
231
|
}
|
|
191
232
|
}
|
|
192
233
|
},
|
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()
|
|
@@ -51,17 +51,27 @@ const CRON_UPLOAD_DEBOUNCE_MS = 6600
|
|
|
51
51
|
let pendingCronUploadCtx: IMsgParams | null = null
|
|
52
52
|
let cronUploadFlushTimer: ReturnType<typeof setTimeout> | null = null
|
|
53
53
|
|
|
54
|
-
async function runCronJobsUpload(
|
|
54
|
+
async function runCronJobsUpload(sessionKey: string): Promise<void> {
|
|
55
55
|
const jobPath = getCronJobsPath()
|
|
56
|
+
const botToken = getParamsDefaults().botToken
|
|
56
57
|
if (fs.existsSync(jobPath)) {
|
|
57
58
|
try {
|
|
58
|
-
const url = await ossUpload(jobPath,
|
|
59
|
+
const url = await ossUpload(jobPath, botToken ?? '', 0)
|
|
59
60
|
dcgLogger(`定时任务创建成功: ${url}`)
|
|
60
|
-
if (!
|
|
61
|
-
dcgLogger(`runCronJobsUpload: missing sessionKey
|
|
61
|
+
if (!sessionKey) {
|
|
62
|
+
dcgLogger(`runCronJobsUpload: missing sessionKey on msgCtx`, 'error')
|
|
62
63
|
return
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
+
const sessionInfo = sessionKey.split(':')
|
|
66
|
+
const sessionId = sessionInfo.at(-1) ?? ''
|
|
67
|
+
const agentId = sessionInfo.at(-2) ?? ''
|
|
68
|
+
const params = {
|
|
69
|
+
event_type: 'cron',
|
|
70
|
+
operation_type: 'install',
|
|
71
|
+
session_id: sessionId,
|
|
72
|
+
agent_id: agentId
|
|
73
|
+
}
|
|
74
|
+
sendEventMessage(url, params)
|
|
65
75
|
} catch (error) {
|
|
66
76
|
dcgLogger(`${jobPath} upload failed: ${error}`, 'error')
|
|
67
77
|
}
|
|
@@ -70,14 +80,6 @@ async function runCronJobsUpload(msgCtx: IMsgParams): Promise<void> {
|
|
|
70
80
|
}
|
|
71
81
|
}
|
|
72
82
|
|
|
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
83
|
/**
|
|
82
84
|
* 将 jobs.json 同步到 OSS 并推送事件。30s 内多次调用合并为一次上传;定时触发后清空待处理项,避免重复执行。
|
|
83
85
|
* @param msgCtx 可选;省略时使用当前会话 getEffectiveMsgParams(sessionKey) 快照
|
|
@@ -85,17 +87,17 @@ function flushCronUploadQueue(): void {
|
|
|
85
87
|
export function sendDcgchatCron(jobId: string): void {
|
|
86
88
|
const jobPath = getCronJobsPath()
|
|
87
89
|
const { sessionKey } = readCronJob(jobPath, jobId) || {}
|
|
88
|
-
|
|
89
|
-
if (!ctx) {
|
|
90
|
+
if (!sessionKey) {
|
|
90
91
|
dcgLogger('sendDcgchatCron: no message context (missing token / params)', 'error')
|
|
91
92
|
return
|
|
92
93
|
}
|
|
93
94
|
dcgLogger(`sessionKey: ${sessionKey}, jobId: ${jobId}`)
|
|
94
|
-
pendingCronUploadCtx = ctx
|
|
95
95
|
if (cronUploadFlushTimer !== null) {
|
|
96
96
|
clearTimeout(cronUploadFlushTimer)
|
|
97
97
|
}
|
|
98
|
-
cronUploadFlushTimer = setTimeout(
|
|
98
|
+
cronUploadFlushTimer = setTimeout(() => {
|
|
99
|
+
runCronJobsUpload(sessionKey)
|
|
100
|
+
}, CRON_UPLOAD_DEBOUNCE_MS)
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
/**
|
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/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 ?? '',
|
|
@@ -47,8 +47,8 @@ export function getEffectiveMsgParams(sessionKey?: string): IMsgParams {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
|
-
* Agent `message`
|
|
51
|
-
* `
|
|
50
|
+
* Agent `message` 工具的 `target` 应为 `effectiveSessionKey`(如 `agent:main:mobook:direct:...`)。
|
|
51
|
+
* `setParamsMessage` 使用的 key 与此一致。若按 preferredKey 查不到 map,
|
|
52
52
|
* 则回落到当前会话 `currentSessionKey`,避免拿到空 `messageId` / `sessionId` 导致无文件卡片、WS 上下文错误。
|
|
53
53
|
*/
|
|
54
54
|
export function getOutboundMsgParams(preferredKey: string): IMsgParams {
|