@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
@@ -1,273 +0,0 @@
1
- import fs from 'node:fs'
2
- import os from 'node:os'
3
- import path from 'node:path'
4
- import type { AnyAgentTool } from 'openclaw/plugin-sdk'
5
- import { jsonResult } from 'openclaw/plugin-sdk/channel-actions'
6
- import { sendDcgchatMedia } from '../channel.js'
7
- import { getOutboundMsgParams } from '../utils/params.js'
8
- import { sendText } from '../transport.js'
9
-
10
- /** 与 `registerTool` 工厂入参一致(主包未导出 `OpenClawPluginToolContext` 时仅用所需字段)。 */
11
- export type DcgchatMessageToolContext = {
12
- sessionKey?: string
13
- workspaceDir?: string
14
- allowedPaths?: string[]
15
- /** 通道配置 `allowedAttachmentExtensions`:在插件内置扩展名之外额外允许发送的附件后缀(如 `.py`、`.ipynb`),项可写 `.py` 或 `py`。 */
16
- allowedAttachmentExtensions?: string[]
17
- }
18
-
19
- /** 统一为 POSIX 风格斜杠,便于跨平台判断(不改变语义,仅用于匹配)。 */
20
- function toPosixPath(p: string): string {
21
- return path.normalize(p.trim()).replace(/\\/g, '/')
22
- }
23
-
24
- /** `filepath` 解析后在 `rootDir` 内或等于 `rootDir`(防 `..` 逃逸)。 */
25
- function isPathInsideDir(filepath: string, rootDir: string): boolean {
26
- const root = path.resolve(rootDir)
27
- const resolved = path.resolve(filepath)
28
- const rel = path.relative(root, resolved)
29
- if (rel.startsWith('..') || path.isAbsolute(rel)) return false
30
- return true
31
- }
32
-
33
- /**
34
- * 允许发送的路径:
35
- * - 当前 Agent 工作区根及其子路径(`workspaceDir`,如 ~/.openclaw/workspace-xxx/output/...);
36
- * - 兼容旧挂载:Unix `/workspace`、`/mobook`;Windows 盘符下 `workspace`、`mobook`。
37
- */
38
- function isSafePath(filepath: string, workspaceDir?: string, allowedPaths?: string[]): boolean {
39
- // Check workspaceDir
40
- const ws = workspaceDir?.trim()
41
- if (ws && isPathInsideDir(filepath, ws)) return true
42
-
43
- // Check allowedPaths from config
44
- if (allowedPaths?.length) {
45
- for (const allowed of allowedPaths) {
46
- if (isPathInsideDir(filepath, allowed)) return true
47
- }
48
- }
49
-
50
- // Check legacy mounts
51
- const p = toPosixPath(filepath)
52
- if (p.startsWith('/workspace/') || p === '/workspace') return true
53
- if (p.startsWith('/mobook/') || p === '/mobook') return true
54
- return /^[A-Za-z]:\/(workspace|mobook)(\/|$)/.test(p)
55
- }
56
-
57
- /** 同一路径在 Windows 上可能大小写不同,用于 Set 去重。 */
58
- function pathKey(filepath: string): string {
59
- const n = path.normalize(filepath.trim())
60
- return os.platform() === 'win32' ? n.toLowerCase() : n
61
- }
62
-
63
- const fileType1 = ['.webp', '.gif', '.bmp', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.pdf', '.txt', '.rtf', '.odt', '.json']
64
- const fileType2 = [
65
- '.xml',
66
- '.csv',
67
- '.yaml',
68
- '.yml',
69
- '.html',
70
- '.htm',
71
- '.md',
72
- '.markdown',
73
- '.css',
74
- '.js',
75
- '.ts',
76
- '.py',
77
- '.pyi',
78
- '.ipynb',
79
- '.png',
80
- '.jpg',
81
- '.jpeg'
82
- ]
83
- const fileType3 = ['.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.xz', '.exe', '.dmg', '.pkg', '.apk', '.ipa', '.log', '.dat', '.bin']
84
- const fileType4 = ['.svg', '.ico', '.mp3', '.wav', '.ogg', '.aac', '.m4a', '.mp4', '.avi', '.mov', '.wmv', '.flv', '.mkv', '.webm']
85
- const DEFAULT_SAFE_EXTENSIONS = new Set([...fileType1, ...fileType2, ...fileType3, ...fileType4])
86
-
87
- function normalizeAttachmentExt(raw: string): string | null {
88
- const t = raw.trim().toLowerCase()
89
- if (!t) return null
90
- return t.startsWith('.') ? t : `.${t}`
91
- }
92
-
93
- function buildSafeExtensions(extra?: string[]): Set<string> {
94
- const set = new Set(DEFAULT_SAFE_EXTENSIONS)
95
- for (const e of extra ?? []) {
96
- const n = normalizeAttachmentExt(e)
97
- if (n && n !== '.') set.add(n)
98
- }
99
- return set
100
- }
101
-
102
- const messageToolParameters = {
103
- type: 'object',
104
- additionalProperties: false,
105
- properties: {
106
- target: {
107
- type: 'string',
108
- description: '目标会话键(sessionKey),必须与当前会话 SessionKey 一致,禁止填写 userId。'
109
- },
110
- content: {
111
- type: 'string',
112
- description: '发送文本内容'
113
- },
114
- media: {
115
- type: 'array',
116
- description: '发送附件',
117
- items: {
118
- type: 'object',
119
- additionalProperties: false,
120
- properties: {
121
- file: {
122
- type: 'string',
123
- description:
124
- '文件绝对路径:须在「当前 Agent 工作区」目录下(如 /root/.openclaw/workspace-xxx/output/28337/slices_result.json),或为兼容环境的 /workspace/、/mobook/(Windows 盘符下 workspace、mobook)'
125
- }
126
- },
127
- required: ['file']
128
- }
129
- }
130
- },
131
- // 须至少提供正文或附件之一;用 anyOf(非 oneOf),否则同时带 content+media 时两个分支都满足会违反「恰好其一」而校验失败
132
- anyOf: [{ required: ['content'] }, { required: ['media'] }]
133
- }
134
-
135
- /** 从正文提取可发送的文件路径(固定挂载 + 当前工作区前缀)。 */
136
- function extractPaths(text: string | undefined, workspaceDir?: string): string[] {
137
- if (!text) return []
138
- const unix = text.match(/\/workspace\/[^\s]+|\/mobook\/[^\s]+/g) ?? []
139
- const win = text.match(/[A-Za-z]:[/\\](?:workspace|mobook)[/\\][^\s]+/g) ?? []
140
- const underWs: string[] = []
141
- const ws = workspaceDir?.trim()
142
- if (ws) {
143
- const variants = new Set<string>()
144
- variants.add(ws)
145
- variants.add(toPosixPath(ws))
146
- if (path.sep === '\\') variants.add(ws.replace(/\//g, '\\'))
147
- for (const prefix of variants) {
148
- if (!prefix) continue
149
- let from = 0
150
- while (from < text.length) {
151
- const i = text.indexOf(prefix, from)
152
- if (i === -1) break
153
- let end = i + prefix.length
154
- while (end < text.length && !/\s/.test(text[end])) end++
155
- underWs.push(text.slice(i, end))
156
- from = i + 1
157
- }
158
- }
159
- }
160
- return [...new Set([...unix, ...win, ...underWs])]
161
- }
162
-
163
- function isSafeFile(filepath: string, extensions: Set<string>) {
164
- if (!fs.existsSync(filepath)) return false
165
- const stat = fs.statSync(filepath)
166
- if (!stat.isFile()) return false
167
- if (stat.size === 0) return false
168
- const ext = path.extname(filepath).toLowerCase()
169
- return extensions.has(ext)
170
- }
171
-
172
- /**
173
- * 书灵墨宝出站消息工具:须符合 OpenClaw `AgentTool`(execute 返回 `AgentToolResult`)。
174
- * 工具名使用 `dcgchat_message`,避免与核心内置 `message` 冲突。
175
- * 通过注册时的 `OpenClawPluginToolContext.sessionKey` 出站,不再使用非标准的 `execute(args, ctx)`。
176
- */
177
- export function createDcgchatMessageTool(pluginCtx: DcgchatMessageToolContext): AnyAgentTool {
178
- const safeExtensions = buildSafeExtensions(pluginCtx.allowedAttachmentExtensions)
179
- return {
180
- name: 'dcgchat_message',
181
- label: 'dcgchat_message',
182
- description: `
183
- 向用户发送消息。
184
- 若传 target,target 必须是 sessionKey,不能是 userId。
185
- 如果发送附件:必须使用 media 字段
186
- 文件路径须在当前 Agent 工作区目录下(随部署变化,如 ~/.openclaw/workspace-xxx/...),或为兼容环境的 /workspace/、/mobook/(Windows 盘符下 workspace、mobook)。
187
- 禁止在正文中直接输出可访问路径(应通过 media 发送)
188
- `,
189
- parameters: messageToolParameters,
190
- execute: async (_toolCallId, args, signal) => {
191
- if (signal?.aborted) {
192
- const err = new Error('Message send aborted')
193
- err.name = 'AbortError'
194
- throw err
195
- }
196
-
197
- const sessionKey = pluginCtx.sessionKey?.trim()
198
- if (!sessionKey) {
199
- return jsonResult({ error: '缺少 sessionKey,无法向当前会话发送消息' })
200
- }
201
-
202
- try {
203
- const sentFiles = new Set<string>()
204
- const sentKeys = new Set<string>()
205
- const workspaceDir = pluginCtx.workspaceDir
206
- const allowedPaths = pluginCtx.allowedPaths
207
-
208
- if (args.media?.length) {
209
- for (const media of args.media) {
210
- const filepath = media.file
211
- if (!filepath) continue
212
- if (!isSafePath(filepath, workspaceDir, allowedPaths)) continue
213
- if (!isSafeFile(filepath, safeExtensions)) continue
214
- const key = pathKey(filepath)
215
- if (sentKeys.has(key)) continue
216
-
217
- await sendDcgchatMedia({ sessionKey, mediaUrl: filepath })
218
- sentFiles.add(filepath)
219
- sentKeys.add(key)
220
- }
221
- }
222
-
223
- const fallbackPaths = extractPaths(args.content, workspaceDir)
224
- for (const filepath of fallbackPaths) {
225
- if (!isSafePath(filepath, workspaceDir, allowedPaths)) continue
226
- if (!isSafeFile(filepath, safeExtensions)) continue
227
- const key = pathKey(filepath)
228
- if (sentKeys.has(key)) continue
229
-
230
- await sendDcgchatMedia({ sessionKey, mediaUrl: filepath })
231
- sentFiles.add(filepath)
232
- sentKeys.add(key)
233
- }
234
-
235
- if (args.media?.length && sentFiles.size === 0) {
236
- return jsonResult({
237
- success: false,
238
- error:
239
- '未能发送任何附件:路径须位于当前 Agent 工作区,或为 /workspace/、/mobook/ 下的真实文件(非空、扩展名在白名单内)。',
240
- sentMediaCount: 0
241
- })
242
- }
243
-
244
- let content = args.content ?? ''
245
- for (const filepath of sentFiles) {
246
- const posix = toPosixPath(filepath)
247
- const variants = posix === filepath ? [filepath] : [filepath, posix]
248
- const seen = new Set<string>()
249
- for (const v of variants) {
250
- if (!v || seen.has(v)) continue
251
- seen.add(v)
252
- content = content.split(v).join('')
253
- }
254
- }
255
- content = content.trim()
256
-
257
- if (content.length > 0) {
258
- const msgCtx = getOutboundMsgParams(sessionKey)
259
- sendText(content, msgCtx)
260
- }
261
-
262
- return jsonResult({
263
- success: true,
264
- sentMediaCount: sentFiles.size
265
- })
266
- } catch (err) {
267
- return jsonResult({
268
- error: err instanceof Error ? err.message : String(err)
269
- })
270
- }
271
- }
272
- }
273
- }
package/src/transport.ts DELETED
@@ -1,206 +0,0 @@
1
- import { clearSentMediaKeys, getWsConnection } from './utils/global.js'
2
- import { isSessionStreamSuppressed } from './sessionTermination.js'
3
- import { dcgLogger } from './utils/log.js'
4
- import type { IMsgParams } from './types.js'
5
- import { getEffectiveMsgParams, getParamsDefaults } from './utils/params.js'
6
-
7
- /** 用 sessionKey 从 map 取参,再合并 overrides(channel 出站、媒体等) */
8
- export function mergeSessionParams(sessionKey: string, overrides?: Partial<IMsgParams>): IMsgParams {
9
- const base = getEffectiveMsgParams(sessionKey)
10
- if (!overrides) return base
11
- return { ...base, ...overrides }
12
- }
13
- export function mergeDefaultParams(overrides?: Partial<IMsgParams>): IMsgParams {
14
- const base = getParamsDefaults()
15
- if (!overrides) return base
16
- return { ...base, ...overrides }
17
- }
18
-
19
- export type InboundMsgForContext = {
20
- _userId: number | string
21
- content: {
22
- bot_token: string
23
- domain_id?: string
24
- app_id?: string
25
- bot_id?: string
26
- agent_id?: string
27
- session_id: string
28
- message_id: string
29
- }
30
- }
31
-
32
- export type OpenclawBotChatEnvelope = {
33
- messageType: 'openclaw_bot_chat'
34
- _userId: number | undefined
35
- source: 'client'
36
- content: Record<string, unknown>
37
- }
38
-
39
- function isInboundWire(arg: unknown): arg is InboundMsgForContext {
40
- return Boolean(arg && typeof arg === 'object' && '_userId' in arg && 'content' in arg)
41
- }
42
-
43
- /** 下行 WebSocket 帧 → 内部上下文(字段缺省用 channel 配置补) */
44
- function inboundToCtx(msg: InboundMsgForContext, d: IMsgParams): IMsgParams {
45
- const c = msg.content
46
- return {
47
- userId: Number(msg._userId ?? d.userId),
48
- botToken: c.bot_token ?? d.botToken,
49
- domainId: String(c.domain_id ?? d.domainId),
50
- appId: String(c.app_id ?? d.appId),
51
- botId: c.bot_id,
52
- agentId: c.agent_id,
53
- sessionId: c.session_id,
54
- messageId: c.message_id
55
- }
56
- }
57
-
58
- /** 上行:与配置合并缺省后再 `...ctx` 覆盖(原 wsSendRaw) */
59
- function mergeOutboundWithDefaults(ctx: IMsgParams, d: IMsgParams): IMsgParams {
60
- return {
61
- userId: Number(ctx.userId ?? d.userId),
62
- botToken: ctx.botToken ?? d.botToken,
63
- domainId: String(ctx.domainId ?? d.domainId),
64
- appId: String(ctx.appId ?? d.appId),
65
- ...ctx
66
- }
67
- }
68
-
69
- /**
70
- * 组装完整 wire `content` 对象:先写会话/机器人基础字段(回落到 d),再合并调用方传入的 payload。
71
- * `content` 在使用处构造(如 response、state、files),同名键可覆盖基础字段。
72
- */
73
- export function buildWireContent(base: IMsgParams, d: IMsgParams, content: Record<string, unknown>): Record<string, unknown> {
74
- const resolvedBotToken = base.botToken ?? d.botToken
75
- const domain = base.domainId ?? d.domainId
76
- const app = base.appId ?? d.appId
77
- return {
78
- bot_token: base.botToken || resolvedBotToken,
79
- domain_id: base.domainId || domain,
80
- app_id: base.appId || app,
81
- bot_id: base.botId,
82
- agent_id: base.agentId,
83
- session_id: base.sessionId,
84
- message_id: base.messageId || Date.now().toString(),
85
- ...content
86
- }
87
- }
88
-
89
- /** 上行:在已合并的 ctx 上套 openclaw_bot_chat 信封(messageType / _userId / source + content) */
90
- function buildOutboundOpenclawBotChatEnvelope(
91
- ctx: IMsgParams,
92
- content: Record<string, unknown>,
93
- opts?: { mergeChannelDefaults?: boolean }
94
- ): OpenclawBotChatEnvelope {
95
- const d = getParamsDefaults()
96
- const base = opts?.mergeChannelDefaults ? mergeOutboundWithDefaults(ctx, d) : ctx
97
- return {
98
- messageType: 'openclaw_bot_chat',
99
- _userId: base.userId,
100
- source: 'client',
101
- content: buildWireContent(base, d, content)
102
- }
103
- }
104
-
105
- /**
106
- * 下行解析为 DcgchatMsgContext,或上行组装 openclaw_bot_chat 信封。
107
- * 上行时 `content` 由调用方传入;基础参数来自 `ctx` 与 `getParamsDefaults()`(可选 mergeChannelDefaults,同原 wsSendRaw)。
108
- */
109
- export function buildOpenclawBotChat(msg: InboundMsgForContext): IMsgParams
110
- export function buildOpenclawBotChat(
111
- ctx: IMsgParams,
112
- content: Record<string, unknown>,
113
- opts?: { mergeChannelDefaults?: boolean }
114
- ): OpenclawBotChatEnvelope
115
- export function buildOpenclawBotChat(
116
- arg1: InboundMsgForContext | IMsgParams,
117
- arg2?: Record<string, unknown>,
118
- opts?: { mergeChannelDefaults?: boolean }
119
- ): IMsgParams | OpenclawBotChatEnvelope {
120
- const d = getParamsDefaults()
121
-
122
- if (arg2 === undefined && isInboundWire(arg1)) {
123
- return inboundToCtx(arg1, d)
124
- }
125
-
126
- const ctx = arg1 as IMsgParams
127
- return buildOutboundOpenclawBotChatEnvelope(ctx, arg2 ?? {}, opts)
128
- }
129
-
130
- export function isWsOpen(): boolean {
131
- const isOpen = getWsConnection()?.readyState === WebSocket.OPEN
132
- if (!isOpen) {
133
- dcgLogger(`server socket not ready ${getWsConnection()?.readyState}`, 'error')
134
- }
135
- return isOpen
136
- }
137
-
138
- /**
139
- * 聊天流路径:content 单独 JSON.stringify(双重编码),符合 dcgchat 协议。
140
- * `ctx` 须由调用方用 getEffectiveMsgParams(sessionKey) 等解析好;`content` 为完整业务 payload。
141
- */
142
- export function wsSend(ctx: IMsgParams, content: Record<string, unknown>): boolean {
143
- if (ctx.sessionKey && isSessionStreamSuppressed(ctx.sessionKey)) return false
144
- const ws = getWsConnection()
145
- if (ws?.readyState !== WebSocket.OPEN) return false
146
- const envelope = buildOpenclawBotChat(ctx, content)
147
- ws.send(JSON.stringify({ ...envelope, content: JSON.stringify(envelope.content) }))
148
- return true
149
- }
150
-
151
- /**
152
- * 媒体 / channel 出站:content 保持嵌套对象(单次编码)。
153
- * `ctx` 须由调用方解析(如需合并覆盖可先 mergeSessionParams)。
154
- */
155
- export function wsSendRaw(ctx: IMsgParams, content: Record<string, unknown>, isLog = true): boolean {
156
- if (ctx.sessionKey && isSessionStreamSuppressed(ctx.sessionKey)) return false
157
- const ws = getWsConnection()
158
- if (ws?.readyState !== WebSocket.OPEN) {
159
- dcgLogger(`server socket not ready ${ws?.readyState}`, 'error')
160
- return false
161
- }
162
- const envelope = buildOpenclawBotChat(ctx, content, { mergeChannelDefaults: true })
163
- ws.send(JSON.stringify(envelope))
164
- if (isLog) {
165
- dcgLogger('已发送:' + JSON.stringify(envelope))
166
- }
167
- return true
168
- }
169
-
170
- export function sendChunk(text: string, ctx: IMsgParams, chunkIdx: number): boolean {
171
- return wsSend(ctx, { response: text, state: 'chunk', chunk_idx: chunkIdx })
172
- }
173
-
174
- export function sendFinal(ctx: IMsgParams, tag: string): boolean {
175
- dcgLogger(` message handling complete state: to=${ctx.sessionId} final tag:${tag}`)
176
- clearSentMediaKeys(ctx.sessionId)
177
- return wsSend(ctx, { response: '', state: 'final' })
178
- }
179
-
180
- export function sendText(text: string, ctx: IMsgParams, event?: Record<string, unknown>): boolean {
181
- return wsSend(ctx, { response: text, ...event })
182
- }
183
-
184
- export function sendError(errorMsg: string, ctx: IMsgParams): boolean {
185
- return wsSend(ctx, { response: `[错误] ${errorMsg}`, state: 'final' })
186
- }
187
-
188
- export function sendEventMessage(params: Record<string, string> = {}) {
189
- const ctx = getParamsDefaults()
190
- const ws = getWsConnection()
191
- if (isWsOpen()) {
192
- ws?.send(
193
- JSON.stringify({
194
- messageType: 'openclaw_bot_event',
195
- source: 'client',
196
- content: {
197
- bot_token: ctx.botToken,
198
- domain_id: ctx.domainId,
199
- app_id: ctx.appId,
200
- bot_id: ctx.botId,
201
- ...params
202
- }
203
- })
204
- )
205
- }
206
- }
package/src/types.ts DELETED
@@ -1,139 +0,0 @@
1
- /**
2
- * 插件配置(channels.dcgchat 下的字段)
3
- */
4
- export type DcgchatConfig = {
5
- enabled?: boolean
6
- /** 后端 WebSocket 地址,例如 ws://localhost:8080/openclaw/ws */
7
- wsUrl?: string
8
- /** 连接认证 token */
9
- botToken?: string
10
- /** 用户标识 */
11
- userId?: string
12
- domainId?: string
13
- appId?: string
14
- /**
15
- * 内置 `message` 工具走 OpenClaw 目标解析:`true`(默认)时仅将符合 sessionKey 形态的字符串视为合法 target,
16
- * 纯数字(WS userId 等)会解析失败;设为 `false` 恢复旧版宽松行为(不推荐)。
17
- */
18
- strictMessageToolTarget?: boolean
19
- }
20
-
21
- export type ResolvedDcgchatAccount = {
22
- accountId: string
23
- enabled: boolean
24
- configured: boolean
25
- wsUrl: string
26
- botToken: string
27
- userId: string
28
- domainId?: string
29
- appId?: string
30
- }
31
-
32
- /**
33
- * 下行消息:后端 → OpenClaw(用户发的消息)
34
- */
35
- // export type InboundMessage = {
36
- // type: "message";
37
- // userId: string;
38
- // text: string;
39
- // };
40
- export type InboundMessage = {
41
- messageType: string // "openclaw_bot_chat",
42
- _userId: number
43
- source: string // 'server',
44
- // content: string;
45
- content: {
46
- skills_scope: Record<string, any>[]
47
- bot_token: string
48
- agent_clone_code?: string
49
- domain_id?: string
50
- app_id?: string
51
- bot_id?: string
52
- agent_id?: string
53
- session_id: string
54
- real_mobook: string | number
55
- message_id: string
56
- text: string
57
- files?: {
58
- url: string
59
- name: string
60
- }[]
61
- }
62
- }
63
-
64
- // {"_userId":40,"content":"{\"bot_token\":\"sk_b7f8a3e1c5d24e6f8a1b3c4d5e6f7a8b\",\"session_id\":\"1\",\"message_id\":\"1\",\"text\":\"你好\"}","messageType":"openclaw_bot_chat","msgId":398599,"source":"server","title":"OPENCLAW机器人对话"}
65
-
66
- /**
67
- * 上行消息:OpenClaw → 后端(Agent 回复)
68
- */
69
- // export type OutboundReply = {
70
- // type: "reply";
71
- // userId: string;
72
- // text: string;
73
- // };
74
-
75
- export type OutboundReply = {
76
- messageType: string // "openclaw_bot_chat",
77
- _userId: number // 100
78
- source: string // 'client',
79
- // content: string;
80
- content: {
81
- bot_token: string // ""
82
- session_id: string // ""
83
- message_id: string // ""
84
- response: string // ""
85
- state: string // final, chunk
86
- domain_id?: string
87
- app_id?: string
88
- bot_id?: string
89
- agent_id?: string
90
- files?: { url: string; name: string }[]
91
- }
92
- }
93
-
94
- export interface IResponse<T = unknown> {
95
- /** 响应状态码 */
96
- code?: number | string
97
- /** 响应数据 */
98
- data?: T
99
- /** 响应消息 */
100
- message?: string
101
- }
102
-
103
- export interface IStsToken {
104
- bucket: string
105
- endPoint: string
106
- expiration: string
107
- ossFileKey: string
108
- policy: string
109
- region: string
110
- signature: string
111
- sourceFileName: string
112
- stsEndPoint: string
113
- tempAccessKeyId: string
114
- tempAccessKeySecret: string
115
- tempSecurityToken: string
116
- uploadDir: string
117
- protocol: string
118
- }
119
-
120
- export interface IStsTokenReq {
121
- sourceFileName: string
122
- isPrivate: number
123
- }
124
-
125
- export interface IMsgParams {
126
- userId?: number
127
- botToken?: string
128
- sessionId?: string
129
- messageId?: string
130
- domainId?: string
131
- appId?: string
132
- botId?: string
133
- agentId?: string
134
- /** 与 OpenClaw 路由一致,用于 map 与异步链路(工具 / HTTP / cron)对齐当前会话 */
135
- sessionKey?: string
136
- real_mobook?: string | number
137
- is_finish?: number
138
- message_tags?: Record<string, string>
139
- }
@@ -1,23 +0,0 @@
1
- /**
2
- * 识别 OpenClaw embedded agent 抛出的上下文/压缩相关错误(日志与异常文案可能略有差异)。
3
- */
4
- function errorText(err: unknown): string {
5
- if (err instanceof Error) return err.message
6
- if (typeof err === 'string') return err
7
- return String(err)
8
- }
9
-
10
- export function isContextOverflowError(err: unknown): boolean {
11
- const t = errorText(err)
12
- return (
13
- /context overflow/i.test(t) ||
14
- /prompt too large/i.test(t) ||
15
- /auto-compaction failed/i.test(t) ||
16
- /\(precheck\)/i.test(t)
17
- )
18
- }
19
-
20
- /** 用户可见说明(不含 transport 层前缀) */
21
- export function contextOverflowUserHint(): string {
22
- return '当前对话过长,已超过模型上下文限制;自动压缩未完全生效时会出现此情况。请尝试新开对话、缩短任务,或换用更大上下文的模型。'
23
- }
@@ -1,7 +0,0 @@
1
- export const ENV: 'production' | 'test' | 'develop' = 'test'
2
-
3
-
4
- export const systemCommand = ['/new', '/status']
5
- export const stopCommand = ['/stop']
6
-
7
- export const ignoreToolCommand = ['/search', '/abort', '/queue interrupt', ...systemCommand, ...stopCommand]