ubix commited on
Commit
00602a5
Β·
verified Β·
1 Parent(s): 095cda6

Update setup-hf-config.mjs

Browse files
Files changed (1) hide show
  1. setup-hf-config.mjs +260 -32
setup-hf-config.mjs CHANGED
@@ -3,19 +3,27 @@
3
  * One-time setup for OpenClaw on Hugging Face Spaces.
4
  * Runs at container startup; writes or merges openclaw.json from env (Secrets/Variables):
5
  *
6
- * Custom Ollama provider (hf-ollama-qwen3-vl) β€” PRIMARY default model:
 
 
 
 
 
 
 
 
 
 
7
  * - providers["hf-ollama-qwen3-vl"] registered with baseUrl + apiKey
8
- * - agents.defaults.model.primary = "hf-ollama-qwen3-vl/voytas26/openclaw-qwen3vl-8b-opt"
9
  * - Configure via:
10
  * OPENCLAW_OLLAMA_BASE_URL (default: https://ubix-Clawd.hf.space/v1)
11
  * OPENCLAW_OLLAMA_API_KEY (default: "ollama")
12
- * - Falls back to OPENCLAW_HF_DEFAULT_MODEL (or HF DeepSeek-R1) when OPENCLAW_OLLAMA_BASE_URL
13
- * is explicitly set to empty string to disable.
14
  *
15
- * OpenRouter / Perplexity (search-augmented model):
16
- * - providers.openrouter.apiKey from OPENROUTER_API_KEY
17
- * - agents.defaults.model.search set to openrouter/perplexity/sonar
18
- * (only written when OPENROUTER_API_KEY is present)
 
19
  *
20
  * Gateway auth:
21
  * - gateway.auth: OPENCLAW_GATEWAY_TOKEN (token) or OPENCLAW_GATEWAY_PASSWORD (password)
@@ -52,23 +60,28 @@ function readGatewayToken() {
52
 
53
  // ── Env reads ──────────────────────────────────────────────────────────────────────────────────
54
 
 
 
 
55
  // Custom Ollama/OpenAI-compat provider hosted on HF Space
56
- // Set OPENCLAW_OLLAMA_BASE_URL="" to disable and fall back to HF Inference
57
  const ollamaBaseUrl = process.env.OPENCLAW_OLLAMA_BASE_URL !== undefined
58
  ? process.env.OPENCLAW_OLLAMA_BASE_URL.trim()
59
  : "https://ubix-Clawd.hf.space/v1";
60
  const ollamaApiKey = process.env.OPENCLAW_OLLAMA_API_KEY?.trim() || "ollama";
61
  const ollamaEnabled = ollamaBaseUrl.length > 0;
62
 
63
- // Fallback HF Inference model (used only when Ollama provider is disabled)
64
  const hfFallbackModel =
65
  process.env.OPENCLAW_HF_DEFAULT_MODEL?.trim() ||
66
  "huggingface/deepseek-ai/DeepSeek-R1";
67
 
68
- // Resolved primary model
69
- const defaultModel = ollamaEnabled
70
- ? "hf-ollama-qwen3-vl/voytas26/openclaw-qwen3vl-8b-opt"
71
- : hfFallbackModel;
 
 
72
 
73
  const gatewayToken = readGatewayToken();
74
  const gatewayPassword = process.env.OPENCLAW_GATEWAY_PASSWORD?.trim();
@@ -118,7 +131,71 @@ if (!config.agents) config.agents = {};
118
  if (!config.agents.defaults) config.agents.defaults = {};
119
  if (!config.agents.defaults.model) config.agents.defaults.model = {};
120
 
121
- // 1a. Custom Ollama/OpenAI-compat provider (hf-ollama-qwen3-vl)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  if (ollamaEnabled) {
123
  config.models.providers["hf-ollama-qwen3-vl"] = {
124
  baseUrl: ollamaBaseUrl,
@@ -149,43 +226,193 @@ if (ollamaEnabled) {
149
  // 1b. Set primary default model
150
  config.agents.defaults.model.primary = defaultModel;
151
 
152
- // ── 2. OpenRouter provider + Perplexity Sonar as fallback model ───────────────────────────────
153
- // Note: model.search is not a valid key. Perplexity is registered as a provider and
154
- // added to model.fallbacks so it can be selected manually via /model in chat.
155
  if (openrouterKey) {
156
  config.models.providers.openrouter = {
157
- apiKey: openrouterKey,
158
- api: "openai-completions",
159
  baseUrl: "https://openrouter.ai/api/v1",
160
  models: [
 
161
  {
162
  id: "perplexity/sonar",
163
- name: "Perplexity Sonar (web search)",
164
  reasoning: false,
165
  input: ["text"],
166
  contextWindow: 127072,
167
  maxTokens: 8192,
168
  cost: { input: 0.000001, output: 0.000001, cacheRead: 0, cacheWrite: 0 },
169
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  ],
171
  };
172
 
173
- // Add Perplexity as a fallback (not primary) β€” use /model in chat to switch
174
- if (!config.agents.defaults.model.fallbacks) {
175
- config.agents.defaults.model.fallbacks = [];
176
- }
177
- if (!config.agents.defaults.model.fallbacks.includes("openrouter/perplexity/sonar")) {
178
- config.agents.defaults.model.fallbacks.push("openrouter/perplexity/sonar");
179
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  console.log(
182
- "[openclaw-hf-setup] OpenRouter configured -> perplexity/sonar added as fallback model"
 
183
  );
184
  } else {
185
  console.warn(
186
  "[openclaw-hf-setup] OPENROUTER_API_KEY not set. " +
187
- "Perplexity Sonar will not be available. " +
188
- "Add OPENROUTER_API_KEY in Space Secrets to enable it."
189
  );
190
  }
191
 
@@ -233,10 +460,11 @@ const parts = [
233
  `token_present=${useTokenAuth ? "1" : "0"}`,
234
  `password_present=${usePasswordAuth ? "1" : "0"}`,
235
  `auth=${authKind}`,
 
236
  `ollama_provider=${ollamaEnabled ? "1" : "0"}`,
237
  `default_model=${defaultModel}`,
238
  `openrouter_configured=${openrouterKey ? "1" : "0"}`,
239
- `search_model=${openrouterKey ? "openrouter/perplexity/sonar (fallback)" : "none"}`,
240
  `trustedProxies=${trustedProxies.length}`,
241
  `allowedOrigins=${allowedOrigins.length}`,
242
  ];
 
3
  * One-time setup for OpenClaw on Hugging Face Spaces.
4
  * Runs at container startup; writes or merges openclaw.json from env (Secrets/Variables):
5
  *
6
+ * Model priority (highest wins):
7
+ * 1. GLM-4.7-Flash via Z.ai (ZHIPU_API_KEY set) β€” fast cloud, free, 203K ctx
8
+ * 2. Custom Ollama HF Space (OPENCLAW_OLLAMA_BASE_URL set) β€” local CPU, slow
9
+ * 3. HF Inference fallback (OPENCLAW_HF_DEFAULT_MODEL) β€” DeepSeek-R1 default
10
+ *
11
+ * Z.ai / GLM provider:
12
+ * - providers["z-ai"] registered with GLM model catalog
13
+ * - agents.defaults.model.primary = "z-ai/glm-4.7-flash" when ZHIPU_API_KEY is set
14
+ * - Configure via: ZHIPU_API_KEY
15
+ *
16
+ * Custom Ollama provider (hf-ollama-qwen3-vl) β€” used when GLM key not set:
17
  * - providers["hf-ollama-qwen3-vl"] registered with baseUrl + apiKey
 
18
  * - Configure via:
19
  * OPENCLAW_OLLAMA_BASE_URL (default: https://ubix-Clawd.hf.space/v1)
20
  * OPENCLAW_OLLAMA_API_KEY (default: "ollama")
 
 
21
  *
22
+ * OpenRouter free model catalog (15 models registered as fallbacks):
23
+ * - providers.openrouter registered under models.providers with full model list
24
+ * - agents.defaults.model.fallbacks populated with all free tier models
25
+ * - Switch model in chat with: /model openrouter/<provider>/<model-id>
26
+ * - Only written when OPENROUTER_API_KEY is present
27
  *
28
  * Gateway auth:
29
  * - gateway.auth: OPENCLAW_GATEWAY_TOKEN (token) or OPENCLAW_GATEWAY_PASSWORD (password)
 
60
 
61
  // ── Env reads ──────────────────────────────────────────────────────────────────────────────────
62
 
63
+ // Z.ai / GLM API key β€” when set, GLM-4.7-Flash becomes primary (fast cloud, free)
64
+ const zhipuApiKey = process.env.ZHIPU_API_KEY?.trim();
65
+
66
  // Custom Ollama/OpenAI-compat provider hosted on HF Space
67
+ // Set OPENCLAW_OLLAMA_BASE_URL="" to disable
68
  const ollamaBaseUrl = process.env.OPENCLAW_OLLAMA_BASE_URL !== undefined
69
  ? process.env.OPENCLAW_OLLAMA_BASE_URL.trim()
70
  : "https://ubix-Clawd.hf.space/v1";
71
  const ollamaApiKey = process.env.OPENCLAW_OLLAMA_API_KEY?.trim() || "ollama";
72
  const ollamaEnabled = ollamaBaseUrl.length > 0;
73
 
74
+ // Fallback HF Inference model (used only when both GLM and Ollama are disabled)
75
  const hfFallbackModel =
76
  process.env.OPENCLAW_HF_DEFAULT_MODEL?.trim() ||
77
  "huggingface/deepseek-ai/DeepSeek-R1";
78
 
79
+ // Resolved primary model β€” GLM wins if key is set (fastest + free cloud API)
80
+ const defaultModel = zhipuApiKey
81
+ ? "z-ai/glm-4.7-flash"
82
+ : ollamaEnabled
83
+ ? "hf-ollama-qwen3-vl/voytas26/openclaw-qwen3vl-8b-opt"
84
+ : hfFallbackModel;
85
 
86
  const gatewayToken = readGatewayToken();
87
  const gatewayPassword = process.env.OPENCLAW_GATEWAY_PASSWORD?.trim();
 
131
  if (!config.agents.defaults) config.agents.defaults = {};
132
  if (!config.agents.defaults.model) config.agents.defaults.model = {};
133
 
134
+ // 1a. Z.ai / GLM provider β€” primary when key is set
135
+ if (zhipuApiKey) {
136
+ config.models.providers["z-ai"] = {
137
+ baseUrl: "https://open.bigmodel.cn/api/paas/v4",
138
+ apiKey: zhipuApiKey,
139
+ api: "openai-completions",
140
+ models: [
141
+ // ── Free models ───────────────────────────────────────────────────────────────────────
142
+ {
143
+ id: "glm-4.7-flash",
144
+ name: "GLM-4.7-Flash (free) β€” fast, 203K ctx, tool calls",
145
+ reasoning: true,
146
+ input: ["text"],
147
+ contextWindow: 203000,
148
+ maxTokens: 16384,
149
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
150
+ },
151
+ {
152
+ id: "glm-4.5-air",
153
+ name: "GLM-4.5-Air (free) β€” MoE, thinking + tools",
154
+ reasoning: true,
155
+ input: ["text"],
156
+ contextWindow: 131072,
157
+ maxTokens: 16384,
158
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
159
+ },
160
+ {
161
+ id: "glm-4v-flash",
162
+ name: "GLM-4V-Flash (free) β€” vision + tools",
163
+ reasoning: false,
164
+ input: ["text", "image"],
165
+ contextWindow: 8192,
166
+ maxTokens: 4096,
167
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
168
+ },
169
+ // ── Paid models (low cost) ────────────────────────────────────────────────────────────
170
+ {
171
+ id: "glm-4.7",
172
+ name: "GLM-4.7 (paid) β€” full model, strongest reasoning",
173
+ reasoning: true,
174
+ input: ["text"],
175
+ contextWindow: 203000,
176
+ maxTokens: 16384,
177
+ cost: { input: 0.000003, output: 0.000003, cacheRead: 0, cacheWrite: 0 },
178
+ },
179
+ {
180
+ id: "glm-4.5",
181
+ name: "GLM-4.5 (paid) β€” MoE flagship, long context",
182
+ reasoning: true,
183
+ input: ["text"],
184
+ contextWindow: 131072,
185
+ maxTokens: 16384,
186
+ cost: { input: 0.000002, output: 0.000002, cacheRead: 0, cacheWrite: 0 },
187
+ },
188
+ ],
189
+ };
190
+ console.log("[openclaw-hf-setup] z-ai provider registered -> primary: glm-4.7-flash");
191
+ } else {
192
+ console.warn(
193
+ "[openclaw-hf-setup] ZHIPU_API_KEY not set. GLM models unavailable. " +
194
+ "Add ZHIPU_API_KEY from https://open.bigmodel.cn to use GLM-4.7-Flash for free."
195
+ );
196
+ }
197
+
198
+ // 1b. Custom Ollama/OpenAI-compat provider (hf-ollama-qwen3-vl)
199
  if (ollamaEnabled) {
200
  config.models.providers["hf-ollama-qwen3-vl"] = {
201
  baseUrl: ollamaBaseUrl,
 
226
  // 1b. Set primary default model
227
  config.agents.defaults.model.primary = defaultModel;
228
 
229
+ // ── 2. OpenRouter provider + free model catalog as fallbacks ──────────────────────────────────
 
 
230
  if (openrouterKey) {
231
  config.models.providers.openrouter = {
232
+ apiKey: openrouterKey,
233
+ api: "openai-completions",
234
  baseUrl: "https://openrouter.ai/api/v1",
235
  models: [
236
+ // ── Web Search ─────────────────────────────────────────────────────────────────────────
237
  {
238
  id: "perplexity/sonar",
239
+ name: "Perplexity Sonar (web search - paid)",
240
  reasoning: false,
241
  input: ["text"],
242
  contextWindow: 127072,
243
  maxTokens: 8192,
244
  cost: { input: 0.000001, output: 0.000001, cacheRead: 0, cacheWrite: 0 },
245
  },
246
+ // ── General Purpose (FREE) ────────────────────────────────────────────────────────────
247
+ {
248
+ id: "meta-llama/llama-3.3-70b-instruct:free",
249
+ name: "Llama 3.3 70B (free) β€” best general purpose",
250
+ reasoning: false,
251
+ input: ["text"],
252
+ contextWindow: 128000,
253
+ maxTokens: 8192,
254
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
255
+ },
256
+ {
257
+ id: "qwen/qwen3-next-80b-a3b-instruct:free",
258
+ name: "Qwen3 Next 80B (free) β€” strong general, 262K ctx",
259
+ reasoning: false,
260
+ input: ["text"],
261
+ contextWindow: 262144,
262
+ maxTokens: 16384,
263
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
264
+ },
265
+ {
266
+ id: "mistralai/mistral-small-3.1-24b-instruct:free",
267
+ name: "Mistral Small 3.1 24B (free) β€” vision + tools",
268
+ reasoning: false,
269
+ input: ["text", "image"],
270
+ contextWindow: 128000,
271
+ maxTokens: 8192,
272
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
273
+ },
274
+ {
275
+ id: "google/gemma-3-27b-it:free",
276
+ name: "Gemma 3 27B (free) β€” vision + tools",
277
+ reasoning: false,
278
+ input: ["text", "image"],
279
+ contextWindow: 131072,
280
+ maxTokens: 8192,
281
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
282
+ },
283
+ // ── Coding (FREE) ─────────────────────────────────────────────────────────────────────
284
+ {
285
+ id: "qwen/qwen3-coder:free",
286
+ name: "Qwen3 Coder 480B (free) β€” best free coding, 262K ctx",
287
+ reasoning: false,
288
+ input: ["text"],
289
+ contextWindow: 262144,
290
+ maxTokens: 16384,
291
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
292
+ },
293
+ {
294
+ id: "openai/gpt-oss-120b:free",
295
+ name: "OpenAI OSS 120B (free) β€” strong coding + tools",
296
+ reasoning: false,
297
+ input: ["text"],
298
+ contextWindow: 131072,
299
+ maxTokens: 16384,
300
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
301
+ },
302
+ // ── Reasoning (FREE) ──────────────────────────────────────────────────────────────────
303
+ {
304
+ id: "qwen/qwen3-235b-a22b-thinking-2507",
305
+ name: "Qwen3 235B Thinking (free) β€” best free reasoning",
306
+ reasoning: true,
307
+ input: ["text"],
308
+ contextWindow: 131072,
309
+ maxTokens: 16384,
310
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
311
+ },
312
+ {
313
+ id: "arcee-ai/trinity-large-preview:free",
314
+ name: "Arcee Trinity Large (free) β€” reasoning + tools",
315
+ reasoning: true,
316
+ input: ["text"],
317
+ contextWindow: 131072,
318
+ maxTokens: 8192,
319
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
320
+ },
321
+ {
322
+ id: "stepfun/step-3.5-flash:free",
323
+ name: "StepFun Step 3.5 Flash (free) β€” fast reasoning, 256K ctx",
324
+ reasoning: true,
325
+ input: ["text"],
326
+ contextWindow: 256000,
327
+ maxTokens: 16384,
328
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
329
+ },
330
+ // ── Vision + Multimodal (FREE) ────────────────────────────────────────────────────────
331
+ {
332
+ id: "qwen/qwen3-vl-30b-a3b-thinking",
333
+ name: "Qwen3 VL 30B Thinking (free) β€” vision + reasoning",
334
+ reasoning: true,
335
+ input: ["text", "image"],
336
+ contextWindow: 131072,
337
+ maxTokens: 8192,
338
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
339
+ },
340
+ {
341
+ id: "nvidia/nemotron-nano-12b-v2-vl:free",
342
+ name: "NVIDIA Nemotron 12B VL (free) β€” vision + tools",
343
+ reasoning: false,
344
+ input: ["text", "image"],
345
+ contextWindow: 128000,
346
+ maxTokens: 8192,
347
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
348
+ },
349
+ // ── Fast / Lightweight (FREE) ─────────────────────────────────────────────────────────
350
+ {
351
+ id: "nvidia/nemotron-3-nano-30b-a3b:free",
352
+ name: "NVIDIA Nemotron Nano 30B (free) β€” fast MoE, agentic",
353
+ reasoning: false,
354
+ input: ["text"],
355
+ contextWindow: 256000,
356
+ maxTokens: 16384,
357
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
358
+ },
359
+ {
360
+ id: "z-ai/glm-4.5-air:free",
361
+ name: "GLM-4.5 Air (free) β€” MoE, thinking + tools",
362
+ reasoning: true,
363
+ input: ["text"],
364
+ contextWindow: 131072,
365
+ maxTokens: 8192,
366
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
367
+ },
368
+ // ── Auto Router (FREE random) ─────────────────────────────────────────────────────────
369
+ {
370
+ id: "openrouter/free",
371
+ name: "OpenRouter Free Router β€” random free model",
372
+ reasoning: false,
373
+ input: ["text", "image"],
374
+ contextWindow: 200000,
375
+ maxTokens: 8192,
376
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
377
+ },
378
  ],
379
  };
380
 
381
+ // Ordered fallback list β€” switch with /model in chat
382
+ config.agents.defaults.model.fallbacks = [
383
+ // GLM (Z.ai free) β€” add first if key is set
384
+ ...(zhipuApiKey ? [
385
+ "z-ai/glm-4.5-air",
386
+ "z-ai/glm-4v-flash",
387
+ ] : []),
388
+ // Web search
389
+ "openrouter/perplexity/sonar",
390
+ // General purpose
391
+ "openrouter/meta-llama/llama-3.3-70b-instruct:free",
392
+ "openrouter/qwen/qwen3-next-80b-a3b-instruct:free",
393
+ "openrouter/mistralai/mistral-small-3.1-24b-instruct:free",
394
+ // Coding
395
+ "openrouter/qwen/qwen3-coder:free",
396
+ "openrouter/openai/gpt-oss-120b:free",
397
+ // Reasoning
398
+ "openrouter/qwen/qwen3-235b-a22b-thinking-2507",
399
+ "openrouter/stepfun/step-3.5-flash:free",
400
+ // Vision
401
+ "openrouter/qwen/qwen3-vl-30b-a3b-thinking",
402
+ "openrouter/mistralai/mistral-small-3.1-24b-instruct:free",
403
+ // Auto
404
+ "openrouter/openrouter/free",
405
+ ];
406
 
407
  console.log(
408
+ `[openclaw-hf-setup] OpenRouter configured -> ${config.models.providers.openrouter.models.length} models registered, ` +
409
+ `${config.agents.defaults.model.fallbacks.length} fallbacks set`
410
  );
411
  } else {
412
  console.warn(
413
  "[openclaw-hf-setup] OPENROUTER_API_KEY not set. " +
414
+ "OpenRouter free models will not be available. " +
415
+ "Add OPENROUTER_API_KEY in Space Secrets to enable them."
416
  );
417
  }
418
 
 
460
  `token_present=${useTokenAuth ? "1" : "0"}`,
461
  `password_present=${usePasswordAuth ? "1" : "0"}`,
462
  `auth=${authKind}`,
463
+ `glm_configured=${zhipuApiKey ? "1" : "0"}`,
464
  `ollama_provider=${ollamaEnabled ? "1" : "0"}`,
465
  `default_model=${defaultModel}`,
466
  `openrouter_configured=${openrouterKey ? "1" : "0"}`,
467
+ `openrouter_models=${openrouterKey ? (config.models?.providers?.openrouter?.models?.length ?? 0) : 0}`,
468
  `trustedProxies=${trustedProxies.length}`,
469
  `allowedOrigins=${allowedOrigins.length}`,
470
  ];