diff --git a/.github/workflows/harness-sidecar-release-gate.yaml b/.github/workflows/harness-sidecar-release-gate.yaml new file mode 100644 index 000000000..518125f3d --- /dev/null +++ b/.github/workflows/harness-sidecar-release-gate.yaml @@ -0,0 +1,82 @@ +name: Harness Sidecar Release Gate + +on: + workflow_call: + push: + paths: + - '.github/workflows/harness-sidecar-release-gate.yaml' + - 'frontend/**' + - 'tests/cli/test_generated_agent_harness_sidecar.py' + - 'tests/cli/test_generated_agent_backend_codegen_extended.py' + - 'tests/cli/test_studio_rbac.py' + - 'tests/extensions/harness/**' + - 'tests/integrations/agentkit/test_app.py' + - 'veadk/cli/generated_agent_codegen.py' + - 'veadk/cli/cli_frontend.py' + - 'veadk/extensions/harness/**' + - 'veadk/integrations/agentkit/app.py' + - 'pyproject.toml' + pull_request: + paths: + - '.github/workflows/harness-sidecar-release-gate.yaml' + - 'frontend/**' + - 'tests/cli/test_generated_agent_harness_sidecar.py' + - 'tests/cli/test_generated_agent_backend_codegen_extended.py' + - 'tests/cli/test_studio_rbac.py' + - 'tests/extensions/harness/**' + - 'tests/integrations/agentkit/test_app.py' + - 'veadk/cli/generated_agent_codegen.py' + - 'veadk/cli/cli_frontend.py' + - 'veadk/extensions/harness/**' + - 'veadk/integrations/agentkit/app.py' + - 'pyproject.toml' + +permissions: + contents: read + +jobs: + gate: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + + - uses: actions/setup-node@v4 + with: + node-version: 22.17.0 + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Install Python test dependencies + run: python -m pip install -e '.[dev]' + + - name: Enforce public Python Sidecar coverage above 90 percent + run: | + python -m pytest -q \ + tests/extensions/harness/test_studio_sidecar.py \ + tests/extensions/harness/test_sidecar_public_api.py \ + tests/extensions/harness/test_extension.py \ + tests/cli/test_generated_agent_harness_sidecar.py \ + tests/integrations/agentkit/test_app.py \ + tests/cli/test_studio_rbac.py::test_sidecar_deployment_uses_agentkit_cli_structured_release \ + tests/cli/test_generated_agent_backend_codegen_extended.py::test_generated_agent_sidecar_debug_uses_runtime_apig_and_active_plan \ + --cov=. --cov-branch --cov-report= --cov-fail-under=0 + python -m coverage report \ + --include='*/veadk/extensions/harness/sidecar.py' \ + --fail-under=91 --show-missing + + - name: Install frontend dependencies + working-directory: frontend + run: npm ci --ignore-scripts + + - name: Enforce public Studio Sidecar coverage above 90 percent + working-directory: frontend + run: npm run test:harness-sidecar-coverage + + - name: Verify frontend Sidecar integration + working-directory: frontend + run: npm test diff --git a/.github/workflows/publish-studio-release.yaml b/.github/workflows/publish-studio-release.yaml index 0dc4450c1..ec7c77383 100644 --- a/.github/workflows/publish-studio-release.yaml +++ b/.github/workflows/publish-studio-release.yaml @@ -39,10 +39,17 @@ concurrency: cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: + harness-sidecar-release-gate: + if: >- + github.repository == 'volcengine/veadk-python' && + (github.event_name == 'pull_request' || github.ref == 'refs/heads/main') + uses: ./.github/workflows/harness-sidecar-release-gate.yaml + verify: if: >- github.repository == 'volcengine/veadk-python' && (github.event_name == 'pull_request' || github.ref == 'refs/heads/main') + needs: harness-sidecar-release-gate runs-on: ubuntu-latest timeout-minutes: 45 diff --git a/.github/workflows/publish-tag-to-pypi.yaml b/.github/workflows/publish-tag-to-pypi.yaml index d820bfc01..43825078c 100644 --- a/.github/workflows/publish-tag-to-pypi.yaml +++ b/.github/workflows/publish-tag-to-pypi.yaml @@ -5,7 +5,11 @@ on: workflow_dispatch: jobs: + harness-sidecar-release-gate: + uses: ./.github/workflows/harness-sidecar-release-gate.yaml + build: + needs: harness-sidecar-release-gate runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/push-preview-image-to-vecr.yaml b/.github/workflows/push-preview-image-to-vecr.yaml index fec65e142..6f52cb72d 100644 --- a/.github/workflows/push-preview-image-to-vecr.yaml +++ b/.github/workflows/push-preview-image-to-vecr.yaml @@ -24,7 +24,12 @@ on: workflow_dispatch: jobs: + harness-sidecar-release-gate: + if: github.repository == 'volcengine/veadk-python' + uses: ./.github/workflows/harness-sidecar-release-gate.yaml + build-and-push: + needs: harness-sidecar-release-gate runs-on: ubuntu-latest # To avoid forked repo execute this workflow @@ -64,4 +69,4 @@ jobs: --push \ --cache-from=type=gha \ --cache-to=type=gha,mode=max \ - . \ No newline at end of file + . diff --git a/.github/workflows/push-stable-image-to-vecr.yaml b/.github/workflows/push-stable-image-to-vecr.yaml index a30e1b65f..e30e8cceb 100644 --- a/.github/workflows/push-stable-image-to-vecr.yaml +++ b/.github/workflows/push-stable-image-to-vecr.yaml @@ -22,7 +22,12 @@ on: workflow_dispatch: jobs: + harness-sidecar-release-gate: + if: github.repository == 'volcengine/veadk-python' + uses: ./.github/workflows/harness-sidecar-release-gate.yaml + build-and-push: + needs: harness-sidecar-release-gate runs-on: ubuntu-latest permissions: contents: read @@ -67,4 +72,4 @@ jobs: --push \ --cache-from=type=gha \ --cache-to=type=gha,mode=max \ - . \ No newline at end of file + . diff --git a/.gitignore b/.gitignore index d8d1ecd12..2f08d84b3 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ htmlcov/ .cache nosetests.xml coverage.xml +coverage/ *.cover *.py,cover .hypothesis/ diff --git a/frontend/README.md b/frontend/README.md index 9df34b293..e58b1b50f 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -112,9 +112,15 @@ server that `veadk frontend` launches — no separate backend. instead of credentials. Long descriptions, names, component summaries, IDs, and environment values stay inside the scrollable panel. - **Custom-agent workbench**: configure an agent with a rich Markdown - system-prompt editor (including heading and list shortcuts), then debug with - expandable, copyable runner error details, per-result Trace inspection, and - review. In-progress drafts are stored only in the current browser and scoped + system-prompt editor (including heading and list shortcuts), choose Harness + Sidecar optimizations, then debug with expandable, copyable runner error + details and per-result Trace inspection before release. The workbench order is + `架构` → `优化` → `调试` → `发布`. On the optimization page, `自定义` appears + first and starts with no components, while `运维场景` applies the `ops` + component combination. Component checkboxes remain editable and an empty + selection keeps Sidecar disabled. Published Agent details display the saved + Sidecar scenario and selected components as read-only information. In-progress drafts are stored only in the + current browser and scoped to the signed-in user. MCP tokens are converted to Runtime environment variables: generated source retains only the `${ENV_NAME}` reference, while YAML and browser drafts preserve the corresponding environment value. diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 66e6c4299..3a582e707 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -36,10 +36,12 @@ "@types/react": "^19.2.18", "@types/react-dom": "^19.2.4", "@vitejs/plugin-react": "^4.3.4", + "@vitest/coverage-v8": "^4.1.9", "esbuild": "^0.21.3", "tailwindcss": "^4.3.3", "typescript": "^5.6.3", - "vite": "^5.4.11" + "vite": "^5.4.11", + "vitest": "^4.1.9" } }, "node_modules/@babel/code-frame": { @@ -333,6 +335,16 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@codemirror/autocomplete": { "version": "6.20.3", "resolved": "https://registry.npmmirror.com/@codemirror/autocomplete/-/autocomplete-6.20.3.tgz", @@ -1063,6 +1075,24 @@ "node": ">=12" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", @@ -1080,6 +1110,24 @@ "node": ">=12" } }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", @@ -1097,6 +1145,24 @@ "node": ">=12" } }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", @@ -2047,6 +2113,16 @@ "tailwindcss": "^4.0.10" } }, + "node_modules/@oxc-project/types": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.143.0.tgz", + "integrity": "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, "node_modules/@preact/signals-core": { "version": "1.14.4", "resolved": "https://registry.npmmirror.com/@preact/signals-core/-/signals-core-1.14.4.tgz", @@ -3568,6 +3644,244 @@ "integrity": "sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==", "license": "MIT" }, + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.3.tgz", + "integrity": "sha512-zrJtHDcaZJ1Fp7xf4hNl+7seH9Cn/N5TwLYkhgXREtBwAd/jaqW3uqeHxpDugJLVICWg4eW44kOQEGJ1r6jCGw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.3.tgz", + "integrity": "sha512-ieIiibVCp0tX7TLu2cafoNPv8wJyYi01ekXpbf8q2j7F4rGAhhXb/eQh7ge9DRBY78GwmRQtvjZDux7EDbA8kA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.3.tgz", + "integrity": "sha512-Zh9tCon19eDXJoihx0rqKhMUlMYqzwj3aPsSuHmI4RWZh62dWUL+DJN4C5YQya5TcQBJU/Fe8+rY0jhXTQITqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.3.tgz", + "integrity": "sha512-nGbJWewA1wrXXZiQhjAT5rhibGfns5ZNkDVqxsO6zJ3f3YvpoDNNmGMSbbhLuXKjNScaBJVOAboztAWVespQMg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.3.tgz", + "integrity": "sha512-QNniJr5Kml0kDEB98jiDOJjXNroxIIi0IXIbdYzY26Xt1pVbeP62+KnoIZLwirOymX/0jDk/2gI/bNUv7A7OIw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.3.tgz", + "integrity": "sha512-TkqEAcmmvH3I/q4114NB4RVt6241Dao48pF45uLcFGrwAaIn0iITgTAKP/dLjbN0R4buJjGb91+UHSoFmpgIWw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.3.tgz", + "integrity": "sha512-NHqjnxpsndf4MPymxteFAWHHfkTL8HjWh1KB7z23ofZ6QO2euONuxDXjat69dKZRALnGypg8k8SsK8vZJoXv1Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.3.tgz", + "integrity": "sha512-6tbrbwfz5GB9DQ4Jwo6hy9v+vR31xZlvzZ6n5Xut6Hhx5PvrA9q/HsK8KMaYQp063iqZGXwNvZtYNLD7EM/x0w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.3.tgz", + "integrity": "sha512-oyuXxXmoZHjXC917IAPFAAv4wWAa0cM9afk8nx1+9/jNNOX1uPf8yDA6p7G0RypOfw/X0PQt5IfoquY1um+zSg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.3.tgz", + "integrity": "sha512-TytMwF2KVGqP2tgd0I1OY0PAv78dZRAYcF5ssDzjM34SUXCED3uXvSd5+lHoC0bTD6eEdFz7LdQNCO1y0oVk9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.3.tgz", + "integrity": "sha512-/E9m3qstrJFVPoULV25mVQblSNExY2+kBsYe4sy0Tn0yOOgJ8wZbZt3KnRbF/XeU2Gl1STKUQnDNTqhIE5MD4A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.3.tgz", + "integrity": "sha512-Kr0OcsoQI816i6HOl3vFHpd1K0eZyh76zgfj4c1nTyaTsd5r2Mj1lwM4R90y/qaCfmTn9eHy0SKwi98eitRxug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.3.tgz", + "integrity": "sha512-hOtMwTqnME+/gJcH/PCZ0wn0zPUjiWOgkHpxbSJpfGKMezHltx1S7/k1SitzVa7Ww2cqrDDaFbZEhcJZO8o+Jw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.3.tgz", + "integrity": "sha512-ekcqMMkI2PlhYnfzQnB/cEdYUVVJViWvoUyLrbzgDoi3Snfc1mVBwdnc306ufA5ejy8JSPjT2RlW1nQSjW7efg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, "node_modules/@rolldown/pluginutils": { "version": "1.0.0-beta.27", "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", @@ -3925,6 +4239,13 @@ "win32" ] }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, "node_modules/@tailwindcss/node": { "version": "4.3.3", "resolved": "https://registry.npmmirror.com/@tailwindcss/node/-/node-4.3.3.tgz", @@ -4148,25 +4469,91 @@ "node": ">=14.0.0" } }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", - "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", - "cpu": [ - "arm64" - ], + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", "dev": true, + "inBundle": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" } }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.3", + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", "resolved": "https://registry.npmmirror.com/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", "cpu": [ @@ -4242,6 +4629,17 @@ "@babel/types": "^7.28.2" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/d3-color": { "version": "3.1.3", "resolved": "https://registry.npmmirror.com/@types/d3-color/-/d3-color-3.1.3.tgz", @@ -4300,6 +4698,13 @@ "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", @@ -4462,6 +4867,123 @@ "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" } }, + "node_modules/@vitest/coverage-v8": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", + "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.10", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.1.10", + "vitest": "4.1.10" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@xyflow/react": { "version": "12.11.0", "resolved": "https://registry.npmmirror.com/@xyflow/react/-/react-12.11.0.tgz", @@ -4543,6 +5065,35 @@ "node": ">=10" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.5.tgz", + "integrity": "sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", + "dev": true, + "license": "MIT" + }, "node_modules/bail": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/bail/-/bail-2.0.2.tgz", @@ -4631,6 +5182,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/character-entities": { "version": "2.0.2", "resolved": "https://registry.npmmirror.com/character-entities/-/character-entities-2.0.2.tgz", @@ -4994,6 +5555,13 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, "node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz", @@ -5079,6 +5647,26 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", @@ -5098,6 +5686,24 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/format": { "version": "0.2.2", "resolved": "https://registry.npmmirror.com/format/-/format-0.2.2.tgz", @@ -5174,6 +5780,16 @@ "dev": true, "license": "ISC" }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/hast-util-from-dom": { "version": "5.0.1", "resolved": "https://registry.npmmirror.com/hast-util-from-dom/-/hast-util-from-dom-5.0.1.tgz", @@ -5401,6 +6017,13 @@ "integrity": "sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==", "license": "CC0-1.0" }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/html-to-image": { "version": "1.11.13", "resolved": "https://registry.npmmirror.com/html-to-image/-/html-to-image-1.11.13.tgz", @@ -5500,6 +6123,45 @@ "url": "https://github.com/sponsors/dmonad" } }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jiti": { "version": "2.7.0", "resolved": "https://registry.npmmirror.com/jiti/-/jiti-2.7.0.tgz", @@ -5976,6 +6638,47 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.4.tgz", + "integrity": "sha512-llBEhWm1SacoRwgHUoQJYtwp4PBLF4faQi5TCpIGyGs9n4y5+juI0tDgyKIfpqxckRHaHzouUEph3THklWh03w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/markdown-table": { "version": "3.0.4", "resolved": "https://registry.npmmirror.com/markdown-table/-/markdown-table-3.0.4.tgz", @@ -7196,9 +7899,9 @@ "license": "MIT" }, "node_modules/nanoid": { - "version": "3.3.12", - "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.12.tgz", - "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", "dev": true, "funding": [ { @@ -7233,6 +7936,20 @@ "node": ">=0.10.0" } }, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/parse-entities": { "version": "4.0.2", "resolved": "https://registry.npmmirror.com/parse-entities/-/parse-entities-4.0.2.tgz", @@ -7270,6 +7987,13 @@ "url": "https://github.com/inikulin/parse5?sponsor=1" } }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", @@ -7277,10 +8001,23 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/postcss": { - "version": "8.5.15", - "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.15.tgz", - "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", "dev": true, "funding": [ { @@ -7298,7 +8035,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.12", + "nanoid": "^3.3.17", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7824,8 +8561,48 @@ "url": "https://opencollective.com/unified" } }, - "node_modules/rollup": { - "version": "4.60.4", + "node_modules/rolldown": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.3.tgz", + "integrity": "sha512-rn9wpmxplLf7NLNyCk9FyWh3FM43DbY8jOzCdEPzH7uflhTftRbCEpqi6Ly2osgoU8OwObtmavMbWLaWy4LX7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@oxc-project/types": "=0.143.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm64": "1.2.3", + "@rolldown/binding-darwin-arm64": "1.2.3", + "@rolldown/binding-darwin-x64": "1.2.3", + "@rolldown/binding-freebsd-x64": "1.2.3", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.3", + "@rolldown/binding-linux-arm64-gnu": "1.2.3", + "@rolldown/binding-linux-arm64-musl": "1.2.3", + "@rolldown/binding-linux-ppc64-gnu": "1.2.3", + "@rolldown/binding-linux-s390x-gnu": "1.2.3", + "@rolldown/binding-linux-x64-gnu": "1.2.3", + "@rolldown/binding-linux-x64-musl": "1.2.3", + "@rolldown/binding-openharmony-arm64": "1.2.3", + "@rolldown/binding-win32-arm64-msvc": "1.2.3", + "@rolldown/binding-win32-x64-msvc": "1.2.3" + } + }, + "node_modules/rolldown/node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/rollup": { + "version": "4.60.4", "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.60.4.tgz", "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", "dev": true, @@ -7897,6 +8674,13 @@ "semver": "bin/semver.js" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", @@ -7917,6 +8701,20 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, "node_modules/stringify-entities": { "version": "4.0.4", "resolved": "https://registry.npmmirror.com/stringify-entities/-/stringify-entities-4.0.4.tgz", @@ -7955,6 +8753,19 @@ "inline-style-parser": "0.2.7" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tabbable": { "version": "6.5.0", "resolved": "https://registry.npmmirror.com/tabbable/-/tabbable-6.5.0.tgz", @@ -7981,6 +8792,50 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/trim-lines": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/trim-lines/-/trim-lines-3.0.1.tgz", @@ -8376,20 +9231,951 @@ } } }, - "node_modules/w3c-keyname": { - "version": "2.2.8", - "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz", - "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", - "license": "MIT" - }, - "node_modules/web-namespaces": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", - "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", + "dev": true, "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/vitest/node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" + } + }, + "node_modules/vitest/node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/vitest/node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/vitest/node_modules/vite": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.1.tgz", + "integrity": "sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.25", + "rolldown": "~1.2.1", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/w3c-keyname": { + "version": "2.2.8", + "resolved": "https://registry.npmmirror.com/w3c-keyname/-/w3c-keyname-2.2.8.tgz", + "integrity": "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==", + "license": "MIT" + }, + "node_modules/web-namespaces": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz", + "integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" } }, "node_modules/yallist": { diff --git a/frontend/package.json b/frontend/package.json index da02241d8..27aaa666e 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,6 +8,7 @@ "dev": "vite", "build": "tsc && vite build", "test": "node --test tests/*.test.mjs", + "test:harness-sidecar-coverage": "vitest run --coverage -c vitest.harness-sidecar.config.ts", "preview": "vite preview" }, "dependencies": { @@ -42,6 +43,8 @@ "esbuild": "^0.21.3", "tailwindcss": "^4.3.3", "typescript": "^5.6.3", - "vite": "^5.4.11" + "@vitest/coverage-v8": "^4.1.9", + "vite": "^5.4.11", + "vitest": "^4.1.9" } } diff --git a/frontend/src/adk/client.ts b/frontend/src/adk/client.ts index 43a0d2935..68242c1e8 100644 --- a/frontend/src/adk/client.ts +++ b/frontend/src/adk/client.ts @@ -18,7 +18,10 @@ import { TRANSFER_REQUEST_TIMEOUT_MS, } from "./timeout"; import type { AgentProject } from "../create/project"; -import type { AgentDraft, NetworkConfig } from "../create/types"; +import type { + AgentDraft, + NetworkConfig, +} from "../create/types"; import type { IssueFeedbackReport } from "./issueFeedback"; import { BYTEPLUS_DEFAULT_REGION, @@ -635,6 +638,11 @@ export function runtimeRegionCandidates(region?: string): string[] { ]; } +function selectedRuntimeRegionCandidates(region?: string): string[] { + const explicit = (region || "").trim(); + return explicit ? [explicit] : runtimeRegionCandidates(); +} + function cacheKey(...parts: Array): string { return parts.map((part) => String(part ?? "")).join("\u0001"); } @@ -848,7 +856,7 @@ export async function getAgentFeedbackCases(args: { if (!options.force && existing?.promise) return existing.promise; let lastError: Error | null = null; const promise = (async () => { - for (const region of runtimeRegionCandidates(args.region)) { + for (const region of selectedRuntimeRegionCandidates(args.region)) { const query = new URLSearchParams({ runtimeId: args.runtimeId, region, @@ -892,7 +900,7 @@ export async function getAutomaticEvaluationStatuses(args: { userId: string; }): Promise { let lastError: Error | null = null; - for (const region of runtimeRegionCandidates(args.region)) { + for (const region of selectedRuntimeRegionCandidates(args.region)) { const query = new URLSearchParams({ runtimeId: args.runtimeId, region, @@ -914,7 +922,7 @@ export async function getAgentOptimizations(args: { appName: string; }): Promise { let lastError: Error | null = null; - for (const region of runtimeRegionCandidates(args.region)) { + for (const region of selectedRuntimeRegionCandidates(args.region)) { const query = new URLSearchParams({ runtimeId: args.runtimeId, region, @@ -1052,7 +1060,7 @@ export async function deleteAgentFeedbackCases(args: { itemIds: string[]; }): Promise<{ deletedCount: number }> { let lastError: Error | null = null; - for (const region of runtimeRegionCandidates(args.region)) { + for (const region of selectedRuntimeRegionCandidates(args.region)) { const res = await apiFetch( "/web/evaluation/feedback-cases/delete", { @@ -2220,6 +2228,7 @@ export async function deployAgentkitProject( }; envs?: { key: string; value: string }[]; resources?: DeployResources; + harnessSidecar?: AgentDraft["harnessSidecar"]; }, ): Promise { const taskId = opts?.taskId; @@ -2262,6 +2271,7 @@ export async function deployAgentkitProject( im: opts?.im, envs: opts?.envs, resources: opts?.resources, + harnessSidecar: opts?.harnessSidecar, }), }, {}, @@ -3027,6 +3037,7 @@ export interface GeneratedAgentTestRun { runId: string; appName: string; expiresAt: number; + planHash?: string; } export async function generateAgentProject( diff --git a/frontend/src/create/CustomCreate.css b/frontend/src/create/CustomCreate.css index b856024a7..5f4f677b6 100644 --- a/frontend/src/create/CustomCreate.css +++ b/frontend/src/create/CustomCreate.css @@ -151,9 +151,9 @@ pointer-events: none; } .cw-workspace-progress { - width: min(132px, 40vw); + width: min(176px, 48vw); display: grid; - grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 5px; margin: 0 auto; } @@ -1403,6 +1403,83 @@ font-style: normal; font-weight: 550; } +.cw-ab-profile-field { + display: grid; + gap: 7px; + margin-bottom: 10px; +} +.cw-ab-profile-label { + color: hsl(var(--foreground)); + font-size: 12px; + font-weight: 600; +} +.cw-ab-profile-options { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 7px; +} +.cw-ab-profile-option { + min-width: 0; + min-height: 44px; + display: flex; + border: 1px solid hsl(var(--border)); + border-radius: 8px; + background: hsl(var(--background) / 0.82); + color: hsl(var(--foreground)); + transition: + border-color 150ms ease, + background-color 150ms ease, + box-shadow 150ms ease; +} +.cw-ab-profile-option:hover:not(.is-disabled) { + border-color: hsl(var(--foreground) / 0.2); + background: hsl(var(--secondary) / 0.28); +} +.cw-ab-profile-option.is-on { + border-color: hsl(var(--foreground) / 0.3); + background: hsl(var(--secondary) / 0.42); +} +.cw-ab-profile-option.is-disabled { + cursor: not-allowed; + opacity: 0.55; +} +.cw-ab-profile-option:focus-within { + outline: none; + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.28); +} +.cw-ab-profile-option > .flex { + align-self: stretch; + flex: 1; + min-width: 0; +} +.cw-ab-profile-control { + align-self: stretch; + width: 100%; + min-width: 0; + min-height: 100%; + padding: 7px 8px; + color: inherit; +} +.cw-ab-profile-copy { + min-width: 0; + display: grid; + gap: 2px; + text-align: left; +} +.cw-ab-profile-copy strong { + overflow: hidden; + font-size: 12px; + font-weight: 650; + text-overflow: ellipsis; + white-space: nowrap; +} +.cw-ab-profile-copy small, +.cw-ab-profile-help { + color: hsl(var(--muted-foreground)); + font-size: 10.5px; + font-weight: 400; + line-height: 1.4; +} .cw-ab-config input[type="text"], .cw-ab-config > label > input, .cw-ab-config > label > textarea { @@ -1436,20 +1513,200 @@ background: hsl(var(--background) / 0.82); color: hsl(var(--foreground)); font-size: 12.5px; - cursor: not-allowed; - opacity: 0.5; + cursor: pointer; } .cw-ab-optimization-checkbox > label { padding-left: 7px; color: inherit; font-size: inherit; } +.cw-ab-optimization-copy { + display: grid; + gap: 2px; +} +.cw-ab-optimization-copy strong { + font-size: 12.5px; + font-weight: 650; +} +.cw-ab-optimization-copy small { + color: hsl(var(--muted-foreground)); + font-size: 10.5px; + font-weight: 400; + line-height: 1.35; +} +.cw-ab-optimization-note, +.cw-ab-optimization-error { + display: block; + margin-top: 7px; + font-size: 11.5px; + line-height: 1.4; +} +.cw-ab-optimization-note { + color: hsl(var(--muted-foreground)); +} +.cw-ab-optimization-error { + color: hsl(var(--destructive)); +} .cw-ab-config > p { margin: 0; color: hsl(var(--muted-foreground)); font-size: 12.5px; line-height: 1.5; } + +/* ---------- Harness optimization workspace ---------- */ +.cw-optimize-workspace { + flex: 1; + min-width: 0; + min-height: 0; + overflow-y: auto; + display: flex; + align-items: flex-start; + justify-content: center; + padding: 4px 0 12px; +} +.cw-optimize-panel { + width: 100%; + display: grid; + gap: 32px; + padding: 4px 0 12px; +} +.cw-optimize-section { + min-width: 0; + display: grid; + gap: 12px; + margin: 0; + padding: 0; + border: 0; +} +.cw-optimize-section legend { + margin-bottom: 16px; + padding: 0; + color: hsl(var(--foreground)); + font-size: 13px; + font-weight: 650; +} +.cw-optimize-profile-options { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + grid-auto-rows: 1fr; + gap: 12px; + margin: -3px 0; + padding: 3px; +} +.cw-optimize-profile-option { + min-width: 0; + min-height: 88px; + height: 100%; + display: flex; + border: 1px solid hsl(var(--border)); + border-radius: 10px; + background: hsl(var(--background)); + color: hsl(var(--foreground)); + transition: + border-color 160ms ease, + background-color 160ms ease, + box-shadow 160ms ease; +} +.cw-optimize-profile-option:hover { + border-color: hsl(var(--foreground) / 0.2); + background: hsl(var(--muted) / 0.42); +} +.cw-optimize-profile-option.is-on { + border-color: hsl(var(--foreground) / 0.34); + background: hsl(var(--secondary) / 0.46); +} +.cw-optimize-profile-option:focus-within { + outline: none; + box-shadow: inset 0 0 0 1px hsl(var(--ring) / 0.28); +} +.cw-optimize-profile-option > .flex { + align-self: stretch; + flex: 1; + min-width: 0; +} +.cw-optimize-profile-control { + align-self: stretch; + width: 100%; + min-width: 0; + min-height: 100%; + padding: 14px 16px; + color: inherit; +} +.cw-optimize-profile-copy, +.cw-optimize-option-copy { + min-width: 0; + display: grid; + gap: 4px; + text-align: left; +} +.cw-optimize-profile-copy strong, +.cw-optimize-option-copy strong { + color: hsl(var(--foreground)); + font-size: 13px; + font-weight: 650; +} +.cw-optimize-profile-copy small, +.cw-optimize-option-copy small { + color: hsl(var(--muted-foreground)); + font-size: 12px; + font-weight: 400; + line-height: 1.5; +} +.cw-optimize-option-list { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 18px; +} +.cw-optimize-option-group { + min-width: 0; + display: grid; + gap: 8px; +} +.cw-optimize-option-group-title { + margin: 0; + color: hsl(var(--muted-foreground)); + font-size: 12px; + font-weight: 550; + line-height: 1.45; +} +.cw-optimize-option-group-items { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 10px; +} +.cw-optimize-option { + min-height: 68px; + display: inline-flex; + align-items: flex-start; + gap: 0; + padding: 12px 14px; + border: 1px solid hsl(var(--border)); + border-radius: 10px; + background: hsl(var(--muted) / 0.32); + color: hsl(var(--foreground)); + cursor: pointer; + transition: + border-color 160ms ease, + background-color 160ms ease, + box-shadow 160ms ease; +} +.cw-optimize-option:hover { + border-color: hsl(var(--foreground) / 0.2); + background: hsl(var(--muted) / 0.52); +} +.cw-optimize-option:has(input:checked) { + border-color: hsl(var(--foreground) / 0.3); + background: hsl(var(--secondary) / 0.5); +} +.cw-optimize-option:focus-within { + box-shadow: 0 0 0 2px hsl(var(--ring) / 0.28); +} +.cw-optimize-option > label { + align-items: flex-start; + padding-left: 10px; + color: inherit; +} .cw-ab-conversation { flex: 1; min-height: 0; @@ -4606,6 +4863,16 @@ .cw-ab-config { grid-template-columns: minmax(0, 1fr); } + .cw-ab-profile-options { + grid-template-columns: minmax(0, 1fr); + } + .cw-optimize-profile-options, + .cw-optimize-option-list { + grid-template-columns: minmax(0, 1fr); + } + .cw-optimize-panel { + padding: 4px 0 12px; + } .cw-ab-composer { grid-template-columns: minmax(0, 1fr); padding-bottom: 12px; diff --git a/frontend/src/create/CustomCreate.tsx b/frontend/src/create/CustomCreate.tsx index 562226c7e..fe30e8cf2 100644 --- a/frontend/src/create/CustomCreate.tsx +++ b/frontend/src/create/CustomCreate.tsx @@ -40,10 +40,24 @@ import { import { type CreateModeProps, type AgentDraft, + type HarnessSidecarOptionId, + type HarnessSidecarProfileId, type McpTool, type SelectedSkill, emptyDraft, } from "./types"; +import { + HARNESS_SIDECAR_OPTIONS, + HARNESS_SIDECAR_OPTION_GROUPS, + HARNESS_SIDECAR_PROFILES, + harnessIntentFromOptimizations, + harnessProfileDefaultOptimizations, + harnessSidecarOptionLabel, + harnessSidecarProfileLabel, + releaseDraftFromDebugVariant, + selectedHarnessProfile, + selectedHarnessOptimizations, +} from "./harnessSidecarOptions"; import { A2A_REGISTRY_DEFAULTS, A2A_REGISTRY_ENV, @@ -2610,7 +2624,7 @@ export function TreeNode({ type DebugPhase = "idle" | "starting" | "ready" | "sending" | "error"; -type WorkspaceMode = "build" | "validate" | "publish"; +type WorkspaceMode = "build" | "optimize" | "validate" | "publish"; interface DebugMessage { role: "user" | "assistant"; content: string; @@ -2624,7 +2638,6 @@ interface DebugVariant { modelName: string; description: string; instruction: string; - optimizations: string[]; configOpen: boolean; phase: DebugPhase; runtimeSnapshot: string; @@ -2795,31 +2808,23 @@ function debugSnapshotKey( function debugVariantSnapshot( draftSnapshot: string, - variant: Pick< - DebugVariant, - "modelName" | "description" | "instruction" | "optimizations" - >, + variant: Pick, ): string { return JSON.stringify({ draftSnapshot, modelName: variant.modelName, description: variant.description, instruction: variant.instruction, - optimizations: variant.optimizations, }); } function debugVariantConfigurationKey( - variant: Pick< - DebugVariant, - "modelName" | "description" | "instruction" | "optimizations" - >, + variant: Pick, ): string { return JSON.stringify({ modelName: variant.modelName.trim(), description: variant.description.trim(), instruction: variant.instruction.trim(), - optimizations: variant.optimizations, }); } @@ -2832,7 +2837,7 @@ function DebugComparisonWorkspace({ onInput, onSend, onStartVariant, - onDeployVariant, + onUseVariant, onAddVariant, onRemoveVariant, onToggleConfig, @@ -2848,7 +2853,7 @@ function DebugComparisonWorkspace({ onInput: (v: string) => void; onSend: () => void; onStartVariant: (id: string) => void; - onDeployVariant: (id: string) => void; + onUseVariant: (id: string) => void; onAddVariant: () => void; onRemoveVariant: (id: string) => void; onToggleConfig: (id: string) => void; @@ -2917,7 +2922,9 @@ function DebugComparisonWorkspace({ (message) => message.role === "assistant", ); const startDisabled = - busy || variant.configOpen || configurationUnavailable; + busy || + variant.configOpen || + configurationUnavailable; const disabledReason = !modelName ? "请先选择模型" : !description @@ -3071,9 +3078,9 @@ function DebugComparisonWorkspace({ type="button" className="cw-ab-deploy" disabled={busy || !modelName} - onClick={() => onDeployVariant(variant.id)} + onClick={() => onUseVariant(variant.id)} > - 部署该配置 + 使用该配置 @@ -3173,25 +3180,6 @@ function DebugComparisonWorkspace({ } /> -
- - 优化选项 - 待开放 - -
- {DEBUG_OPTIMIZATIONS.map((item) => ( - - ))} -
-

