@dcrays/dcgchat-test 0.5.0-alpha.2 → 0.5.0-alpha.3

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.
Files changed (42) hide show
  1. package/index.js +292 -0
  2. package/package.json +7 -15
  3. package/schemas/gateway-cron-finished.payload.json +39 -0
  4. package/index.ts +0 -24
  5. package/src/agent.ts +0 -128
  6. package/src/bot.ts +0 -515
  7. package/src/channel.ts +0 -474
  8. package/src/cron.ts +0 -199
  9. package/src/cronToolCall.ts +0 -202
  10. package/src/gateway/cronFinishedPayload.ts +0 -118
  11. package/src/gateway/index.ts +0 -452
  12. package/src/gateway/security.ts +0 -95
  13. package/src/gateway/socket.ts +0 -285
  14. package/src/libs/ali-oss-6.23.0.tgz +0 -0
  15. package/src/libs/axios-1.13.6.tgz +0 -0
  16. package/src/libs/md5-2.3.0.tgz +0 -0
  17. package/src/libs/mime-types-3.0.2.tgz +0 -0
  18. package/src/libs/unzipper-0.12.3.tgz +0 -0
  19. package/src/libs/ws-8.19.0.tgz +0 -0
  20. package/src/monitor.ts +0 -165
  21. package/src/request/api.ts +0 -70
  22. package/src/request/oss.ts +0 -212
  23. package/src/request/request.ts +0 -192
  24. package/src/request/userInfo.ts +0 -93
  25. package/src/session.ts +0 -19
  26. package/src/sessionTermination.ts +0 -168
  27. package/src/skill.ts +0 -146
  28. package/src/tool.ts +0 -403
  29. package/src/tools/messageTool.ts +0 -273
  30. package/src/transport.ts +0 -206
  31. package/src/types.ts +0 -139
  32. package/src/utils/agentErrors.ts +0 -23
  33. package/src/utils/constant.ts +0 -7
  34. package/src/utils/gatewayMsgHanlder.ts +0 -84
  35. package/src/utils/global.ts +0 -161
  36. package/src/utils/log.ts +0 -15
  37. package/src/utils/params.ts +0 -88
  38. package/src/utils/searchFile.ts +0 -228
  39. package/src/utils/workspaceFilePaths.ts +0 -89
  40. package/src/utils/wsMessageHandler.ts +0 -64
  41. package/src/utils/zipExtract.ts +0 -97
  42. package/src/utils/zipPath.ts +0 -24
