Anurag commited on
Commit
15103d7
·
unverified ·
2 Parent(s): 6f65a3cc8a2bdb

env-builder improvements, gateway/browser robustness, and key-rotator fixes

Browse files
health-server.js CHANGED
@@ -72,7 +72,6 @@ if (_spacPrivacyEnv === "public") {
72
  SPACE_IS_PRIVATE = false;
73
  _privacyDetectionDone = true;
74
  console.log("[health-server] Space privacy: public (SPACE_PRIVACY env var override)");
75
- privacyDetectionReady.then ? void 0 : null;
76
  _privacyDetectionResolve && _privacyDetectionResolve();
77
  } else if (_spacPrivacyEnv === "private") {
78
  // User explicitly set SPACE_PRIVACY=private — skip API call entirely
 
72
  SPACE_IS_PRIVATE = false;
73
  _privacyDetectionDone = true;
74
  console.log("[health-server] Space privacy: public (SPACE_PRIVACY env var override)");
 
75
  _privacyDetectionResolve && _privacyDetectionResolve();
76
  } else if (_spacPrivacyEnv === "private") {
77
  // User explicitly set SPACE_PRIVACY=private — skip API call entirely
jupyter-devdata-sync.py CHANGED
@@ -174,6 +174,7 @@ def is_jupyter_running(port: int = 8888) -> bool:
174
  return False
175
 
176
  def restore_once(api, rid: str):
 
177
  from huggingface_hub.errors import RepositoryNotFoundError
178
  tmp = Path(tempfile.mkdtemp(prefix="devdata-restore-"))
179
  try:
 
174
  return False
175
 
176
  def restore_once(api, rid: str):
177
+ from huggingface_hub import snapshot_download
178
  from huggingface_hub.errors import RepositoryNotFoundError
179
  tmp = Path(tempfile.mkdtemp(prefix="devdata-restore-"))
180
  try:
multi-provider-key-rotator.cjs CHANGED
@@ -192,6 +192,12 @@ const PROVIDERS = [
192
  envPlural: 'MODELSTUDIO_API_KEYS',
193
  envSingular:'MODELSTUDIO_API_KEY',
194
  },
 
 
 
 
 
 
195
 
196
  ];
197
 
@@ -320,7 +326,25 @@ function patchFetch() {
320
  // Gemini: key URL query param mein jaata hai, Bearer nahi
321
  const url = new URL(typeof input === 'string' ? input : input.url);
322
  url.searchParams.set('key', key);
323
- input = typeof input === 'string' ? url.toString() : new Request(url.toString(), input);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  } else {
325
  const headers = init.headers || (input && input.headers) || undefined;
326
  const patchedHeaders = setAuthHeader(headers, key);
 
192
  envPlural: 'MODELSTUDIO_API_KEYS',
193
  envSingular:'MODELSTUDIO_API_KEY',
194
  },
195
+ {
196
+ name: 'synthetic',
197
+ hostname: /(?:^|\.)synthetic\.local$/i,
198
+ envPlural: 'SYNTHETIC_API_KEYS',
199
+ envSingular: 'SYNTHETIC_API_KEY',
200
+ },
201
 
202
  ];
203
 
 
326
  // Gemini: key URL query param mein jaata hai, Bearer nahi
327
  const url = new URL(typeof input === 'string' ? input : input.url);
328
  url.searchParams.set('key', key);
