openclaw-openagent 1.0.13 → 1.0.14

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 (128) hide show
  1. package/dist/src/messaging/executor.d.ts +2 -3
  2. package/dist/src/messaging/executor.js +4 -31
  3. package/dist/src/plugin-ui/assets/openagent-override.js +4 -5
  4. package/dist/src/runtime/update-checker.d.ts +1 -1
  5. package/dist/src/runtime/update-checker.js +9 -46
  6. package/package.json +1 -3
  7. package/src/app/channel-tools.ts +0 -249
  8. package/src/app/discovery-tools.ts +0 -273
  9. package/src/app/download-file-tool.ts +0 -133
  10. package/src/app/hooks.ts +0 -144
  11. package/src/app/index.ts +0 -84
  12. package/src/app/messaging-tools.ts +0 -79
  13. package/src/app/ops-tools.ts +0 -155
  14. package/src/app/remote-agent-tool.ts +0 -762
  15. package/src/app/types.ts +0 -68
  16. package/src/app/upload-file-tool.ts +0 -411
  17. package/src/app/verbose-preflight.ts +0 -190
  18. package/src/auth/config.ts +0 -266
  19. package/src/auth/credential-manager.ts +0 -146
  20. package/src/auth/index.ts +0 -24
  21. package/src/auth/verify.ts +0 -99
  22. package/src/channel.ts +0 -566
  23. package/src/compat.ts +0 -94
  24. package/src/config/config-schema.ts +0 -45
  25. package/src/messaging/aggregator.ts +0 -120
  26. package/src/messaging/collector.ts +0 -89
  27. package/src/messaging/executor.ts +0 -72
  28. package/src/messaging/inbound.ts +0 -150
  29. package/src/messaging/index.ts +0 -11
  30. package/src/messaging/mention-protocol.ts +0 -94
  31. package/src/messaging/process-c2c-request.ts +0 -564
  32. package/src/messaging/process-message.ts +0 -373
  33. package/src/messaging/scheduler.ts +0 -55
  34. package/src/messaging/types.ts +0 -38
  35. package/src/plugin-ui/adapters/oc-2026-04.js +0 -103
  36. package/src/plugin-ui/adapters/oc-2026-05.js +0 -125
  37. package/src/plugin-ui/adapters/oc-2026-06.js +0 -125
  38. package/src/plugin-ui/adapters/oc-unknown.js +0 -48
  39. package/src/plugin-ui/assets/agentbook-icon.svg +0 -5
  40. package/src/plugin-ui/assets/bg.png +0 -0
  41. package/src/plugin-ui/assets/icon.png +0 -0
  42. package/src/plugin-ui/assets/magic.svg +0 -5
  43. package/src/plugin-ui/assets/openagent-override.js +0 -11263
  44. package/src/plugin-ui/build.cjs +0 -463
  45. package/src/plugin-ui/index.ts +0 -18
  46. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -570
  47. package/src/plugin-ui/modules/agent-book/panel/agent-card.js +0 -170
  48. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -643
  49. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +0 -665
  50. package/src/plugin-ui/modules/agent-book/panel/mention-state.js +0 -206
  51. package/src/plugin-ui/modules/agent-book/panel/styles.js +0 -832
  52. package/src/plugin-ui/modules/agent-book/panel/theme-adapter.js +0 -86
  53. package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +0 -295
  54. package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +0 -211
  55. package/src/plugin-ui/modules/agent-book/scanner.js +0 -131
  56. package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +0 -500
  57. package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +0 -652
  58. package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +0 -262
  59. package/src/plugin-ui/modules/loader/bootstrap.js +0 -133
  60. package/src/plugin-ui/modules/loader/shared-state.js +0 -838
  61. package/src/plugin-ui/modules/loader/ws-intercept.js +0 -199
  62. package/src/plugin-ui/modules/remote-agent/chunk-parser.js +0 -161
  63. package/src/plugin-ui/modules/remote-agent/execution-card.js +0 -530
  64. package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +0 -256
  65. package/src/plugin-ui/modules/remote-agent/media-links.js +0 -151
  66. package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +0 -134
  67. package/src/plugin-ui/modules/remote-agent/output-card.js +0 -342
  68. package/src/plugin-ui/modules/remote-agent/progress-store.js +0 -363
  69. package/src/plugin-ui/modules/remote-agent/render-hooks.js +0 -1700
  70. package/src/plugin-ui/modules/remote-agent/styles.js +0 -903
  71. package/src/plugin-ui/modules/remote-agent/tool-card-model.js +0 -130
  72. package/src/plugin-ui/postinstall-deploy.cjs +0 -52
  73. package/src/plugin-ui/ui-extension-loader/backup.ts +0 -92
  74. package/src/plugin-ui/ui-extension-loader/index.ts +0 -276
  75. package/src/plugin-ui/ui-extension-loader/locator.ts +0 -152
  76. package/src/plugin-ui/ui-extension-loader/manifest.ts +0 -57
  77. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +0 -944
  78. package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +0 -70
  79. package/src/plugin-ui/ui-extension-loader/types.ts +0 -72
  80. package/src/proxy/auth-proxy.ts +0 -414
  81. package/src/runtime/account.ts +0 -549
  82. package/src/runtime/index.ts +0 -7
  83. package/src/runtime/plugin-runtime.ts +0 -94
  84. package/src/runtime/registry.ts +0 -71
  85. package/src/runtime/update-checker.ts +0 -286
  86. package/src/sdk/CLASS_MAP.md +0 -143
  87. package/src/sdk/index.d.ts +0 -126
  88. package/src/sdk/index.js +0 -23990
  89. package/src/sdk/modules/cloud-search-module.js +0 -1117
  90. package/src/sdk/modules/follow-module.js +0 -1069
  91. package/src/sdk/modules/group-module.js +0 -7397
  92. package/src/sdk/modules/relationship-module.js +0 -2269
  93. package/src/sdk/modules/signaling-module.js +0 -1468
  94. package/src/sdk/modules/tim-upload-plugin.js +0 -730
  95. package/src/sdk/node-env/http-request.js +0 -90
  96. package/src/sdk/node-env/index.js +0 -57
  97. package/src/sdk/node-env/storage.js +0 -114
  98. package/src/sdk/package.json +0 -10
  99. package/src/sdk/tsconfig.json +0 -16
  100. package/src/state/pending-invocation-store.ts +0 -43
  101. package/src/state/store.ts +0 -756
  102. package/src/tim/c2c.ts +0 -451
  103. package/src/tim/channels.ts +0 -364
  104. package/src/tim/client.ts +0 -330
  105. package/src/tim/index.ts +0 -18
  106. package/src/tim/messages.ts +0 -166
  107. package/src/tim/sdk-logger-init.ts +0 -50
  108. package/src/tools.ts +0 -10
  109. package/src/transport/factory.ts +0 -95
  110. package/src/transport/oasn/index.ts +0 -17
  111. package/src/transport/oasn/oasn-agent-card.ts +0 -111
  112. package/src/transport/oasn/oasn-discovery.ts +0 -108
  113. package/src/transport/oasn/oasn-files.ts +0 -210
  114. package/src/transport/oasn/oasn-http.ts +0 -529
  115. package/src/transport/oasn/oasn-invocation.ts +0 -604
  116. package/src/transport/oasn/oasn-normalize.ts +0 -133
  117. package/src/transport/oasn/oasn-register.ts +0 -33
  118. package/src/transport/oasn/oasn-transport.ts +0 -318
  119. package/src/transport/oasn/oasn-types.ts +0 -404
  120. package/src/transport/tim/index.ts +0 -8
  121. package/src/transport/tim/tim-transport.ts +0 -515
  122. package/src/transport/types.ts +0 -538
  123. package/src/types/openclaw-plugin-sdk-media-store.d.ts +0 -9
  124. package/src/types/openclaw.d.ts +0 -97
  125. package/src/types/tencentcloud-chat.d.ts +0 -15
  126. package/src/util/http.ts +0 -113
  127. package/src/util/logger.ts +0 -131
  128. package/src/util/url-resolver.ts +0 -77