package/src/skill.ts DELETED
@@ -1,146 +0,0 @@
1
- import axios from 'axios'
2
- /** @ts-ignore */
3
- import unzipper from 'unzipper'
4
- import { pipeline } from 'stream/promises'
5
- import fs from 'fs'
6
- import path from 'path'
7
- import { getWorkspaceDir } from './utils/global.js'
8
- import { getWsConnection } from './utils/global.js'
9
- import { dcgLogger } from './utils/log.js'
10
- import { isWsOpen } from './transport.js'
11
- import { sendMessageToGateway } from './gateway/socket.js'
12
- import { decodeZipEntryPath } from './utils/zipPath.js'
13
-
14
- type ISkillParams = {
15
- path: string
16
- code: string
17
- }
18
-
19
- function sendEvent(msgContent: Record<string, any>) {
20
- const ws = getWsConnection()
21
- if (isWsOpen()) {
22
- const msg = JSON.stringify({
23
- messageType: 'openclaw_bot_event',
24
- source: 'client',
25
- content: msgContent
26
- });
27
- ws?.send(msg);
28
- dcgLogger(`[Send]技能安装: ${msg}`)
29
- }
30
- }
31
-
32
- export async function installSkill(params: ISkillParams, msgContent: Record<string, any>) {
33
- const { path: cdnUrl, code } = params
34
- const workspacePath = getWorkspaceDir()
35
-
36
- // 确保 skills 目录存在
37
- const skillsDir = path.join(workspacePath, 'skills')
38
- if (!fs.existsSync(skillsDir)) {
39
- fs.mkdirSync(skillsDir, { recursive: true })
40
- }
41
- // 如果目标目录已存在,先删除
42
- const skillDir = path.join(workspacePath, 'skills', code)
43
- if (fs.existsSync(skillDir)) {
44
- fs.rmSync(skillDir, { recursive: true, force: true })
45
- }
46
-
47
- try {
48
- // 下载 zip 文件
49
- const response = await axios({
50
- method: 'get',
51
- url: cdnUrl,
52
- responseType: 'stream'
53
- })
54
- // 创建目标目录
55
- fs.mkdirSync(skillDir, { recursive: true })
56
- // 解压文件到目标目录,跳过顶层文件夹
57
- const result = await new Promise((resolve, reject) => {
58
- const tasks: Promise<void>[] = []
59
- let rootDir: string | null = null
60
- let hasError = false
61
-
62
- response.data
63
- .pipe(unzipper.Parse())
64
- .on('entry', (entry: any) => {
65
- if (hasError) {
66
- entry.autodrain() // 消耗并丢弃当前 zip 条目的数据流
67
- return
68
- }
69
- try {
70
- const flags = entry.props?.flags ?? 0
71
- const entryPath = decodeZipEntryPath(entry.props?.pathBuffer, flags, entry.path)
72
- const pathParts = entryPath.split('/')
73
-
74
- // 检测根目录
75
- if (!rootDir && pathParts.length > 1) {
76
- rootDir = pathParts[0]
77
- }
78
- let newPath = entryPath
79
- // 移除顶层文件夹
80
- if (rootDir && entryPath.startsWith(rootDir + '/')) {
81
- newPath = entryPath.slice(rootDir.length + 1)
82
- }
83
-
84
- if (!newPath) {
85
- entry.autodrain()
86
- return
87
- }
88
-
89
- const targetPath = path.join(skillDir, newPath)
90
-
91
- if (entry.type === 'Directory') {
92
- fs.mkdirSync(targetPath, { recursive: true })
93
- entry.autodrain()
94
- } else {
95
- const parentDir = path.dirname(targetPath)
96
- fs.mkdirSync(parentDir, { recursive: true })
97
- const writeStream = fs.createWriteStream(targetPath)
98
- const task = pipeline(entry, writeStream).catch((err) => {
99
- hasError = true
100
- throw new Error(`解压文件失败 ${entryPath}: ${err.message}`)
101
- })
102
- tasks.push(task)
103
- }
104
- } catch (err) {
105
- hasError = true
106
- entry.autodrain()
107
- reject(new Error(`处理entry失败: ${err}`))
108
- }
109
- })
110
- .on('close', async () => {
111
- try {
112
- await Promise.all(tasks)
113
- resolve(null)
114
- } catch (err) {
115
- hasError = true
116
- reject(err)
117
- }
118
- })
119
- .on('error', (err: { message: any }) => {
120
- hasError = true
121
- reject(new Error(`解压流错误: ${err.message}`))
122
- })
123
- })
124
- sendEvent({ ...msgContent, status: result === null ? 'ok' : 'fail' })
125
- sendMessageToGateway(JSON.stringify({ method: 'skills.status', params: {} }))
126
- } catch (error) {
127
- // 如果安装失败,清理目录
128
- if (fs.existsSync(skillDir)) {
129
- fs.rmSync(skillDir, { recursive: true, force: true })
130
- }
131
- sendEvent({ ...msgContent, status: 'fail' })
132
- }
133
- }
134
-
135
- export function uninstallSkill(params: Omit<ISkillParams, 'path'>, msgContent: Record<string, any>) {
136
- const { code } = params
137
-
138
- const workspacePath = getWorkspaceDir()
139
- if (workspacePath) {
140
- const skillDir = path.join(workspacePath, 'skills', code)
141
- if (fs.existsSync(skillDir)) {
142
- fs.rmSync(skillDir, { recursive: true, force: true })
143
- }
144
- }
145
- sendEvent({ ...msgContent, status: 'ok' })
146
- }
package/src/tool.ts DELETED
@@ -1,403 +0,0 @@
1
- import type { OpenClawPluginApi } from 'openclaw/plugin-sdk'
2
- import { getMsgStatus } from './utils/global.js'
3
- import { dcgLogger } from './utils/log.js'
4
- import { sendFinal, sendText, wsSendRaw } from './transport.js'
5
- import { getEffectiveMsgParams, deleteSessionKeyBySubAgentRunId, setSessionKeyBySubAgentRunId } from './utils/params.js'
6
- import { cronToolCall } from './cronToolCall.js'
7
-
8
- /** 与 `OpenClawPluginApi['on']` 对齐,随宿主 SDK 扩展钩子名时自动一致 */
9
- type PluginHookName = Parameters<OpenClawPluginApi['on']>[0]
10
-
11
- // message_received 没有 sessionKey 前置到bot中执行
12
- const eventList: ReadonlyArray<{ event: PluginHookName; message: string }> = [
13
- // { event: 'message_received', message: '' },
14
- // {event: 'before_model_resolve', message: ''},
15
- // {event: 'before_prompt_build', message: '正在查阅背景资料,构建思考逻辑'},
16
- // {event: 'before_agent_start', message: '书灵墨宝已就位,准备开始执行任务'},
17
- { event: 'subagent_spawning', message: '' },
18
- { event: 'subagent_spawned', message: '' },
19
- { event: 'subagent_delivery_target', message: '' },
20
- // {event: 'llm_input', message: ''},
21
- { event: 'llm_output', message: '' },
22
- // {event: 'agent_end', message: '核心任务已处理完毕...'},
23
- { event: 'subagent_ended', message: '' },
24
- // {event: 'before_message_write', message: '正在将本次对话存入记忆库...'},
25
- // {event: 'message_sending', message: ''},
26
- // {event: 'message_send', message: ''},
27
- { event: 'before_tool_call', message: '' },
28
- { event: 'after_tool_call', message: '' }
29
- ]
30
-
31
- /** 子 agent 的 sessionKey 往往未写入 params map,回落到主会话 outbound 参数避免 messageId 缺失 */
32
- function resolveOutboundParamsForSession(sk: string) {
33
- const k = sk.trim()
34
- let params = getEffectiveMsgParams(k)
35
- if (params.messageId?.trim() || params.sessionId?.trim()) return params
36
- const parent = requesterByChildSessionKey.get(k)
37
- if (parent) {
38
- const parentParams = getEffectiveMsgParams(parent)
39
- if (parentParams.messageId?.trim() || parentParams.sessionId?.trim()) return parentParams
40
- }
41
- return params
42
- }
43
-
44
- /** 主会话已 running 时,子会话上的工具/事件也应下发(否则子 key 无 running 状态会整段丢消息) */
45
- export function isSessionActiveForTool(sk: string): boolean {
46
- const k = sk.trim()
47
- if (!k) return false
48
- if (getMsgStatus(k) === 'running') return true
49
- const parent = requesterByChildSessionKey.get(k)
50
- return parent ? getMsgStatus(parent) === 'running' : false
51
- }
52
-
53
- function sendToolCallMessage(sk: string, text: string, toolCallId: string, isCover: number) {
54
- const params = resolveOutboundParamsForSession(sk)
55
- const content = { is_finish: -1, tool_call_id: toolCallId, is_cover: isCover, thinking_content: text, response: '' }
56
- wsSendRaw(params, content, false)
57
- }
58
-
59
- /**
60
- * 深拷贝 params 并注入 bestEffort: true
61
- */
62
- interface CronDelivery {
63
- mode?: string
64
- channel?: string
65
- to?: string
66
- bestEffort?: boolean
67
- [key: string]: unknown
68
- }
69
-
70
- // --- Subagent 活跃跟踪(按主会话 requesterSessionKey)---
71
-
72
- /** 主会话 sessionKey -> 仍活跃的子 agent runId */
73
- const activeSubagentRunIdsByRequester = new Map<string, Set<string>>()
74
- /** 子会话 childSessionKey -> 主会话 requesterSessionKey */
75
- const requesterByChildSessionKey = new Map<string, string>()
76
- /** 子会话 childSessionKey -> spawn 时的 runId(ended 事件可能不带 runId) */
77
- const runIdByChildSessionKey = new Map<string, string>()
78
- /** 主会话 -> 等待「子 agent 全部结束」的回调 */
79
- const subagentIdleWaiters = new Map<string, Set<() => void>>()
80
-
81
- function getOrCreateRunIdSet(requesterSessionKey: string): Set<string> {
82
- let set = activeSubagentRunIdsByRequester.get(requesterSessionKey)
83
- if (!set) {
84
- set = new Set()
85
- activeSubagentRunIdsByRequester.set(requesterSessionKey, set)
86
- }
87
- return set
88
- }
89
-
90
- function flushSubagentIdleWaiters(requesterSessionKey: string): void {
91
- const set = activeSubagentRunIdsByRequester.get(requesterSessionKey)
92
- if (set && set.size > 0) return
93
- activeSubagentRunIdsByRequester.delete(requesterSessionKey)
94
- const waiters = subagentIdleWaiters.get(requesterSessionKey)
95
- if (!waiters?.size) return
96
- subagentIdleWaiters.delete(requesterSessionKey)
97
- for (const w of waiters) {
98
- try {
99
- w()
100
- } catch (e) {
101
- dcgLogger(`subagent idle waiter error: ${String(e)}`, 'error')
102
- }
103
- }
104
- }
105
-
106
- function registerSubagentSpawn(requesterSessionKey: string, runId: string, childSessionKey: string): void {
107
- const req = requesterSessionKey.trim()
108
- const rid = runId.trim()
109
- const child = childSessionKey.trim()
110
- if (!req || !rid || !child) {
111
- dcgLogger(`subagent track spawn skipped: missing key req=${req} runId=${rid} child=${child}`)
112
- return
113
- }
114
- getOrCreateRunIdSet(req).add(rid)
115
- requesterByChildSessionKey.set(child, req)
116
- runIdByChildSessionKey.set(child, rid)
117
- dcgLogger(`subagent track spawn: requester=${req} runId=${rid} child=${child} active=${getOrCreateRunIdSet(req).size}`)
118
- }
119
-
120
- function registerSubagentEnd(
121
- ctx: { requesterSessionKey?: string; sessionKey?: string },
122
- targetSessionKey: string,
123
- runId?: string
124
- ): void {
125
- const child = targetSessionKey.trim()
126
- if (!child) return
127
- const req = ctx.requesterSessionKey?.trim() || requesterByChildSessionKey.get(child) || ctx.sessionKey?.trim() || ''
128
- const resolvedRunId = (runId?.trim() || runIdByChildSessionKey.get(child) || '').trim()
129
- deleteSessionKeyBySubAgentRunId(resolvedRunId)
130
- if (!req) {
131
- dcgLogger(`subagent track end: no requester for child=${child} runId=${resolvedRunId}`)
132
- requesterByChildSessionKey.delete(child)
133
- runIdByChildSessionKey.delete(child)
134
- return
135
- }
136
- const set = activeSubagentRunIdsByRequester.get(req)
137
- if (set && resolvedRunId) {
138
- set.delete(resolvedRunId)
139
- }
140
- requesterByChildSessionKey.delete(child)
141
- runIdByChildSessionKey.delete(child)
142
- dcgLogger(`subagent track end: requester=${req} runId=${resolvedRunId || 'n/a'} remaining=${set?.size ?? 0}`)
143
- if (set && set.size === 0) {
144
- activeSubagentRunIdsByRequester.delete(req)
145
- }
146
- flushSubagentIdleWaiters(req)
147
- }
148
-
149
- /** 当前跟踪到的、挂在该主会话下的子会话 sessionKey(供 /stop 时逐个 chat.abort) */
150
- export function getChildSessionKeysTrackedForRequester(requesterSessionKey: string): string[] {
151
- const req = requesterSessionKey.trim()
152
- if (!req) return []
153
- const out: string[] = []
154
- for (const [child, parent] of requesterByChildSessionKey.entries()) {
155
- if (parent === req) out.push(child)
156
- }
157
- return out
158
- }
159
-
160
- /**
161
- * 自根 requester 起 BFS 收集所有已跟踪后代子会话(含嵌套)。网关 abort 时宜自深到浅,调用方对结果 `.reverse()` 后再逐个 chat.abort。
162
- */
163
- export function getDescendantSessionKeysForRequester(rootRequesterSessionKey: string): string[] {
164
- const root = rootRequesterSessionKey.trim()
165
- if (!root) return []
166
- const ordered: string[] = []
167
- const seen = new Set<string>()
168
- let frontier = getChildSessionKeysTrackedForRequester(root)
169
- while (frontier.length > 0) {
170
- const next: string[] = []
171
- for (const sk of frontier) {
172
- const k = sk.trim()
173
- if (!k || seen.has(k)) continue
174
- seen.add(k)
175
- ordered.push(k)
176
- next.push(...getChildSessionKeysTrackedForRequester(k))
177
- }
178
- frontier = next
179
- }
180
- return ordered
181
- }
182
-
183
- /**
184
- * 打断后清空本地子 agent 跟踪(runId、父子映射、子 runId→sessionKey),并唤醒 waitUntilSubagentsIdle,避免永久挂起。
185
- */
186
- export function resetSubagentStateForRequesterSession(requesterSessionKey: string): void {
187
- const req = requesterSessionKey.trim()
188
- if (!req) return
189
-
190
- const runIdSet = activeSubagentRunIdsByRequester.get(req)
191
- if (runIdSet) {
192
- for (const rid of runIdSet) {
193
- deleteSessionKeyBySubAgentRunId(rid)
194
- }
195
- }
196
-
197
- for (const [child, parent] of [...requesterByChildSessionKey.entries()]) {
198
- if (parent === req) {
199
- requesterByChildSessionKey.delete(child)
200
- runIdByChildSessionKey.delete(child)
201
- }
202
- }
203
-
204
- activeSubagentRunIdsByRequester.delete(req)
205
-
206
- const waiters = subagentIdleWaiters.get(req)
207
- if (!waiters?.size) return
208
- subagentIdleWaiters.delete(req)
209
- for (const w of waiters) {
210
- try {
211
- w()
212
- } catch (e) {
213
- dcgLogger(`subagent idle waiter error: ${String(e)}`, 'error')
214
- }
215
- }
216
- }
217
-
218
- /** 当前主会话下仍在跑的子 agent 数量(按 spawn 时 runId 去重) */
219
- export function getActiveSubagentCount(sessionKey: string): number {
220
- const sk = sessionKey?.trim()
221
- if (!sk) return 0
222
- return activeSubagentRunIdsByRequester.get(sk)?.size ?? 0
223
- }
224
-
225
- /**
226
- * 等到指定主会话下已跟踪的子 agent 全部结束(spawn 失败等路径也会触发 subagent_ended,一般会配对清理)。
227
- * 注意:须在收到 `subagent_spawned` 之后才会计入;仅 spawning 未 spawned 的不会阻塞。
228
- */
229
- export function waitUntilSubagentsIdle(sessionKey: string, opts?: { timeoutMs?: number; signal?: AbortSignal }): Promise<void> {
230
- const sk = sessionKey?.trim()
231
- if (!sk) return Promise.resolve()
232
-
233
- if (getActiveSubagentCount(sk) === 0) return Promise.resolve()
234
-
235
- return new Promise<void>((resolve, reject) => {
236
- let settled = false
237
- const finish = (fn: () => void) => {
238
- if (settled) return
239
- settled = true
240
- if (timeoutId) clearTimeout(timeoutId)
241
- opts?.signal?.removeEventListener('abort', onAbort)
242
- removeWaiter()
243
- fn()
244
- }
245
-
246
- const removeWaiter = () => {
247
- const bucket = subagentIdleWaiters.get(sk)
248
- if (!bucket) return
249
- bucket.delete(onIdle)
250
- if (bucket.size === 0) subagentIdleWaiters.delete(sk)
251
- }
252
-
253
- const onIdle = () => finish(() => resolve())
254
-
255
- const onAbort = () => {
256
- const reason = opts?.signal?.reason
257
- finish(() => reject(reason instanceof Error ? reason : new Error(String(reason ?? 'Aborted'))))
258
- }
259
-
260
- let timeoutId: ReturnType<typeof setTimeout> | undefined
261
- if (opts?.timeoutMs != null && opts.timeoutMs > 0) {
262
- timeoutId = setTimeout(
263
- () => finish(() => reject(new Error(`waitUntilSubagentsIdle timeout ${opts.timeoutMs}ms`))),
264
- opts.timeoutMs
265
- )
266
- }
267
-
268
- if (opts?.signal) {
269
- if (opts.signal.aborted) {
270
- onAbort()
271
- return
272
- }
273
- opts.signal.addEventListener('abort', onAbort, { once: true })
274
- }
275
-
276
- let set = subagentIdleWaiters.get(sk)
277
- if (!set) {
278
- set = new Set()
279
- subagentIdleWaiters.set(sk, set)
280
- }
281
- set.add(onIdle)
282
-
283
- if (getActiveSubagentCount(sk) === 0) {
284
- onIdle()
285
- }
286
- })
287
- }
288
-
289
- function resolveHookSessionKey(
290
- eventName: string,
291
- args: { sessionKey?: string; requesterSessionKey?: string; runId?: string }
292
- ): string {
293
- if (
294
- eventName === 'subagent_spawned' ||
295
- eventName === 'subagent_ended' ||
296
- eventName === 'subagent_spawning' ||
297
- eventName === 'subagent_delivery_target'
298
- ) {
299
- if (args?.runId && args?.requesterSessionKey) setSessionKeyBySubAgentRunId(args?.runId, args?.requesterSessionKey)
300
- return (args?.requesterSessionKey || args?.sessionKey || '').trim()
301
- }
302
- return (args?.sessionKey || '').trim()
303
- }
304
-
305
- /** 定时触发时会话往往非 running,但仍需跑 before_tool_call 以注入 sessionKey / delivery(见 cronToolCall) */
306
- function shouldRunBeforeToolCallWithoutRunningSession(event: { toolName?: string; params?: { command?: string } }): boolean {
307
- if (event?.toolName === 'cron') return true
308
- const cmd = event?.params?.command
309
- if (event?.toolName === 'exec' && typeof cmd === 'string') {
310
- return cmd.includes('cron create') || cmd.includes('cron add')
311
- }
312
- return false
313
- }
314
-
315
- function trackSubagentLifecycle(eventName: string, event: any, args: any): void {
316
- if (eventName === 'subagent_spawned') {
317
- const runId = typeof event?.runId === 'string' ? event.runId : ''
318
- const childSessionKey = typeof event?.childSessionKey === 'string' ? event.childSessionKey : ''
319
- const requester =
320
- typeof args?.requesterSessionKey === 'string'
321
- ? args.requesterSessionKey
322
- : typeof args?.sessionKey === 'string'
323
- ? args.sessionKey
324
- : ''
325
- registerSubagentSpawn(requester, runId, childSessionKey)
326
- return
327
- }
328
- if (eventName === 'subagent_ended') {
329
- const targetSessionKey = typeof event?.targetSessionKey === 'string' ? event.targetSessionKey : ''
330
- const runId = typeof event?.runId === 'string' ? event.runId : undefined
331
- registerSubagentEnd(args ?? {}, targetSessionKey, runId)
332
- }
333
- }
334
-
335
- export function monitoringToolMessage(api: OpenClawPluginApi) {
336
- for (const item of eventList) {
337
- api.on(item.event, (event: any, args: any) => {
338
- // ACP 等非 subagent 的 ended 事件不应驱动书灵子会话状态机(见 SDK PluginHookSubagentEndedEvent.targetKind)
339
- if (item.event === 'subagent_ended' && event?.targetKind === 'acp') {
340
- return
341
- }
342
- trackSubagentLifecycle(item.event, event, args)
343
- const sk = resolveHookSessionKey(item.event, args ?? {})
344
- if (sk) {
345
- const toolHooksOk =
346
- isSessionActiveForTool(sk) || (item.event === 'before_tool_call' && shouldRunBeforeToolCallWithoutRunningSession(event))
347
- if (toolHooksOk) {
348
- if (['after_tool_call', 'before_tool_call'].includes(item.event)) {
349
- const { result: _result, ...rest } = event
350
- dcgLogger(`工具调用结果: ~ event:${item.event} ~ params:${JSON.stringify(rest)}`)
351
-
352
- if (item.event === 'before_tool_call') {
353
- const hookResult = cronToolCall(rest, sk)
354
- const text = JSON.stringify({
355
- type: item.event,
356
- specialIdentification: 'dcgchat_tool_call_special_identification',
357
- callId: event.toolCallId || event.runId || Date.now().toString(),
358
- ...rest,
359
- status: 'running'
360
- })
361
- sendToolCallMessage(sk, text, event.toolCallId || event.runId || Date.now().toString(), 0)
362
- return hookResult
363
- }
364
- const text = JSON.stringify({
365
- type: item.event,
366
- specialIdentification: 'dcgchat_tool_call_special_identification',
367
- callId: event.toolCallId || event.runId || Date.now().toString(),
368
- ...rest,
369
- status: item.event === 'after_tool_call' ? 'finished' : 'running'
370
- })
371
- sendToolCallMessage(
372
- sk,
373
- text,
374
- event.toolCallId || event.runId || Date.now().toString(),
375
- item.event === 'after_tool_call' ? 1 : 0
376
- )
377
- } else if (item.event) {
378
- const msgCtx = resolveOutboundParamsForSession(sk)
379
- if (item.event === 'llm_output') {
380
- if (event.lastAssistant?.errorMessage === '1003-额度不足请充值') {
381
- const message = '您的墨滴已消耗完,您可以通过充值墨滴来继续使用'
382
- sendText(message, msgCtx, { message_tags: { insufficient_balance: 1 }, is_finish: -1 })
383
- sendFinal(msgCtx, '墨滴不足')
384
- return
385
- }
386
- }
387
- const text = JSON.stringify({
388
- type: item.event,
389
- specialIdentification: 'dcgchat_tool_call_special_identification',
390
- toolName: '',
391
- callId: event.runId || Date.now().toString(),
392
- params: item.message
393
- })
394
- sendToolCallMessage(sk, text, event.runId || Date.now().toString(), 0)
395
- dcgLogger(`工具调用结果: ~ event:${item.event}`)
396
- }
397
- }
398
- } else if (item.event !== 'before_tool_call') {
399
- dcgLogger(`工具调用结果: ~ event:${item.event} ~ 没有sessionKey 为执行`)
400
- }
401
- })
402
- }
403
- }