329
+ if (typeof input === 'string') {
330
+ input = url.toString();
331
+ } else {
332
+ // Do NOT pass the Request object as init — that clones (consumes) the body stream.
333
+ // Instead patch only the URL via init object; fetch spec merges headers from Request.
334
+ init = {
335
+ method: input.method,
336
+ headers: input.headers,
337
+ body: input.body,
338
+ mode: input.mode,
339
+ credentials: input.credentials,
340
+ cache: input.cache,
341
+ redirect: input.redirect,
342
+ referrer: input.referrer,
343
+ integrity: input.integrity,
344
+ ...init,
345
+ };
346
+ input = url.toString();
347
+ }
348
  } else {
349
  const headers = init.headers || (input && input.headers) || undefined;
350
  const patchedHeaders = setAuthHeader(headers, key);
start.sh CHANGED
@@ -359,8 +359,10 @@ CONFIG_JSON=$(jq \
359
  --arg fileLevel "$OPENCLAW_FILE_LOG_LEVEL" \
360
  --arg consoleLevel "$OPENCLAW_CONSOLE_LOG_LEVEL" \
361
  --arg consoleStyle "$OPENCLAW_CONSOLE_LOG_STYLE" \
 
362
  '.gateway.auth.token = $token
363
  | .agents.defaults.model = $model
 
364
  | .logging.level = $fileLevel
365
  | .logging.consoleLevel = $consoleLevel
366
  | .logging.consoleStyle = $consoleStyle' <<<"$CONFIG_JSON")
@@ -373,7 +375,7 @@ CUSTOM_MODEL_NAME="${CUSTOM_MODEL_NAME:-$CUSTOM_MODEL_ID}"
373
  CUSTOM_API_KEY="${CUSTOM_API_KEY:-$LLM_API_KEY}"
374
  CUSTOM_API_TYPE="${CUSTOM_API_TYPE:-openai-completions}"
375
  CUSTOM_CONTEXT_WINDOW="${CUSTOM_CONTEXT_WINDOW:-128000}"
376
- CUSTOM_MAX_TOKENS="${CUSTOM_MAX_TOKENS:-500}"
377
 
378
  if [ -n "$CUSTOM_PROVIDER_NAME" ] || [ -n "$CUSTOM_BASE_URL" ] || [ -n "$CUSTOM_MODEL_ID" ]; then
379
  CUSTOM_PROVIDER_NORMALIZED=$(printf '%s' "$CUSTOM_PROVIDER_NAME" | tr '[:upper:]' '[:lower:]')
@@ -715,6 +717,10 @@ WHATSAPP_CONFIG_ENABLED=false
715
  if [ "$WHATSAPP_ENABLED_NORMALIZED" = "true" ]; then
716
  WHATSAPP_CONFIG_ENABLED=true
717
  fi
 
 
 
 
718
  if [ -f "$EXISTING_CONFIG" ]; then
719
  echo "Restored config found — patching required fields and runtime channel/plugin toggles..."
720
  PATCHED=$(jq \
@@ -729,6 +735,7 @@ if [ -f "$EXISTING_CONFIG" ]; then
729
  --argjson consoleStyleConfigured "$OPENCLAW_CONSOLE_LOG_STYLE_CONFIGURED" \
730
  --argjson whatsappConfigured "$WHATSAPP_ENABLED_CONFIGURED" \
731
  --argjson whatsappEnabled "$WHATSAPP_CONFIG_ENABLED" \
 
732
  '(.channels.whatsapp // {}) as $existingWhatsapp
733
  | .gateway.auth.token = $token
734
  | .agents.defaults.model = $model
@@ -750,6 +757,13 @@ if [ -f "$EXISTING_CONFIG" ]; then
750
  | del(.channels.whatsapp)
751
  else
752
  .
 
 
 
 
 
 
 
753
  end' \
754
  "$EXISTING_CONFIG" 2>/dev/null)
755
 
 
359
  --arg fileLevel "$OPENCLAW_FILE_LOG_LEVEL" \
360
  --arg consoleLevel "$OPENCLAW_CONSOLE_LOG_LEVEL" \
361
  --arg consoleStyle "$OPENCLAW_CONSOLE_LOG_STYLE" \
362
+ --arg port "$GATEWAY_PORT" \
363
  '.gateway.auth.token = $token
364
  | .agents.defaults.model = $model
365
+ | .gateway.port = ($port | tonumber)
366
  | .logging.level = $fileLevel
367
  | .logging.consoleLevel = $consoleLevel
368
  | .logging.consoleStyle = $consoleStyle' <<<"$CONFIG_JSON")
 
375
  CUSTOM_API_KEY="${CUSTOM_API_KEY:-$LLM_API_KEY}"
376
  CUSTOM_API_TYPE="${CUSTOM_API_TYPE:-openai-completions}"
377
  CUSTOM_CONTEXT_WINDOW="${CUSTOM_CONTEXT_WINDOW:-128000}"
378
+ CUSTOM_MAX_TOKENS="${CUSTOM_MAX_TOKENS:-8192}"
379
 
380
  if [ -n "$CUSTOM_PROVIDER_NAME" ] || [ -n "$CUSTOM_BASE_URL" ] || [ -n "$CUSTOM_MODEL_ID" ]; then
381
  CUSTOM_PROVIDER_NORMALIZED=$(printf '%s' "$CUSTOM_PROVIDER_NAME" | tr '[:upper:]' '[:lower:]')
 
717
  if [ "$WHATSAPP_ENABLED_NORMALIZED" = "true" ]; then
718
  WHATSAPP_CONFIG_ENABLED=true
719
  fi
720
+ TELEGRAM_CONFIG_ENABLED=false
721
+ if [ -n "${TELEGRAM_BOT_TOKEN:-}" ]; then
722
+ TELEGRAM_CONFIG_ENABLED=true
723
+ fi
724
  if [ -f "$EXISTING_CONFIG" ]; then
725
  echo "Restored config found — patching required fields and runtime channel/plugin toggles..."
726
  PATCHED=$(jq \
 
735
  --argjson consoleStyleConfigured "$OPENCLAW_CONSOLE_LOG_STYLE_CONFIGURED" \
736
  --argjson whatsappConfigured "$WHATSAPP_ENABLED_CONFIGURED" \
737
  --argjson whatsappEnabled "$WHATSAPP_CONFIG_ENABLED" \
738
+ --argjson telegramConfigured "$TELEGRAM_CONFIG_ENABLED" \
739
  '(.channels.whatsapp // {}) as $existingWhatsapp
740
  | .gateway.auth.token = $token
741
  | .agents.defaults.model = $model
 
757
  | del(.channels.whatsapp)
758
  else
759
  .
760
+ end
761
+ | if $telegramConfigured then
762
+ .channels.telegram = (($desired.channels.telegram // {}) * (.channels.telegram // {}))
763
+ | .channels.telegram.botToken = $desired.channels.telegram.botToken
764
+ else
765
+ del(.channels.telegram)
766
+ | .plugins.entries.telegram.enabled = false
767
  end' \
768
  "$EXISTING_CONFIG" 2>/dev/null)
769
 
wa-guardian.js CHANGED
@@ -125,7 +125,8 @@ async function createConnection() {
125
  });
126
  }
127
 
128
- async function callRpc(ws, method, params) {
 
129
  return new Promise((resolve, reject) => {
130
  const id = randomUUID();
131
  const handler = (data) => {
@@ -148,7 +149,7 @@ async function callRpc(ws, method, params) {
148
  reject(sendErr);
149
  return;
150
  }
151
- setTimeout(() => { ws.removeListener("message", handler); reject(new Error("RPC Timeout")); }, WAIT_TIMEOUT + 5000);
152
  });
153
  }
154
 
@@ -188,7 +189,7 @@ async function checkStatus() {
188
  }
189
 
190
  console.log("[guardian] Waiting for pairing completion...");
191
- const waitRes = await callRpc(ws, "web.login.wait", { timeoutMs: WAIT_TIMEOUT });
192
  const result = waitRes.payload || waitRes.result;
193
  const message = result?.message || "";
194
  const linkedAfter515 = !result?.connected && message.includes("515");
@@ -202,19 +203,27 @@ async function checkStatus() {
202
  lastConnectedAt = Date.now();
203
  writeStatus({ configured: true, connected: true, pairing: false });
204
 
 
 
 
 
205
  if (linkedAfter515) {
206
  console.log("[guardian] 515 after scan: credentials saved, reloading config to start WhatsApp...");
207
  } else {
208
  console.log("[guardian] Pairing completed! Reloading config...");
209
  }
210
 
211
- const getRes = await callRpc(ws, "config.get", {});
212
- if (getRes.payload?.raw && getRes.payload?.hash) {
213
- await callRpc(ws, "config.apply", { raw: getRes.payload.raw, baseHash: getRes.payload.hash });
214
- console.log("[guardian] Configuration re-applied.");
 
 
 
 
 
 
215
  }
216
-
217
- shouldStop = true;
218
  setTimeout(() => process.exit(0), 1000);
219
  } else if (!message.includes("No active") && !message.includes("Still waiting")) {
220
  console.log(`[guardian] Wait result: ${message}`);
 
125
  });
126
  }
127
 
128
+ async function callRpc(ws, method, params, timeoutMs) {
129
+ const ms = timeoutMs !== undefined ? timeoutMs : 10000; // default 10s for normal calls
130
  return new Promise((resolve, reject) => {
131
  const id = randomUUID();
132
  const handler = (data) => {
 
149
  reject(sendErr);
150
  return;
151
  }
152
+ setTimeout(() => { ws.removeListener("message", handler); reject(new Error("RPC Timeout")); }, ms);
153
  });
154
  }
155
 
 
189
  }
