clawd-models 1.0.2 → 1.0.4
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 +29 -3
- package/bin/clawd-models.js +420 -72
- package/docs/setup-flow.svg +86 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
CLI tool to manage OpenClaw model configurations.
|
|
4
4
|
|
|
5
|
+
## Quick Start Flow
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
5
9
|
## Prerequisite
|
|
6
10
|
Install and Setup `openclaw` firstly, refer to https://github.com/openclaw/openclaw
|
|
7
11
|
```
|
|
@@ -22,10 +26,26 @@ npm i -g clawd-models
|
|
|
22
26
|
## Usage
|
|
23
27
|
|
|
24
28
|
```bash
|
|
25
|
-
clawd-models <command>
|
|
29
|
+
clawd-models <command> [--bot <openclaw|clawdbot|moltbot>]
|
|
26
30
|
# clawd-models help
|
|
27
31
|
```
|
|
28
32
|
|
|
33
|
+
**Global Options:**
|
|
34
|
+
- `--bot <bot-id>` - Target bot (openclaw, clawdbot, moltbot). Also saves as default for future commands.
|
|
35
|
+
- `--clear-bot` - Clear the default bot setting
|
|
36
|
+
|
|
37
|
+
**Bot Priority (when --bot not specified):**
|
|
38
|
+
1. Saved preference (if set via previous `--bot` use)
|
|
39
|
+
2. Auto-detect: openclaw → clawdbot → moltbot
|
|
40
|
+
|
|
41
|
+
**Config Locations:**
|
|
42
|
+
- OpenClaw: `~/.openclaw/openclaw.json`
|
|
43
|
+
- ClawdBot: `~/.clawdbot/clawdbot.json`
|
|
44
|
+
- MoltBot: `~/.moltbot/moltbot.json`
|
|
45
|
+
- Preferred bot: `~/.clawd-models/bot`
|
|
46
|
+
|
|
47
|
+
**Default Bot Priority:** `openclaw` → `clawdbot` → `moltbot` (auto-selected if not specified via `--bot`)
|
|
48
|
+
|
|
29
49
|
## Commands
|
|
30
50
|
|
|
31
51
|
### Core
|
|
@@ -43,13 +63,15 @@ clawd-models <command>
|
|
|
43
63
|
| `providers:add -n <name> -u <url> [-k <api-key>]` | Add a new model provider |
|
|
44
64
|
| `providers:remove -n <name>` | Remove a model provider |
|
|
45
65
|
| `providers:list` | List all configured providers |
|
|
66
|
+
Should add a provider firstly, then add a model (refer to next section).
|
|
46
67
|
|
|
47
68
|
### Model Management
|
|
48
69
|
| Command | Description |
|
|
49
70
|
|---------|-------------|
|
|
50
71
|
| `models:add -p <provider> -i <model-id> --name <name>` | Add a model to a provider |
|
|
51
72
|
| `models:remove -p <provider> -i <model-id>` | Remove a model from a provider |
|
|
52
|
-
| `
|
|
73
|
+
| `models:list [--provider <name>]` | List all configured models |
|
|
74
|
+
| `models:test` | Test the default model configuration by sending a test message |
|
|
53
75
|
|
|
54
76
|
Use `agents:set-default` in next section or refer to `openclaw models set` to set a default model for 'main' and all agents.
|
|
55
77
|
|
|
@@ -79,4 +101,8 @@ Refer to `openclaw gateway status` for more.
|
|
|
79
101
|
|
|
80
102
|
## Configuration Location
|
|
81
103
|
|
|
82
|
-
`~/.openclaw/openclaw.json`
|
|
104
|
+
`~/.openclaw/openclaw.json`
|
|
105
|
+
or
|
|
106
|
+
`~/.clawdbot/clawdbot.json`
|
|
107
|
+
or
|
|
108
|
+
`~/.moltbot/moltbot.json`
|
package/bin/clawd-models.js
CHANGED
|
@@ -6,14 +6,210 @@ const path = require('path');
|
|
|
6
6
|
const os = require('os');
|
|
7
7
|
|
|
8
8
|
const OPENCLAW_CONFIG_PATH = path.join(os.homedir(), '.openclaw', 'openclaw.json');
|
|
9
|
+
const CLAWD_MODELS_DIR = path.join(os.homedir(), '.clawd-models');
|
|
10
|
+
const CLAWD_MODELS_BOT_FILE = path.join(CLAWD_MODELS_DIR, 'bot.json');
|
|
9
11
|
|
|
10
12
|
const CURRENT_VERSION = '2026.2.1';
|
|
11
13
|
|
|
14
|
+
// Supported bot configurations
|
|
15
|
+
const BOT_CONFIGS = [
|
|
16
|
+
{ id: 'openclaw', name: 'OpenClaw', path: '.openclaw/openclaw.json' },
|
|
17
|
+
{ id: 'clawdbot', name: 'ClawdBot', path: '.clawdbot/clawdbot.json' },
|
|
18
|
+
{ id: 'moltbot', name: 'MoltBot', path: '.moltbot/moltbot.json' }
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
function getBotConfigPath(botId) {
|
|
22
|
+
const bot = BOT_CONFIGS.find(b => b.id === botId);
|
|
23
|
+
if (!bot) return null;
|
|
24
|
+
return path.join(os.homedir(), bot.path);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function loadPreferredBot() {
|
|
28
|
+
if (fs.existsSync(CLAWD_MODELS_BOT_FILE)) {
|
|
29
|
+
try {
|
|
30
|
+
const content = JSON.parse(fs.readFileSync(CLAWD_MODELS_BOT_FILE, 'utf8'));
|
|
31
|
+
const botId = content.bot;
|
|
32
|
+
// Validate it's a known bot
|
|
33
|
+
if (botId && BOT_CONFIGS.some(b => b.id === botId)) {
|
|
34
|
+
return botId;
|
|
35
|
+
}
|
|
36
|
+
} catch (e) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function savePreferredBot(botId) {
|
|
44
|
+
// Validate bot ID
|
|
45
|
+
if (!BOT_CONFIGS.some(b => b.id === botId)) {
|
|
46
|
+
console.error(`Unknown bot: ${botId}. Valid options: ${BOT_CONFIGS.map(b => b.id).join(', ')}`);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
fs.ensureDirSync(CLAWD_MODELS_DIR);
|
|
50
|
+
fs.writeFileSync(CLAWD_MODELS_BOT_FILE, JSON.stringify({ bot: botId }, null, 2));
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function clearPreferredBot() {
|
|
54
|
+
if (fs.existsSync(CLAWD_MODELS_BOT_FILE)) {
|
|
55
|
+
fs.unlinkSync(CLAWD_MODELS_BOT_FILE);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async function promptBotSelection() {
|
|
60
|
+
const available = [];
|
|
61
|
+
for (const bot of BOT_CONFIGS) {
|
|
62
|
+
const configPath = getBotConfigPath(bot.id);
|
|
63
|
+
if (fs.existsSync(configPath)) {
|
|
64
|
+
available.push(bot);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (available.length === 0) {
|
|
69
|
+
console.log('No bot configurations found.');
|
|
70
|
+
console.log('Expected locations:');
|
|
71
|
+
for (const bot of BOT_CONFIGS) {
|
|
72
|
+
console.log(` ${bot.name}: ${getBotConfigPath(bot.id)}`);
|
|
73
|
+
}
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (available.length === 1) {
|
|
78
|
+
return available[0];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
console.log('Multiple bot configurations found. Select one:');
|
|
82
|
+
for (let i = 0; i < available.length; i++) {
|
|
83
|
+
console.log(` ${i + 1}. ${available[i].name} (${getBotConfigPath(available[i].id)})`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const { promisify } = require('util');
|
|
87
|
+
const readline = require('readline');
|
|
88
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
89
|
+
const question = promisify(rl.question).bind(rl);
|
|
90
|
+
|
|
91
|
+
while (true) {
|
|
92
|
+
const answer = await question('\nEnter number (1-' + available.length + '): ');
|
|
93
|
+
const idx = parseInt(answer) - 1;
|
|
94
|
+
if (idx >= 0 && idx < available.length) {
|
|
95
|
+
rl.close();
|
|
96
|
+
return available[idx];
|
|
97
|
+
}
|
|
98
|
+
console.log('Invalid selection. Please try again.');
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function resolveConfig(botOption) {
|
|
103
|
+
if (botOption) {
|
|
104
|
+
const bot = BOT_CONFIGS.find(b => b.id === botOption);
|
|
105
|
+
if (!bot) {
|
|
106
|
+
throw new Error(`Unknown bot: ${botOption}. Available: ${BOT_CONFIGS.map(b => b.id).join(', ')}`);
|
|
107
|
+
}
|
|
108
|
+
const configPath = getBotConfigPath(bot.id);
|
|
109
|
+
if (!fs.existsSync(configPath)) {
|
|
110
|
+
throw new Error(`${bot.name} config not found at ~/.${bot.name}/${bot.name}.json`);
|
|
111
|
+
}
|
|
112
|
+
return { bot, configPath };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// No bot specified, prompt or auto-detect
|
|
116
|
+
const bot = await promptBotSelection();
|
|
117
|
+
if (!bot) {
|
|
118
|
+
throw new Error('No bot configurations available');
|
|
119
|
+
}
|
|
120
|
+
return { bot, configPath: getBotConfigPath(bot.id) };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function loadBotConfig(botOption) {
|
|
124
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
125
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
126
|
+
return JSON.parse(content);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function resolveConfigSync(botOption) {
|
|
130
|
+
// If botOption is provided, validate and use it
|
|
131
|
+
if (botOption) {
|
|
132
|
+
const bot = BOT_CONFIGS.find(b => b.id === botOption);
|
|
133
|
+
if (!bot) {
|
|
134
|
+
throw new Error(`Unknown bot: ${botOption}. Available: ${BOT_CONFIGS.map(b => b.id).join(', ')}`);
|
|
135
|
+
}
|
|
136
|
+
const configPath = getBotConfigPath(bot.id);
|
|
137
|
+
if (!fs.existsSync(configPath)) {
|
|
138
|
+
throw new Error(`${bot.name} config not found at ${configPath}`);
|
|
139
|
+
}
|
|
140
|
+
return { bot, configPath };
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Auto-detect: try saved preference first, then priority order
|
|
144
|
+
const savedBot = loadPreferredBot();
|
|
145
|
+
if (savedBot) {
|
|
146
|
+
const bot = BOT_CONFIGS.find(b => b.id === savedBot);
|
|
147
|
+
const configPath = getBotConfigPath(savedBot);
|
|
148
|
+
if (bot && fs.existsSync(configPath)) {
|
|
149
|
+
return { bot, configPath };
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Try bots in priority order: openclaw -> clawdbot -> moltbot
|
|
154
|
+
const priorityOrder = ['openclaw', 'clawdbot', 'moltbot'];
|
|
155
|
+
for (const botId of priorityOrder) {
|
|
156
|
+
const configPath = getBotConfigPath(botId);
|
|
157
|
+
if (fs.existsSync(configPath)) {
|
|
158
|
+
const bot = BOT_CONFIGS.find(b => b.id === botId);
|
|
159
|
+
// Auto-detected and valid, save as preference
|
|
160
|
+
savePreferredBot(bot.id);
|
|
161
|
+
console.log(`Auto-detected bot: ${bot.id}`);
|
|
162
|
+
return { bot, configPath };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
throw new Error('No bot configurations found');
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
async function resolveConfig(botOption) {
|
|
170
|
+
return resolveConfigSync(botOption);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function getBotFromArgs() {
|
|
174
|
+
const botIdx = process.argv.indexOf('--bot');
|
|
175
|
+
if (botIdx !== -1 && botIdx + 1 < process.argv.length) {
|
|
176
|
+
const botId = process.argv[botIdx + 1];
|
|
177
|
+
// Validate bot ID
|
|
178
|
+
const bot = BOT_CONFIGS.find(b => b.id === botId);
|
|
179
|
+
if (!bot) {
|
|
180
|
+
console.error(`Unknown bot: ${botId}. Valid options: ${BOT_CONFIGS.map(b => b.id).join(', ')}`);
|
|
181
|
+
process.exit(1);
|
|
182
|
+
}
|
|
183
|
+
// Verify config file exists
|
|
184
|
+
const configPath = getBotConfigPath(botId);
|
|
185
|
+
if (!fs.existsSync(configPath)) {
|
|
186
|
+
console.error(`${bot.name} config not found at ${configPath}`);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
}
|
|
189
|
+
// Save to bot.json
|
|
190
|
+
fs.ensureDirSync(CLAWD_MODELS_DIR);
|
|
191
|
+
fs.writeFileSync(CLAWD_MODELS_BOT_FILE, JSON.stringify({ bot: botId }, null, 2));
|
|
192
|
+
console.log(`Default bot set to: ${botId}`);
|
|
193
|
+
return botId;
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
|
|
12
198
|
program
|
|
13
199
|
.name('clawd-models')
|
|
14
200
|
.description('CLI tool to manage OpenClaw model configurations')
|
|
15
|
-
.version('1.0.
|
|
16
|
-
.showHelpAfterError()
|
|
201
|
+
.version('1.0.4')
|
|
202
|
+
.showHelpAfterError()
|
|
203
|
+
.option('--bot <bot-id>', 'Target bot: openclaw, clawdbot, moltbot (also sets as default)')
|
|
204
|
+
.option('--clear-bot', 'Clear the default bot setting');
|
|
205
|
+
|
|
206
|
+
// Handle --clear-bot before normal command parsing
|
|
207
|
+
const clearBotIdx = process.argv.indexOf('--clear-bot');
|
|
208
|
+
if (clearBotIdx !== -1) {
|
|
209
|
+
clearPreferredBot();
|
|
210
|
+
console.log('Default bot cleared.');
|
|
211
|
+
process.exit(0);
|
|
212
|
+
}
|
|
17
213
|
|
|
18
214
|
// ============ Core Commands ============
|
|
19
215
|
|
|
@@ -84,25 +280,29 @@ program
|
|
|
84
280
|
program
|
|
85
281
|
.command('view')
|
|
86
282
|
.description('View current configuration')
|
|
87
|
-
.action(() => {
|
|
88
|
-
const
|
|
283
|
+
.action((cmdOptions) => {
|
|
284
|
+
const botOption = getBotFromArgs();
|
|
285
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
286
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
89
287
|
console.log(JSON.stringify(config, null, 2));
|
|
90
|
-
console.log(`\n${
|
|
288
|
+
console.log(`\n${bot.name}: ${configPath}`);
|
|
91
289
|
});
|
|
92
290
|
|
|
93
291
|
program
|
|
94
292
|
.command('edit')
|
|
95
293
|
.description('Edit configuration in default editor')
|
|
96
294
|
.action(() => {
|
|
97
|
-
const
|
|
295
|
+
const botOption = getBotFromArgs();
|
|
296
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
297
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
98
298
|
config.meta.lastTouchedVersion = CURRENT_VERSION;
|
|
99
299
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
100
|
-
|
|
300
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
101
301
|
|
|
102
302
|
const editor = process.env.EDITOR || 'vi';
|
|
103
|
-
require('child_process').execSync(`${editor} "${
|
|
303
|
+
require('child_process').execSync(`${editor} "${configPath}"`, { stdio: 'inherit' });
|
|
104
304
|
|
|
105
|
-
console.log(`Configuration updated at ${
|
|
305
|
+
console.log(`Configuration updated at ${bot.name}: ${configPath}`);
|
|
106
306
|
});
|
|
107
307
|
|
|
108
308
|
// ============ Provider Commands ============
|
|
@@ -116,7 +316,9 @@ program
|
|
|
116
316
|
.option('--api <api-type>', 'API type (e.g., openai-completions, anthropic-messages)', 'openai-completions')
|
|
117
317
|
.option('--auth <auth-type>', 'Auth method (e.g., api-key, bearer)', 'api-key')
|
|
118
318
|
.action((options) => {
|
|
119
|
-
const
|
|
319
|
+
const botOption = getBotFromArgs();
|
|
320
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
321
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
120
322
|
config.models.providers = config.models.providers || {};
|
|
121
323
|
|
|
122
324
|
const provider = {
|
|
@@ -133,8 +335,8 @@ program
|
|
|
133
335
|
config.models.providers[options.name] = provider;
|
|
134
336
|
|
|
135
337
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
136
|
-
|
|
137
|
-
console.log(`Provider "${options.name}" added
|
|
338
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
339
|
+
console.log(`Provider "${options.name}" added to ${bot.name}.`);
|
|
138
340
|
});
|
|
139
341
|
|
|
140
342
|
program
|
|
@@ -142,12 +344,14 @@ program
|
|
|
142
344
|
.description('Remove a model provider')
|
|
143
345
|
.requiredOption('-n, --name <name>', 'Provider name')
|
|
144
346
|
.action((options) => {
|
|
145
|
-
const
|
|
347
|
+
const botOption = getBotFromArgs();
|
|
348
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
349
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
146
350
|
if (config.models.providers && config.models.providers[options.name]) {
|
|
147
351
|
delete config.models.providers[options.name];
|
|
148
352
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
149
|
-
|
|
150
|
-
console.log(`Provider "${options.name}" removed.`);
|
|
353
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
354
|
+
console.log(`Provider "${options.name}" removed from ${bot.name}.`);
|
|
151
355
|
} else {
|
|
152
356
|
console.log(`Provider "${options.name}" not found.`);
|
|
153
357
|
}
|
|
@@ -156,8 +360,10 @@ program
|
|
|
156
360
|
program
|
|
157
361
|
.command('providers:list')
|
|
158
362
|
.description('List all configured providers')
|
|
159
|
-
.action(() => {
|
|
160
|
-
const
|
|
363
|
+
.action((options) => {
|
|
364
|
+
const botOption = getBotFromArgs();
|
|
365
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
366
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
161
367
|
const providers = config.models?.providers || {};
|
|
162
368
|
|
|
163
369
|
if (Object.keys(providers).length === 0) {
|
|
@@ -193,7 +399,9 @@ program
|
|
|
193
399
|
.option('--context <tokens>', 'Context window size', '200000')
|
|
194
400
|
.option('--max-tokens <tokens>', 'Max output tokens', '8192')
|
|
195
401
|
.action((options) => {
|
|
196
|
-
const
|
|
402
|
+
const botOption = getBotFromArgs();
|
|
403
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
404
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
197
405
|
|
|
198
406
|
if (!config.models.providers || !config.models.providers[options.provider]) {
|
|
199
407
|
console.log(`Provider "${options.provider}" not found. Add it first with "clawd-models providers:add".`);
|
|
@@ -227,8 +435,8 @@ program
|
|
|
227
435
|
|
|
228
436
|
provider.models.push(model);
|
|
229
437
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
230
|
-
|
|
231
|
-
console.log(`Model "${options.id}" added to provider "${options.provider}".`);
|
|
438
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
439
|
+
console.log(`Model "${options.id}" added to provider "${options.provider}" in ${bot.name}.`);
|
|
232
440
|
});
|
|
233
441
|
|
|
234
442
|
program
|
|
@@ -237,7 +445,9 @@ program
|
|
|
237
445
|
.requiredOption('-p, --provider <provider>', 'Provider name')
|
|
238
446
|
.requiredOption('-i, --id <id>', 'Model ID')
|
|
239
447
|
.action((options) => {
|
|
240
|
-
const
|
|
448
|
+
const botOption = getBotFromArgs();
|
|
449
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
450
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
241
451
|
|
|
242
452
|
if (!config.models.providers || !config.models.providers[options.provider]) {
|
|
243
453
|
console.log(`Provider "${options.provider}" not found.`);
|
|
@@ -254,8 +464,8 @@ program
|
|
|
254
464
|
|
|
255
465
|
provider.models.splice(idx, 1);
|
|
256
466
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
257
|
-
|
|
258
|
-
console.log(`Model "${options.id}" removed from provider "${options.provider}".`);
|
|
467
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
468
|
+
console.log(`Model "${options.id}" removed from provider "${options.provider}" in ${bot.name}.`);
|
|
259
469
|
});
|
|
260
470
|
|
|
261
471
|
program
|
|
@@ -263,7 +473,9 @@ program
|
|
|
263
473
|
.description('List all configured models')
|
|
264
474
|
.option('--provider <provider>', 'Filter by provider')
|
|
265
475
|
.action((options) => {
|
|
266
|
-
const
|
|
476
|
+
const botOption = getBotFromArgs();
|
|
477
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
478
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
267
479
|
const providers = config.models?.providers || {};
|
|
268
480
|
|
|
269
481
|
if (options.provider) {
|
|
@@ -288,6 +500,146 @@ program
|
|
|
288
500
|
}
|
|
289
501
|
});
|
|
290
502
|
|
|
503
|
+
program
|
|
504
|
+
.command('models:test')
|
|
505
|
+
.description('Test the default model configuration by sending a test message')
|
|
506
|
+
.action(async () => {
|
|
507
|
+
const botOption = getBotFromArgs();
|
|
508
|
+
const { bot, configPath } = await resolveConfig(botOption);
|
|
509
|
+
console.log(`\nUsing ${bot.name} configuration`);
|
|
510
|
+
|
|
511
|
+
let config;
|
|
512
|
+
try {
|
|
513
|
+
config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error(`Error loading configuration: ${error.message}`);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const defaultModel = config.agents?.defaults?.model?.primary;
|
|
520
|
+
|
|
521
|
+
if (!defaultModel) {
|
|
522
|
+
console.log('No default model configured. Use "clawd-models agents:set-default" to set one.');
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
// Parse provider/model from default model
|
|
527
|
+
const [providerName, ...modelPath] = defaultModel.split('/');
|
|
528
|
+
const modelId = modelPath.join('/');
|
|
529
|
+
|
|
530
|
+
const provider = config.models?.providers?.[providerName];
|
|
531
|
+
if (!provider) {
|
|
532
|
+
console.log(`Provider "${providerName}" not found in configuration.`);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
console.log(`Testing model: ${defaultModel}`);
|
|
537
|
+
console.log(`Provider: ${providerName}`);
|
|
538
|
+
console.log(`Base URL: ${provider.baseUrl}`);
|
|
539
|
+
console.log(`API: ${provider.api}`);
|
|
540
|
+
|
|
541
|
+
const apiKey = provider.apiKey;
|
|
542
|
+
if (!apiKey) {
|
|
543
|
+
console.log('\nWarning: No API key configured for this provider.');
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// Build the endpoint URL based on API type
|
|
547
|
+
let endpoint;
|
|
548
|
+
if (provider.api === 'openai-completions') {
|
|
549
|
+
endpoint = `${provider.baseUrl.replace(/\/$/, '')}/chat/completions`;
|
|
550
|
+
} else if (provider.api === 'anthropic-messages') {
|
|
551
|
+
endpoint = `${provider.baseUrl.replace(/\/$/, '')}/v1/messages`;
|
|
552
|
+
} else {
|
|
553
|
+
console.log(`Unsupported API type: ${provider.api}`);
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
console.log(`\nEndpoint: ${endpoint}`);
|
|
558
|
+
|
|
559
|
+
// Prepare the request body
|
|
560
|
+
let body;
|
|
561
|
+
let headers = {};
|
|
562
|
+
|
|
563
|
+
if (apiKey) {
|
|
564
|
+
if (provider.auth === 'bearer') {
|
|
565
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
566
|
+
} else {
|
|
567
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
568
|
+
headers['X-API-Key'] = apiKey;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (provider.api === 'openai-completions') {
|
|
573
|
+
body = JSON.stringify({
|
|
574
|
+
model: modelId,
|
|
575
|
+
messages: [{ role: 'user', content: 'hi, there' }],
|
|
576
|
+
max_tokens: 10
|
|
577
|
+
});
|
|
578
|
+
headers['Content-Type'] = 'application/json';
|
|
579
|
+
} else if (provider.api === 'anthropic-messages') {
|
|
580
|
+
body = JSON.stringify({
|
|
581
|
+
model: modelId,
|
|
582
|
+
messages: [{ role: 'user', content: 'hi, there' }],
|
|
583
|
+
max_tokens: 10
|
|
584
|
+
});
|
|
585
|
+
headers['Content-Type'] = 'application/json';
|
|
586
|
+
headers['anthropic-version'] = '2023-06-01';
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
console.log('\n--- Request Headers ---');
|
|
590
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
591
|
+
// Mask API key for display - hide last 32 chars
|
|
592
|
+
const displayValue = key.toLowerCase().includes('api') || key.toLowerCase().includes('authorization')
|
|
593
|
+
? value.length > 32 ? value.slice(0, -32) + '********************************' : '********************************'
|
|
594
|
+
: value;
|
|
595
|
+
console.log(`${key}: ${displayValue}`);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
try {
|
|
599
|
+
const response = await fetch(endpoint, {
|
|
600
|
+
method: 'POST',
|
|
601
|
+
headers,
|
|
602
|
+
body
|
|
603
|
+
});
|
|
604
|
+
|
|
605
|
+
const status = response.status;
|
|
606
|
+
const contentType = response.headers.get('content-type');
|
|
607
|
+
|
|
608
|
+
console.log('\n--- Response Headers ---');
|
|
609
|
+
for (const [key, value] of response.headers.entries()) {
|
|
610
|
+
console.log(`${key}: ${value}`);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
let responseBody;
|
|
614
|
+
|
|
615
|
+
if (contentType && contentType.includes('application/json')) {
|
|
616
|
+
responseBody = await response.json();
|
|
617
|
+
} else {
|
|
618
|
+
responseBody = await response.text();
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
console.log(`\nStatus: ${status}`);
|
|
622
|
+
console.log('Response body:');
|
|
623
|
+
console.log(JSON.stringify(responseBody, null, 2));
|
|
624
|
+
|
|
625
|
+
// Provide helpful advice on 404 errors
|
|
626
|
+
if (status === 404) {
|
|
627
|
+
console.log('\n--- Troubleshooting ---');
|
|
628
|
+
if (provider.api === 'openai-completions') {
|
|
629
|
+
console.log('For OpenAI-compatible APIs, ensure your base URL ends with /v1');
|
|
630
|
+
console.log('Expected format: <schema>://<hostname>[:port]/v1');
|
|
631
|
+
console.log('Example: https://api.example.com/v1');
|
|
632
|
+
} else if (provider.api === 'anthropic-messages') {
|
|
633
|
+
console.log('For Anthropic Messages APIs, ensure your base URL ends with /v1');
|
|
634
|
+
console.log('Expected format: <schema>://<hostname>[:port]/v1');
|
|
635
|
+
console.log('Example: https://api.anthropic.com/v1');
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
} catch (error) {
|
|
639
|
+
console.error(`\nRequest failed: ${error.message}`);
|
|
640
|
+
}
|
|
641
|
+
});
|
|
642
|
+
|
|
291
643
|
// ============ Agent Commands ============
|
|
292
644
|
|
|
293
645
|
program
|
|
@@ -299,7 +651,9 @@ program
|
|
|
299
651
|
.option('--workspace <path>', 'Workspace directory')
|
|
300
652
|
.option('--agent-dir <path>', 'Agent directory')
|
|
301
653
|
.action((options) => {
|
|
302
|
-
const
|
|
654
|
+
const botOption = getBotFromArgs();
|
|
655
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
656
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
303
657
|
config.agents = config.agents || { defaults: {}, list: [] };
|
|
304
658
|
|
|
305
659
|
const existing = config.agents.list.find(a => a.id === options.id);
|
|
@@ -316,8 +670,8 @@ program
|
|
|
316
670
|
|
|
317
671
|
config.agents.list.push(agent);
|
|
318
672
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
319
|
-
|
|
320
|
-
console.log(`Agent "${options.id}" added.`);
|
|
673
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
674
|
+
console.log(`Agent "${options.id}" added to ${bot.name}.`);
|
|
321
675
|
});
|
|
322
676
|
|
|
323
677
|
program
|
|
@@ -325,7 +679,9 @@ program
|
|
|
325
679
|
.description('Remove an agent')
|
|
326
680
|
.requiredOption('-i, --id <id>', 'Agent ID')
|
|
327
681
|
.action((options) => {
|
|
328
|
-
const
|
|
682
|
+
const botOption = getBotFromArgs();
|
|
683
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
684
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
329
685
|
if (!config.agents?.list) {
|
|
330
686
|
console.log('No agents configured.');
|
|
331
687
|
return;
|
|
@@ -339,15 +695,17 @@ program
|
|
|
339
695
|
|
|
340
696
|
config.agents.list.splice(idx, 1);
|
|
341
697
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
342
|
-
|
|
698
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
343
699
|
console.log(`Agent "${options.id}" removed.`);
|
|
344
700
|
});
|
|
345
701
|
|
|
346
702
|
program
|
|
347
703
|
.command('agents:list')
|
|
348
704
|
.description('List all configured agents')
|
|
349
|
-
.action(() => {
|
|
350
|
-
const
|
|
705
|
+
.action((options) => {
|
|
706
|
+
const botOption = getBotFromArgs();
|
|
707
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
708
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
351
709
|
const agents = config.agents?.list || [];
|
|
352
710
|
const defaults = config.agents?.defaults || {};
|
|
353
711
|
|
|
@@ -385,15 +743,17 @@ program
|
|
|
385
743
|
.requiredOption('-a, --agent <agent>', 'Agent type (e.g., main, code)')
|
|
386
744
|
.requiredOption('-m, --model <model>', 'Model ID')
|
|
387
745
|
.action((options) => {
|
|
388
|
-
const
|
|
746
|
+
const botOption = getBotFromArgs();
|
|
747
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
748
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
389
749
|
config.agents = config.agents || { defaults: {}, list: [] };
|
|
390
750
|
config.agents.defaults = config.agents.defaults || {};
|
|
391
751
|
config.agents.defaults.model = config.agents.defaults.model || {};
|
|
392
752
|
config.agents.defaults.model.primary = options.model;
|
|
393
753
|
|
|
394
754
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
395
|
-
|
|
396
|
-
console.log(`Default model for agent "${options.agent}" set to "${options.model}".`);
|
|
755
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
756
|
+
console.log(`Default model for agent "${options.agent}" set to "${options.model}" in ${bot.name}.`);
|
|
397
757
|
});
|
|
398
758
|
|
|
399
759
|
// ============ Gateway Commands ============
|
|
@@ -401,8 +761,10 @@ program
|
|
|
401
761
|
program
|
|
402
762
|
.command('gateway:view')
|
|
403
763
|
.description('View gateway configuration')
|
|
404
|
-
.action(() => {
|
|
405
|
-
const
|
|
764
|
+
.action((options) => {
|
|
765
|
+
const botOption = getBotFromArgs();
|
|
766
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
767
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
406
768
|
const gw = config.gateway || {};
|
|
407
769
|
console.log(`Port: ${gw.port || 18789}`);
|
|
408
770
|
console.log(`Mode: ${gw.mode || 'local'}`);
|
|
@@ -416,13 +778,15 @@ program
|
|
|
416
778
|
program
|
|
417
779
|
.command('gateway:refresh-token')
|
|
418
780
|
.description('Refresh gateway auth token')
|
|
419
|
-
.action(() => {
|
|
420
|
-
const
|
|
781
|
+
.action((options) => {
|
|
782
|
+
const botOption = getBotFromArgs();
|
|
783
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
784
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
421
785
|
config.gateway = config.gateway || {};
|
|
422
786
|
config.gateway.auth = config.gateway.auth || { mode: 'token' };
|
|
423
787
|
config.gateway.auth.token = generateToken();
|
|
424
788
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
425
|
-
|
|
789
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
426
790
|
console.log('Gateway auth token refreshed.');
|
|
427
791
|
});
|
|
428
792
|
|
|
@@ -431,8 +795,10 @@ program
|
|
|
431
795
|
program
|
|
432
796
|
.command('auth:profiles')
|
|
433
797
|
.description('List all auth profiles (configured and supported)')
|
|
434
|
-
.action(() => {
|
|
435
|
-
const
|
|
798
|
+
.action((options) => {
|
|
799
|
+
const botOption = getBotFromArgs();
|
|
800
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
801
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
436
802
|
const providers = config.models?.providers || {};
|
|
437
803
|
const profiles = config.auth?.profiles || {};
|
|
438
804
|
|
|
@@ -467,7 +833,9 @@ program
|
|
|
467
833
|
.requiredOption('-p, --provider <provider>', 'Auth provider')
|
|
468
834
|
.requiredOption('-m, --mode <mode>', 'Auth mode (api_key, bearer)')
|
|
469
835
|
.action((options) => {
|
|
470
|
-
const
|
|
836
|
+
const botOption = getBotFromArgs();
|
|
837
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
838
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
471
839
|
config.auth = config.auth || { profiles: {} };
|
|
472
840
|
|
|
473
841
|
config.auth.profiles[options.name] = {
|
|
@@ -476,8 +844,8 @@ program
|
|
|
476
844
|
};
|
|
477
845
|
|
|
478
846
|
config.meta.lastTouchedAt = new Date().toISOString();
|
|
479
|
-
|
|
480
|
-
console.log(`Auth profile "${options.name}" added.`);
|
|
847
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
848
|
+
console.log(`Auth profile "${options.name}" added to ${bot.name}.`);
|
|
481
849
|
});
|
|
482
850
|
|
|
483
851
|
// ============ Import/Export ============
|
|
@@ -487,6 +855,8 @@ program
|
|
|
487
855
|
.description('Import configuration from a JSON file')
|
|
488
856
|
.requiredOption('-f, --file <file>', 'Path to JSON file')
|
|
489
857
|
.action((options) => {
|
|
858
|
+
const botOption = getBotFromArgs();
|
|
859
|
+
const { bot, configPath } = resolveConfigSync(botOption);
|
|
490
860
|
if (!fs.existsSync(options.file)) {
|
|
491
861
|
console.error(`File not found: ${options.file}`);
|
|
492
862
|
return;
|
|
@@ -500,44 +870,22 @@ program
|
|
|
500
870
|
lastTouchedAt: new Date().toISOString()
|
|
501
871
|
};
|
|
502
872
|
|
|
503
|
-
|
|
504
|
-
console.log(`Configuration imported from ${options.file}
|
|
873
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
874
|
+
console.log(`Configuration imported from ${options.file} to ${bot.name}.`);
|
|
505
875
|
});
|
|
506
876
|
|
|
507
877
|
program
|
|
508
878
|
.command('export')
|
|
509
879
|
.description('Export configuration to stdout')
|
|
510
|
-
.action(() => {
|
|
511
|
-
const
|
|
880
|
+
.action((options) => {
|
|
881
|
+
const botOption = getBotFromArgs();
|
|
882
|
+
const { configPath } = resolveConfigSync(botOption);
|
|
883
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
512
884
|
console.log(JSON.stringify(config, null, 2));
|
|
513
885
|
});
|
|
514
886
|
|
|
515
887
|
// ============ Helpers ============
|
|
516
888
|
|
|
517
|
-
function loadConfig() {
|
|
518
|
-
try {
|
|
519
|
-
if (fs.existsSync(OPENCLAW_CONFIG_PATH)) {
|
|
520
|
-
const content = fs.readFileSync(OPENCLAW_CONFIG_PATH, 'utf8');
|
|
521
|
-
return JSON.parse(content);
|
|
522
|
-
}
|
|
523
|
-
return {};
|
|
524
|
-
} catch (error) {
|
|
525
|
-
console.error(`Error loading configuration: ${error.message}`);
|
|
526
|
-
return {};
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
function saveConfig(config) {
|
|
531
|
-
try {
|
|
532
|
-
const dir = path.dirname(OPENCLAW_CONFIG_PATH);
|
|
533
|
-
fs.ensureDirSync(dir);
|
|
534
|
-
fs.writeFileSync(OPENCLAW_CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
535
|
-
} catch (error) {
|
|
536
|
-
console.error(`Error saving configuration: ${error.message}`);
|
|
537
|
-
process.exit(1);
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
|
|
541
889
|
function generateToken() {
|
|
542
890
|
const chars = 'abcdef0123456789';
|
|
543
891
|
let token = '';
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 380">
|
|
2
|
+
<defs>
|
|
3
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="7" refX="9" refY="3.5" orient="auto">
|
|
4
|
+
<polygon points="0 0, 10 3.5, 0 7" fill="#333"/>
|
|
5
|
+
</marker>
|
|
6
|
+
<filter id="shadow" x="-20%" y="-20%" width="140%" height="140%">
|
|
7
|
+
<feDropShadow dx="2" dy="2" stdDeviation="3" flood-opacity="0.2"/>
|
|
8
|
+
</filter>
|
|
9
|
+
</defs>
|
|
10
|
+
|
|
11
|
+
<!-- Background -->
|
|
12
|
+
<rect width="800" height="380" fill="#fafafa"/>
|
|
13
|
+
|
|
14
|
+
<!-- Title -->
|
|
15
|
+
<text x="400" y="30" text-anchor="middle" font-size="20" font-weight="bold" fill="#333">Setup Models for OpenClaw with clawd-models</text>
|
|
16
|
+
|
|
17
|
+
<!-- Step 1: Install OpenClaw -->
|
|
18
|
+
<rect x="20" y="55" width="150" height="90" rx="8" fill="#e3f2fd" stroke="#1976d2" stroke-width="2" filter="url(#shadow)"/>
|
|
19
|
+
<text x="95" y="80" text-anchor="middle" font-size="13" font-weight="bold" fill="#1976d2">1. Install &</text>
|
|
20
|
+
<text x="95" y="98" text-anchor="middle" font-size="13" font-weight="bold" fill="#1976d2">Init OpenClaw</text>
|
|
21
|
+
<text x="95" y="118" text-anchor="middle" font-size="9" fill="#555">npm i -g openclaw@latest</text>
|
|
22
|
+
<text x="95" y="128" text-anchor="middle" font-size="9" fill="#555">openclaw setup</text>
|
|
23
|
+
|
|
24
|
+
<!-- Arrow 1 -->
|
|
25
|
+
<path d="M175 90 L210 90" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
26
|
+
|
|
27
|
+
<!-- Step 2: Install clawd-models -->
|
|
28
|
+
<rect x="220" y="55" width="150" height="70" rx="8" fill="#e8f5e9" stroke="#388e3c" stroke-width="2" filter="url(#shadow)"/>
|
|
29
|
+
<text x="295" y="80" text-anchor="middle" font-size="13" font-weight="bold" fill="#388e3c">2. Install</text>
|
|
30
|
+
<text x="295" y="98" text-anchor="middle" font-size="13" font-weight="bold" fill="#388e3c">clawd-models</text>
|
|
31
|
+
<text x="295" y="118" text-anchor="middle" font-size="9" fill="#555">npm i -g clawd-models</text>
|
|
32
|
+
|
|
33
|
+
<!-- Arrow 2 -->
|
|
34
|
+
<path d="M375 90 L410 90" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
35
|
+
|
|
36
|
+
<!-- Step 3: Add Providers -->
|
|
37
|
+
<rect x="420" y="55" width="150" height="70" rx="8" fill="#fff3e0" stroke="#f57c00" stroke-width="2" filter="url(#shadow)"/>
|
|
38
|
+
<text x="495" y="80" text-anchor="middle" font-size="13" font-weight="bold" fill="#f57c00">3. Add Providers</text>
|
|
39
|
+
<text x="495" y="100" text-anchor="middle" font-size="10" fill="#555">providers:add</text>
|
|
40
|
+
<text x="495" y="115" text-anchor="middle" font-size="9" fill="#555">-n <name> -u <url></text>
|
|
41
|
+
|
|
42
|
+
<!-- Arrow 3 -->
|
|
43
|
+
<path d="M575 90 L610 90" stroke="#333" stroke-width="2" marker-end="url(#arrowhead)"/>
|
|
44
|
+
|
|
45
|
+
<!-- Step 4: Add Models -->
|
|
46
|
+
<rect x="620" y="55" width="150" height="70" rx="8" fill="#fff3e0" stroke="#f57c00" stroke-width="2" filter="url(#shadow)"/>
|
|
47
|
+
<text x="695" y="80" text-anchor="middle" font-size="13" font-weight="bold" fill="#f57c00">4. Add Models</text>
|
|
48
|
+
<text x="695" y="100" text-anchor="middle" font-size="10" fill="#555">models:add</text>
|
|
49
|
+
<text x="695" y="115" text-anchor="middle" font-size="9" fill="#555">-p <provider> -i <model-id></text>
|
|
50
|
+
|
|
51
|
+
<!-- Row 2: Test & loop -->
|
|
52
|
+
<rect x="100" y="180" width="160" height="60" rx="8" fill="#e8f5e9" stroke="#388e3c" stroke-width="2" filter="url(#shadow)"/>
|
|
53
|
+
<text x="180" y="205" text-anchor="middle" font-size="13" font-weight="bold" fill="#388e3c">5. Test Models</text>
|
|
54
|
+
<text x="180" y="225" text-anchor="middle" font-size="9" fill="#555">models:test [--bot <name>]</text>
|
|
55
|
+
|
|
56
|
+
<!-- Arrow from Add Models to Test -->
|
|
57
|
+
<path d="M695 125 L695 160 L210 160 L210 180" stroke="#333" stroke-width="1.5" fill="none" marker-end="url(#arrowhead)"/>
|
|
58
|
+
|
|
59
|
+
<!-- Alternative: Direct OpenClaw Commands -->
|
|
60
|
+
<rect x="550" y="180" width="220" height="90" rx="8" fill="#fafafa" stroke="#999" stroke-width="1" stroke-dasharray="5,5"/>
|
|
61
|
+
<text x="660" y="200" text-anchor="middle" font-size="11" font-weight="bold" fill="#333">Native Commands</text>
|
|
62
|
+
<text x="660" y="212" text-anchor="middle" font-size="9" fill="#555">openclaw models list</text>
|
|
63
|
+
<text x="660" y="224" text-anchor="middle" font-size="9" fill="#555">openclaw models set <model-id></text>
|
|
64
|
+
<text x="660" y="236" text-anchor="middle" font-size="9" fill="#555">openclaw agent --agent main -m "hi, there"</text>
|
|
65
|
+
|
|
66
|
+
<!-- Legend -->
|
|
67
|
+
<rect x="20" y="280" width="100" height="80" rx="6" fill="#fff" stroke="#ccc" stroke-width="1"/>
|
|
68
|
+
<text x="70" y="298" text-anchor="middle" font-size="10" font-weight="bold" fill="#333">Legend</text>
|
|
69
|
+
<circle cx="35" cy="320" r="5" fill="#1976d2"/>
|
|
70
|
+
<text x="48" y="324" font-size="9" fill="#555" text-anchor="start">OpenClaw</text>
|
|
71
|
+
<circle cx="35" cy="338" r="5" fill="#f57c00"/>
|
|
72
|
+
<text x="48" y="342" font-size="9" fill="#555" text-anchor="start">Config</text>
|
|
73
|
+
<circle cx="35" cy="354" r="5" fill="#388e3c"/>
|
|
74
|
+
<text x="48" y="358" font-size="9" fill="#555" text-anchor="start">Test</text>
|
|
75
|
+
|
|
76
|
+
<!-- Default Bot Priority -->
|
|
77
|
+
<rect x="350" y="190" width="140" height="50" rx="6" fill="#f5f5f5" stroke="#ddd" stroke-width="1"/>
|
|
78
|
+
<text x="420" y="210" text-anchor="middle" font-size="10" font-weight="bold" fill="#333">Default Bot</text>
|
|
79
|
+
<text x="420" y="228" text-anchor="middle" font-size="9" fill="#555">openclaw → clawdbot → moltbot</text>
|
|
80
|
+
|
|
81
|
+
<!-- Dashed line from Step 5 to Default Bot -->
|
|
82
|
+
<path d="M260 210 L350 210" stroke="#777" stroke-width="1" stroke-dasharray="4,4" fill="none"/>
|
|
83
|
+
|
|
84
|
+
<!-- Dashed line from Default Bot to Step 3 -->
|
|
85
|
+
<path d="M440 190 L440 150 L495 150 L495 125" stroke="#777" stroke-width="1" stroke-dasharray="4,4" fill="none" marker-end="url(#arrowhead)"/>
|
|
86
|
+
</svg>
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawd-models",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "CLI tool to manage OpenClaw model configurations",
|
|
5
5
|
"main": "bin/clawd-models.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"clawd-models": "
|
|
7
|
+
"clawd-models": "bin/clawd-models.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"test": "echo \"Error: no test specified\" && exit 1"
|