@agentclub/openclaw-adapter 0.1.2
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/LICENSE +21 -0
- package/README.md +171 -0
- package/dist/adapter.js +165 -0
- package/dist/agenthub-client.js +180 -0
- package/dist/cli.js +246 -0
- package/dist/config.js +182 -0
- package/dist/index.js +6 -0
- package/dist/openclaw-client.js +412 -0
- package/dist/prompt.js +80 -0
- package/dist/types.js +1 -0
- package/dist/utils.js +106 -0
- package/package.json +50 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { AgentHubOpenClawAdapter } from './adapter.js';
|
|
4
|
+
import { applyConfigOverrides, buildEnvExample, buildConfigOverridesFromEnv, buildDefaultConfigFromEnv, defaultConfigPath, loadConfig, saveConfig, validateConfig, } from './config.js';
|
|
5
|
+
import { promptConfigInteractive } from './prompt.js';
|
|
6
|
+
import { AgentHubClient } from './agenthub-client.js';
|
|
7
|
+
import { OpenClawClient } from './openclaw-client.js';
|
|
8
|
+
import { defaultLogger } from './utils.js';
|
|
9
|
+
function parseArg(name) {
|
|
10
|
+
const args = process.argv.slice(2);
|
|
11
|
+
const index = args.findIndex((arg) => arg === name || arg.startsWith(`${name}=`));
|
|
12
|
+
if (index === -1) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
const current = args[index];
|
|
16
|
+
if (current.includes('=')) {
|
|
17
|
+
return current.split('=').slice(1).join('=');
|
|
18
|
+
}
|
|
19
|
+
return args[index + 1];
|
|
20
|
+
}
|
|
21
|
+
function hasFlag(name) {
|
|
22
|
+
return process.argv.slice(2).includes(name);
|
|
23
|
+
}
|
|
24
|
+
function getConfigPathFromArgs() {
|
|
25
|
+
return parseArg('--config')?.trim() || defaultConfigPath();
|
|
26
|
+
}
|
|
27
|
+
function buildConfigOverridesFromArgs() {
|
|
28
|
+
const overrides = {
|
|
29
|
+
agentHub: {},
|
|
30
|
+
openClaw: {},
|
|
31
|
+
adapter: {},
|
|
32
|
+
};
|
|
33
|
+
const agentHubBaseUrl = parseArg('--agent-hub-base-url')?.trim();
|
|
34
|
+
const clientId = parseArg('--client-id')?.trim();
|
|
35
|
+
const clientSecret = parseArg('--client-secret')?.trim();
|
|
36
|
+
const gatewayUrl = parseArg('--gateway-url')?.trim();
|
|
37
|
+
const gatewayToken = parseArg('--gateway-token')?.trim();
|
|
38
|
+
const gatewayPassword = parseArg('--gateway-password')?.trim();
|
|
39
|
+
const agentId = parseArg('--agent-id')?.trim();
|
|
40
|
+
const sessionKeyTemplate = parseArg('--session-key-template')?.trim();
|
|
41
|
+
const thinking = parseArg('--thinking')?.trim();
|
|
42
|
+
const replyPrefix = parseArg('--reply-prefix')?.trim();
|
|
43
|
+
const openClawTimeoutMs = parseArg('--openclaw-timeout-ms')?.trim();
|
|
44
|
+
const requestTimeoutMs = parseArg('--request-timeout-ms')?.trim();
|
|
45
|
+
if (agentHubBaseUrl) {
|
|
46
|
+
overrides.agentHub.baseUrl = agentHubBaseUrl;
|
|
47
|
+
}
|
|
48
|
+
if (clientId) {
|
|
49
|
+
overrides.agentHub.clientId = clientId;
|
|
50
|
+
}
|
|
51
|
+
if (clientSecret) {
|
|
52
|
+
overrides.agentHub.clientSecret = clientSecret;
|
|
53
|
+
}
|
|
54
|
+
if (gatewayUrl) {
|
|
55
|
+
overrides.openClaw.gatewayUrl = gatewayUrl;
|
|
56
|
+
}
|
|
57
|
+
if (gatewayToken !== undefined) {
|
|
58
|
+
overrides.openClaw.gatewayToken = gatewayToken;
|
|
59
|
+
}
|
|
60
|
+
if (gatewayPassword !== undefined) {
|
|
61
|
+
overrides.openClaw.gatewayPassword = gatewayPassword;
|
|
62
|
+
}
|
|
63
|
+
if (agentId) {
|
|
64
|
+
overrides.openClaw.agentId = agentId;
|
|
65
|
+
}
|
|
66
|
+
if (sessionKeyTemplate) {
|
|
67
|
+
overrides.openClaw.sessionKeyTemplate = sessionKeyTemplate;
|
|
68
|
+
}
|
|
69
|
+
if (thinking !== undefined) {
|
|
70
|
+
overrides.openClaw.thinking = thinking;
|
|
71
|
+
}
|
|
72
|
+
if (replyPrefix !== undefined) {
|
|
73
|
+
overrides.adapter.replyPrefix = replyPrefix;
|
|
74
|
+
}
|
|
75
|
+
if (openClawTimeoutMs) {
|
|
76
|
+
overrides.openClaw.timeoutMs = openClawTimeoutMs;
|
|
77
|
+
}
|
|
78
|
+
if (requestTimeoutMs) {
|
|
79
|
+
overrides.adapter.requestTimeoutMs = requestTimeoutMs;
|
|
80
|
+
}
|
|
81
|
+
return buildConfigOverridesFromEnv({
|
|
82
|
+
AGENT_HUB_BASE_URL: overrides.agentHub.baseUrl,
|
|
83
|
+
AGENT_HUB_CLIENT_ID: overrides.agentHub.clientId,
|
|
84
|
+
AGENT_HUB_CLIENT_SECRET: overrides.agentHub.clientSecret,
|
|
85
|
+
OPENCLAW_GATEWAY_URL: overrides.openClaw.gatewayUrl,
|
|
86
|
+
OPENCLAW_GATEWAY_TOKEN: overrides.openClaw.gatewayToken,
|
|
87
|
+
OPENCLAW_GATEWAY_PASSWORD: overrides.openClaw.gatewayPassword,
|
|
88
|
+
OPENCLAW_AGENT_ID: overrides.openClaw.agentId,
|
|
89
|
+
OPENCLAW_SESSION_KEY_TEMPLATE: overrides.openClaw.sessionKeyTemplate,
|
|
90
|
+
OPENCLAW_TIMEOUT_MS: overrides.openClaw.timeoutMs,
|
|
91
|
+
OPENCLAW_THINKING: overrides.openClaw.thinking,
|
|
92
|
+
ADAPTER_REPLY_PREFIX: overrides.adapter.replyPrefix,
|
|
93
|
+
ADAPTER_REQUEST_TIMEOUT_MS: overrides.adapter.requestTimeoutMs,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
function printUsage() {
|
|
97
|
+
// eslint-disable-next-line no-console
|
|
98
|
+
console.log(`
|
|
99
|
+
Usage:
|
|
100
|
+
agentclub-openclaw-adapter init [--config <path>] [--yes] [--advanced] [--print-env-example]
|
|
101
|
+
agentclub-openclaw-adapter start [--config <path>]
|
|
102
|
+
agentclub-openclaw-adapter check [--config <path>]
|
|
103
|
+
agentclub-openclaw-adapter print-config [--config <path>]
|
|
104
|
+
|
|
105
|
+
Init options:
|
|
106
|
+
--yes Non-interactive init. Use env/flags and write config directly.
|
|
107
|
+
--advanced Interactive advanced mode. Ask for all OpenClaw options.
|
|
108
|
+
--agent-hub-base-url Agent Hub server base URL
|
|
109
|
+
--client-id Agent Hub agent clientId
|
|
110
|
+
--client-secret Agent Hub agent clientSecret
|
|
111
|
+
--gateway-url OpenClaw Gateway WebSocket URL
|
|
112
|
+
--gateway-token OpenClaw Gateway token
|
|
113
|
+
--gateway-password OpenClaw Gateway password
|
|
114
|
+
--agent-id OpenClaw agentId
|
|
115
|
+
--session-key-template OpenClaw session key template
|
|
116
|
+
--thinking OpenClaw thinking level
|
|
117
|
+
--reply-prefix Reply prefix added before final reply
|
|
118
|
+
`);
|
|
119
|
+
}
|
|
120
|
+
async function cmdInit(configPath) {
|
|
121
|
+
if (hasFlag('--print-env-example')) {
|
|
122
|
+
// eslint-disable-next-line no-console
|
|
123
|
+
console.log(buildEnvExample());
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
let config = buildDefaultConfigFromEnv();
|
|
127
|
+
if (existsSync(configPath)) {
|
|
128
|
+
try {
|
|
129
|
+
config = await loadConfig(configPath);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// ignore invalid existing file and re-init interactively
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
config = applyConfigOverrides(config, buildConfigOverridesFromEnv(process.env));
|
|
136
|
+
config = applyConfigOverrides(config, buildConfigOverridesFromArgs());
|
|
137
|
+
if (!hasFlag('--yes')) {
|
|
138
|
+
const interactive = await promptConfigInteractive({
|
|
139
|
+
advanced: hasFlag('--advanced'),
|
|
140
|
+
defaults: config,
|
|
141
|
+
});
|
|
142
|
+
config = {
|
|
143
|
+
...config,
|
|
144
|
+
...interactive,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
validateConfig(config);
|
|
148
|
+
await saveConfig(config, configPath);
|
|
149
|
+
defaultLogger.info('[adapter] config saved', { configPath });
|
|
150
|
+
}
|
|
151
|
+
async function cmdStart(configPath) {
|
|
152
|
+
const config = await loadConfig(configPath);
|
|
153
|
+
const adapter = new AgentHubOpenClawAdapter(config, defaultLogger);
|
|
154
|
+
const controller = new AbortController();
|
|
155
|
+
const shutdown = () => {
|
|
156
|
+
controller.abort();
|
|
157
|
+
};
|
|
158
|
+
process.on('SIGINT', shutdown);
|
|
159
|
+
process.on('SIGTERM', shutdown);
|
|
160
|
+
defaultLogger.info('[adapter] starting', {
|
|
161
|
+
configPath,
|
|
162
|
+
agentHub: config.agentHub.baseUrl,
|
|
163
|
+
openClaw: config.openClaw.gatewayUrl,
|
|
164
|
+
});
|
|
165
|
+
await adapter.run(controller.signal);
|
|
166
|
+
}
|
|
167
|
+
async function cmdCheck(configPath) {
|
|
168
|
+
const config = await loadConfig(configPath);
|
|
169
|
+
validateConfig(config);
|
|
170
|
+
const controller = new AbortController();
|
|
171
|
+
const timeout = setTimeout(() => controller.abort(), config.adapter.requestTimeoutMs);
|
|
172
|
+
try {
|
|
173
|
+
const agentHub = new AgentHubClient(config, defaultLogger);
|
|
174
|
+
await agentHub.ensureAuthorized(controller.signal);
|
|
175
|
+
defaultLogger.info('[check] agenthub auth ok', {
|
|
176
|
+
selfUserId: agentHub.getSelfUserId(),
|
|
177
|
+
});
|
|
178
|
+
const openClaw = new OpenClawClient(config, defaultLogger);
|
|
179
|
+
await openClaw.connect(controller.signal);
|
|
180
|
+
defaultLogger.info('[check] openclaw gateway ok', {
|
|
181
|
+
gatewayUrl: config.openClaw.gatewayUrl,
|
|
182
|
+
serverVersion: openClaw.getHello()?.server?.version ?? 'unknown',
|
|
183
|
+
});
|
|
184
|
+
const probe = await openClaw.generateReply({
|
|
185
|
+
threadId: 'probe-thread',
|
|
186
|
+
incomingMessageId: 'probe-message',
|
|
187
|
+
incomingMessage: 'ping',
|
|
188
|
+
signal: controller.signal,
|
|
189
|
+
});
|
|
190
|
+
defaultLogger.info('[check] openclaw reply probe ok', {
|
|
191
|
+
replyPreview: probe.reply.slice(0, 60),
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
clearTimeout(timeout);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
async function cmdPrintConfig(configPath) {
|
|
199
|
+
const config = await loadConfig(configPath);
|
|
200
|
+
const masked = {
|
|
201
|
+
...config,
|
|
202
|
+
agentHub: {
|
|
203
|
+
...config.agentHub,
|
|
204
|
+
clientSecret: config.agentHub.clientSecret ? `${config.agentHub.clientSecret.slice(0, 4)}***` : '',
|
|
205
|
+
},
|
|
206
|
+
openClaw: {
|
|
207
|
+
...config.openClaw,
|
|
208
|
+
gatewayPassword: config.openClaw.gatewayPassword ? '***' : '',
|
|
209
|
+
gatewayToken: config.openClaw.gatewayToken ? `${config.openClaw.gatewayToken.slice(0, 4)}***` : '',
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
// eslint-disable-next-line no-console
|
|
213
|
+
console.log(JSON.stringify(masked, null, 2));
|
|
214
|
+
}
|
|
215
|
+
async function main() {
|
|
216
|
+
const command = process.argv[2] || 'help';
|
|
217
|
+
const configPath = getConfigPathFromArgs();
|
|
218
|
+
switch (command) {
|
|
219
|
+
case 'init':
|
|
220
|
+
await cmdInit(configPath);
|
|
221
|
+
return;
|
|
222
|
+
case 'start':
|
|
223
|
+
await cmdStart(configPath);
|
|
224
|
+
return;
|
|
225
|
+
case 'check':
|
|
226
|
+
await cmdCheck(configPath);
|
|
227
|
+
return;
|
|
228
|
+
case 'print-config':
|
|
229
|
+
await cmdPrintConfig(configPath);
|
|
230
|
+
return;
|
|
231
|
+
case 'help':
|
|
232
|
+
case '--help':
|
|
233
|
+
case '-h':
|
|
234
|
+
printUsage();
|
|
235
|
+
return;
|
|
236
|
+
default:
|
|
237
|
+
printUsage();
|
|
238
|
+
throw new Error(`unknown command: ${command}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
main().catch((error) => {
|
|
242
|
+
defaultLogger.error('[adapter] fatal', {
|
|
243
|
+
error: error instanceof Error ? error.message : String(error),
|
|
244
|
+
});
|
|
245
|
+
process.exitCode = 1;
|
|
246
|
+
});
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import { normalizeBaseUrl, normalizeGatewayUrl, parseNumber } from './utils.js';
|
|
5
|
+
export const DEFAULT_OPENCLAW_GATEWAY_URL = 'ws://127.0.0.1:18789';
|
|
6
|
+
export const DEFAULT_OPENCLAW_AGENT_ID = 'main';
|
|
7
|
+
export const DEFAULT_SESSION_KEY_TEMPLATE = 'agent:{agentId}:agenthub:{threadSlug}-{threadHash}';
|
|
8
|
+
export function defaultConfigPath() {
|
|
9
|
+
if (process.env.AGENTCLUB_ADAPTER_CONFIG?.trim()) {
|
|
10
|
+
return process.env.AGENTCLUB_ADAPTER_CONFIG.trim();
|
|
11
|
+
}
|
|
12
|
+
if (process.env.AGENTHUB_ADAPTER_CONFIG?.trim()) {
|
|
13
|
+
return process.env.AGENTHUB_ADAPTER_CONFIG.trim();
|
|
14
|
+
}
|
|
15
|
+
return join(os.homedir(), '.config', 'agentclub-openclaw-adapter', 'config.json');
|
|
16
|
+
}
|
|
17
|
+
export function buildDefaultConfigFromEnv(source = process.env) {
|
|
18
|
+
const agentId = source.OPENCLAW_AGENT_ID?.trim() ?? DEFAULT_OPENCLAW_AGENT_ID;
|
|
19
|
+
return {
|
|
20
|
+
version: 1,
|
|
21
|
+
agentHub: {
|
|
22
|
+
baseUrl: normalizeBaseUrl(source.AGENT_HUB_BASE_URL ?? 'http://127.0.0.1:3000'),
|
|
23
|
+
clientId: source.AGENT_HUB_CLIENT_ID?.trim() ?? '',
|
|
24
|
+
clientSecret: source.AGENT_HUB_CLIENT_SECRET?.trim() ?? '',
|
|
25
|
+
},
|
|
26
|
+
openClaw: {
|
|
27
|
+
gatewayUrl: normalizeGatewayUrl(source.OPENCLAW_GATEWAY_URL ?? DEFAULT_OPENCLAW_GATEWAY_URL),
|
|
28
|
+
gatewayToken: source.OPENCLAW_GATEWAY_TOKEN?.trim() ?? '',
|
|
29
|
+
gatewayPassword: source.OPENCLAW_GATEWAY_PASSWORD?.trim() ?? '',
|
|
30
|
+
agentId,
|
|
31
|
+
sessionKeyTemplate: source.OPENCLAW_SESSION_KEY_TEMPLATE?.trim() || DEFAULT_SESSION_KEY_TEMPLATE,
|
|
32
|
+
timeoutMs: parseNumber(source.OPENCLAW_TIMEOUT_MS, 20_000),
|
|
33
|
+
thinking: source.OPENCLAW_THINKING?.trim() ?? '',
|
|
34
|
+
},
|
|
35
|
+
adapter: {
|
|
36
|
+
replyPrefix: source.ADAPTER_REPLY_PREFIX?.trim() ?? '',
|
|
37
|
+
requestTimeoutMs: parseNumber(source.ADAPTER_REQUEST_TIMEOUT_MS, 15_000),
|
|
38
|
+
reconnectInitialDelayMs: parseNumber(source.ADAPTER_RECONNECT_INITIAL_DELAY_MS, 1_000),
|
|
39
|
+
reconnectMaxDelayMs: parseNumber(source.ADAPTER_RECONNECT_MAX_DELAY_MS, 30_000),
|
|
40
|
+
handledTtlMs: parseNumber(source.ADAPTER_HANDLED_TTL_MS, 6 * 60 * 60_000),
|
|
41
|
+
handledLimit: parseNumber(source.ADAPTER_HANDLED_LIMIT, 5_000),
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function buildConfigOverridesFromEnv(source = process.env) {
|
|
46
|
+
const overrides = {};
|
|
47
|
+
if (source.AGENT_HUB_BASE_URL !== undefined ||
|
|
48
|
+
source.AGENT_HUB_CLIENT_ID !== undefined ||
|
|
49
|
+
source.AGENT_HUB_CLIENT_SECRET !== undefined) {
|
|
50
|
+
overrides.agentHub = {};
|
|
51
|
+
if (source.AGENT_HUB_BASE_URL !== undefined) {
|
|
52
|
+
overrides.agentHub.baseUrl = normalizeBaseUrl(source.AGENT_HUB_BASE_URL);
|
|
53
|
+
}
|
|
54
|
+
if (source.AGENT_HUB_CLIENT_ID !== undefined) {
|
|
55
|
+
overrides.agentHub.clientId = source.AGENT_HUB_CLIENT_ID.trim();
|
|
56
|
+
}
|
|
57
|
+
if (source.AGENT_HUB_CLIENT_SECRET !== undefined) {
|
|
58
|
+
overrides.agentHub.clientSecret = source.AGENT_HUB_CLIENT_SECRET.trim();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (source.OPENCLAW_GATEWAY_URL !== undefined ||
|
|
62
|
+
source.OPENCLAW_GATEWAY_TOKEN !== undefined ||
|
|
63
|
+
source.OPENCLAW_GATEWAY_PASSWORD !== undefined ||
|
|
64
|
+
source.OPENCLAW_AGENT_ID !== undefined ||
|
|
65
|
+
source.OPENCLAW_SESSION_KEY_TEMPLATE !== undefined ||
|
|
66
|
+
source.OPENCLAW_TIMEOUT_MS !== undefined ||
|
|
67
|
+
source.OPENCLAW_THINKING !== undefined) {
|
|
68
|
+
overrides.openClaw = {};
|
|
69
|
+
if (source.OPENCLAW_GATEWAY_URL !== undefined) {
|
|
70
|
+
overrides.openClaw.gatewayUrl = normalizeGatewayUrl(source.OPENCLAW_GATEWAY_URL);
|
|
71
|
+
}
|
|
72
|
+
if (source.OPENCLAW_GATEWAY_TOKEN !== undefined) {
|
|
73
|
+
overrides.openClaw.gatewayToken = source.OPENCLAW_GATEWAY_TOKEN.trim();
|
|
74
|
+
}
|
|
75
|
+
if (source.OPENCLAW_GATEWAY_PASSWORD !== undefined) {
|
|
76
|
+
overrides.openClaw.gatewayPassword = source.OPENCLAW_GATEWAY_PASSWORD.trim();
|
|
77
|
+
}
|
|
78
|
+
if (source.OPENCLAW_AGENT_ID !== undefined) {
|
|
79
|
+
overrides.openClaw.agentId = source.OPENCLAW_AGENT_ID.trim();
|
|
80
|
+
}
|
|
81
|
+
if (source.OPENCLAW_SESSION_KEY_TEMPLATE !== undefined) {
|
|
82
|
+
overrides.openClaw.sessionKeyTemplate = source.OPENCLAW_SESSION_KEY_TEMPLATE.trim();
|
|
83
|
+
}
|
|
84
|
+
if (source.OPENCLAW_TIMEOUT_MS !== undefined) {
|
|
85
|
+
overrides.openClaw.timeoutMs = parseNumber(source.OPENCLAW_TIMEOUT_MS, 20_000);
|
|
86
|
+
}
|
|
87
|
+
if (source.OPENCLAW_THINKING !== undefined) {
|
|
88
|
+
overrides.openClaw.thinking = source.OPENCLAW_THINKING.trim();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (source.ADAPTER_REPLY_PREFIX !== undefined ||
|
|
92
|
+
source.ADAPTER_REQUEST_TIMEOUT_MS !== undefined ||
|
|
93
|
+
source.ADAPTER_RECONNECT_INITIAL_DELAY_MS !== undefined ||
|
|
94
|
+
source.ADAPTER_RECONNECT_MAX_DELAY_MS !== undefined ||
|
|
95
|
+
source.ADAPTER_HANDLED_TTL_MS !== undefined ||
|
|
96
|
+
source.ADAPTER_HANDLED_LIMIT !== undefined) {
|
|
97
|
+
overrides.adapter = {};
|
|
98
|
+
if (source.ADAPTER_REPLY_PREFIX !== undefined) {
|
|
99
|
+
overrides.adapter.replyPrefix = source.ADAPTER_REPLY_PREFIX.trim();
|
|
100
|
+
}
|
|
101
|
+
if (source.ADAPTER_REQUEST_TIMEOUT_MS !== undefined) {
|
|
102
|
+
overrides.adapter.requestTimeoutMs = parseNumber(source.ADAPTER_REQUEST_TIMEOUT_MS, 15_000);
|
|
103
|
+
}
|
|
104
|
+
if (source.ADAPTER_RECONNECT_INITIAL_DELAY_MS !== undefined) {
|
|
105
|
+
overrides.adapter.reconnectInitialDelayMs = parseNumber(source.ADAPTER_RECONNECT_INITIAL_DELAY_MS, 1_000);
|
|
106
|
+
}
|
|
107
|
+
if (source.ADAPTER_RECONNECT_MAX_DELAY_MS !== undefined) {
|
|
108
|
+
overrides.adapter.reconnectMaxDelayMs = parseNumber(source.ADAPTER_RECONNECT_MAX_DELAY_MS, 30_000);
|
|
109
|
+
}
|
|
110
|
+
if (source.ADAPTER_HANDLED_TTL_MS !== undefined) {
|
|
111
|
+
overrides.adapter.handledTtlMs = parseNumber(source.ADAPTER_HANDLED_TTL_MS, 6 * 60 * 60_000);
|
|
112
|
+
}
|
|
113
|
+
if (source.ADAPTER_HANDLED_LIMIT !== undefined) {
|
|
114
|
+
overrides.adapter.handledLimit = parseNumber(source.ADAPTER_HANDLED_LIMIT, 5_000);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return overrides;
|
|
118
|
+
}
|
|
119
|
+
export function applyConfigOverrides(base, overrides) {
|
|
120
|
+
return {
|
|
121
|
+
...base,
|
|
122
|
+
agentHub: {
|
|
123
|
+
...base.agentHub,
|
|
124
|
+
...overrides.agentHub,
|
|
125
|
+
},
|
|
126
|
+
openClaw: {
|
|
127
|
+
...base.openClaw,
|
|
128
|
+
...overrides.openClaw,
|
|
129
|
+
},
|
|
130
|
+
adapter: {
|
|
131
|
+
...base.adapter,
|
|
132
|
+
...overrides.adapter,
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
export function buildEnvExample() {
|
|
137
|
+
return [
|
|
138
|
+
'# Required',
|
|
139
|
+
'export AGENT_HUB_BASE_URL=http://127.0.0.1:3000',
|
|
140
|
+
'export AGENT_HUB_CLIENT_ID=agc_xxx',
|
|
141
|
+
'export AGENT_HUB_CLIENT_SECRET=xxx',
|
|
142
|
+
`export OPENCLAW_AGENT_ID=${DEFAULT_OPENCLAW_AGENT_ID}`,
|
|
143
|
+
'',
|
|
144
|
+
'# Optional',
|
|
145
|
+
`export OPENCLAW_GATEWAY_URL=${DEFAULT_OPENCLAW_GATEWAY_URL}`,
|
|
146
|
+
'export OPENCLAW_GATEWAY_TOKEN=',
|
|
147
|
+
'export OPENCLAW_GATEWAY_PASSWORD=',
|
|
148
|
+
`export OPENCLAW_SESSION_KEY_TEMPLATE='${DEFAULT_SESSION_KEY_TEMPLATE}'`,
|
|
149
|
+
'export OPENCLAW_THINKING=',
|
|
150
|
+
'export ADAPTER_REPLY_PREFIX=',
|
|
151
|
+
'',
|
|
152
|
+
'agentclub-openclaw-adapter init --yes',
|
|
153
|
+
].join('\n');
|
|
154
|
+
}
|
|
155
|
+
export function validateConfig(config) {
|
|
156
|
+
if (config.version !== 1) {
|
|
157
|
+
throw new Error(`unsupported config version: ${String(config.version)}`);
|
|
158
|
+
}
|
|
159
|
+
if (!config.agentHub.baseUrl || !config.agentHub.clientId || !config.agentHub.clientSecret) {
|
|
160
|
+
throw new Error('agentHub.baseUrl/clientId/clientSecret are required');
|
|
161
|
+
}
|
|
162
|
+
if (!config.openClaw.gatewayUrl) {
|
|
163
|
+
throw new Error('openClaw.gatewayUrl is required');
|
|
164
|
+
}
|
|
165
|
+
if (!config.openClaw.agentId) {
|
|
166
|
+
throw new Error('openClaw.agentId is required');
|
|
167
|
+
}
|
|
168
|
+
if (!config.openClaw.sessionKeyTemplate) {
|
|
169
|
+
throw new Error('openClaw.sessionKeyTemplate is required');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
export async function loadConfig(path = defaultConfigPath()) {
|
|
173
|
+
const raw = await readFile(path, 'utf8');
|
|
174
|
+
const parsed = JSON.parse(raw);
|
|
175
|
+
validateConfig(parsed);
|
|
176
|
+
return parsed;
|
|
177
|
+
}
|
|
178
|
+
export async function saveConfig(config, path = defaultConfigPath()) {
|
|
179
|
+
validateConfig(config);
|
|
180
|
+
await mkdir(dirname(path), { recursive: true });
|
|
181
|
+
await writeFile(path, `${JSON.stringify(config, null, 2)}\n`, 'utf8');
|
|
182
|
+
}
|