190
 
191
  console.log("[guardian] Waiting for pairing completion...");
192
+ const waitRes = await callRpc(ws, "web.login.wait", { timeoutMs: WAIT_TIMEOUT }, WAIT_TIMEOUT + 5000);
193
  const result = waitRes.payload || waitRes.result;
194
  const message = result?.message || "";
195
  const linkedAfter515 = !result?.connected && message.includes("515");
 
203
  lastConnectedAt = Date.now();
204
  writeStatus({ configured: true, connected: true, pairing: false });
205
 
206
+ // Set shouldStop BEFORE config.apply — gateway restart during apply must not
207
+ // leave guardian running (it would then incorrectly wipe valid credentials).
208
+ shouldStop = true;
209
+
210
  if (linkedAfter515) {
211
  console.log("[guardian] 515 after scan: credentials saved, reloading config to start WhatsApp...");
212
  } else {
213
  console.log("[guardian] Pairing completed! Reloading config...");
214
  }
215
 
216
+ try {
217
+ const getRes = await callRpc(ws, "config.get", {});
218
+ if (getRes.payload?.raw && getRes.payload?.hash) {
219
+ await callRpc(ws, "config.apply", { raw: getRes.payload.raw, baseHash: getRes.payload.hash });
220
+ console.log("[guardian] Configuration re-applied.");
221
+ }
222
+ } catch (applyErr) {
223
+ // Gateway restarted during config.apply — that is expected and fine.
224
+ // shouldStop is already true so we will not retry or attempt logout.
225
+ console.log(`[guardian] Config re-apply interrupted (gateway restarting): ${applyErr.message}`);
226
  }
 
 
227
  setTimeout(() => process.exit(0), 1000);
228
  } else if (!message.includes("No active") && !message.includes("Still waiting")) {
229
  console.log(`[guardian] Wait result: ${message}`);