mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-07 07:58:36 +00:00
test: add upgrade survivor package lane
This commit is contained in:
174
scripts/e2e/lib/upgrade-survivor/assertions.mjs
Normal file
174
scripts/e2e/lib/upgrade-survivor/assertions.mjs
Normal file
@@ -0,0 +1,174 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const command = process.argv[2];
|
||||
|
||||
function requireEnv(name) {
|
||||
const value = process.env[name];
|
||||
if (!value) {
|
||||
throw new Error(`${name} is required`);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function readJson(file) {
|
||||
return JSON.parse(fs.readFileSync(file, "utf8"));
|
||||
}
|
||||
|
||||
function write(file, contents) {
|
||||
fs.mkdirSync(path.dirname(file), { recursive: true });
|
||||
fs.writeFileSync(file, contents);
|
||||
}
|
||||
|
||||
function writeJson(file, value) {
|
||||
write(file, `${JSON.stringify(value, null, 2)}\n`);
|
||||
}
|
||||
|
||||
function assert(condition, message) {
|
||||
if (!condition) {
|
||||
throw new Error(message);
|
||||
}
|
||||
}
|
||||
|
||||
function getConfig() {
|
||||
return readJson(requireEnv("OPENCLAW_CONFIG_PATH"));
|
||||
}
|
||||
|
||||
function seedState() {
|
||||
const stateDir = requireEnv("OPENCLAW_STATE_DIR");
|
||||
const workspace = requireEnv("OPENCLAW_TEST_WORKSPACE_DIR");
|
||||
|
||||
write(
|
||||
path.join(workspace, "IDENTITY.md"),
|
||||
"# Upgrade Survivor\n\nThis workspace must survive package update and doctor repair.\n",
|
||||
);
|
||||
writeJson(path.join(workspace, ".openclaw", "workspace-state.json"), {
|
||||
version: 1,
|
||||
setupCompletedAt: "2026-04-01T00:00:00.000Z",
|
||||
});
|
||||
writeJson(path.join(stateDir, "agents", "main", "sessions", "legacy-session.json"), {
|
||||
id: "legacy-session",
|
||||
agentId: "main",
|
||||
title: "Existing user session",
|
||||
});
|
||||
|
||||
const runtimeRoot = path.join(stateDir, "plugin-runtime-deps");
|
||||
for (const plugin of ["discord", "telegram", "whatsapp"]) {
|
||||
writeJson(path.join(runtimeRoot, plugin, ".openclaw-runtime-deps-stamp.json"), {
|
||||
version: 0,
|
||||
plugin,
|
||||
stale: true,
|
||||
});
|
||||
write(
|
||||
path.join(
|
||||
runtimeRoot,
|
||||
plugin,
|
||||
".openclaw-runtime-deps-copy-stale",
|
||||
"node_modules",
|
||||
"stale-sentinel",
|
||||
"package.json",
|
||||
),
|
||||
`${JSON.stringify({ name: "stale-sentinel", version: "0.0.0" }, null, 2)}\n`,
|
||||
);
|
||||
}
|
||||
|
||||
writeJson(path.join(stateDir, "survivor-baseline.json"), {
|
||||
agents: ["main", "ops"],
|
||||
discordGuild: "222222222222222222",
|
||||
discordChannel: "333333333333333333",
|
||||
telegramGroup: "-1001234567890",
|
||||
whatsappGroup: "120363000000000000@g.us",
|
||||
workspaceIdentity: path.join(workspace, "IDENTITY.md"),
|
||||
});
|
||||
}
|
||||
|
||||
function assertConfigSurvived() {
|
||||
const config = getConfig();
|
||||
assert(config.update?.channel === "stable", "update.channel was not preserved");
|
||||
assert(config.gateway?.auth?.mode === "token", "gateway auth mode was not preserved");
|
||||
|
||||
const agents = config.agents?.list ?? [];
|
||||
assert(Array.isArray(agents), "agents.list missing after update/doctor");
|
||||
assert(
|
||||
agents.some((agent) => agent?.id === "main"),
|
||||
"main agent missing",
|
||||
);
|
||||
assert(
|
||||
agents.some((agent) => agent?.id === "ops"),
|
||||
"ops agent missing",
|
||||
);
|
||||
assert(
|
||||
agents.find((agent) => agent?.id === "main")?.contextTokens === 64000,
|
||||
"main agent contextTokens changed",
|
||||
);
|
||||
assert(
|
||||
agents.find((agent) => agent?.id === "ops")?.fastModeDefault === true,
|
||||
"ops fastModeDefault changed",
|
||||
);
|
||||
|
||||
const discord = config.channels?.discord;
|
||||
assert(discord?.enabled === true, "discord enabled flag changed");
|
||||
const discordAllowFrom = discord.allowFrom ?? discord.dm?.allowFrom;
|
||||
const discordDmPolicy = discord.dmPolicy ?? discord.dm?.policy;
|
||||
assert(discordDmPolicy === "allowlist", "discord DM policy changed");
|
||||
assert(
|
||||
Array.isArray(discordAllowFrom) && discordAllowFrom.includes("111111111111111111"),
|
||||
"discord allowFrom changed",
|
||||
);
|
||||
assert(
|
||||
discord.guilds?.["222222222222222222"]?.channels?.["333333333333333333"]?.requireMention ===
|
||||
true,
|
||||
"discord guild channel mention policy changed",
|
||||
);
|
||||
assert(discord.threadBindings?.idleHours === 72, "discord thread binding ttl changed");
|
||||
|
||||
assert(config.channels?.telegram?.enabled === true, "telegram enabled flag changed");
|
||||
assert(
|
||||
config.channels?.telegram?.groups?.["-1001234567890"]?.requireMention === true,
|
||||
"telegram group policy changed",
|
||||
);
|
||||
assert(config.channels?.whatsapp?.enabled === true, "whatsapp enabled flag changed");
|
||||
assert(
|
||||
config.channels?.whatsapp?.groups?.["120363000000000000@g.us"]?.systemPrompt ===
|
||||
"Use the existing WhatsApp group prompt.",
|
||||
"whatsapp group policy changed",
|
||||
);
|
||||
|
||||
const pluginAllow = config.plugins?.allow ?? [];
|
||||
assert(pluginAllow.includes("discord"), "discord plugin allow entry missing");
|
||||
assert(pluginAllow.includes("telegram"), "telegram plugin allow entry missing");
|
||||
assert(pluginAllow.includes("whatsapp"), "whatsapp plugin allow entry missing");
|
||||
}
|
||||
|
||||
function assertStateSurvived() {
|
||||
const stateDir = requireEnv("OPENCLAW_STATE_DIR");
|
||||
const workspace = requireEnv("OPENCLAW_TEST_WORKSPACE_DIR");
|
||||
assert(fs.existsSync(path.join(workspace, "IDENTITY.md")), "workspace identity file missing");
|
||||
assert(
|
||||
fs.existsSync(path.join(stateDir, "agents", "main", "sessions", "legacy-session.json")),
|
||||
"legacy session file missing",
|
||||
);
|
||||
assert(
|
||||
fs.existsSync(path.join(stateDir, "plugin-runtime-deps", "discord")),
|
||||
"plugin runtime deps root missing",
|
||||
);
|
||||
}
|
||||
|
||||
function assertStatusJson([file]) {
|
||||
const status = readJson(file);
|
||||
assert(status && typeof status === "object", "gateway status JSON was not an object");
|
||||
const text = JSON.stringify(status);
|
||||
assert(/running|connected|ok|ready/u.test(text), "gateway status did not report a healthy state");
|
||||
}
|
||||
|
||||
if (command === "seed") {
|
||||
seedState();
|
||||
} else if (command === "assert-config") {
|
||||
assertConfigSurvived();
|
||||
} else if (command === "assert-state") {
|
||||
assertStateSurvived();
|
||||
} else if (command === "assert-status-json") {
|
||||
assertStatusJson(process.argv.slice(3));
|
||||
} else {
|
||||
throw new Error(`unknown upgrade-survivor assertion command: ${command ?? "<missing>"}`);
|
||||
}
|
||||
127
scripts/e2e/upgrade-survivor-docker.sh
Executable file
127
scripts/e2e/upgrade-survivor-docker.sh
Executable file
@@ -0,0 +1,127 @@
|
||||
#!/usr/bin/env bash
|
||||
# Installs the packed OpenClaw tarball over a dirty old-user state fixture, runs
|
||||
# the package update/doctor paths, then proves the Gateway still boots.
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$ROOT_DIR/scripts/lib/docker-e2e-image.sh"
|
||||
source "$ROOT_DIR/scripts/lib/docker-e2e-package.sh"
|
||||
|
||||
IMAGE_NAME="$(docker_e2e_resolve_image "openclaw-upgrade-survivor-e2e" OPENCLAW_UPGRADE_SURVIVOR_E2E_IMAGE)"
|
||||
SKIP_BUILD="${OPENCLAW_UPGRADE_SURVIVOR_E2E_SKIP_BUILD:-0}"
|
||||
PACKAGE_TGZ="$(docker_e2e_prepare_package_tgz upgrade-survivor "${OPENCLAW_CURRENT_PACKAGE_TGZ:-}")"
|
||||
DOCKER_RUN_TIMEOUT="${OPENCLAW_UPGRADE_SURVIVOR_DOCKER_RUN_TIMEOUT:-900s}"
|
||||
|
||||
docker_e2e_package_mount_args "$PACKAGE_TGZ"
|
||||
OPENCLAW_TEST_STATE_SCRIPT_B64="$(docker_e2e_test_state_shell_b64 upgrade-survivor upgrade-survivor)"
|
||||
|
||||
docker_e2e_build_or_reuse "$IMAGE_NAME" upgrade-survivor "$ROOT_DIR/scripts/e2e/Dockerfile" "$ROOT_DIR" "bare" "$SKIP_BUILD"
|
||||
|
||||
echo "Running upgrade survivor Docker E2E..."
|
||||
docker_e2e_run_with_harness \
|
||||
-e COREPACK_ENABLE_DOWNLOAD_PROMPT=0 \
|
||||
-e OPENCLAW_TEST_STATE_SCRIPT_B64="$OPENCLAW_TEST_STATE_SCRIPT_B64" \
|
||||
-e OPENCLAW_UPGRADE_SURVIVOR_START_BUDGET_SECONDS="${OPENCLAW_UPGRADE_SURVIVOR_START_BUDGET_SECONDS:-90}" \
|
||||
-e OPENCLAW_UPGRADE_SURVIVOR_STATUS_BUDGET_SECONDS="${OPENCLAW_UPGRADE_SURVIVOR_STATUS_BUDGET_SECONDS:-30}" \
|
||||
"${DOCKER_E2E_PACKAGE_ARGS[@]}" \
|
||||
"$IMAGE_NAME" \
|
||||
timeout "$DOCKER_RUN_TIMEOUT" bash -lc 'set -euo pipefail
|
||||
source scripts/lib/openclaw-e2e-instance.sh
|
||||
|
||||
export npm_config_loglevel=error
|
||||
export npm_config_fund=false
|
||||
export npm_config_audit=false
|
||||
export npm_config_prefix=/tmp/npm-prefix
|
||||
export NPM_CONFIG_PREFIX=/tmp/npm-prefix
|
||||
export PATH="/tmp/npm-prefix/bin:$PATH"
|
||||
export CI=true
|
||||
export OPENCLAW_NO_ONBOARD=1
|
||||
export OPENCLAW_NO_PROMPT=1
|
||||
export OPENCLAW_SKIP_PROVIDERS=1
|
||||
export OPENCLAW_SKIP_CHANNELS=1
|
||||
export OPENCLAW_DISABLE_BONJOUR=1
|
||||
export GATEWAY_AUTH_TOKEN_REF="upgrade-survivor-token"
|
||||
export OPENAI_API_KEY="sk-openclaw-upgrade-survivor"
|
||||
export DISCORD_BOT_TOKEN="upgrade-survivor-discord-token"
|
||||
export TELEGRAM_BOT_TOKEN="123456:upgrade-survivor-telegram-token"
|
||||
|
||||
gateway_pid=""
|
||||
cleanup() {
|
||||
openclaw_e2e_terminate_gateways "${gateway_pid:-}"
|
||||
}
|
||||
trap cleanup EXIT
|
||||
|
||||
openclaw_e2e_eval_test_state_from_b64 "${OPENCLAW_TEST_STATE_SCRIPT_B64:?missing OPENCLAW_TEST_STATE_SCRIPT_B64}"
|
||||
node scripts/e2e/lib/upgrade-survivor/assertions.mjs seed
|
||||
|
||||
openclaw_e2e_install_package /tmp/openclaw-upgrade-survivor-install.log "upgrade survivor package" /tmp/npm-prefix
|
||||
command -v openclaw >/dev/null
|
||||
package_version="$(node -p "JSON.parse(require(\"node:fs\").readFileSync(\"/tmp/npm-prefix/lib/node_modules/openclaw/package.json\", \"utf8\")).version")"
|
||||
OPENCLAW_PACKAGE_ACCEPTANCE_LEGACY_COMPAT="$(
|
||||
node scripts/e2e/lib/package-compat.mjs "$package_version"
|
||||
)"
|
||||
export OPENCLAW_PACKAGE_ACCEPTANCE_LEGACY_COMPAT
|
||||
|
||||
echo "Checking dirty-state config before update..."
|
||||
node scripts/e2e/lib/upgrade-survivor/assertions.mjs assert-config
|
||||
node scripts/e2e/lib/upgrade-survivor/assertions.mjs assert-state
|
||||
|
||||
echo "Running package update against the mounted tarball..."
|
||||
set +e
|
||||
openclaw update --tag "${OPENCLAW_CURRENT_PACKAGE_TGZ:?missing OPENCLAW_CURRENT_PACKAGE_TGZ}" --yes --json --no-restart >/tmp/openclaw-upgrade-survivor-update.json 2>/tmp/openclaw-upgrade-survivor-update.err
|
||||
update_status=$?
|
||||
set -e
|
||||
if [ "$update_status" -ne 0 ]; then
|
||||
echo "openclaw update failed" >&2
|
||||
cat /tmp/openclaw-upgrade-survivor-update.err >&2 || true
|
||||
cat /tmp/openclaw-upgrade-survivor-update.json >&2 || true
|
||||
exit "$update_status"
|
||||
fi
|
||||
|
||||
echo "Running non-interactive doctor repair..."
|
||||
if ! openclaw doctor --fix --non-interactive >/tmp/openclaw-upgrade-survivor-doctor.log 2>&1; then
|
||||
echo "openclaw doctor failed" >&2
|
||||
cat /tmp/openclaw-upgrade-survivor-doctor.log >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Verifying config and state survived update/doctor..."
|
||||
node scripts/e2e/lib/upgrade-survivor/assertions.mjs assert-config
|
||||
node scripts/e2e/lib/upgrade-survivor/assertions.mjs assert-state
|
||||
|
||||
PORT=18789
|
||||
START_BUDGET="${OPENCLAW_UPGRADE_SURVIVOR_START_BUDGET_SECONDS:-90}"
|
||||
STATUS_BUDGET="${OPENCLAW_UPGRADE_SURVIVOR_STATUS_BUDGET_SECONDS:-30}"
|
||||
|
||||
echo "Starting gateway from upgraded state..."
|
||||
start_epoch="$(node -e "process.stdout.write(String(Date.now()))")"
|
||||
openclaw gateway --port "$PORT" --bind loopback --allow-unconfigured >/tmp/openclaw-upgrade-survivor-gateway.log 2>&1 &
|
||||
gateway_pid="$!"
|
||||
openclaw_e2e_wait_gateway_ready "$gateway_pid" /tmp/openclaw-upgrade-survivor-gateway.log 360
|
||||
ready_epoch="$(node -e "process.stdout.write(String(Date.now()))")"
|
||||
start_seconds=$(((ready_epoch - start_epoch + 999) / 1000))
|
||||
if [ "$start_seconds" -gt "$START_BUDGET" ]; then
|
||||
echo "gateway startup exceeded survivor budget: ${start_seconds}s > ${START_BUDGET}s" >&2
|
||||
cat /tmp/openclaw-upgrade-survivor-gateway.log >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Checking gateway RPC status..."
|
||||
status_start="$(node -e "process.stdout.write(String(Date.now()))")"
|
||||
if ! openclaw gateway status --url "ws://127.0.0.1:$PORT" --token "$GATEWAY_AUTH_TOKEN_REF" --require-rpc --timeout 30000 --json >/tmp/openclaw-upgrade-survivor-status.json 2>/tmp/openclaw-upgrade-survivor-status.err; then
|
||||
echo "gateway status failed" >&2
|
||||
cat /tmp/openclaw-upgrade-survivor-status.err >&2 || true
|
||||
cat /tmp/openclaw-upgrade-survivor-gateway.log >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
status_end="$(node -e "process.stdout.write(String(Date.now()))")"
|
||||
status_seconds=$(((status_end - status_start + 999) / 1000))
|
||||
if [ "$status_seconds" -gt "$STATUS_BUDGET" ]; then
|
||||
echo "gateway status exceeded survivor budget: ${status_seconds}s > ${STATUS_BUDGET}s" >&2
|
||||
cat /tmp/openclaw-upgrade-survivor-status.json >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
node scripts/e2e/lib/upgrade-survivor/assertions.mjs assert-status-json /tmp/openclaw-upgrade-survivor-status.json
|
||||
|
||||
echo "Upgrade survivor Docker E2E passed in startup=${start_seconds}s status=${status_seconds}s."
|
||||
'
|
||||
@@ -278,6 +278,11 @@ export const mainLanes = [
|
||||
weight: 3,
|
||||
},
|
||||
),
|
||||
npmLane("upgrade-survivor", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:upgrade-survivor", {
|
||||
stateScenario: "upgrade-survivor",
|
||||
timeoutMs: 20 * 60 * 1000,
|
||||
weight: 3,
|
||||
}),
|
||||
lane("plugins", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:plugins", {
|
||||
resources: ["npm", "service"],
|
||||
stateScenario: "empty",
|
||||
@@ -530,6 +535,11 @@ const releasePathPackageUpdateCoreLanes = [
|
||||
weight: 3,
|
||||
},
|
||||
),
|
||||
npmLane("upgrade-survivor", "OPENCLAW_SKIP_DOCKER_BUILD=1 pnpm test:docker:upgrade-survivor", {
|
||||
stateScenario: "upgrade-survivor",
|
||||
timeoutMs: 20 * 60 * 1000,
|
||||
weight: 3,
|
||||
}),
|
||||
];
|
||||
|
||||
const primaryReleasePathChunks = {
|
||||
|
||||
@@ -11,6 +11,7 @@ const SCENARIOS = new Set([
|
||||
"empty",
|
||||
"minimal",
|
||||
"update-stable",
|
||||
"upgrade-survivor",
|
||||
"gateway-loopback",
|
||||
"external-service",
|
||||
]);
|
||||
@@ -86,6 +87,135 @@ function scenarioConfig(scenario, options = {}) {
|
||||
plugins: {},
|
||||
};
|
||||
}
|
||||
if (scenario === "upgrade-survivor") {
|
||||
return {
|
||||
update: {
|
||||
channel: "stable",
|
||||
},
|
||||
gateway: {
|
||||
mode: "local",
|
||||
port: Number(options.port || 18789),
|
||||
bind: "loopback",
|
||||
auth: {
|
||||
mode: "token",
|
||||
token: { source: "env", provider: "default", id: "GATEWAY_AUTH_TOKEN_REF" },
|
||||
},
|
||||
controlUi: {
|
||||
enabled: false,
|
||||
},
|
||||
},
|
||||
models: {
|
||||
providers: {
|
||||
openai: {
|
||||
api: "openai-responses",
|
||||
apiKey: { source: "env", provider: "default", id: "OPENAI_API_KEY" },
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
models: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
agents: {
|
||||
defaults: {
|
||||
model: {
|
||||
primary: "openai/gpt-4.1-mini",
|
||||
},
|
||||
contextTokens: 64000,
|
||||
skills: ["memory"],
|
||||
},
|
||||
list: [
|
||||
{
|
||||
id: "main",
|
||||
default: true,
|
||||
name: "Main",
|
||||
workspace: "~/workspace",
|
||||
model: {
|
||||
primary: "openai/gpt-4.1-mini",
|
||||
},
|
||||
thinkingDefault: "low",
|
||||
skills: ["memory"],
|
||||
contextTokens: 64000,
|
||||
},
|
||||
{
|
||||
id: "ops",
|
||||
name: "Ops",
|
||||
workspace: "~/workspace/ops",
|
||||
model: {
|
||||
primary: "openai/gpt-4.1-mini",
|
||||
},
|
||||
fastModeDefault: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
skills: {
|
||||
allowBundled: ["memory", "openclaw-testing"],
|
||||
limits: {
|
||||
maxSkillsInPrompt: 8,
|
||||
maxSkillsPromptChars: 30000,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
enabled: true,
|
||||
allow: ["discord", "telegram", "whatsapp", "memory"],
|
||||
entries: {
|
||||
discord: { enabled: true },
|
||||
telegram: { enabled: true },
|
||||
whatsapp: { enabled: true },
|
||||
},
|
||||
},
|
||||
channels: {
|
||||
discord: {
|
||||
enabled: true,
|
||||
token: { source: "env", provider: "default", id: "DISCORD_BOT_TOKEN" },
|
||||
dm: {
|
||||
policy: "allowlist",
|
||||
allowFrom: ["111111111111111111"],
|
||||
},
|
||||
groupPolicy: "allowlist",
|
||||
guilds: {
|
||||
"222222222222222222": {
|
||||
slug: "survivor-guild",
|
||||
channels: {
|
||||
"333333333333333333": {
|
||||
enabled: true,
|
||||
requireMention: true,
|
||||
tools: {
|
||||
allow: ["message_send"],
|
||||
deny: ["exec"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
idleHours: 72,
|
||||
},
|
||||
},
|
||||
telegram: {
|
||||
enabled: true,
|
||||
botToken: { source: "env", provider: "default", id: "TELEGRAM_BOT_TOKEN" },
|
||||
dmPolicy: "allowlist",
|
||||
allowFrom: ["123456789"],
|
||||
groups: {
|
||||
"-1001234567890": {
|
||||
enabled: true,
|
||||
requireMention: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
whatsapp: {
|
||||
enabled: true,
|
||||
dmPolicy: "allowlist",
|
||||
allowFrom: ["+15555550123"],
|
||||
groups: {
|
||||
"120363000000000000@g.us": {
|
||||
systemPrompt: "Use the existing WhatsApp group prompt.",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
if (scenario === "gateway-loopback") {
|
||||
return {
|
||||
gateway: {
|
||||
@@ -216,7 +346,7 @@ export function renderShellFunction() {
|
||||
local label="$raw_label"
|
||||
local scenario="\${2:-empty}"
|
||||
case "$scenario" in
|
||||
empty|minimal|update-stable|gateway-loopback|external-service) ;;
|
||||
empty|minimal|update-stable|upgrade-survivor|gateway-loopback|external-service) ;;
|
||||
*)
|
||||
echo "unknown OpenClaw test-state scenario: $scenario" >&2
|
||||
return 1
|
||||
@@ -257,6 +387,181 @@ OPENCLAW_TEST_STATE_JSON
|
||||
},
|
||||
"plugins": {}
|
||||
}
|
||||
OPENCLAW_TEST_STATE_JSON
|
||||
;;
|
||||
upgrade-survivor)
|
||||
cat > "$OPENCLAW_CONFIG_PATH" <<'OPENCLAW_TEST_STATE_JSON'
|
||||
{
|
||||
"update": {
|
||||
"channel": "stable"
|
||||
},
|
||||
"gateway": {
|
||||
"mode": "local",
|
||||
"port": 18789,
|
||||
"bind": "loopback",
|
||||
"auth": {
|
||||
"mode": "token",
|
||||
"token": {
|
||||
"source": "env",
|
||||
"provider": "default",
|
||||
"id": "GATEWAY_AUTH_TOKEN_REF"
|
||||
}
|
||||
},
|
||||
"controlUi": {
|
||||
"enabled": false
|
||||
}
|
||||
},
|
||||
"models": {
|
||||
"providers": {
|
||||
"openai": {
|
||||
"api": "openai-responses",
|
||||
"apiKey": {
|
||||
"source": "env",
|
||||
"provider": "default",
|
||||
"id": "OPENAI_API_KEY"
|
||||
},
|
||||
"baseUrl": "https://api.openai.com/v1",
|
||||
"models": []
|
||||
}
|
||||
}
|
||||
},
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"model": {
|
||||
"primary": "openai/gpt-4.1-mini"
|
||||
},
|
||||
"contextTokens": 64000,
|
||||
"skills": [
|
||||
"memory"
|
||||
]
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"default": true,
|
||||
"name": "Main",
|
||||
"workspace": "~/workspace",
|
||||
"model": {
|
||||
"primary": "openai/gpt-4.1-mini"
|
||||
},
|
||||
"thinkingDefault": "low",
|
||||
"skills": [
|
||||
"memory"
|
||||
],
|
||||
"contextTokens": 64000
|
||||
},
|
||||
{
|
||||
"id": "ops",
|
||||
"name": "Ops",
|
||||
"workspace": "~/workspace/ops",
|
||||
"model": {
|
||||
"primary": "openai/gpt-4.1-mini"
|
||||
},
|
||||
"fastModeDefault": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"skills": {
|
||||
"allowBundled": [
|
||||
"memory",
|
||||
"openclaw-testing"
|
||||
],
|
||||
"limits": {
|
||||
"maxSkillsInPrompt": 8,
|
||||
"maxSkillsPromptChars": 30000
|
||||
}
|
||||
},
|
||||
"plugins": {
|
||||
"enabled": true,
|
||||
"allow": [
|
||||
"discord",
|
||||
"telegram",
|
||||
"whatsapp",
|
||||
"memory"
|
||||
],
|
||||
"entries": {
|
||||
"discord": {
|
||||
"enabled": true
|
||||
},
|
||||
"telegram": {
|
||||
"enabled": true
|
||||
},
|
||||
"whatsapp": {
|
||||
"enabled": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"channels": {
|
||||
"discord": {
|
||||
"enabled": true,
|
||||
"token": {
|
||||
"source": "env",
|
||||
"provider": "default",
|
||||
"id": "DISCORD_BOT_TOKEN"
|
||||
},
|
||||
"dm": {
|
||||
"policy": "allowlist",
|
||||
"allowFrom": [
|
||||
"111111111111111111"
|
||||
]
|
||||
},
|
||||
"groupPolicy": "allowlist",
|
||||
"guilds": {
|
||||
"222222222222222222": {
|
||||
"slug": "survivor-guild",
|
||||
"channels": {
|
||||
"333333333333333333": {
|
||||
"enabled": true,
|
||||
"requireMention": true,
|
||||
"tools": {
|
||||
"allow": [
|
||||
"message_send"
|
||||
],
|
||||
"deny": [
|
||||
"exec"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"threadBindings": {
|
||||
"enabled": true,
|
||||
"idleHours": 72
|
||||
}
|
||||
},
|
||||
"telegram": {
|
||||
"enabled": true,
|
||||
"botToken": {
|
||||
"source": "env",
|
||||
"provider": "default",
|
||||
"id": "TELEGRAM_BOT_TOKEN"
|
||||
},
|
||||
"dmPolicy": "allowlist",
|
||||
"allowFrom": [
|
||||
"123456789"
|
||||
],
|
||||
"groups": {
|
||||
"-1001234567890": {
|
||||
"enabled": true,
|
||||
"requireMention": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"whatsapp": {
|
||||
"enabled": true,
|
||||
"dmPolicy": "allowlist",
|
||||
"allowFrom": [
|
||||
"+15555550123"
|
||||
],
|
||||
"groups": {
|
||||
"120363000000000000@g.us": {
|
||||
"systemPrompt": "Use the existing WhatsApp group prompt."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
OPENCLAW_TEST_STATE_JSON
|
||||
;;
|
||||
gateway-loopback)
|
||||
|
||||
Reference in New Issue
Block a user