设置完成后返回正面,再启动当前测试环境。

@@ -3253,42 +3241,121 @@ function DebugComparisonWorkspace({ ); } +function HarnessOptimizationWorkspace({ + profile, + optimizations, + onProfileChange, + onOptimizationChange, +}: { + profile: HarnessSidecarProfileId; + optimizations: HarnessSidecarOptionId[]; + onProfileChange: (profile: HarnessSidecarProfileId) => void; + onOptimizationChange: ( + optionId: HarnessSidecarOptionId, + selected: boolean, + ) => void; +}) { + return ( +
+
+
+ 优化场景 + + className="cw-optimize-profile-options" + aria-label="优化场景" + value={profile} + onChange={onProfileChange} + > + {HARNESS_SIDECAR_PROFILES.map((item) => ( +
+ + + {item.displayName} + {item.description} + + +
+ ))} + +
+ +
+ 优化组件 +
+ {HARNESS_SIDECAR_OPTION_GROUPS.map((group) => ( +
+

+ {group.displayName} +

+
+ {group.componentIds.map((optionId) => { + const item = HARNESS_SIDECAR_OPTIONS.find( + (option) => option.id === optionId, + ); + if (!item) return null; + const checked = optimizations.includes(item.id); + return ( + { + const selected = Boolean(next); + if (selected !== checked) { + onOptimizationChange(item.id, selected); + } + }} + label={ + + {item.displayName} + {item.description} + + } + className="cw-optimize-option" + /> + ); + })} +
+
+ ))} +
+
+
+
+ ); +} + const WORKSPACE_MODES: Array<{ id: WorkspaceMode; label: string; }> = [ { id: "build", label: "架构" }, + { id: "optimize", label: "优化" }, { id: "validate", label: "调试" }, { id: "publish", label: "发布" }, ]; -const DEBUG_OPTIMIZATIONS = [ - { - id: "context", - label: "上下文优化", - description: "压缩历史对话,保留与当前任务相关的信息", - }, - { - id: "grounding", - label: "幻觉抑制", - description: "对不确定内容要求依据,并明确表达未知", - }, - { - id: "tools", - label: "工具调用优化", - description: "减少重复调用,优先复用可信的工具结果", - }, - { - id: "latency", - label: "响应加速", - description: "缓存稳定上下文,降低重复推理开销", - }, -] as const; - function WorkspaceHeader({ mode }: { mode: WorkspaceMode }) { const title = mode === "validate" ? "调试您的智能体" + : mode === "optimize" + ? "为您的智能体选择优化项" : mode === "publish" ? "准备好部署您的智能体" : "个性化您的智能体架构"; @@ -3496,7 +3563,6 @@ export function CustomCreate({ modelName: defaultDebugModelName(initialProviderDraft), description: initialProviderDraft.description, instruction: initialProviderDraft.instruction, - optimizations: [], configOpen: false, phase: "idle", runtimeSnapshot: "", @@ -3816,6 +3882,8 @@ export function CustomCreate({ () => draftForCloudProvider(draft, cloudProvider), [cloudProvider, draft], ); + const harnessOptimizationProfile = selectedHarnessProfile(draft); + const harnessOptimizations = selectedHarnessOptimizations(draft); const currentDebugSnapshot = useMemo( () => debugSnapshotKey(providerDraft, transientModelSecretValues), [providerDraft, transientModelSecretValues], @@ -3840,13 +3908,39 @@ export function CustomCreate({ requirement.label === `${node.name.trim() || "自定义模型"} 模型 API Key`, ); - // Smooth-scroll to the first invalid section during validation. - const scrollToSection = (id: StepId) => { - sectionRefs.current[id]?.scrollIntoView({ + function focusValidationProblem(problem: TreeProblem) { + const sectionId = problem.problem === "缺少子 Agent" ? "type" : "basic"; + const section = sectionRefs.current[sectionId]; + section?.scrollIntoView({ behavior: "smooth", block: "start", }); - }; + + const field = + problem.problem === "缺少描述" + ? "description" + : problem.problem === "缺少系统提示词" + ? "instruction" + : problem.problem === "缺少 AgentKit 智能体中心" + ? "a2a-registry" + : problem.problem === "缺少子 Agent" || + problem.problem === "远程 Agent 只能作为子 Agent" + ? null + : "name"; + const fieldRoot = field + ? section?.querySelector( + `[data-validation-field="${field}"]`, + ) + : section; + const focusTarget = fieldRoot?.matches( + 'input, textarea, button:not([disabled]), [contenteditable="true"], [tabindex]:not([tabindex="-1"])', + ) + ? fieldRoot + : fieldRoot?.querySelector( + 'input, textarea, button:not([disabled]), [contenteditable="true"], [tabindex]:not([tabindex="-1"])', + ); + focusTarget?.focus({ preventScroll: true }); + } const requireCompleteDraft = () => { if (canFinish) return true; @@ -3854,11 +3948,11 @@ export function CustomCreate({ setValidationPulse((pulse) => pulse + 1); if (problems[0]) { setSelectedPath(problems[0].path); - window.requestAnimationFrame(() => - scrollToSection( - problems[0].problem === "缺少子 Agent" ? "type" : "basic", - ), - ); + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => + focusValidationProblem(problems[0]), + ); + }); } return false; }; @@ -3946,8 +4040,7 @@ export function CustomCreate({ }); }; - const openPublishPreview = async (variantId?: string) => { - if (!(await confirmLeaveDebug())) return; + const materializePublishRelease = async (variantId?: string) => { setBuildErr(""); if (!requireCompleteDraft()) { setWorkspaceMode("build"); @@ -3971,15 +4064,10 @@ export function CustomCreate({ : selectedDebugVariant; if (releaseVariant) setSelectedVariantId(releaseVariant.id); const releaseDraft = releaseVariant - ? { - ...providerDraft, - modelName: releaseVariant.modelName || providerDraft.modelName, - description: releaseVariant.description, - instruction: releaseVariant.instruction, - } + ? releaseDraftFromDebugVariant(providerDraft, releaseVariant) : providerDraft; const generated = await generateAgentProject(codegenDraft(releaseDraft)); - if (releaseDraft !== draft) setDraft(releaseDraft); + setDraft(releaseDraft); setProject(generated); setWorkspaceMode("publish"); } catch (error) { @@ -3989,6 +4077,20 @@ export function CustomCreate({ } }; + const openPublishPreview = async (variantId?: string) => { + if (!(await confirmLeaveDebug())) return; + await materializePublishRelease(variantId); + }; + + const openOptimization = async () => { + if (!(await confirmLeaveDebug())) return; + if (!requireCompleteDraft()) { + setWorkspaceMode("build"); + return; + } + setWorkspaceMode("optimize"); + }; + const startDebugVariant = async (id: string) => { if (!debugEnabled || building) return; if (!requireCompleteDraft()) return; @@ -4201,7 +4303,6 @@ export function CustomCreate({ modelName: draft.modelName ?? "", description: draft.description, instruction: draft.instruction, - optimizations: [], configOpen: true, phase: "idle", runtimeSnapshot: "", @@ -4227,6 +4328,34 @@ export function CustomCreate({ ), ); + const updateHarnessOptimization = ( + optionId: HarnessSidecarOptionId, + selected: boolean, + ) => { + const optimizations = selected + ? [...new Set([...harnessOptimizations, optionId])] + : harnessOptimizations.filter((item) => item !== optionId); + setDraft((current) => ({ + ...current, + harnessSidecar: harnessIntentFromOptimizations( + optimizations, + harnessOptimizationProfile, + ), + })); + setProject(null); + }; + + const updateHarnessOptimizationProfile = ( + profile: HarnessSidecarProfileId, + ) => { + const optimizations = harnessProfileDefaultOptimizations(profile); + setDraft((current) => ({ + ...current, + harnessSidecar: harnessIntentFromOptimizations(optimizations, profile), + })); + setProject(null); + }; + const updateDebugVariantConfig = ( id: string, field: "modelName" | "description" | "instruction", @@ -4295,6 +4424,7 @@ export function CustomCreate({ runtimeName: deploymentRuntimeName, appName: deploymentTarget?.appName, description: draft.description, + harnessSidecar: draft.harnessSidecar, }, ); }; @@ -4320,9 +4450,12 @@ export function CustomCreate({ const handleWorkspaceChange = async (nextMode: WorkspaceMode) => { if (nextMode === "publish") { - if (!requireCompleteDraft()) return; - if (project) setWorkspaceMode("publish"); - else openPublishPreview(); + if (!(await confirmLeaveDebug())) return; + await materializePublishRelease(); + return; + } + if (nextMode === "optimize") { + await openOptimization(); return; } if (nextMode === "validate") { @@ -4533,14 +4666,25 @@ export function CustomCreate({ patch({ name: e.target.value }) } /> {showErrors && nameProblem ? ( - + {nameProblem} ) : ( @@ -4559,14 +4703,27 @@ export function CustomCreate({ className={`cw-textarea cw-textarea-sm ${invalidClass( descriptionMissing, )}`} + data-validation-field="description" value={node.description} placeholder="简要描述这个 Agent 的用途,便于团队识别…" + aria-invalid={ + showErrors && descriptionMissing + } + aria-describedby={ + showErrors && descriptionMissing + ? "cw-agent-description-error" + : undefined + } onChange={(e) => patch({ description: e.target.value }) } /> {showErrors && descriptionMissing ? ( - + 描述为必填项 ) : ( @@ -4610,7 +4767,10 @@ export function CustomCreate({ )} ) : a2a ? ( -
+
AgentKit 智能体中心 @@ -4683,13 +4843,16 @@ export function CustomCreate({ )} {showErrors && a2aRegistrySpaceMissing && ( - + 请选择 AgentKit 智能体中心 )}
) : ( -
+
@@ -4712,7 +4875,7 @@ export function CustomCreate({ /> {showErrors && instructionMissing ? ( - + 系统提示词为必填项 ) : ( @@ -5201,6 +5364,15 @@ export function CustomCreate({
)} + {workspaceMode === "optimize" && ( + + )} + {workspaceMode === "validate" && (
@@ -5213,7 +5385,7 @@ export function CustomCreate({ onInput={setDebugInput} onSend={sendDebugMessage} onStartVariant={startDebugVariant} - onDeployVariant={(id) => void openPublishPreview(id)} + onUseVariant={(id) => void openPublishPreview(id)} onAddVariant={addDebugVariant} onRemoveVariant={removeDebugVariant} onToggleConfig={(id) => { @@ -5248,13 +5420,10 @@ export function CustomCreate({ "默认模型", description: selectedDebugVariant.description, instruction: selectedDebugVariant.instruction, - optimizations: - selectedDebugVariant.optimizations.flatMap((id) => { - const option = DEBUG_OPTIMIZATIONS.find( - (item) => item.id === id, - ); - return option ? [option.label] : []; - }), + optimizations: [ + `优化场景:${harnessSidecarProfileLabel(harnessOptimizationProfile)}`, + ...harnessOptimizations.map(harnessSidecarOptionLabel), + ], } : undefined } diff --git a/frontend/src/create/configYaml.ts b/frontend/src/create/configYaml.ts index 4497ee637..4d27ee3ae 100644 --- a/frontend/src/create/configYaml.ts +++ b/frontend/src/create/configYaml.ts @@ -9,7 +9,7 @@ import { prepareMcpAuth } from "./mcpAuth"; import type { AgentDraft } from "./types"; /** Build a clean, minimal config object (omit empty/false fields). */ -function toConfig(draft: AgentDraft): Record { +function toConfig(draft: AgentDraft, root = true): Record { const o: Record = { agentType: draft.agentType ?? "llm", }; @@ -79,6 +79,13 @@ function toConfig(draft: AgentDraft): Record { o.tracing = true; o.tracingExporters = [...draft.tracingExporters]; } + if (root && draft.harnessSidecar?.enabled) { + o.harnessSidecar = { + enabled: true, + profile: draft.harnessSidecar.profile, + componentOverrides: { ...draft.harnessSidecar.componentOverrides }, + }; + } if ( draft.deployment?.feishuEnabled || draft.deployment?.runtimeName?.trim() || @@ -128,7 +135,9 @@ function toConfig(draft: AgentDraft): Record { } return base; }); - if (draft.subAgents?.length) o.subAgents = draft.subAgents.map(toConfig); + if (draft.subAgents?.length) { + o.subAgents = draft.subAgents.map((child) => toConfig(child, false)); + } return o; } diff --git a/frontend/src/create/harnessSidecarOptions.ts b/frontend/src/create/harnessSidecarOptions.ts new file mode 100644 index 000000000..59a46da9c --- /dev/null +++ b/frontend/src/create/harnessSidecarOptions.ts @@ -0,0 +1,225 @@ +import type { + AgentDraft, + HarnessSidecarIntent, + HarnessSidecarOptionId, + HarnessSidecarProfileId, +} from "./types"; + +export interface HarnessSidecarOption { + id: HarnessSidecarOptionId; + displayName: string; + description: string; +} + +export interface HarnessSidecarProfile { + id: HarnessSidecarProfileId; + displayName: string; + description: string; + defaultComponents: readonly HarnessSidecarOptionId[]; + autoAddedComponents: readonly string[]; +} + +export interface HarnessSidecarOptionGroup { + id: "quality" | "cost" | "stability"; + displayName: string; + componentIds: readonly HarnessSidecarOptionId[]; +} + +export const HARNESS_SIDECAR_OPTIONS: readonly HarnessSidecarOption[] = [ + { + id: "context_engine", + displayName: "上下文治理", + description: "治理上下文组装、任务锚定和上下文预算。", + }, + { + id: "compressor", + displayName: "上下文与结果压缩", + description: "压缩长上下文和大型工具结果,降低 Token 成本。", + }, + { + id: "verifier", + displayName: "回答校验与修复", + description: "校验证据和回答,在失败时执行修复或告警。", + }, + { + id: "long_run_control", + displayName: "Goal任务控制", + description: "管理 Goal 任务的进度、续跑和结束条件。", + }, + { + id: "mcp_resilience", + displayName: "MCP 稳定性治理", + description: "治理连接、超时、空结果、大返回和调用预算;默认包含 SQL 只读保护。", + }, +]; + +export const HARNESS_SIDECAR_OPTION_GROUPS: readonly HarnessSidecarOptionGroup[] = [ + { + id: "quality", + displayName: "提升回答质量", + componentIds: ["context_engine", "verifier"], + }, + { + id: "cost", + displayName: "降低运行成本", + componentIds: ["compressor"], + }, + { + id: "stability", + displayName: "增强运行稳定性", + componentIds: ["long_run_control", "mcp_resilience"], + }, +]; + +export const HARNESS_SIDECAR_OPTION_IDS: HarnessSidecarOptionId[] = + HARNESS_SIDECAR_OPTIONS.map((item) => item.id); + +const HARNESS_MODEL_PROXY_OPTION_IDS: readonly HarnessSidecarOptionId[] = [ + "context_engine", + "compressor", + "verifier", + "long_run_control", +]; + +const ENABLED_RUNTIME_ENV_VALUES = new Set(["1", "true", "yes", "on"]); + +export const HARNESS_SIDECAR_PROFILES: readonly HarnessSidecarProfile[] = [ + { + id: "default", + displayName: "自定义", + description: "按需选择组件,不勾选时不启动 Sidecar。", + defaultComponents: [], + autoAddedComponents: [], + }, + { + id: "ops", + displayName: "运维场景", + description: "适用于运维诊断、数据库、日志和监控 MCP。", + defaultComponents: [ + "context_engine", + "compressor", + "verifier", + "long_run_control", + "mcp_resilience", + ], + autoAddedComponents: ["sql_readonly"], + }, +]; + +export function harnessSidecarOptionLabel(id: string): string { + return HARNESS_SIDECAR_OPTIONS.find((item) => item.id === id)?.displayName ?? id; +} + +export function harnessSidecarProfileLabel(id: string): string { + return HARNESS_SIDECAR_PROFILES.find((item) => item.id === id)?.displayName ?? id; +} + +export function harnessProfileDefaultOptimizations( + profile: HarnessSidecarProfileId, +): HarnessSidecarOptionId[] { + const metadata = HARNESS_SIDECAR_PROFILES.find((item) => item.id === profile); + if (!metadata) return []; + return [...metadata.defaultComponents]; +} + +export function harnessIntentFromOptimizations( + optimizations: readonly HarnessSidecarOptionId[], + profile: HarnessSidecarProfileId = "default", +): HarnessSidecarIntent { + const selected = new Set(optimizations); + const intent: HarnessSidecarIntent = { + enabled: selected.size > 0, + profile, + componentOverrides: Object.fromEntries( + HARNESS_SIDECAR_OPTION_IDS.map((id) => [id, selected.has(id)]), + ) as HarnessSidecarIntent["componentOverrides"], + }; + return intent; +} + +function runtimeEnvEnabled(value: string | undefined): boolean { + return ENABLED_RUNTIME_ENV_VALUES.has(value?.trim().toLowerCase() ?? ""); +} + +function runtimeComponentOverrides(value: string | undefined): Record | null { + if (!value) return null; + try { + const parsed: unknown = JSON.parse(value); + return parsed && typeof parsed === "object" && !Array.isArray(parsed) + ? parsed as Record + : null; + } catch { + return null; + } +} + +export function harnessIntentFromRuntimeEnvs( + envs: readonly { key: string; value: string }[] | null | undefined, +): HarnessSidecarIntent | null { + const values = new Map(envs?.map(({ key, value }) => [key, value]) ?? []); + const enabledValue = values.get("HARNESS_SIDECAR_ENABLED"); + if (enabledValue === undefined) return null; + + const profile: HarnessSidecarProfileId = + values.get("HARNESS_PROFILE")?.trim() === "ops" ? "ops" : "default"; + if (!runtimeEnvEnabled(enabledValue)) { + return harnessIntentFromOptimizations([], profile); + } + if (profile === "ops") { + return harnessIntentFromOptimizations( + harnessProfileDefaultOptimizations(profile), + profile, + ); + } + + const exactOverrides = runtimeComponentOverrides( + values.get("HARNESS_SIDECAR_COMPONENT_OVERRIDES"), + ); + const selected = exactOverrides + ? HARNESS_SIDECAR_OPTION_IDS.filter((id) => exactOverrides[id] === true) + : [ + ...(runtimeEnvEnabled(values.get("HARNESS_MODEL_PROXY_ENABLED")) + ? HARNESS_MODEL_PROXY_OPTION_IDS + : []), + ...(runtimeEnvEnabled(values.get("HARNESS_MCP_GATEWAY_ENABLED")) + ? ["mcp_resilience" as const] + : []), + ]; + return { + ...harnessIntentFromOptimizations(selected, profile), + enabled: true, + }; +} + +export interface HarnessSidecarDebugVariant { + modelName: string; + description: string; + instruction: string; +} + +export function releaseDraftFromDebugVariant( + draft: AgentDraft, + variant: HarnessSidecarDebugVariant, +): AgentDraft { + return { + ...draft, + modelName: variant.modelName || draft.modelName, + description: variant.description, + instruction: variant.instruction, + }; +} + +export function selectedHarnessProfile( + draft: AgentDraft, +): HarnessSidecarProfileId { + return draft.harnessSidecar?.profile ?? "default"; +} + +export function selectedHarnessOptimizations( + draft: AgentDraft, +): HarnessSidecarOptionId[] { + const overrides = draft.harnessSidecar?.componentOverrides; + return overrides + ? HARNESS_SIDECAR_OPTION_IDS.filter((id) => overrides[id]) + : []; +} diff --git a/frontend/src/create/normalizeDraft.ts b/frontend/src/create/normalizeDraft.ts index b18271131..6beab7f51 100644 --- a/frontend/src/create/normalizeDraft.ts +++ b/frontend/src/create/normalizeDraft.ts @@ -3,6 +3,9 @@ import { type A2aRegistryConfig, type AgentDraft, type CustomTool, + type HarnessSidecarIntent, + type HarnessSidecarOptionId, + type HarnessSidecarProfileId, type SelectedSkill, } from "./types"; import { createBuiltinToolsForProvider, DEFAULT_KB_BACKEND } from "./veadkCatalog"; @@ -32,6 +35,17 @@ const TOOL_IDS = new Set([ "vesearch", ]); const AGENT_TYPES = new Set(["llm", "sequential", "parallel", "loop", "a2a"]); +const HARNESS_SIDECAR_OPTION_IDS: HarnessSidecarOptionId[] = [ + "context_engine", + "compressor", + "verifier", + "long_run_control", + "mcp_resilience", +]; +const HARNESS_SIDECAR_PROFILE_IDS = new Set([ + "default", + "ops", +]); function asString(v: unknown, fallback = ""): string { return typeof v === "string" ? v : fallback; @@ -41,6 +55,13 @@ function asBool(v: unknown): boolean { return v === true; } +function asHarnessSidecarProfile(v: unknown): HarnessSidecarProfileId { + return typeof v === "string" && + HARNESS_SIDECAR_PROFILE_IDS.has(v as HarnessSidecarProfileId) + ? (v as HarnessSidecarProfileId) + : "default"; +} + function asStringArray(v: unknown): string[] { return Array.isArray(v) ? v.filter((x): x is string => typeof x === "string") : []; } @@ -97,6 +118,29 @@ function asA2aRegistry(v: unknown): A2aRegistryConfig { }; } +function asHarnessSidecarIntent(v: unknown): HarnessSidecarIntent | undefined { + if (!v || typeof v !== "object" || Array.isArray(v)) return undefined; + const raw = v as Record; + const rawOverrides = ( + raw.componentOverrides && typeof raw.componentOverrides === "object" + ? raw.componentOverrides + : {} + ) as Record; + const componentOverrides = Object.fromEntries( + HARNESS_SIDECAR_OPTION_IDS.map((id) => [id, rawOverrides[id] === true]), + ) as Record; + const intent: HarnessSidecarIntent = { + enabled: Object.values(componentOverrides).some(Boolean), + profile: asHarnessSidecarProfile(raw.profile), + componentOverrides, + }; + const catalogVersion = asString(raw.catalogVersion).trim(); + const planHash = asString(raw.planHash).trim(); + if (catalogVersion) intent.catalogVersion = catalogVersion; + if (planHash) intent.planHash = planHash; + return intent; +} + function parseSubAgents( v: unknown, cloudProvider: NonNullable = "volcengine", @@ -292,6 +336,7 @@ export function normalizeDraft(raw: unknown): AgentDraft { ? { envValues: deploymentEnvValues } : {}), }, + harnessSidecar: asHarnessSidecarIntent(o.harnessSidecar), subAgents: parseSubAgents(o.subAgents, cloudProvider), selectedSkills: parseSelectedSkills(o), }; diff --git a/frontend/src/create/types.ts b/frontend/src/create/types.ts index 7133b60a1..caf6c24ef 100644 --- a/frontend/src/create/types.ts +++ b/frontend/src/create/types.ts @@ -81,6 +81,23 @@ export interface DeploymentConfig { envValues?: Record; } +export type HarnessSidecarOptionId = + | "context_engine" + | "compressor" + | "verifier" + | "long_run_control" + | "mcp_resilience"; + +export type HarnessSidecarProfileId = "default" | "ops"; + +export interface HarnessSidecarIntent { + enabled: boolean; + profile: HarnessSidecarProfileId; + componentOverrides: Record; + catalogVersion?: string; + planHash?: string; +} + /** A draft VeADK agent configuration produced by a creation flow. */ export interface AgentDraft { name: string; @@ -147,6 +164,8 @@ export interface AgentDraft { }; /** Deployment-time options that do not change generated agent code. */ deployment?: DeploymentConfig; + /** Root Runtime-level Harness Sidecar selection. Never set on sub-Agents. */ + harnessSidecar?: HarnessSidecarIntent; } // Pre-filled defaults so description / system prompt / model are never empty diff --git a/frontend/src/ui/AgentWorkspace.tsx b/frontend/src/ui/AgentWorkspace.tsx index 3e17ba84d..09b86de94 100644 --- a/frontend/src/ui/AgentWorkspace.tsx +++ b/frontend/src/ui/AgentWorkspace.tsx @@ -33,7 +33,6 @@ import { getRuntimeUpdateCapability, probeRuntimeA2a, probeRuntimeApps, - prefetchAgentFeedbackCases, prefetchRuntimeAgentInfo, prefetchRuntimeDetail, revealRuntimeApiKey, @@ -54,6 +53,12 @@ import { } from "../adk/client"; import type { AgentEntry } from "../adk/connections"; import { AgentBuildCanvas } from "../create/AgentBuildCanvas"; +import { + HARNESS_SIDECAR_OPTION_IDS, + harnessIntentFromRuntimeEnvs, + harnessSidecarOptionLabel, + harnessSidecarProfileLabel, +} from "../create/harnessSidecarOptions"; import { emptyDraft, type AgentDraft } from "../create/types"; import type { WorkspaceAgentDraft } from "../create/agentDraftStorage"; import { BUILTIN_TOOLS } from "../create/veadkCatalog"; @@ -1309,6 +1314,14 @@ export function AgentWorkspace({ selectedPendingTask?.agentDraft, ], ); + const publishedHarnessSidecar = + selectedAgentInfo?.draft?.harnessSidecar ?? + harnessIntentFromRuntimeEnvs(runtimeDetail?.envs); + const publishedHarnessOptimizations = publishedHarnessSidecar + ? HARNESS_SIDECAR_OPTION_IDS.filter( + (id) => publishedHarnessSidecar.componentOverrides[id], + ) + : []; const updateBlockedReason = selectedDraft ? canCreate ? "" : "当前账号没有新建 Agent 的权限。" : !canUpdate @@ -1460,35 +1473,9 @@ export function AgentWorkspace({ const region = agent.region ?? "cn-beijing"; prefetchRuntimeDetail(agent.runtimeId, region); prefetchRuntimeAgentInfo(agent.runtimeId, region, agent.runtimeApp ?? ""); - void getRuntimeAgentInfo(agent.runtimeId, region, agent.runtimeApp ?? "") - .then((info) => { - const appName = info.appName || agent.app; - if (!appName) return; - prefetchAgentFeedbackCases({ - runtimeId: agent.runtimeId ?? "", - region, - appName, - pageSize: 100, - }); - }) - .catch(() => {}); } }, [listedAgents]); - useEffect(() => { - if (!selectedAgent?.runtimeId || !selectedAgentAppName) return; - prefetchAgentFeedbackCases({ - runtimeId: selectedAgent.runtimeId, - region: selectedAgent.region ?? "cn-beijing", - appName: selectedAgentAppName, - pageSize: 100, - }); - }, [ - selectedAgentAppName, - selectedAgent?.region, - selectedAgent?.runtimeId, - ]); - useEffect(() => { let cancelled = false; const runtimeId = selectedAgent?.runtimeId ?? ""; @@ -2806,6 +2793,51 @@ export function AgentWorkspace({
+
+
+
+

已选择的优化项

+

发布时选择的智能体优化项,只读展示。

+
+
+
+
+
配置状态
+
+ {publishedHarnessSidecar + ? publishedHarnessSidecar.enabled + ? <>已启用 + : "未启用" + : "未记录"} +
+
+
+
优化场景
+
+ {publishedHarnessSidecar + ? harnessSidecarProfileLabel(publishedHarnessSidecar.profile) + : "旧版本未保存此配置"} +
+
+
+
已选优化项
+
+ {!publishedHarnessSidecar + ? "旧版本未保存此配置" + : publishedHarnessOptimizations.length + ? publishedHarnessOptimizations.map((optionId) => ( + + {harnessSidecarOptionLabel(optionId)} + + )) + : "未选择"} +
+
+
+
)} {section === "usage" && selectedAgent?.runtimeId && ( diff --git a/frontend/src/ui/ProjectPreview.tsx b/frontend/src/ui/ProjectPreview.tsx index d1a8c5618..e86d2460a 100644 --- a/frontend/src/ui/ProjectPreview.tsx +++ b/frontend/src/ui/ProjectPreview.tsx @@ -593,6 +593,9 @@ export interface ProjectPreviewProps { description: string; instruction: string; optimizations: string[]; + effectiveOptimizations?: string[]; + autoAddedOptimizations?: string[]; + planHash?: string; }; /** When provided, files are editable and changes call onChange with the new project. Omit for read-only. */ onChange?: (project: AgentProject) => void; @@ -801,6 +804,7 @@ export function ProjectPreview({ : runtimeNameProblem(effectiveRuntimeName); const selectedModelApiKeyId = agentDraft?.deployment?.modelApiKeyId?.trim() ?? ""; + const sidecarEnabled = agentDraft?.harnessSidecar?.enabled === true; // Initialize all hooks BEFORE any conditional returns (React hooks rule) const [selected, setSelected] = useState( @@ -848,7 +852,7 @@ export function ProjectPreview({ const deployRegionLabel = formatCloudRegion(deployRegion, cloudProvider); const [minInstance, setMinInstance] = useState("1"); const [maxInstance, setMaxInstance] = useState( - inMemorySession ? "1" : "5", + inMemorySession || sidecarEnabled ? "1" : "5", ); const [createEvaluationSets, setCreateEvaluationSets] = useState(true); const supportsEvaluationSets = cloudProvider !== "byteplus"; @@ -1049,8 +1053,8 @@ export function ProjectPreview({ useEffect(() => { setMinInstance("1"); - setMaxInstance(inMemorySession ? "1" : "5"); - }, [inMemorySession]); + setMaxInstance(inMemorySession || sidecarEnabled ? "1" : "5"); + }, [inMemorySession, sidecarEnabled]); useEffect(() => { if (previousDeployRegionRef.current === deployRegion) return; @@ -1851,6 +1855,32 @@ export function ProjectPreview({ : "未启用"}
+ {releaseConfiguration.effectiveOptimizations && + releaseConfiguration.effectiveOptimizations.length > 0 && ( +
+
生效能力
+
+ {releaseConfiguration.effectiveOptimizations.join("、")} +
+
+ )} + {releaseConfiguration.autoAddedOptimizations && + releaseConfiguration.autoAddedOptimizations.length > 0 && ( +
+
自动保护
+
+ {releaseConfiguration.autoAddedOptimizations.join("、")} +
+
+ )} + {releaseConfiguration.planHash && ( +
+
Plan Hash
+
+ {releaseConfiguration.planHash} +
+
+ )} )} @@ -2160,7 +2190,7 @@ export function ProjectPreview({ step="1" inputMode="numeric" value={minInstance} - disabled={deploying} + disabled={deploying || sidecarEnabled} aria-invalid={!instanceRange.valid} onChange={(event) => setMinInstance(event.currentTarget.value)} /> @@ -2174,15 +2204,17 @@ export function ProjectPreview({ step="1" inputMode="numeric" value={maxInstance} - disabled={deploying} + disabled={deploying || sidecarEnabled} aria-invalid={!instanceRange.valid} onChange={(event) => setMaxInstance(event.currentTarget.value)} />
- {inMemorySession && ( + {(inMemorySession || sidecarEnabled) && (

- 为避免多实例间会话丢失,推荐将 Runtime 固定为 1~1 + {sidecarEnabled + ? "Harness Sidecar 首期仅支持单实例,Runtime 固定为 1~1" + : "为避免多实例间会话丢失,推荐将 Runtime 固定为 1~1"}

)} {!instanceRange.valid && ( diff --git a/frontend/src/ui/Sidebar.tsx b/frontend/src/ui/Sidebar.tsx index 59b74e38f..29d8d6e3d 100644 --- a/frontend/src/ui/Sidebar.tsx +++ b/frontend/src/ui/Sidebar.tsx @@ -268,8 +268,7 @@ export function Sidebar({ userInfo, onLogout, }: SidebarProps) { - // Agent creation still lives outside the main navigation. - void onQuickCreate; + // The legacy full-page creator remains outside the main navigation. void onAddAgent; // Per-module feature gates; a missing flag defaults to shown. const show = (k: keyof NonNullable) => features?.[k] !== false; @@ -367,6 +366,17 @@ export function Sidebar({ 智能体 + {access.capabilities.createAgents && show("addAgent") ? ( + + ) : null} {show("skillCenter") ? (