@dcrays/dcgchat-test 0.2.30 → 0.2.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/index.ts +2 -2
- package/openclaw.plugin.json +4 -2
- package/package.json +3 -12
- package/src/bot.ts +9 -9
- package/src/channel.ts +8 -12
- package/src/utils/constant.ts +0 -4
- package/src/utils/global.ts +7 -2
- package/src/utils/log.ts +1 -2
- package/README.md +0 -83
package/index.ts
CHANGED
|
@@ -3,11 +3,10 @@ import { emptyPluginConfigSchema } from 'openclaw/plugin-sdk'
|
|
|
3
3
|
import { dcgchatPlugin } from './src/channel.js'
|
|
4
4
|
import { setDcgchatRuntime, setWorkspaceDir } from './src/utils/global.js'
|
|
5
5
|
import { monitoringToolMessage } from './src/tool.js'
|
|
6
|
-
import { channelInfo, ENV } from './src/utils/constant.js'
|
|
7
6
|
import { setOpenClawConfig } from './src/utils/global.js'
|
|
8
7
|
|
|
9
8
|
const plugin = {
|
|
10
|
-
id:
|
|
9
|
+
id: "dcgchat-test",
|
|
11
10
|
name: '书灵墨宝',
|
|
12
11
|
description: '连接 OpenClaw 与 书灵墨宝 产品(WebSocket)',
|
|
13
12
|
configSchema: emptyPluginConfigSchema(),
|
|
@@ -16,6 +15,7 @@ const plugin = {
|
|
|
16
15
|
monitoringToolMessage(api)
|
|
17
16
|
setOpenClawConfig(api.config)
|
|
18
17
|
api.registerChannel({ plugin: dcgchatPlugin })
|
|
18
|
+
setWorkspaceDir(api.config?.agents?.defaults?.workspace)
|
|
19
19
|
api.registerTool((ctx) => {
|
|
20
20
|
const workspaceDir = ctx.workspaceDir
|
|
21
21
|
setWorkspaceDir(workspaceDir)
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dcrays/dcgchat-test",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.32",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw channel plugin for 书灵墨宝 (WebSocket)",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -16,12 +16,6 @@
|
|
|
16
16
|
"websocket",
|
|
17
17
|
"ai"
|
|
18
18
|
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"typecheck": "tsc --noEmit",
|
|
21
|
-
"build:production": "npx tsx scripts/build.ts production",
|
|
22
|
-
"build:prod": "npx tsx scripts/build.ts production",
|
|
23
|
-
"build:test": "npx tsx scripts/build.ts test"
|
|
24
|
-
},
|
|
25
19
|
"dependencies": {
|
|
26
20
|
"ali-oss": "file:src/libs/ali-oss-6.23.0.tgz",
|
|
27
21
|
"axios": "file:src/libs/axios-1.13.6.tgz",
|
|
@@ -37,18 +31,15 @@
|
|
|
37
31
|
"id": "dcgchat-test",
|
|
38
32
|
"label": "书灵墨宝",
|
|
39
33
|
"selectionLabel": "书灵墨宝",
|
|
40
|
-
"docsPath": "/channels/dcgchat",
|
|
34
|
+
"docsPath": "/channels/dcgchat-test",
|
|
41
35
|
"docsLabel": "dcgchat-test",
|
|
42
36
|
"blurb": "连接 OpenClaw 与 书灵墨宝 产品",
|
|
43
37
|
"order": 80
|
|
44
38
|
},
|
|
45
39
|
"install": {
|
|
46
40
|
"npmSpec": "@dcrays/dcgchat-test",
|
|
47
|
-
"localPath": "extensions/dcgchat",
|
|
41
|
+
"localPath": "extensions/dcgchat-test",
|
|
48
42
|
"defaultChoice": "npm"
|
|
49
43
|
}
|
|
50
|
-
},
|
|
51
|
-
"devDependencies": {
|
|
52
|
-
"openclaw": "^2026.3.13"
|
|
53
44
|
}
|
|
54
45
|
}
|
package/src/bot.ts
CHANGED
|
@@ -156,7 +156,7 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
156
156
|
|
|
157
157
|
const route = core.channel.routing.resolveAgentRoute({
|
|
158
158
|
cfg: config,
|
|
159
|
-
channel:
|
|
159
|
+
channel: "dcgchat-test",
|
|
160
160
|
accountId: account.accountId,
|
|
161
161
|
peer: { kind: 'direct', id: conversationId }
|
|
162
162
|
})
|
|
@@ -208,13 +208,13 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
208
208
|
ChatType: 'direct',
|
|
209
209
|
SenderName: agentDisplayName,
|
|
210
210
|
SenderId: userId,
|
|
211
|
-
Provider:
|
|
212
|
-
Surface:
|
|
211
|
+
Provider: "dcgchat-test",
|
|
212
|
+
Surface: "dcgchat-test",
|
|
213
213
|
MessageSid: msg.content.message_id,
|
|
214
214
|
Timestamp: Date.now(),
|
|
215
215
|
WasMentioned: true,
|
|
216
216
|
CommandAuthorized: true,
|
|
217
|
-
OriginatingChannel:
|
|
217
|
+
OriginatingChannel: "dcgchat-test",
|
|
218
218
|
OriginatingTo: `user:${userId}`,
|
|
219
219
|
...mediaPayload
|
|
220
220
|
})
|
|
@@ -226,7 +226,7 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
226
226
|
const prefixContext = createReplyPrefixContext({
|
|
227
227
|
cfg: config,
|
|
228
228
|
agentId: effectiveAgentId ?? '',
|
|
229
|
-
channel:
|
|
229
|
+
channel: "dcgchat-test",
|
|
230
230
|
accountId: account.accountId
|
|
231
231
|
})
|
|
232
232
|
|
|
@@ -236,8 +236,6 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
236
236
|
humanDelay: core.channel.reply.resolveHumanDelayConfig(config, route.agentId),
|
|
237
237
|
onReplyStart: async () => {},
|
|
238
238
|
deliver: async (payload: ReplyPayload, info) => {
|
|
239
|
-
dcgLogger(`[deliver]: kind=${info.kind}, text=${payload.text?.length ?? 0} chars, ${payload.text?.slice(0, 50)}`)
|
|
240
|
-
// Media from the outbound pipeline (post-streaming)
|
|
241
239
|
const mediaList = resolveReplyMediaList(payload)
|
|
242
240
|
for (const mediaUrl of mediaList) {
|
|
243
241
|
const key = getMediaKey(mediaUrl)
|
|
@@ -249,7 +247,9 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
249
247
|
onError: (err: unknown, info: { kind: string }) => {
|
|
250
248
|
dcgLogger(`${info.kind} reply failed: ${String(err)}`, 'error')
|
|
251
249
|
},
|
|
252
|
-
onIdle: () => {
|
|
250
|
+
onIdle: () => {
|
|
251
|
+
sendFinal(msgCtx)
|
|
252
|
+
}
|
|
253
253
|
})
|
|
254
254
|
|
|
255
255
|
let wasAborted = false
|
|
@@ -338,8 +338,8 @@ export async function handleDcgchatMessage(msg: InboundMessage, accountId: strin
|
|
|
338
338
|
}
|
|
339
339
|
await sendDcgchatMedia({ msgCtx, mediaUrl: resolved, text: '' })
|
|
340
340
|
}
|
|
341
|
-
sendFinal(msgCtx)
|
|
342
341
|
}
|
|
342
|
+
sendFinal(msgCtx)
|
|
343
343
|
clearSentMediaKeys(msg.content.message_id)
|
|
344
344
|
setMsgStatus('finished')
|
|
345
345
|
|
package/src/channel.ts
CHANGED
|
@@ -5,7 +5,6 @@ import { ossUpload } from './request/oss.js'
|
|
|
5
5
|
import { addSentMediaKey, getMsgParams, hasSentMediaKey } from './utils/global.js'
|
|
6
6
|
import { type DcgchatMsgContext, isWsOpen, sendFinal, wsSendRaw } from './transport.js'
|
|
7
7
|
import { dcgLogger, setLogger } from './utils/log.js'
|
|
8
|
-
import { channelInfo, ENV } from './utils/constant.js'
|
|
9
8
|
|
|
10
9
|
export type DcgchatMediaSendOptions = {
|
|
11
10
|
msgCtx: DcgchatMsgContext
|
|
@@ -15,8 +14,6 @@ export type DcgchatMediaSendOptions = {
|
|
|
15
14
|
|
|
16
15
|
export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<void> {
|
|
17
16
|
const { msgCtx } = opts
|
|
18
|
-
console.log('🚀 ~ sendDcgchatMedia ~ msgCtx:', msgCtx)
|
|
19
|
-
|
|
20
17
|
if (!isWsOpen()) {
|
|
21
18
|
dcgLogger(`outbound media skipped -> ws not open: ${opts.mediaUrl ?? ''}`)
|
|
22
19
|
return
|
|
@@ -51,7 +48,7 @@ export async function sendDcgchatMedia(opts: DcgchatMediaSendOptions): Promise<v
|
|
|
51
48
|
|
|
52
49
|
export function resolveAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedDcgchatAccount {
|
|
53
50
|
const id = accountId ?? DEFAULT_ACCOUNT_ID
|
|
54
|
-
const raw = (cfg.channels?.[
|
|
51
|
+
const raw = (cfg.channels?.["dcgchat-test"] as DcgchatConfig | undefined) ?? {}
|
|
55
52
|
return {
|
|
56
53
|
accountId: id,
|
|
57
54
|
enabled: raw.enabled !== false,
|
|
@@ -81,13 +78,13 @@ function createOutboundMsgContext(cfg: OpenClawConfig, accountId?: string | null
|
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
84
|
-
id:
|
|
81
|
+
id: "dcgchat-test",
|
|
85
82
|
meta: {
|
|
86
|
-
id:
|
|
83
|
+
id: "dcgchat-test",
|
|
87
84
|
label: '书灵墨宝',
|
|
88
85
|
selectionLabel: '书灵墨宝',
|
|
89
86
|
docsPath: '/channels/dcgchat',
|
|
90
|
-
docsLabel:
|
|
87
|
+
docsLabel: "dcgchat-test",
|
|
91
88
|
blurb: '连接 OpenClaw 与 书灵墨宝 产品',
|
|
92
89
|
order: 80
|
|
93
90
|
},
|
|
@@ -128,7 +125,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
128
125
|
channels: {
|
|
129
126
|
...cfg.channels,
|
|
130
127
|
dcgchat: {
|
|
131
|
-
...(cfg.channels?.[
|
|
128
|
+
...(cfg.channels?.["dcgchat-test"] as Record<string, unknown> | undefined),
|
|
132
129
|
enabled
|
|
133
130
|
}
|
|
134
131
|
}
|
|
@@ -159,11 +156,10 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
159
156
|
const msgCtx = createOutboundMsgContext(ctx.cfg, ctx.accountId)
|
|
160
157
|
if (isWsOpen()) {
|
|
161
158
|
wsSendRaw(msgCtx, { response: ctx.text })
|
|
162
|
-
|
|
163
|
-
dcgLogger(`channel sendText to ${msgCtx.userId}`)
|
|
159
|
+
dcgLogger(`channel sendText to ${msgCtx.userId} ${ctx.text?.slice(0, 50)}`)
|
|
164
160
|
}
|
|
165
161
|
return {
|
|
166
|
-
channel:
|
|
162
|
+
channel: "dcgchat-test",
|
|
167
163
|
messageId: `dcg-${Date.now()}`,
|
|
168
164
|
chatId: msgCtx.userId.toString()
|
|
169
165
|
}
|
|
@@ -172,7 +168,7 @@ export const dcgchatPlugin: ChannelPlugin<ResolvedDcgchatAccount> = {
|
|
|
172
168
|
const msgCtx = createOutboundMsgContext(ctx.cfg, ctx.accountId)
|
|
173
169
|
await sendDcgchatMedia({ msgCtx, mediaUrl: ctx.mediaUrl })
|
|
174
170
|
return {
|
|
175
|
-
channel:
|
|
171
|
+
channel: "dcgchat-test",
|
|
176
172
|
messageId: `dcg-${Date.now()}`,
|
|
177
173
|
chatId: msgCtx.userId.toString()
|
|
178
174
|
}
|
package/src/utils/constant.ts
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
export const ENV: 'production' | 'test' | 'develop' = 'test'
|
|
2
2
|
|
|
3
|
-
export const channelInfo: Record<string, string> = {
|
|
4
|
-
production: 'dcgchat',
|
|
5
|
-
test: 'dcgchat-test'
|
|
6
|
-
}
|
|
7
3
|
|
|
8
4
|
export const systemCommand = ['/new', '/status']
|
|
9
5
|
export const interruptCommand = ['/stop']
|
package/src/utils/global.ts
CHANGED
|
@@ -22,16 +22,21 @@ export function getOpenClawConfig(): OpenClawConfig | null {
|
|
|
22
22
|
return config
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
import type {
|
|
25
|
+
import type { OpenClawConfig, PluginRuntime } from 'openclaw/plugin-sdk'
|
|
26
26
|
import { dcgLogger } from './log.js'
|
|
27
27
|
import { IMsgParams } from '../types.js'
|
|
28
|
+
import { channelInfo, ENV } from './constant.js'
|
|
28
29
|
|
|
29
30
|
const path = require('path')
|
|
30
31
|
const fs = require('fs')
|
|
31
32
|
const os = require('os')
|
|
32
33
|
|
|
33
34
|
function getWorkspacePath() {
|
|
34
|
-
const workspacePath = path.join(
|
|
35
|
+
const workspacePath = path.join(
|
|
36
|
+
os.homedir(),
|
|
37
|
+
config?.channels?.["dcgchat-test"]?.appId == 110 ? '.mobook' : '.openclaw',
|
|
38
|
+
'workspace'
|
|
39
|
+
)
|
|
35
40
|
if (fs.existsSync(workspacePath)) {
|
|
36
41
|
return workspacePath
|
|
37
42
|
}
|
package/src/utils/log.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { RuntimeEnv } from 'openclaw/plugin-sdk'
|
|
2
|
-
import { channelInfo, ENV } from './constant.js'
|
|
3
2
|
|
|
4
3
|
let logger: RuntimeEnv | null = null
|
|
5
4
|
|
|
@@ -11,6 +10,6 @@ export function dcgLogger(message: string, type: 'log' | 'error' = 'log'): void
|
|
|
11
10
|
if (logger) {
|
|
12
11
|
logger[type](`书灵墨宝🚀 ~ [${new Date().toISOString()}] ${message}`)
|
|
13
12
|
} else {
|
|
14
|
-
console[type](`书灵墨宝🚀 ~ ${new Date().toISOString()} [${
|
|
13
|
+
console[type](`书灵墨宝🚀 ~ ${new Date().toISOString()} [${"dcgchat-test"}]: ${message}`)
|
|
15
14
|
}
|
|
16
15
|
}
|
package/README.md
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# OpenClaw 书灵墨宝 插件
|
|
2
|
-
|
|
3
|
-
连接 OpenClaw 与 书灵墨宝 产品的通道插件。
|
|
4
|
-
|
|
5
|
-
## 架构
|
|
6
|
-
|
|
7
|
-
```
|
|
8
|
-
┌──────────┐ WebSocket ┌──────────────┐ WebSocket ┌─────────────────────┐
|
|
9
|
-
│ Web 前端 │ ←───────────────→ │ 公司后端服务 │ ←───────────────→ │ OpenClaw(工作电脑) │
|
|
10
|
-
└──────────┘ └──────────────┘ (OpenClaw 主动连) └─────────────────────┘
|
|
11
|
-
```
|
|
12
|
-
|
|
13
|
-
- OpenClaw 插件**主动连接**后端的 WebSocket 服务(不需要公网 IP)
|
|
14
|
-
- 后端收到用户消息后转发给 OpenClaw,OpenClaw 回复后发回后端
|
|
15
|
-
|
|
16
|
-
## 快速开始
|
|
17
|
-
|
|
18
|
-
### 1. 安装插件
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
pnpm openclaw plugins install -l /path/to/openclaw-dcgchat
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### 2. 配置
|
|
25
|
-
|
|
26
|
-
```bash
|
|
27
|
-
openclaw config set channels.dcgchat.enabled true
|
|
28
|
-
openclaw config set channels.dcgchat.wsUrl "ws://your-backend:8080/openclaw/ws"
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
### 3. 启动
|
|
32
|
-
|
|
33
|
-
```bash
|
|
34
|
-
pnpm openclaw gateway
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## 消息协议(MVP)
|
|
38
|
-
|
|
39
|
-
### 下行:后端 → OpenClaw(用户消息)
|
|
40
|
-
|
|
41
|
-
```json
|
|
42
|
-
{ "type": "message", "userId": "user_001", "text": "你好" }
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### 上行:OpenClaw → 后端(Agent 回复)
|
|
46
|
-
|
|
47
|
-
```json
|
|
48
|
-
{ "type": "reply", "userId": "user_001", "text": "你好!有什么可以帮你的?" }
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## 配置项
|
|
52
|
-
|
|
53
|
-
| 配置键 | 类型 | 说明 |
|
|
54
|
-
|--------|------|------|
|
|
55
|
-
| `channels.dcgchat.enabled` | boolean | 是否启用 |
|
|
56
|
-
| `channels.dcgchat.wsUrl` | string | 后端 WebSocket 地址 |
|
|
57
|
-
|
|
58
|
-
## 开发
|
|
59
|
-
|
|
60
|
-
```bash
|
|
61
|
-
# 安装依赖
|
|
62
|
-
pnpm install
|
|
63
|
-
|
|
64
|
-
# 类型检查
|
|
65
|
-
pnpm typecheck
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## 文件结构
|
|
69
|
-
|
|
70
|
-
- `index.ts` - 插件入口
|
|
71
|
-
- `src/channel.ts` - ChannelPlugin 定义
|
|
72
|
-
- `src/runtime.ts` - 插件 runtime
|
|
73
|
-
- `src/types.ts` - 类型定义
|
|
74
|
-
- `src/monitor.ts` - WebSocket 连接与断线重连
|
|
75
|
-
- `src/bot.ts` - 消息处理与 Agent 调用
|
|
76
|
-
|
|
77
|
-
## 后续迭代
|
|
78
|
-
|
|
79
|
-
- [ ] Token 认证
|
|
80
|
-
- [ ] 流式输出
|
|
81
|
-
- [ ] Typing 指示
|
|
82
|
-
- [ ] messageId 去重
|
|
83
|
-
- [ ] 错误消息类型
|