From 1e6d73fdb5c4f82c9e7c546a7d88a83afc158ce2 Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Wed, 15 Jul 2026 11:26:55 +0800 Subject: [PATCH] fix(e2e): restore shellctl external runtime (#38968) --- .github/workflows/post-merge.yml | 1 + e2e/features/agent-v2/AGENTS.md | 2 +- e2e/scripts/common.ts | 1 + e2e/scripts/run-cucumber.ts | 2 +- e2e/scripts/setup.ts | 5 +++-- 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/post-merge.yml b/.github/workflows/post-merge.yml index 491f65c28ee..60e15c25e13 100644 --- a/.github/workflows/post-merge.yml +++ b/.github/workflows/post-merge.yml @@ -38,6 +38,7 @@ jobs: - '.github/workflows/web-e2e.yml' - '.github/actions/setup-web/**' - 'dify-agent/**' + - 'dify-agent-runtime/**' - 'api/clients/agent_backend/**' - 'api/core/app/apps/agent_app/**' - 'api/core/workflow/nodes/agent_v2/**' diff --git a/e2e/features/agent-v2/AGENTS.md b/e2e/features/agent-v2/AGENTS.md index 5c45561fafb..26ab4bd1ae8 100644 --- a/e2e/features/agent-v2/AGENTS.md +++ b/e2e/features/agent-v2/AGENTS.md @@ -164,7 +164,7 @@ Agent Builder preflight is read-only. It checks long-lived seed resources and re Treat preseeded Agent Builder resources as environment contracts. Preflight can report that a stable model, dataset, Skill, Tool credential, fixed Agent, published Web app, or workflow reference is missing, inactive, not indexed, or drifted, but it must not repair that drift during a scenario. Seed scripts, CI bootstrap, or the documented environment maintenance flow own creating and keeping those resources valid. -Use `the Agent v2 runtime backend is available` before scenarios tagged `@agent-backend-runtime`. The step checks the standalone `dify-agent` run server through `E2E_AGENT_BACKEND_URL`, `AGENT_BACKEND_BASE_URL`, or the default `http://127.0.0.1:5050` when `E2E_START_AGENT_BACKEND=1`. The E2E runner starts this service with `uv run --project dify-agent --extra server uvicorn dify_agent.server.app:app --host 127.0.0.1 --port 5050` only when `E2E_START_AGENT_BACKEND=1` is explicit. Because Agent App runtime always carries the `dify.config` layer and that layer depends on `dify.shell`, the same runner path also starts the `dify-agent/docker/local-sandbox` shellctl container on `E2E_SHELLCTL_PORT` (default `5004`) and injects `DIFY_AGENT_SHELLCTL_ENTRYPOINT` into the Agent backend. Missing or unreachable runtime backend or shellctl sandbox should be reported as a blocked precondition, not discovered later as a `/build-chat/finalize` 400 or Web app response timeout. +Use `the Agent v2 runtime backend is available` before scenarios tagged `@agent-backend-runtime`. The step checks the standalone `dify-agent` run server through `E2E_AGENT_BACKEND_URL`, `AGENT_BACKEND_BASE_URL`, or the default `http://127.0.0.1:5050` when `E2E_START_AGENT_BACKEND=1`. The E2E runner starts this service with `uv run --project dify-agent --extra server uvicorn dify_agent.server.app:app --host 127.0.0.1 --port 5050` only when `E2E_START_AGENT_BACKEND=1` is explicit. Because Agent App runtime always carries the `dify.config` layer and that layer depends on `dify.shell`, the same runner path also starts the `dify-agent-runtime/docker` shellctl container on `E2E_SHELLCTL_PORT` (default `5004`) and injects `DIFY_AGENT_SHELLCTL_ENTRYPOINT` into the Agent backend. Missing or unreachable runtime backend or shellctl sandbox should be reported as a blocked precondition, not discovered later as a `/build-chat/finalize` 400 or Web app response timeout. Use `the Agent Builder stable chat model is available` before scenarios that need a real Agent Soul model configuration. This includes true runtime scenarios, model-backed build-mode assertions, and Workflow Agent v2 node setup because the backend rejects Agent nodes without model config. Do not add the model preflight to pure navigation or identity checks unless the setup API itself requires model config. `E2E_STABLE_MODEL_PROVIDER`, `E2E_STABLE_MODEL_NAME`, and optional `E2E_STABLE_MODEL_TYPE` are selectors for a model already configured in the workspace; they are not provider credentials. The step defaults to `openai` / `gpt-5-nano` / `llm`, verifies the selected model is present and `active` through `/console/api/workspaces/current/models/model-types/{type}`, then stores it on `DifyWorld.agentBuilder.preflight.stableModel`. diff --git a/e2e/scripts/common.ts b/e2e/scripts/common.ts index d37cddd71d6..f0969f06543 100644 --- a/e2e/scripts/common.ts +++ b/e2e/scripts/common.ts @@ -33,6 +33,7 @@ export const rootDir = fileURLToPath(new URL('../..', import.meta.url)) export const e2eDir = path.join(rootDir, 'e2e') export const apiDir = path.join(rootDir, 'api') export const difyAgentDir = path.join(rootDir, 'dify-agent') +export const difyAgentRuntimeDir = path.join(rootDir, 'dify-agent-runtime') export const dockerDir = path.join(rootDir, 'docker') export const webDir = path.join(rootDir, 'web') diff --git a/e2e/scripts/run-cucumber.ts b/e2e/scripts/run-cucumber.ts index fd58c6cf028..1b26926c53f 100644 --- a/e2e/scripts/run-cucumber.ts +++ b/e2e/scripts/run-cucumber.ts @@ -184,7 +184,7 @@ const main = async () => { try { const shellctlPort = process.env.E2E_SHELLCTL_PORT || '5004' await Promise.race([ - waitForUrl(`http://127.0.0.1:${shellctlPort}/openapi.json`, 180_000, 1_000), + waitForUrl(`http://127.0.0.1:${shellctlPort}/healthz`, 180_000, 1_000), waitForUnexpectedProcessExit(shellctlProcess, () => !waitingForShellctl), ]) } catch (error) { diff --git a/e2e/scripts/setup.ts b/e2e/scripts/setup.ts index 5302a75db7d..4bf42ca0a91 100644 --- a/e2e/scripts/setup.ts +++ b/e2e/scripts/setup.ts @@ -6,6 +6,7 @@ import { apiDir, apiEnvExampleFile, difyAgentDir, + difyAgentRuntimeDir, dockerDir, e2eDir, e2eWebEnvOverrides, @@ -376,12 +377,12 @@ const ensureShellctlSandboxImage = async () => { args: [ 'build', '-f', - path.join(difyAgentDir, 'docker', 'local-sandbox', 'Dockerfile'), + path.join(difyAgentRuntimeDir, 'docker', 'Dockerfile'), '-t', shellctlImage, '.', ], - cwd: difyAgentDir, + cwd: difyAgentRuntimeDir, }) }