package/src/channel.ts DELETED
@@ -1,566 +0,0 @@
1
- /**
2
- * OpenAgent Channel Adapter — OpenClaw channel plugin interface
3
- *
4
- * Assembles the v3 modular architecture:
5
- * auth/ → runtime/ → tim/ → messaging/ → tools
6
- *
7
- * Gateway lifecycle uses AccountRuntime with transaction-style
8
- * start/stop and RuntimeRegistry enforcement.
9
- */
10
-
11
- import { DEFAULT_OASN_API_BASE, isUnconfiguredOasnApiBase, resolveOpenagentAccount, getOpenagentConfig } from './auth/config.js';
12
- import { registry } from './runtime/registry.js';
13
- import { AccountRuntime } from './runtime/account.js';
14
-
15
- import { logger } from './util/logger.js';
16
- import { resolveOasnRelativeUrl } from './util/url-resolver.js';
17
- import * as timMessages from './tim/messages.js';
18
-
19
- const API_BASE = 'https://api.clawlink.club';
20
- const OASN_TRANSPORT = 'oasn';
21
-
22
- // ── Channel adapter meta ──
23
-
24
- const meta = {
25
- id: 'openagent',
26
- label: 'OpenAgent',
27
- selectionLabel: 'OpenAgent (Agent Network)',
28
- detailLabel: 'OpenAgent Agent Network',
29
- docsPath: '/channels/openagent',
30
- docsLabel: 'openagent',
31
- blurb: 'Connect to OASN agent social network via Tencent IM.',
32
- aliases: ['openagent', 'agent-network'],
33
- order: 90,
34
- quickstartAllowFrom: true,
35
- };
36
-
37
- // ── Channel plugin object ──
38
-
39
- export const openagentPlugin = {
40
- id: 'openagent',
41
- meta,
42
-
43
- capabilities: {
44
- chatTypes: ['group'],
45
- media: false,
46
- reactions: true,
47
- threads: false,
48
- polls: false,
49
- nativeCommands: false,
50
- },
51
-
52
- reload: { configPrefixes: ['channels.openagent'] },
53
-
54
- config: {
55
- listAccountIds: (cfgOrCtx: Record<string, unknown>) => {
56
- const cfg = (cfgOrCtx as { cfg?: Record<string, unknown> })?.cfg
57
- || (cfgOrCtx?.['channels'] ? cfgOrCtx : {});
58
- const clCfg = getOpenagentConfig(cfg);
59
- const keys = Object.keys((clCfg['accounts'] || {}) as Record<string, unknown>);
60
- return keys.length > 0 ? keys : ['default'];
61
- },
62
- resolveAccount: (cfg: Record<string, unknown>, accountId: string) =>
63
- resolveOpenagentAccount(cfg, accountId),
64
- defaultAccountId: (cfgOrCtx: Record<string, unknown>) => {
65
- const cfg = (cfgOrCtx as { cfg?: Record<string, unknown> })?.cfg
66
- || (cfgOrCtx?.['channels'] ? cfgOrCtx : {});
67
- const clCfg = getOpenagentConfig(cfg);
68
- const keys = Object.keys((clCfg['accounts'] || {}) as Record<string, unknown>);
69
- return keys.length > 0 ? keys[0] : 'default';
70
- },
71
- setAccountEnabled: ({ cfg, enabled }: { cfg: Record<string, unknown>; enabled: boolean }) => ({
72
- ...cfg,
73
- channels: {
74
- ...(cfg['channels'] as Record<string, unknown>),
75
- openagent: { ...((cfg['channels'] as Record<string, unknown>)?.['openagent'] as Record<string, unknown>), enabled },
76
- },
77
- }),
78
- deleteAccount: ({ cfg }: { cfg: Record<string, unknown> }) => {
79
- const channels = { ...(cfg['channels'] as Record<string, unknown>) };
80
- delete channels['openagent'];
81
- return { ...cfg, channels };
82
- },
83
- isConfigured: (account: { configured: boolean }) => account.configured,
84
- describeAccount: (account: { accountId: string; name: string; enabled: boolean; configured: boolean; transport?: string; status?: string }) => ({
85
- accountId: account.accountId,
86
- name: account.name,
87
- enabled: account.enabled,
88
- configured: account.configured,
89
- tokenStatus: account.configured ? 'available' : 'missing',
90
- transport: account.transport ?? 'oasn',
91
- claimStatus: account.status ?? 'unknown',
92
- }),
93
- },
94
-
95
- security: {
96
- resolveDmPolicy: () => ({
97
- policy: 'open',
98
- allowFrom: ['*'],
99
- policyPath: 'channels.openagent.dm.policy',
100
- allowFromPath: 'channels.openagent.dm.allowFrom',
101
- normalizeEntry: (raw: string) => raw.trim(),
102
- }),
103
- },
104
-
105
- groups: {
106
- resolveRequireMention: () => false,
107
- },
108
-
109
- threading: {
110
- resolveReplyToMode: () => 'first',
111
- },
112
-
113
- messaging: {
114
- normalizeTarget: (raw: string) => {
115
- const trimmed = raw.trim();
116
- if (!trimmed) return undefined;
117
- return trimmed.replace(/^(openagent):/i, '').trim() || undefined;
118
- },
119
- targetResolver: {
120
- looksLikeId: (raw: string) => Boolean(raw.trim()),
121
- hint: '<channel-id> e.g. ch-001',
122
- },
123
- },
124
-
125
- outbound: {
126
- deliveryMode: 'direct',
127
- chunkerMode: 'text',
128
- textChunkLimit: 3000,
129
-
130
- sendText: async ({ to, text }: { cfg: unknown; to: string; text: string; accountId?: string }) => {
131
- logger.info(`[outbound] sendText to=${to} len=${text.length}`);
132
- const rt = registry.getDefault();
133
- if (!rt?.isRunning) {
134
- logger.warn('[outbound] sendText failed: not connected');
135
- return { channel: 'openagent', ok: false, messageId: '', error: new Error('OpenAgent not connected') };
136
- }
137
-
138
- // v3.9+ 双轨抽象:群聊外发仅在 TIM 路径有效(IMChannelTransport)。
139
- // OASN 路径下没有"主动发群消息"语义 —— ClientAgent 只通过 sendTask
140
- // 向远端 ServiceAgent 发起 Invocation,原则上不会触达此分支;
141
- // 但若上层误调用,直接告警并返回 ok=false,避免崩溃。
142
- if (rt.transportType === 'oasn') {
143
- logger.warn(`[outbound] sendText not supported on OASN transport (to=${to})`);
144
- return {
145
- channel: 'openagent',
146
- ok: false,
147
- messageId: '',
148
- error: new Error('sendText not supported on OASN transport'),
149
- };
150
- }
151
-
152
- try {
153
- const result = await rt.sendMessage(to, text);
154
- logger.info(`[outbound] sendText OK msgId=${result.messageId}`);
155
- return { channel: 'openagent', ok: true, messageId: result.messageId };
156
- } catch (err) {
157
- logger.error(`[outbound] sendText failed: ${(err as Error).message}`);
158
- return {
159
- channel: 'openagent', ok: false, messageId: '',
160
- error: err instanceof Error ? err : new Error(String(err)),
161
- };
162
- }
163
- },
164
- },
165
-
166
- status: {
167
- defaultRuntime: {
168
- accountId: 'default',
169
- running: false,
170
- lastStartAt: null as number | null,
171
- lastStopAt: null as number | null,
172
- lastError: null as string | null,
173
- },
174
- buildChannelSummary: ({ snapshot }: { snapshot: Record<string, unknown> }) => ({
175
- configured: snapshot['configured'] ?? false,
176
- running: snapshot['running'] ?? false,
177
- connected: snapshot['connected'] ?? false,
178
- transport: snapshot['transport'] ?? 'oasn',
179
- claimStatus: snapshot['claimStatus'] ?? 'unknown',
180
- claimUrl: snapshot['claimUrl'] ?? '',
181
- lastStartAt: snapshot['lastStartAt'] ?? null,
182
- lastStopAt: snapshot['lastStopAt'] ?? null,
183
- lastError: snapshot['lastError'] ?? null,
184
- lastInboundAt: snapshot['lastInboundAt'] ?? null,
185
- lastOutboundAt: snapshot['lastOutboundAt'] ?? null,
186
- }),
187
- probeAccount: async () => ({ ok: true }),
188
- buildAccountSnapshot: ({ account, runtime }: {
189
- account: { accountId: string; name: string; enabled: boolean; configured: boolean; transport?: string; status?: string; claimUrl?: string };
190
- runtime?: { running?: boolean; lastStartAt?: number; lastStopAt?: number; lastError?: string };
191
- }) => ({
192
- accountId: account.accountId,
193
- name: account.name,
194
- enabled: account.enabled,
195
- configured: account.configured,
196
- tokenStatus: account.configured ? 'available' : 'missing',
197
- transport: account.transport ?? 'oasn',
198
- claimStatus: runtime && 'claimStatus' in runtime ? (runtime as { claimStatus?: string }).claimStatus : account.status ?? 'unknown',
199
- claimUrl: account.claimUrl ?? '',
200
- running: runtime?.running ?? false,
201
- connected: runtime?.running ?? false,
202
- lastStartAt: runtime?.lastStartAt ?? null,
203
- lastStopAt: runtime?.lastStopAt ?? null,
204
- lastError: runtime?.lastError ?? null,
205
- }),
206
-
207
- // Outbound handlers: intentionally no-op (LLM text is intercepted here)
208
- sendText: async () => ({ ok: true }),
209
- sendMedia: async () => ({ ok: true }),
210
- },
211
-
212
- // ── Gateway lifecycle ──
213
- gateway: {
214
- startAccount: async (ctx: {
215
- account: {
216
- accountId: string;
217
- agentId: string;
218
- apiBase: string;
219
- accessApiBase?: string;
220
- apiKey: string;
221
- configured: boolean;
222
- config: Record<string, unknown>;
223
- };
224
- cfg: Record<string, unknown>;
225
- abortSignal?: AbortSignal;
226
- log?: { info?: (msg: string) => void; warn?: (msg: string) => void; error?: (msg: string) => void };
227
- setStatus: (status: Record<string, unknown>) => void;
228
- }) => {
229
- const { account, abortSignal } = ctx;
230
-
231
- // Guard is installed in register() (index.ts), not here.
232
-
233
- // OASN 模式以 CLI install/register/write-config 为首次注册入口。
234
- // runtime 只消费已经写入的 agent_id + api_key。
235
- const accountConfig = resolveOpenagentAccount(ctx.cfg);
236
- if (accountConfig.transport === 'oasn' && isUnconfiguredOasnApiBase(accountConfig.apiBase)) {
237
- logger.warn('[channel] OASN api_base not configured; skipping start');
238
- ctx.setStatus({
239
- accountId: account.accountId,
240
- running: false,
241
- configured: false,
242
- transport: 'oasn',
243
- claimStatus: accountConfig.status,
244
- lastError: 'OASN api_base is not configured',
245
- });
246
- return;
247
- }
248
- if (accountConfig.transport === 'oasn' && !accountConfig.configured) {
249
- const message = 'OASN account is not configured; run openclaw-plugin-openagent-cli install to register this device';
250
- logger.warn(`[channel] ${message}`);
251
- ctx.setStatus({
252
- accountId: account.accountId,
253
- running: false,
254
- configured: false,
255
- transport: 'oasn',
256
- claimStatus: accountConfig.status,
257
- claimUrl: accountConfig.claimUrl,
258
- lastError: message,
259
- });
260
- return;
261
- }
262
- if (!account.configured && accountConfig.transport !== 'oasn') {
263
- logger.warn('[channel] Not configured; skipping');
264
- ctx.setStatus({ accountId: account.accountId, running: false, configured: false });
265
- return;
266
- }
267
-
268
- logger.info(`[channel] Starting account '${account.accountId}' for agent ${accountConfig.agentId || account.agentId || '(unconfigured)'}`);
269
-
270
- const runtime = new AccountRuntime(account.accountId);
271
-
272
- try {
273
- // Register in registry (throws if another account is active)
274
- registry.register(runtime);
275
-
276
- // Transaction-style start
277
- await runtime.start(
278
- {
279
- accountId: account.accountId,
280
- name: 'OpenAgent',
281
- enabled: true,
282
- configured: accountConfig.configured,
283
- agentId: accountConfig.agentId,
284
- apiKey: accountConfig.apiKey,
285
- apiBase: accountConfig.apiBase,
286
- accessApiBase: accountConfig.accessApiBase,
287
- claimUrl: accountConfig.claimUrl,
288
- status: accountConfig.status,
289
- registeredAt: accountConfig.registeredAt,
290
- // v3.9+ 双轨抽象:用 resolveOpenagentAccount 从 raw cfg 解析 transport(不依赖 OpenClaw 框架透传 account.config 自定义字段)
291
- transport: accountConfig.transport,
292
- config: account.config || {},
293
- },
294
- {
295
- batchWindowMs: (account.config?.['batchWindowMs'] as number) || 20_000,
296
- maxBatchSize: (account.config?.['maxBatchSize'] as number) || 20,
297
- },
298
- ctx.cfg,
299
- );
300
-
301
- ctx.setStatus({
302
- accountId: account.accountId,
303
- running: true,
304
- configured: accountConfig.configured,
305
- transport: runtime.transportType,
306
- claimStatus: runtime.claimStatus,
307
- claimUrl: runtime.claimUrl,
308
- lastStartAt: Date.now(),
309
- });
310
-
311
- logger.info('[channel] Pipeline active: Push mode');
312
-
313
- // Block until aborted
314
- await new Promise<void>((_, reject) => {
315
- if (abortSignal) {
316
- abortSignal.addEventListener('abort', () => {
317
- void runtime.stop().then(() => {
318
- registry.unregister(runtime);
319
- ctx.setStatus({
320
- accountId: account.accountId,
321
- running: false,
322
- lastStopAt: Date.now(),
323
- });
324
- logger.info(`[channel] Account '${account.accountId}' stopped via abort`);
325
- reject(new Error('abort'));
326
- });
327
- }, { once: true });
328
- }
329
- });
330
- } catch (err) {
331
- // Controlled failure: catch registry error or start error
332
- const message = (err as Error).message;
333
- if (message !== 'abort') {
334
- logger.error(`[channel] Start failed: ${message}`);
335
- registry.unregister(runtime);
336
- ctx.setStatus({
337
- accountId: account.accountId,
338
- running: false,
339
- lastError: message,
340
- });
341
- }
342
- }
343
- },
344
-
345
- stopAccount: async (ctx: {
346
- account: { accountId: string };
347
- setStatus: (status: Record<string, unknown>) => void;
348
- }) => {
349
- const rt = registry.getDefault();
350
- if (rt) {
351
- await rt.stop();
352
- registry.unregister(rt);
353
- }
354
- ctx.setStatus({
355
- accountId: ctx.account.accountId,
356
- running: false,
357
- lastStopAt: Date.now(),
358
- });
359
- },
360
- },
361
-
362
- // ── Onboarding wizard ──
363
- onboarding: {
364
- channel: 'openagent',
365
- getStatus: async ({ cfg }: { cfg: Record<string, unknown> }) => {
366
- const account = resolveOpenagentAccount(cfg);
367
- const apiBaseMissing = account.transport === 'oasn' && isUnconfiguredOasnApiBase(account.apiBase);
368
- const statusLine = buildOnboardingStatusLine(account, apiBaseMissing);
369
- return {
370
- channel: 'openagent',
371
- configured: account.transport === 'oasn' ? account.configured && !apiBaseMissing : account.configured,
372
- statusLines: [statusLine],
373
- selectionHint: apiBaseMissing
374
- ? 'needs api_base'
375
- : account.transport === 'oasn' && !account.configured
376
- ? 'needs CLI install'
377
- : account.configured ? 'configured' : 'needs credentials',
378
- quickstartScore: apiBaseMissing ? 0 : account.configured ? 2 : 0,
379
- };
380
- },
381
- configure: async ({ cfg, prompter }: {
382
- cfg: Record<string, unknown>;
383
- prompter: { text: (opts: { message: string; validate: (v: string) => string | undefined }) => Promise<string> };
384
- }) => {
385
- const existing = ((cfg['channels'] as Record<string, unknown>)?.['openagent'] || {}) as Record<string, unknown>;
386
- const accounts = (existing['accounts'] || {}) as Record<string, Record<string, unknown>>;
387
- const firstAccKey = Object.keys(accounts)[0];
388
- const fallbackAcc = firstAccKey ? accounts[firstAccKey]! : {};
389
- const resolved = resolveOpenagentAccount(cfg);
390
-
391
- if (resolved.transport === OASN_TRANSPORT) {
392
- let apiBase = resolved.apiBase;
393
- if (isUnconfiguredOasnApiBase(apiBase)) {
394
- apiBase = String(await prompter.text({
395
- message: 'Enter OASN API Base URL',
396
- validate: (v: string) => {
397
- const value = v?.trim();
398
- if (!value || isUnconfiguredOasnApiBase(value)) return 'Required';
399
- try {
400
- // eslint-disable-next-line no-new
401
- new URL(value);
402
- return undefined;
403
- } catch {
404
- return 'Must be a valid URL';
405
- }
406
- },
407
- })).trim();
408
- }
409
- const accessApiBase = String(
410
- resolved.accessApiBase
411
- || fallbackAcc['access_api_base']
412
- || fallbackAcc['accessApiBase']
413
- || existing['access_api_base']
414
- || existing['accessApiBase']
415
- || apiBase,
416
- );
417
-
418
- let claimUpdates: Record<string, unknown> = {};
419
- if (resolved.agentId && resolved.apiKey && resolved.status !== 'claimed') {
420
- const ownerEmail = String(await prompter.text({
421
- message: 'Enter Owner email to claim this OASN ClientAgent (leave blank to skip)',
422
- validate: () => undefined,
423
- })).trim();
424
- if (ownerEmail) {
425
- claimUpdates = await claimOasnAgent(apiBase, resolved.apiKey, resolved.agentId, ownerEmail);
426
- }
427
- }
428
-
429
- return {
430
- cfg: {
431
- ...cfg,
432
- channels: {
433
- ...(cfg['channels'] as Record<string, unknown>),
434
- openagent: {
435
- ...existing,
436
- enabled: true,
437
- transport: 'oasn',
438
- api_base: apiBase,
439
- access_api_base: accessApiBase,
440
- accounts: {
441
- default: compactConfig({
442
- ...fallbackAcc,
443
- transport: 'oasn',
444
- api_base: apiBase,
445
- access_api_base: accessApiBase,
446
- agent_id: resolved.agentId || fallbackAcc['agent_id'],
447
- api_key: resolved.apiKey || fallbackAcc['api_key'],
448
- claim_url: resolved.claimUrl || fallbackAcc['claim_url'],
449
- status: claimUpdates.status || resolved.status,
450
- registered_at: resolved.registeredAt || fallbackAcc['registered_at'],
451
- ...claimUpdates,
452
- }),
453
- },
454
- },
455
- },
456
- },
457
- accountId: 'default',
458
- };
459
- }
460
-
461
- let agentId = (fallbackAcc['agentId'] || fallbackAcc['agent_id'] || firstAccKey || '') as string;
462
- let apiKey = (fallbackAcc['api_key'] || fallbackAcc['apiKey'] || '') as string;
463
- const apiBase = (fallbackAcc['apiBase'] || fallbackAcc['api_base'] || API_BASE) as string;
464
-
465
- if (!agentId) {
466
- agentId = String(await prompter.text({
467
- message: 'Enter your OpenAgent Agent ID',
468
- validate: (v: string) => v?.trim() ? undefined : 'Required',
469
- })).trim();
470
- }
471
-
472
- if (!apiKey) {
473
- apiKey = String(await prompter.text({
474
- message: 'Enter your OpenAgent API Key',
475
- validate: (v: string) => v?.trim() ? undefined : 'Required',
476
- })).trim();
477
- }
478
-
479
- const cleanedExisting = { ...existing };
480
- delete cleanedExisting['agentId'];
481
- delete cleanedExisting['apiKey'];
482
- delete cleanedExisting['agent_id'];
483
- delete cleanedExisting['api_key'];
484
-
485
- return {
486
- cfg: {
487
- ...cfg,
488
- channels: {
489
- ...(cfg['channels'] as Record<string, unknown>),
490
- openagent: {
491
- ...cleanedExisting,
492
- enabled: true,
493
- accounts: {
494
- default: {
495
- agent_id: agentId,
496
- api_key: apiKey,
497
- api_base: apiBase,
498
- },
499
- },
500
- },
501
- },
502
- },
503
- accountId: 'default',
504
- };
505
- },
506
- disable: (cfg: Record<string, unknown>) => ({
507
- ...cfg,
508
- channels: {
509
- ...(cfg['channels'] as Record<string, unknown>),
510
- openagent: {
511
- ...((cfg['channels'] as Record<string, unknown>)?.['openagent'] as Record<string, unknown>),
512
- enabled: false,
513
- },
514
- },
515
- }),
516
- },
517
- };
518
-
519
- function buildOnboardingStatusLine(
520
- account: ReturnType<typeof resolveOpenagentAccount>,
521
- apiBaseMissing: boolean,
522
- ): string {
523
- if (account.transport !== 'oasn') {
524
- return account.configured
525
- ? `OpenAgent: configured (agent=${account.agentId})`
526
- : 'OpenAgent: needs agentId + apiKey';
527
- }
528
- if (apiBaseMissing) return 'OASN: needs api_base';
529
- if (!account.configured) return `OASN: run openclaw-plugin-openagent-cli install to register (${account.apiBase})`;
530
- const claimHint = account.status === 'claimed'
531
- ? 'claimed'
532
- : `${account.status}${account.claimUrl ? ` claim=${account.claimUrl}` : ''}`;
533
- return `OASN: ${claimHint} (agent=${account.agentId})`;
534
- }
535
-
536
- function compactConfig(input: Record<string, unknown>): Record<string, unknown> {
537
- return Object.fromEntries(
538
- Object.entries(input).filter(([, value]) => value !== undefined && value !== ''),
539
- );
540
- }
541
-
542
- async function claimOasnAgent(
543
- apiBase: string,
544
- apiKey: string,
545
- agentId: string,
546
- ownerEmail: string,
547
- ): Promise<Record<string, unknown>> {
548
- const res = await fetch(resolveOasnRelativeUrl(apiBase, '/api/agents/claim'), {
549
- method: 'POST',
550
- headers: {
551
- 'Content-Type': 'application/json',
552
- Authorization: `Bearer ${apiKey}`,
553
- },
554
- body: JSON.stringify({ agentId, ownerEmail }),
555
- signal: AbortSignal.timeout(15_000),
556
- });
557
- const body = await res.json().catch(() => ({})) as Record<string, unknown>;
558
- if (!res.ok) {
559
- throw new Error(`claim failed: ${res.status} ${JSON.stringify(body).slice(0, 200)}`);
560
- }
561
- return {
562
- status: 'claim_pending',
563
- claim_expires_at: body['expiresAt'] || body['expires_at'],
564
- owner_email_masked: body['ownerEmailMasked'] || body['owner_email_masked'],
565
- };
566
- }
package/src/compat.ts DELETED
@@ -1,94 +0,0 @@
1
- /**
2
- * Runtime host-version compatibility check for openclaw-openagent.
3
- *
4
- * OpenClaw uses a date-based version format: YYYY.M.DD (e.g. 2026.3.22).
5
- * This module parses that format and validates the running host is within
6
- * the supported range for this plugin version.
7
- *
8
- * Ported from openclaw-weixin v2.1.1 src/compat.ts
9
- * Reference: docs/reference/plugins/openclaw-weixin-latest-v2.1.1/src/compat.ts
10
- */
11
-
12
- import { logger } from './util/logger.js';
13
-
14
- export const PLUGIN_VERSION = '1.0.0';
15
-
16
- export const SUPPORTED_HOST_MIN = '2026.3.22';
17
-
18
- /** Plugin has been verified up to this OpenClaw host version */
19
- export const MAX_TESTED_VERSION = '2026.6.30';
20
-
21
- export interface OpenClawVersion {
22
- year: number;
23
- month: number;
24
- day: number;
25
- }
26
-
27
- /**
28
- * Parse an OpenClaw date version string (e.g. "2026.3.22") into components.
29
- * Returns null for unparseable strings.
30
- */
31
- export function parseOpenClawVersion(version: string): OpenClawVersion | null {
32
- // Strip any pre-release suffix (e.g. "2026.3.22-beta.1" -> "2026.3.22")
33
- const base = version.trim().split('-')[0];
34
- const parts = base.split('.');
35
- if (parts.length !== 3) return null;
36
- const [year, month, day] = parts.map(Number);
37
- if (Number.isNaN(year) || Number.isNaN(month) || Number.isNaN(day)) return null;
38
- return { year, month, day };
39
- }
40
-
41
- /**
42
- * Compare two parsed versions. Returns -1 | 0 | 1.
43
- */
44
- export function compareVersions(a: OpenClawVersion, b: OpenClawVersion): -1 | 0 | 1 {
45
- for (const key of ['year', 'month', 'day'] as const) {
46
- if (a[key] < b[key]) return -1;
47
- if (a[key] > b[key]) return 1;
48
- }
49
- return 0;
50
- }
51
-
52
- /**
53
- * Check whether a host version string is >= SUPPORTED_HOST_MIN.
54
- */
55
- export function isHostVersionSupported(hostVersion: string): boolean {
56
- const host = parseOpenClawVersion(hostVersion);
57
- if (!host) return false;
58
- const min = parseOpenClawVersion(SUPPORTED_HOST_MIN)!;
59
- return compareVersions(host, min) >= 0;
60
- }
61
-
62
- /**
63
- * Fail-fast guard. Call at the very start of `register()` to prevent the
64
- * plugin from loading on an incompatible host.
65
- *
66
- * @throws {Error} with a human-readable message when the host is out of range.
67
- */
68
- export function assertHostCompatibility(hostVersion: string | undefined): void {
69
- if (!hostVersion || hostVersion === 'unknown') {
70
- logger.warn(
71
- '[compat] Could not determine host OpenClaw version; skipping compatibility check.',
72
- );
73
- return;
74
- }
75
- if (isHostVersionSupported(hostVersion)) {
76
- logger.info(`[compat] Host OpenClaw ${hostVersion} >= ${SUPPORTED_HOST_MIN}, OK.`);
77
- // Warn but don't block for versions beyond tested range
78
- const host = parseOpenClawVersion(hostVersion);
79
- const max = parseOpenClawVersion(MAX_TESTED_VERSION);
80
- if (host && max && compareVersions(host, max) > 0) {
81
- logger.warn(
82
- `[compat] Host OpenClaw ${hostVersion} is beyond max tested version ${MAX_TESTED_VERSION}. ` +
83
- `The plugin may encounter compatibility issues.`,
84
- );
85
- }
86
- return;
87
- }
88
- throw new Error(
89
- `openclaw-openagent@${PLUGIN_VERSION} requires OpenClaw >=${SUPPORTED_HOST_MIN}, ` +
90
- `but found ${hostVersion}. ` +
91
- `Please upgrade OpenClaw, or install the legacy version:\n` +
92
- ` npm install openclaw-openagent@legacy`,
93
- );
94
- }