@dcrays/dcgchat-test 0.2.26 → 0.2.28
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 +19 -17
- package/openclaw.plugin.json +4 -2
- package/package.json +5 -7
- package/src/bot.ts +214 -592
- package/src/channel.ts +119 -184
- package/src/monitor.ts +129 -178
- package/src/{api.ts → request/api.ts} +34 -35
- package/src/request/oss.ts +58 -0
- package/src/request/request.ts +198 -0
- package/src/{userInfo.ts → request/userInfo.ts} +36 -34
- package/src/skill.ts +119 -197
- package/src/tool.ts +109 -113
- package/src/transport.ts +108 -0
- package/src/types.ts +75 -64
- package/src/utils/constant.ts +4 -0
- package/src/utils/global.ts +112 -0
- package/src/utils/log.ts +15 -0
- package/src/utils/searchFile.ts +212 -0
- package/README.md +0 -83
- package/src/connection.ts +0 -11
- package/src/log.ts +0 -46
- package/src/oss.ts +0 -72
- package/src/request.ts +0 -201
- package/src/runtime.ts +0 -40
package/src/tool.ts
CHANGED
|
@@ -1,140 +1,136 @@
|
|
|
1
|
+
import type { OpenClawPluginApi } from 'openclaw/plugin-sdk'
|
|
2
|
+
import { getMsgParams, getMsgStatus, getWsConnection } from './utils/global.js'
|
|
3
|
+
import { dcgLogger } from './utils/log.js'
|
|
4
|
+
import { isWsOpen } from './transport.js'
|
|
1
5
|
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
return msgStatus;
|
|
30
|
-
}
|
|
31
|
-
let toolCallId = '';
|
|
32
|
-
let toolName = '';
|
|
33
|
-
type PluginHookName = "before_model_resolve" | "before_prompt_build" | "before_agent_start" | "llm_input" | "llm_output" | "agent_end" | "before_compaction" | "after_compaction" | "before_reset" | "message_received" | "message_sending" | "message_sent" | "before_tool_call" | "after_tool_call" | "tool_result_persist" | "before_message_write" | "session_start" | "session_end" | "subagent_spawning" | "subagent_delivery_target" | "subagent_spawned" | "subagent_ended" | "gateway_start" | "gateway_stop";
|
|
6
|
+
let toolCallId = ''
|
|
7
|
+
let toolName = ''
|
|
8
|
+
type PluginHookName =
|
|
9
|
+
| 'before_model_resolve'
|
|
10
|
+
| 'before_prompt_build'
|
|
11
|
+
| 'before_agent_start'
|
|
12
|
+
| 'llm_input'
|
|
13
|
+
| 'llm_output'
|
|
14
|
+
| 'agent_end'
|
|
15
|
+
| 'before_compaction'
|
|
16
|
+
| 'after_compaction'
|
|
17
|
+
| 'before_reset'
|
|
18
|
+
| 'message_received'
|
|
19
|
+
| 'message_sending'
|
|
20
|
+
| 'message_sent'
|
|
21
|
+
| 'before_tool_call'
|
|
22
|
+
| 'after_tool_call'
|
|
23
|
+
| 'tool_result_persist'
|
|
24
|
+
| 'before_message_write'
|
|
25
|
+
| 'session_start'
|
|
26
|
+
| 'session_end'
|
|
27
|
+
| 'subagent_spawning'
|
|
28
|
+
| 'subagent_delivery_target'
|
|
29
|
+
| 'subagent_spawned'
|
|
30
|
+
| 'subagent_ended'
|
|
31
|
+
| 'gateway_start'
|
|
32
|
+
| 'gateway_stop'
|
|
34
33
|
const eventList = [
|
|
35
|
-
{event: 'message_received', message: ''},
|
|
34
|
+
{ event: 'message_received', message: '' },
|
|
36
35
|
// {event: 'before_model_resolve', message: ''},
|
|
37
36
|
// {event: 'before_prompt_build', message: '正在查阅背景资料,构建思考逻辑'},
|
|
38
37
|
// {event: 'before_agent_start', message: '书灵墨宝已就位,准备开始执行任务'},
|
|
39
|
-
{event: 'subagent_spawning', message: ''},
|
|
40
|
-
{event: 'subagent_spawned', message: ''},
|
|
41
|
-
{event: 'subagent_delivery_target', message: ''},
|
|
38
|
+
{ event: 'subagent_spawning', message: '' },
|
|
39
|
+
{ event: 'subagent_spawned', message: '' },
|
|
40
|
+
{ event: 'subagent_delivery_target', message: '' },
|
|
42
41
|
// {event: 'llm_input', message: ''},
|
|
43
|
-
{event: 'llm_output', message: ''},
|
|
42
|
+
{ event: 'llm_output', message: '' },
|
|
44
43
|
// {event: 'agent_end', message: '核心任务已处理完毕...'},
|
|
45
|
-
{event: 'subagent_ended', message: ''},
|
|
44
|
+
{ event: 'subagent_ended', message: '' },
|
|
46
45
|
// {event: 'before_message_write', message: '正在将本次对话存入记忆库...'},
|
|
47
46
|
// {event: 'message_sending', message: ''},
|
|
48
47
|
// {event: 'message_send', message: ''},
|
|
49
|
-
{event: 'before_tool_call', message: ''},
|
|
50
|
-
{event: 'after_tool_call', message: ''}
|
|
51
|
-
]
|
|
48
|
+
{ event: 'before_tool_call', message: '' },
|
|
49
|
+
{ event: 'after_tool_call', message: '' }
|
|
50
|
+
]
|
|
52
51
|
|
|
53
52
|
function sendToolCallMessage(text: string, toolCallId: string, isCover: number) {
|
|
54
53
|
const ws = getWsConnection()
|
|
55
|
-
const params = getMsgParams()
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
domain_id: params?.domainId,
|
|
80
|
-
app_id: params?.appId,
|
|
81
|
-
bot_id: params?.botId,
|
|
82
|
-
agent_id: params?.agentId,
|
|
83
|
-
tool_call_id: toolCallId,
|
|
84
|
-
is_cover: isCover,
|
|
85
|
-
thinking_content: text,
|
|
86
|
-
response: '',
|
|
87
|
-
session_id:params?.sessionId,
|
|
88
|
-
message_id: params?.messageId || Date.now().toString()
|
|
89
|
-
},
|
|
90
|
-
}));
|
|
91
|
-
ws.send(JSON.stringify({
|
|
92
|
-
messageType: "openclaw_bot_chat",
|
|
93
|
-
_userId: params?.userId,
|
|
94
|
-
source: "client",
|
|
95
|
-
content: {
|
|
96
|
-
bot_token: params?.token,
|
|
97
|
-
domain_id: params?.domainId,
|
|
98
|
-
app_id: params?.appId,
|
|
99
|
-
bot_id: params?.botId,
|
|
100
|
-
agent_id: params?.agentId,
|
|
101
|
-
response: 'all_finished',
|
|
102
|
-
session_id:params?.sessionId,
|
|
103
|
-
message_id: params?.messageId || Date.now().toString()
|
|
104
|
-
},
|
|
105
|
-
}))
|
|
54
|
+
const params = getMsgParams()
|
|
55
|
+
if (isWsOpen()) {
|
|
56
|
+
ws?.send(
|
|
57
|
+
JSON.stringify({
|
|
58
|
+
messageType: 'openclaw_bot_chat',
|
|
59
|
+
_userId: params?.userId,
|
|
60
|
+
source: 'client',
|
|
61
|
+
is_finish: -1,
|
|
62
|
+
content: {
|
|
63
|
+
is_finish: -1,
|
|
64
|
+
bot_token: params?.token,
|
|
65
|
+
domain_id: params?.domainId,
|
|
66
|
+
app_id: params?.appId,
|
|
67
|
+
bot_id: params?.botId,
|
|
68
|
+
agent_id: params?.agentId,
|
|
69
|
+
tool_call_id: toolCallId,
|
|
70
|
+
is_cover: isCover,
|
|
71
|
+
thinking_content: text,
|
|
72
|
+
response: '',
|
|
73
|
+
session_id: params?.sessionId,
|
|
74
|
+
message_id: params?.messageId || Date.now().toString()
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
)
|
|
106
78
|
}
|
|
107
79
|
}
|
|
108
80
|
|
|
109
81
|
export function monitoringToolMessage(api: OpenClawPluginApi) {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
82
|
+
for (const item of eventList) {
|
|
83
|
+
api.on(item.event as PluginHookName, (event: any) => {
|
|
84
|
+
const status = getMsgStatus()
|
|
85
|
+
if (status === 'running') {
|
|
86
|
+
dcgLogger(`工具调用结果: ~ event:${item.event} ${JSON.stringify(event)}`)
|
|
113
87
|
if (['after_tool_call', 'before_tool_call'].includes(item.event)) {
|
|
114
|
-
const { result: _result, ...rest } = event
|
|
88
|
+
const { result: _result, ...rest } = event
|
|
115
89
|
const text = JSON.stringify({
|
|
116
90
|
type: item.event,
|
|
117
91
|
specialIdentification: 'dcgchat_tool_call_special_identification',
|
|
118
92
|
callId: event.toolCallId || event.runId || Date.now().toString(),
|
|
119
93
|
...rest,
|
|
120
94
|
status: item.event === 'after_tool_call' ? 'finished' : 'running'
|
|
121
|
-
})
|
|
95
|
+
})
|
|
122
96
|
sendToolCallMessage(text, event.toolCallId || event.runId || Date.now().toString(), item.event === 'after_tool_call' ? 1 : 0)
|
|
123
97
|
} else if (item.event) {
|
|
98
|
+
if (item.event === 'llm_output') {
|
|
99
|
+
if (event.lastAssistant?.errorMessage === '429-账户额度耗尽') {
|
|
100
|
+
const ws = getWsConnection()
|
|
101
|
+
const params = getMsgParams()
|
|
102
|
+
if (isWsOpen()) {
|
|
103
|
+
ws?.send(
|
|
104
|
+
JSON.stringify({
|
|
105
|
+
messageType: 'openclaw_bot_cost',
|
|
106
|
+
_userId: params?.userId,
|
|
107
|
+
source: 'client',
|
|
108
|
+
content: {
|
|
109
|
+
bot_token: params?.token,
|
|
110
|
+
domain_id: params?.domainId,
|
|
111
|
+
app_id: params?.appId,
|
|
112
|
+
bot_id: params?.botId,
|
|
113
|
+
agent_id: params?.agentId,
|
|
114
|
+
response: '您的余额不足,请充值后继续使用',
|
|
115
|
+
session_id: params?.sessionId,
|
|
116
|
+
message_id: params?.messageId || Date.now().toString()
|
|
117
|
+
}
|
|
118
|
+
})
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
124
|
const text = JSON.stringify({
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
// }
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
125
|
+
type: item.event,
|
|
126
|
+
specialIdentification: 'dcgchat_tool_call_special_identification',
|
|
127
|
+
toolName: '',
|
|
128
|
+
callId: event.runId || Date.now().toString(),
|
|
129
|
+
params: item.message
|
|
130
|
+
})
|
|
131
|
+
sendToolCallMessage(text, event.runId || Date.now().toString(), 0)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
})
|
|
135
|
+
}
|
|
136
|
+
}
|
package/src/transport.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { getWsConnection } from './utils/global.js'
|
|
2
|
+
import { dcgLogger } from './utils/log.js'
|
|
3
|
+
|
|
4
|
+
export type DcgchatMsgContext = {
|
|
5
|
+
userId: number
|
|
6
|
+
botToken: string
|
|
7
|
+
domainId?: string
|
|
8
|
+
appId?: string
|
|
9
|
+
botId?: string
|
|
10
|
+
agentId?: string
|
|
11
|
+
sessionId: string
|
|
12
|
+
messageId: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function createMsgContext(msg: {
|
|
16
|
+
_userId: number
|
|
17
|
+
content: {
|
|
18
|
+
bot_token: string
|
|
19
|
+
domain_id?: string
|
|
20
|
+
app_id?: string
|
|
21
|
+
bot_id?: string
|
|
22
|
+
agent_id?: string
|
|
23
|
+
session_id: string
|
|
24
|
+
message_id: string
|
|
25
|
+
}
|
|
26
|
+
}): DcgchatMsgContext {
|
|
27
|
+
return {
|
|
28
|
+
userId: msg._userId,
|
|
29
|
+
botToken: msg.content.bot_token,
|
|
30
|
+
domainId: msg.content.domain_id,
|
|
31
|
+
appId: msg.content.app_id,
|
|
32
|
+
botId: msg.content.bot_id,
|
|
33
|
+
agentId: msg.content.agent_id,
|
|
34
|
+
sessionId: msg.content.session_id,
|
|
35
|
+
messageId: msg.content.message_id
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildContent(ctx: DcgchatMsgContext, extra: Record<string, unknown>) {
|
|
40
|
+
return {
|
|
41
|
+
bot_token: ctx.botToken,
|
|
42
|
+
domain_id: ctx.domainId,
|
|
43
|
+
app_id: ctx.appId,
|
|
44
|
+
bot_id: ctx.botId,
|
|
45
|
+
agent_id: ctx.agentId,
|
|
46
|
+
session_id: ctx.sessionId,
|
|
47
|
+
message_id: ctx.messageId || Date.now().toString(),
|
|
48
|
+
...extra
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function buildEnvelope(ctx: DcgchatMsgContext, extra: Record<string, unknown>) {
|
|
53
|
+
return {
|
|
54
|
+
messageType: 'openclaw_bot_chat' as const,
|
|
55
|
+
_userId: ctx.userId,
|
|
56
|
+
source: 'client' as const,
|
|
57
|
+
content: buildContent(ctx, extra)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function isWsOpen(): boolean {
|
|
62
|
+
const isOpen = getWsConnection()?.readyState === WebSocket.OPEN
|
|
63
|
+
if (!isOpen) {
|
|
64
|
+
dcgLogger(`socket not ready ${getWsConnection()?.readyState}`, 'error')
|
|
65
|
+
}
|
|
66
|
+
return isOpen
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Content is stringified separately (double-encoded) to match the
|
|
71
|
+
* dcgchat wire protocol used by the chat stream path.
|
|
72
|
+
*/
|
|
73
|
+
export function wsSend(ctx: DcgchatMsgContext, extra: Record<string, unknown>): boolean {
|
|
74
|
+
const ws = getWsConnection()
|
|
75
|
+
if (ws?.readyState !== WebSocket.OPEN) return false
|
|
76
|
+
const envelope = buildEnvelope(ctx, extra)
|
|
77
|
+
ws.send(JSON.stringify({ ...envelope, content: JSON.stringify(envelope.content) }))
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Content stays as a nested object (single-encoded).
|
|
83
|
+
* Matches the legacy wire format used by media and outbound-pipeline messages.
|
|
84
|
+
*/
|
|
85
|
+
export function wsSendRaw(ctx: DcgchatMsgContext, extra: Record<string, unknown>): boolean {
|
|
86
|
+
const ws = getWsConnection()
|
|
87
|
+
if (isWsOpen()) {
|
|
88
|
+
ws?.send(JSON.stringify(buildEnvelope(ctx, extra)))
|
|
89
|
+
}
|
|
90
|
+
return true
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function sendChunk(ctx: DcgchatMsgContext, text: string): boolean {
|
|
94
|
+
return wsSend(ctx, { response: text, state: 'chunk' })
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function sendFinal(ctx: DcgchatMsgContext): boolean {
|
|
98
|
+
dcgLogger(` message handling complete`)
|
|
99
|
+
return wsSend(ctx, { response: '', state: 'final' })
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function sendText(ctx: DcgchatMsgContext, text: string): boolean {
|
|
103
|
+
return wsSend(ctx, { response: text })
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function sendError(ctx: DcgchatMsgContext, errorMsg: string): boolean {
|
|
107
|
+
return wsSend(ctx, { response: `[错误] ${errorMsg}`, state: 'final' })
|
|
108
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
* 插件配置(channels.dcgchat 下的字段)
|
|
3
3
|
*/
|
|
4
4
|
export type DcgchatConfig = {
|
|
5
|
-
enabled?: boolean
|
|
5
|
+
enabled?: boolean
|
|
6
6
|
/** 后端 WebSocket 地址,例如 ws://localhost:8080/openclaw/ws */
|
|
7
|
-
wsUrl?: string
|
|
7
|
+
wsUrl?: string
|
|
8
8
|
/** 连接认证 token */
|
|
9
|
-
botToken?: string
|
|
9
|
+
botToken?: string
|
|
10
10
|
/** 用户标识 */
|
|
11
|
-
userId?: string
|
|
12
|
-
domainId?: string
|
|
13
|
-
appId?: string
|
|
14
|
-
}
|
|
11
|
+
userId?: string
|
|
12
|
+
domainId?: string
|
|
13
|
+
appId?: string
|
|
14
|
+
}
|
|
15
15
|
|
|
16
16
|
export type ResolvedDcgchatAccount = {
|
|
17
|
-
accountId: string
|
|
18
|
-
enabled: boolean
|
|
19
|
-
configured: boolean
|
|
20
|
-
wsUrl: string
|
|
21
|
-
botToken: string
|
|
22
|
-
userId: string
|
|
23
|
-
domainId?: string
|
|
24
|
-
appId?: string
|
|
25
|
-
}
|
|
17
|
+
accountId: string
|
|
18
|
+
enabled: boolean
|
|
19
|
+
configured: boolean
|
|
20
|
+
wsUrl: string
|
|
21
|
+
botToken: string
|
|
22
|
+
userId: string
|
|
23
|
+
domainId?: string
|
|
24
|
+
appId?: string
|
|
25
|
+
}
|
|
26
26
|
|
|
27
27
|
/**
|
|
28
28
|
* 下行消息:后端 → OpenClaw(用户发的消息)
|
|
@@ -33,25 +33,25 @@ export type ResolvedDcgchatAccount = {
|
|
|
33
33
|
// text: string;
|
|
34
34
|
// };
|
|
35
35
|
export type InboundMessage = {
|
|
36
|
-
messageType: string
|
|
37
|
-
_userId: number
|
|
38
|
-
source: string
|
|
36
|
+
messageType: string // "openclaw_bot_chat",
|
|
37
|
+
_userId: number
|
|
38
|
+
source: string // 'server',
|
|
39
39
|
// content: string;
|
|
40
40
|
content: {
|
|
41
|
-
bot_token: string
|
|
42
|
-
domain_id?: string
|
|
43
|
-
app_id?: string
|
|
44
|
-
bot_id?: string
|
|
45
|
-
agent_id?: string
|
|
46
|
-
session_id: string
|
|
47
|
-
message_id: string
|
|
48
|
-
text: string
|
|
41
|
+
bot_token: string
|
|
42
|
+
domain_id?: string
|
|
43
|
+
app_id?: string
|
|
44
|
+
bot_id?: string
|
|
45
|
+
agent_id?: string
|
|
46
|
+
session_id: string
|
|
47
|
+
message_id: string
|
|
48
|
+
text: string
|
|
49
49
|
files?: {
|
|
50
|
-
url: string
|
|
51
|
-
name: string
|
|
52
|
-
}[]
|
|
53
|
-
}
|
|
54
|
-
}
|
|
50
|
+
url: string
|
|
51
|
+
name: string
|
|
52
|
+
}[]
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
55
|
|
|
56
56
|
// {"_userId":40,"content":"{\"bot_token\":\"sk_b7f8a3e1c5d24e6f8a1b3c4d5e6f7a8b\",\"session_id\":\"1\",\"message_id\":\"1\",\"text\":\"你好\"}","messageType":"openclaw_bot_chat","msgId":398599,"source":"server","title":"OPENCLAW机器人对话"}
|
|
57
57
|
|
|
@@ -65,51 +65,62 @@ export type InboundMessage = {
|
|
|
65
65
|
// };
|
|
66
66
|
|
|
67
67
|
export type OutboundReply = {
|
|
68
|
-
messageType: string
|
|
69
|
-
_userId: number
|
|
70
|
-
source: string
|
|
68
|
+
messageType: string // "openclaw_bot_chat",
|
|
69
|
+
_userId: number // 100
|
|
70
|
+
source: string // 'client',
|
|
71
71
|
// content: string;
|
|
72
72
|
content: {
|
|
73
|
-
bot_token: string
|
|
74
|
-
session_id: string
|
|
75
|
-
message_id: string
|
|
76
|
-
response: string
|
|
77
|
-
state: string
|
|
78
|
-
domain_id?: string
|
|
79
|
-
app_id?: string
|
|
80
|
-
bot_id?: string
|
|
81
|
-
agent_id?: string
|
|
82
|
-
files?: {url: string
|
|
83
|
-
}
|
|
84
|
-
}
|
|
73
|
+
bot_token: string // ""
|
|
74
|
+
session_id: string // ""
|
|
75
|
+
message_id: string // ""
|
|
76
|
+
response: string // ""
|
|
77
|
+
state: string // final, chunk
|
|
78
|
+
domain_id?: string
|
|
79
|
+
app_id?: string
|
|
80
|
+
bot_id?: string
|
|
81
|
+
agent_id?: string
|
|
82
|
+
files?: { url: string; name: string }[]
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
85
|
|
|
86
86
|
export interface IResponse<T = unknown> {
|
|
87
87
|
/** 响应状态码 */
|
|
88
|
-
code?: number | string
|
|
88
|
+
code?: number | string
|
|
89
89
|
/** 响应数据 */
|
|
90
|
-
data?: T
|
|
90
|
+
data?: T
|
|
91
91
|
/** 响应消息 */
|
|
92
|
-
message?: string
|
|
92
|
+
message?: string
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
export interface IStsToken {
|
|
96
|
-
bucket: string
|
|
97
|
-
endPoint: string
|
|
98
|
-
expiration: string
|
|
99
|
-
ossFileKey: string
|
|
100
|
-
policy: string
|
|
101
|
-
region: string
|
|
102
|
-
signature: string
|
|
103
|
-
sourceFileName: string
|
|
104
|
-
stsEndPoint: string
|
|
105
|
-
tempAccessKeyId: string
|
|
106
|
-
tempAccessKeySecret: string
|
|
107
|
-
tempSecurityToken: string
|
|
108
|
-
uploadDir: string
|
|
109
|
-
protocol: string
|
|
96
|
+
bucket: string
|
|
97
|
+
endPoint: string
|
|
98
|
+
expiration: string
|
|
99
|
+
ossFileKey: string
|
|
100
|
+
policy: string
|
|
101
|
+
region: string
|
|
102
|
+
signature: string
|
|
103
|
+
sourceFileName: string
|
|
104
|
+
stsEndPoint: string
|
|
105
|
+
tempAccessKeyId: string
|
|
106
|
+
tempAccessKeySecret: string
|
|
107
|
+
tempSecurityToken: string
|
|
108
|
+
uploadDir: string
|
|
109
|
+
protocol: string
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
export interface IStsTokenReq {
|
|
113
113
|
sourceFileName: string
|
|
114
114
|
isPrivate: number
|
|
115
115
|
}
|
|
116
|
+
|
|
117
|
+
export interface IMsgParams {
|
|
118
|
+
userId: number
|
|
119
|
+
token: string
|
|
120
|
+
sessionId: string
|
|
121
|
+
messageId: string
|
|
122
|
+
domainId: string
|
|
123
|
+
appId: string
|
|
124
|
+
botId: string
|
|
125
|
+
agentId: string
|
|
126
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/** socket connection */
|
|
2
|
+
import type WebSocket from 'ws'
|
|
3
|
+
|
|
4
|
+
let ws: WebSocket | null = null
|
|
5
|
+
|
|
6
|
+
export function setWsConnection(next: WebSocket | null) {
|
|
7
|
+
ws = next
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function getWsConnection(): WebSocket | null {
|
|
11
|
+
return ws
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// OpenClawConfig
|
|
15
|
+
let config: OpenClawConfig | null = null
|
|
16
|
+
|
|
17
|
+
export function setOpenClawConfig(next: OpenClawConfig | null) {
|
|
18
|
+
config = next
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getOpenClawConfig(): OpenClawConfig | null {
|
|
22
|
+
return config
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
import type { ChannelLogSink, OpenClawConfig, PluginRuntime } from 'openclaw/plugin-sdk'
|
|
26
|
+
import { dcgLogger } from './log.js'
|
|
27
|
+
import { IMsgParams } from '../types.js'
|
|
28
|
+
|
|
29
|
+
const path = require('path')
|
|
30
|
+
const fs = require('fs')
|
|
31
|
+
const os = require('os')
|
|
32
|
+
|
|
33
|
+
function getWorkspacePath() {
|
|
34
|
+
const workspacePath = path.join(os.homedir(), '.openclaw', 'workspace')
|
|
35
|
+
if (fs.existsSync(workspacePath)) {
|
|
36
|
+
return workspacePath
|
|
37
|
+
}
|
|
38
|
+
return null
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let runtime: PluginRuntime | null = null
|
|
42
|
+
let workspaceDir: string = getWorkspacePath()
|
|
43
|
+
|
|
44
|
+
export function setWorkspaceDir(dir?: string) {
|
|
45
|
+
if (dir) {
|
|
46
|
+
workspaceDir = dir
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
export function getWorkspaceDir(): string {
|
|
50
|
+
if (!workspaceDir) {
|
|
51
|
+
dcgLogger?.('Workspace directory not initialized', 'error')
|
|
52
|
+
}
|
|
53
|
+
return workspaceDir
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function setDcgchatRuntime(next: PluginRuntime) {
|
|
57
|
+
runtime = next
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function getDcgchatRuntime(): PluginRuntime {
|
|
61
|
+
if (!runtime) {
|
|
62
|
+
dcgLogger?.('runtime not initialized', 'error')
|
|
63
|
+
}
|
|
64
|
+
return runtime as PluginRuntime
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let msgParams = {} as IMsgParams
|
|
68
|
+
export function setMsgParams(params: any) {
|
|
69
|
+
msgParams = params
|
|
70
|
+
}
|
|
71
|
+
export function getMsgParams() {
|
|
72
|
+
return msgParams
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
let msgStatus: 'running' | 'finished' | '' = ''
|
|
76
|
+
export function setMsgStatus(status: 'running' | 'finished' | '') {
|
|
77
|
+
msgStatus = status
|
|
78
|
+
}
|
|
79
|
+
export function getMsgStatus() {
|
|
80
|
+
return msgStatus
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const getMediaKey = (url: string) => url.split(/[\\/]/).pop() ?? url
|
|
84
|
+
|
|
85
|
+
/** 已发送媒体去重:外层 messageId → 内层该会话下已发送的媒体 key(文件名) */
|
|
86
|
+
const sentMediaKeysBySession = new Map<string, Set<string>>()
|
|
87
|
+
|
|
88
|
+
function getSessionMediaSet(messageId: string): Set<string> {
|
|
89
|
+
let set = sentMediaKeysBySession.get(messageId)
|
|
90
|
+
if (!set) {
|
|
91
|
+
set = new Set<string>()
|
|
92
|
+
sentMediaKeysBySession.set(messageId, set)
|
|
93
|
+
}
|
|
94
|
+
return set
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function addSentMediaKey(messageId: string, url: string) {
|
|
98
|
+
getSessionMediaSet(messageId).add(getMediaKey(url))
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function hasSentMediaKey(messageId: string, url: string): boolean {
|
|
102
|
+
return sentMediaKeysBySession.get(messageId)?.has(getMediaKey(url)) ?? false
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** 不传 messageId 时清空全部会话;传入则只清空该会话 */
|
|
106
|
+
export function clearSentMediaKeys(messageId?: string) {
|
|
107
|
+
if (messageId) {
|
|
108
|
+
sentMediaKeysBySession.delete(messageId)
|
|
109
|
+
} else {
|
|
110
|
+
sentMediaKeysBySession.clear()
|
|
111
|
+
}
|
|
112
|
+
}
|
package/src/utils/log.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RuntimeEnv } from 'openclaw/plugin-sdk'
|
|
2
|
+
|
|
3
|
+
let logger: RuntimeEnv | null = null
|
|
4
|
+
|
|
5
|
+
export function setLogger(next: RuntimeEnv | null) {
|
|
6
|
+
logger = next
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function dcgLogger(message: string, type: 'log' | 'error' = 'log'): void {
|
|
10
|
+
if (logger) {
|
|
11
|
+
logger[type](`书灵墨宝🚀 ~ [${new Date().toISOString()}] ${message}`)
|
|
12
|
+
} else {
|
|
13
|
+
console[type](`书灵墨宝🚀 ~ ${new Date().toISOString()} [${"dcgchat-test"}]: ${message}`)
|
|
14
|
+
}
|
|
15
|
+
}
|