Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e16a89b
test(e2e): add inference adapter fixture
deepujain Jul 12, 2026
fcd21e1
test(e2e): map Hermes adapter parity coverage
prekshivyas Jul 12, 2026
bfe48ab
test(e2e): bound mock inference requests
prekshivyas Jul 12, 2026
66caf7a
test(e2e): keep Hermes inference adapter-owned
prekshivyas Jul 12, 2026
3bdc09f
test(e2e): exempt adapter-owned inference mode
prekshivyas Jul 12, 2026
bfb019b
fix(e2e): isolate inference adapter trust
prekshivyas Jul 12, 2026
42fcaf9
test(e2e): document inference adapter migration
prekshivyas Jul 12, 2026
129ffb1
test(e2e): simplify inference adapter requests
deepujain Jul 12, 2026
1295e49
Merge remote-tracking branch 'upstream/main' into codex/pr-6672-curre…
prekshivyas Jul 12, 2026
d3e122a
fix(e2e): separate mock credential exposure and prove inference route…
prekshivyas Jul 13, 2026
17a9c98
fix(e2e): resolve mock-parity merge conflict for hermes-e2e entry
prekshivyas Jul 13, 2026
e89290e
merge(main): resolve mock-parity hermes-e2e fast array conflict
prekshivyas Jul 13, 2026
6141995
Merge branch 'main' into test/5745-e2e-inference-adapter
prekshivyas Jul 13, 2026
7f4b560
Merge remote-tracking branch 'origin/main' into fix/6672-cjagwani-p1s
prekshivyas Jul 14, 2026
51d4309
test(e2e): make planner schema fixture portable
prekshivyas Jul 14, 2026
650edaf
test(e2e): cover provider-backed adapter requests
prekshivyas Jul 14, 2026
d9e02c1
fix(e2e): keep live key out of PR checkouts
prekshivyas Jul 14, 2026
3ca03ac
test(e2e): prove unrelated egress stays denied
prekshivyas Jul 14, 2026
be24cdf
test(e2e): accept curl policy denial variants
prekshivyas Jul 14, 2026
d137277
Merge remote-tracking branch 'origin/main' into fix/6672-cjagwani-p1s
prekshivyas Jul 14, 2026
fb8452c
Merge branch 'main' into test/5745-e2e-inference-adapter
prekshivyas Jul 14, 2026
4e6aad2
Merge branch 'main' into test/5745-e2e-inference-adapter
cv Jul 14, 2026
3d6d126
test(e2e): reconcile inference adapter with main
prekshivyas Jul 14, 2026
9fc648e
test(e2e): keep secret sentinel cleanup linear
prekshivyas Jul 14, 2026
6e9c376
Merge remote-tracking branch 'origin/main' into fix/6672-cjagwani-p1s
prekshivyas Jul 14, 2026
18ac7e9
test(e2e): keep workflow guard linear
prekshivyas Jul 14, 2026
9c230ca
Merge branch 'main' into test/5745-e2e-inference-adapter
prekshivyas Jul 15, 2026
12008a0
Merge branch 'main' into test/5745-e2e-inference-adapter
cv Jul 15, 2026
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
18 changes: 16 additions & 2 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ on:
required: false
default: ""
type: string
inference_mode:
description: "Inference adapter mode for compatible Vitest E2E jobs: mock, internal-nvidia, or public-nvidia."
required: false
default: "mock"
type: choice
options:
- mock
- internal-nvidia
- public-nvidia
allow_jetson_runner_queue:
description: "Repository administrators only: before setting true for jetson-nvmap-gpu, confirm an online Jetson runner in the authoritative NVIDIA/NemoClaw Settings -> Actions -> Runners inventory; queued jobs do not honor timeout-minutes before assignment."
required: false
Expand Down Expand Up @@ -134,10 +143,15 @@ jobs:
- id: matrix
name: Generate E2E target matrix
env:
INFERENCE_MODE: ${{ inputs.inference_mode || 'mock' }}
JOBS: ${{ inputs.jobs }}
TARGETS: ${{ inputs.targets }}
run: |
set -euo pipefail
case "${INFERENCE_MODE}" in
mock|internal-nvidia|public-nvidia) ;;
*) echo "::error::Invalid inference_mode: ${INFERENCE_MODE}" >&2; exit 1 ;;
esac
if [ -n "${JOBS}" ] && [ -n "${TARGETS}" ]; then
echo "::error::Use either targets or jobs, not both." >&2
exit 1
Expand Down Expand Up @@ -1674,7 +1688,7 @@ jobs:
E2E_ARTIFACT_DIR: ${{ github.workspace }}/e2e-artifacts/live/hermes-e2e
NEMOCLAW_CLI_BIN: ${{ github.workspace }}/bin/nemoclaw.js
NEMOCLAW_RUN_LIVE_E2E: "1"
NEMOCLAW_E2E_USE_HOSTED_INFERENCE: "1"
NEMOCLAW_E2E_INFERENCE_MODE: ${{ inputs.inference_mode || 'mock' }}
NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1"
NEMOCLAW_AGENT: hermes
NEMOCLAW_NON_INTERACTIVE: "1"
Expand All @@ -1694,7 +1708,7 @@ jobs:

- name: Run Hermes live Vitest test
env:
NVIDIA_INFERENCE_API_KEY: ${{ secrets.NVIDIA_INFERENCE_API_KEY }}
NVIDIA_INFERENCE_API_KEY: ${{ github.repository == 'NVIDIA/NemoClaw' && github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch' && inputs.checkout_sha == '' && (inputs.inference_mode || 'mock') != 'mock' && secrets.NVIDIA_INFERENCE_API_KEY || '' }}
run: |
set -euo pipefail
npx vitest run --project e2e-live \
Expand Down
10 changes: 10 additions & 0 deletions test/e2e/fixtures/e2e-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
StateClient,
} from "./clients/index.ts";
import { DockerPrerequisite, DockerProbe } from "./docker-probe.ts";
import { createE2EInferenceAdapter, type E2EInferenceAdapter } from "./inference-adapter.ts";
import {
EnvironmentPhaseFixture,
LifecyclePhaseFixture,
Expand All @@ -33,6 +34,7 @@ export interface E2ETargetFixtures {
gateway: GatewayClient;
sandbox: SandboxClient;
provider: ProviderClient;
inference: E2EInferenceAdapter;
state: StateClient;
environment: EnvironmentPhaseFixture;
onboard: OnboardingPhaseFixture;
Expand Down Expand Up @@ -95,6 +97,14 @@ export const test = base.extend<E2ETargetFixtures>({
provider: async ({ shellProbe }, use) => {
await use(new ProviderClient(shellProbe));
},
inference: async ({ artifacts, provider, secrets }, use) => {
const inference = await createE2EInferenceAdapter({ artifacts, provider, secrets });
try {
await use(inference);
} finally {
await inference.close();
}
},
state: async ({}, use) => {
await use(new StateClient());
},
Expand Down
18 changes: 17 additions & 1 deletion test/e2e/fixtures/fake-openai-compatible.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export interface FakeOpenAiCompatibleServer {
readonly baseUrl: string;
readonly logFile: string;
readonly requestsFile: string;
environmentKeys(): readonly string[];
requests(): readonly FakeOpenAiCompatibleRequest[];
close(): Promise<void>;
}
Expand Down Expand Up @@ -119,19 +120,33 @@ function parseRequests(requestsFile: string): FakeOpenAiCompatibleRequest[] {
}
}

function parseEnvironmentKeys(environmentFile: string): string[] {
try {
const parsed = JSON.parse(fs.readFileSync(environmentFile, "utf8")) as unknown;
return Array.isArray(parsed)
? parsed.filter((value): value is string => typeof value === "string")
: [];
} catch {
return [];
}
}

export async function startFakeOpenAiCompatibleServer(
options: FakeOpenAiCompatibleServerOptions = {},
): Promise<FakeOpenAiCompatibleServer> {
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-fake-openai-"));
const environmentFile = path.join(tmpDir, "environment-keys.json");
const portFile = path.join(tmpDir, "port");
const logFile = path.join(tmpDir, "server.log");
const requestsFile = path.join(tmpDir, "requests.jsonl");
const host = options.host ?? "127.0.0.1";
const child = spawn(process.execPath, ["--experimental-strip-types", SERVER_SCRIPT], {
env: {
...process.env,
PATH: process.env.PATH ?? "",
HOME: process.env.HOME ?? "",
NEMOCLAW_FAKE_OPENAI_API_KEY: options.apiKey ?? "",
NEMOCLAW_FAKE_OPENAI_CHAT_CONTENT: options.chatContent ?? "ok",
NEMOCLAW_FAKE_OPENAI_ENVIRONMENT_FILE: environmentFile,
NEMOCLAW_FAKE_OPENAI_FORBIDDEN_MARKERS: JSON.stringify(options.forbiddenMarkers ?? []),
NEMOCLAW_FAKE_OPENAI_HOST: host,
NEMOCLAW_FAKE_OPENAI_LOG_FILE: logFile,
Expand Down Expand Up @@ -162,6 +177,7 @@ export async function startFakeOpenAiCompatibleServer(
baseUrl: `http://${formatHttpHost(publicHost)}:${port}/v1`,
logFile,
requestsFile,
environmentKeys: () => parseEnvironmentKeys(environmentFile),
requests: () => parseRequests(requestsFile),
close: async () => {
child.kill("SIGTERM");
Expand Down
Loading
Loading