@workclaw/openclaw-workclaw 1.0.0
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/README.md +325 -0
- package/index.ts +298 -0
- package/openclaw.plugin.json +10 -0
- package/package.json +43 -0
- package/skills/openclaw-workclaw-cron/SKILL.md +458 -0
- package/src/accounts.ts +287 -0
- package/src/api/accounts-api.ts +157 -0
- package/src/api/prompts-api.ts +123 -0
- package/src/api/session-api.ts +247 -0
- package/src/api/skills-api.ts +74 -0
- package/src/api/workspace.ts +43 -0
- package/src/channel.ts +227 -0
- package/src/config-schema.ts +110 -0
- package/src/connection/workclaw-client.ts +656 -0
- package/src/gateway/agent-handlers.ts +557 -0
- package/src/gateway/config-writer.ts +311 -0
- package/src/gateway/message-context.ts +422 -0
- package/src/gateway/message-dispatcher.ts +601 -0
- package/src/gateway/reconnect.ts +149 -0
- package/src/gateway/skills-handler.ts +759 -0
- package/src/gateway/skills-list-handler.ts +332 -0
- package/src/gateway/tools-list-handler.ts +162 -0
- package/src/gateway/workclaw-gateway.ts +521 -0
- package/src/media/upload.ts +168 -0
- package/src/outbound/index.ts +183 -0
- package/src/outbound/workclaw-sender.ts +157 -0
- package/src/runtime.ts +400 -0
- package/src/send.ts +1 -0
- package/src/tools/openclaw-workclaw-cron/api/index.ts +326 -0
- package/src/tools/openclaw-workclaw-cron/index.ts +39 -0
- package/src/tools/openclaw-workclaw-cron/src/add/params.ts +176 -0
- package/src/tools/openclaw-workclaw-cron/src/add/sync.ts +188 -0
- package/src/tools/openclaw-workclaw-cron/src/disable/params.ts +100 -0
- package/src/tools/openclaw-workclaw-cron/src/disable/sync.ts +127 -0
- package/src/tools/openclaw-workclaw-cron/src/enable/params.ts +100 -0
- package/src/tools/openclaw-workclaw-cron/src/enable/sync.ts +127 -0
- package/src/tools/openclaw-workclaw-cron/src/notify/sync.ts +148 -0
- package/src/tools/openclaw-workclaw-cron/src/remove/params.ts +109 -0
- package/src/tools/openclaw-workclaw-cron/src/remove/sync.ts +127 -0
- package/src/tools/openclaw-workclaw-cron/src/update/params.ts +197 -0
- package/src/tools/openclaw-workclaw-cron/src/update/sync.ts +161 -0
- package/src/tools/openclaw-workclaw-cron/types/index.ts +55 -0
- package/src/tools/openclaw-workclaw-cron/utils/index.ts +141 -0
- package/src/types.ts +60 -0
- package/src/utils/content.ts +40 -0
- package/templates/IDENTITY.md +14 -0
- package/templates/SOUL.md +0 -0
- package/tsconfig.json +11 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reconnect Scheduler - manages WebSocket reconnection with exponential backoff
|
|
3
|
+
* Supports both per-account and per-appKey strategies
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { WorkClawBaseConfig } from '../types.js'
|
|
7
|
+
import { clearOpenclawWorkclawTokenCache } from '../connection/workclaw-client.js'
|
|
8
|
+
import { clearOpenclawWorkclawWsConnection, setOpenclawWorkclawWsConnection } from '../runtime.js'
|
|
9
|
+
|
|
10
|
+
export interface ReconnectSchedulerOptions {
|
|
11
|
+
/** Key for WebSocket storage: accountId (per-account) or appKey (per-appKey) */
|
|
12
|
+
key: string
|
|
13
|
+
config: WorkClawBaseConfig
|
|
14
|
+
log?: {
|
|
15
|
+
info?: (msg: string) => void
|
|
16
|
+
warn?: (msg: string) => void
|
|
17
|
+
error?: (msg: string) => void
|
|
18
|
+
debug?: (msg: string) => void
|
|
19
|
+
}
|
|
20
|
+
onMessage: (data: string) => void
|
|
21
|
+
onReconnectSuccess?: () => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function createReconnectScheduler(options: ReconnectSchedulerOptions): {
|
|
25
|
+
scheduleReconnect: () => void
|
|
26
|
+
stopReconnect: () => void
|
|
27
|
+
} {
|
|
28
|
+
const { key, config, log, onMessage, onReconnectSuccess } = options
|
|
29
|
+
|
|
30
|
+
let reconnectBackoff = 5000
|
|
31
|
+
let shouldStopReconnect = false
|
|
32
|
+
let pendingReconnectTimer: NodeJS.Timeout | null = null
|
|
33
|
+
|
|
34
|
+
const scheduleReconnect = (): void => {
|
|
35
|
+
if (shouldStopReconnect) {
|
|
36
|
+
log?.info?.(`Reconnect: Stopped due to previous auth failure`)
|
|
37
|
+
return
|
|
38
|
+
}
|
|
39
|
+
if (pendingReconnectTimer !== null) {
|
|
40
|
+
log?.info?.(`Reconnect: Already scheduled, skipping duplicate`)
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const jitter = Math.floor(Math.random() * 3000)
|
|
45
|
+
const delayMs = reconnectBackoff + jitter
|
|
46
|
+
log?.info?.(`Reconnect: Scheduling in ${delayMs}ms (base=${reconnectBackoff} + jitter=${jitter}) key=${key}`)
|
|
47
|
+
|
|
48
|
+
pendingReconnectTimer = setTimeout(async () => {
|
|
49
|
+
pendingReconnectTimer = null
|
|
50
|
+
try {
|
|
51
|
+
log?.info?.(`Reconnect: Attempting... key=${key}`)
|
|
52
|
+
|
|
53
|
+
const tokenCacheKey = config.appKey || key
|
|
54
|
+
clearOpenclawWorkclawTokenCache(tokenCacheKey)
|
|
55
|
+
|
|
56
|
+
const connConfig = {
|
|
57
|
+
baseUrl: config.baseUrl || '',
|
|
58
|
+
websocketUrl: config.websocketUrl,
|
|
59
|
+
appKey: config.appKey,
|
|
60
|
+
appSecret: config.appSecret,
|
|
61
|
+
localIp: config.localIp,
|
|
62
|
+
allowInsecureTls: config.allowInsecureTls,
|
|
63
|
+
requestTimeout: config.requestTimeout,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const { openOpenclawWorkclawConnection } = await import('../connection/workclaw-client.js')
|
|
67
|
+
const { endpoint, ticket } = await openOpenclawWorkclawConnection(tokenCacheKey, connConfig)
|
|
68
|
+
const url = `${endpoint}?ticket=${encodeURIComponent(ticket)}`
|
|
69
|
+
|
|
70
|
+
const { Agent } = await import('undici')
|
|
71
|
+
const dispatcher = connConfig.allowInsecureTls
|
|
72
|
+
? new Agent({ connect: { rejectUnauthorized: false } })
|
|
73
|
+
: undefined
|
|
74
|
+
const wsOptions = dispatcher ? { dispatcher } : undefined
|
|
75
|
+
|
|
76
|
+
const ws = new (await import('undici')).WebSocket(url, wsOptions)
|
|
77
|
+
setOpenclawWorkclawWsConnection(key, ws)
|
|
78
|
+
|
|
79
|
+
ws.onopen = () => {
|
|
80
|
+
log?.info?.(`Reconnect: Success`)
|
|
81
|
+
reconnectBackoff = 5000
|
|
82
|
+
onReconnectSuccess?.()
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
ws.onmessage = (event: any) => {
|
|
86
|
+
const data = typeof event.data === 'string' ? event.data : String(event.data ?? '')
|
|
87
|
+
log?.info?.(`Reconnect: Message bytes=${data.length}`)
|
|
88
|
+
onMessage(data)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
ws.onclose = (event: any) => {
|
|
92
|
+
const code = String(event?.code ?? '')
|
|
93
|
+
const reason = String(event?.reason ?? '')
|
|
94
|
+
log?.warn?.(`Reconnect: Closed code=${code} reason=${reason}`)
|
|
95
|
+
clearOpenclawWorkclawWsConnection(key)
|
|
96
|
+
scheduleReconnect()
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
ws.onerror = (event: any) => {
|
|
100
|
+
log?.error?.(`Reconnect: Error: ${String(event?.message ?? event)}`)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const errorStr = String(err)
|
|
105
|
+
log?.error?.(`Reconnect: Failed: ${errorStr}`)
|
|
106
|
+
|
|
107
|
+
if (errorStr.includes('访问过于频繁')) {
|
|
108
|
+
log?.warn?.(`Reconnect: Rate limited, retrying with minimal backoff`)
|
|
109
|
+
if (pendingReconnectTimer !== null) {
|
|
110
|
+
clearTimeout(pendingReconnectTimer)
|
|
111
|
+
pendingReconnectTimer = null
|
|
112
|
+
}
|
|
113
|
+
reconnectBackoff = 1000
|
|
114
|
+
scheduleReconnect()
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const isAuthError
|
|
119
|
+
= errorStr.includes('"errCode":2001')
|
|
120
|
+
|| errorStr.includes('"code":2001')
|
|
121
|
+
|| errorStr.includes('鉴权失败')
|
|
122
|
+
|| errorStr.includes('invalid credentials')
|
|
123
|
+
|| errorStr.includes('unauthorized')
|
|
124
|
+
|
|
125
|
+
if (isAuthError) {
|
|
126
|
+
log?.error?.(`Reconnect: Authentication failed, stopping`)
|
|
127
|
+
shouldStopReconnect = true
|
|
128
|
+
if (pendingReconnectTimer !== null) {
|
|
129
|
+
clearTimeout(pendingReconnectTimer)
|
|
130
|
+
pendingReconnectTimer = null
|
|
131
|
+
}
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
scheduleReconnect()
|
|
136
|
+
}
|
|
137
|
+
}, delayMs)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const stopReconnect = (): void => {
|
|
141
|
+
shouldStopReconnect = true
|
|
142
|
+
if (pendingReconnectTimer !== null) {
|
|
143
|
+
clearTimeout(pendingReconnectTimer)
|
|
144
|
+
pendingReconnectTimer = null
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return { scheduleReconnect, stopReconnect }
|
|
149
|
+
}
|