Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions .github/workflows/nightly-e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1716,15 +1716,23 @@ jobs:
- *target-ref-checkout

- *dockerhub-auth-step
- name: Install NemoClaw
env:
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
NEMOCLAW_NON_INTERACTIVE: "1"
NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1"
run: bash install.sh --non-interactive --yes-i-accept-third-party-software
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.0.0
with:
node-version: 22
cache: npm

- name: Install root dependencies
run: npm ci --ignore-scripts

- name: Build CLI
run: npm run build:cli

- name: Install OpenShell CLI
run: env -u DOCKER_CONFIG -u DOCKERHUB_USERNAME -u DOCKERHUB_TOKEN -u NVIDIA_INFERENCE_API_KEY -u GITHUB_TOKEN bash scripts/install-openshell.sh

- name: Run double onboard E2E test
env:
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
NEMOCLAW_NON_INTERACTIVE: "1"
NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1"
run: |
Expand Down Expand Up @@ -2256,15 +2264,22 @@ jobs:
steps:
- *target-ref-checkout
- *dockerhub-auth-step
- name: Install NemoClaw
env:
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
NEMOCLAW_NON_INTERACTIVE: "1"
NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1"
run: bash install.sh --non-interactive --yes-i-accept-third-party-software
- name: Set up Node
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.0.0
with:
node-version: 22
cache: npm

- name: Install root dependencies
run: npm ci --ignore-scripts

- name: Build CLI
run: npm run build:cli

- name: Install OpenShell CLI
run: env -u DOCKER_CONFIG -u DOCKERHUB_USERNAME -u DOCKERHUB_TOKEN -u NVIDIA_INFERENCE_API_KEY -u GITHUB_TOKEN bash scripts/install-openshell.sh

- name: Run concurrent gateway ports E2E test
env:
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
run: |
[ -f "$HOME/.bashrc" ] && source "$HOME/.bashrc" 2>/dev/null || true
export NVM_DIR="${NVM_DIR:-$HOME/.nvm}"
Expand Down
1 change: 1 addition & 0 deletions biome.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"nemoclaw/package-lock.json",
"*.ts",
"**/*.ts",
"**/*.mts",
"bin/**/*.js",
"scripts/**/*.js",
"scripts/**/*.mjs",
Expand Down
22 changes: 7 additions & 15 deletions scripts/generate-openclaw-config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@ function buildOpenClawOtelConfig(env: Env): JsonObject | undefined {
throw new Error("NEMOCLAW_OPENCLAW_OTEL_ENDPOINT must not include credentials");
}

const serviceName = (env.NEMOCLAW_OPENCLAW_OTEL_SERVICE_NAME || DEFAULT_OPENCLAW_OTEL_SERVICE_NAME).trim();
const serviceName = (
env.NEMOCLAW_OPENCLAW_OTEL_SERVICE_NAME || DEFAULT_OPENCLAW_OTEL_SERVICE_NAME
).trim();
if (!serviceName) {
throw new Error("NEMOCLAW_OPENCLAW_OTEL_SERVICE_NAME must not be empty");
}
Expand Down Expand Up @@ -596,9 +598,7 @@ function validateExtraAgentTools(entry: JsonObject, label: string): JsonObject {
const value = tools[key];
if (value === undefined) continue;
if (!Array.isArray(value) || value.some((token) => typeof token !== "string" || !token)) {
throw new Error(
`${label}.tools.${key} must be an array of non-empty strings when present.`,
);
throw new Error(`${label}.tools.${key} must be an array of non-empty strings when present.`);
}
}
if (tools.profile !== undefined && typeof tools.profile !== "string") {
Expand All @@ -617,9 +617,7 @@ function validateExtraAgentSubagents(entry: JsonObject, label: string): JsonObje
rejectUnknownKeys(subagents, ALLOWED_SUBAGENTS_KEYS, `${label}.subagents`);
const depth = subagents.maxSpawnDepth;
if (typeof depth !== "number" || !Number.isInteger(depth) || depth < 0) {
throw new Error(
`${label}.subagents.maxSpawnDepth must be a non-negative integer.`,
);
throw new Error(`${label}.subagents.maxSpawnDepth must be a non-negative integer.`);
}
return pickAllowed(subagents, ALLOWED_SUBAGENTS_KEYS);
}
Expand All @@ -629,9 +627,7 @@ function validateExtraAgents(value: unknown): JsonObject[] {
return [];
}
if (!Array.isArray(value)) {
throw new Error(
"NEMOCLAW_EXTRA_AGENTS_JSON must decode to a JSON array of agent objects",
);
throw new Error("NEMOCLAW_EXTRA_AGENTS_JSON must decode to a JSON array of agent objects");
}
const seenIds = new Set<string>([MAIN_AGENT_ID]);
return value.map((entry, index) => {
Expand Down Expand Up @@ -661,9 +657,7 @@ function validateExtraAgents(value: unknown): JsonObject[] {
throw new Error(`${label}.${pathKey} must be a non-empty string`);
}
if (!isAbsolute(pathValue)) {
throw new Error(
`${label}.${pathKey} must be an absolute path, got "${pathValue}"`,
);
throw new Error(`${label}.${pathKey} must be an absolute path, got "${pathValue}"`);
}
const expected = expectedAgentPath(pathKey, id);
if (resolve(pathValue) !== expected) {
Expand Down Expand Up @@ -830,7 +824,6 @@ export function buildConfig(env: Env = process.env): JsonObject {
inferenceCompat.supportsUsageInStreaming ??= true;
}


const normalizedUrl = normalizeUrlForParse(chatUiUrl);
const parsed = parseUrl(normalizedUrl);
const loopbackOrigin = `http://127.0.0.1:${gatewayPort}`;
Expand Down Expand Up @@ -964,7 +957,6 @@ export function buildConfig(env: Env = process.env): JsonObject {
};
}


return config;
}

Expand Down
2 changes: 1 addition & 1 deletion scripts/patch-openclaw-slack-deny-feedback.mts
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ function buildHelperSource(): string {
"\t\t// Only fall back to a DM when Slack definitively did not deliver the",
"\t\t// ephemeral. Ambiguous failures (network/HTTP, timeout, service errors)",
"\t\t// may have been accepted, so a DM there could double-notify the sender.",
'\t\tconst ephemeralErrorCode = ephemeralError?.data?.error ?? ephemeralError?.code;',
"\t\tconst ephemeralErrorCode = ephemeralError?.data?.error ?? ephemeralError?.code;",
'\t\tctx?.logger?.warn?.({ err: ephemeralError, channel, code: ephemeralErrorCode }, "nemoclaw: slack denial ephemeral feedback failed (#4752)");',
'\t\tconst nonDeliveryCodes = ["user_not_in_channel", "not_in_channel", "channel_not_found", "cannot_reply_to_message", "is_archived", "messages_tab_disabled"];',
"\t\tif (!nonDeliveryCodes.includes(ephemeralErrorCode)) return;",
Expand Down
Loading
Loading