Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
520e005
fix(studio): simplify MCP credential editing
Sep 9, 2026
bb4b4c5
fix(studio): preserve explicit MCP credentials in debug
Sep 9, 2026
09b8141
fix: resolve installed sidecar debug runtime
Sep 9, 2026
c27fc40
fix: propagate sidecar debug MCP upstreams
Sep 9, 2026
2d437f0
fix: extend generated debug startup timeout
Sep 10, 2026
bb37806
fix: harden studio update recovery
Sep 10, 2026
442f727
fix(studio): migrate legacy update output repository
Sep 11, 2026
d6ea8fb
fix(studio): align sidecar runtime role policy
Sep 11, 2026
dcab71f
test: isolate studio backend gate workers
Sep 12, 2026
b7d62bc
fix(studio): finalize sidecar runtime access rollout
Sep 14, 2026
0b3639c
perf(studio): defer generated cloud SDK imports
Sep 14, 2026
a74802e
perf(agentkit): lazily expose server helpers
Sep 14, 2026
d0acb46
chore: add release gate license header
Sep 14, 2026
b678e1a
fix(studio): preserve sidecar updates without user mcp
Sep 14, 2026
a7de072
chore(studio): pin released agentkit cli artifacts
Sep 14, 2026
3a38569
fix: harden Studio cold starts
Sep 14, 2026
a5a15bf
fix(studio): normalize release bundle permissions
Sep 14, 2026
a0e07a5
fix(studio): normalize legacy bundle entrypoint
Sep 14, 2026
1a92395
fix(studio): keep optional tools off cold start path
Sep 14, 2026
588d775
perf(studio): defer optional startup dependencies
Sep 14, 2026
712ee19
fix(studio): defer optional cold-start dependencies
Sep 14, 2026
8e071ad
fix(studio): defer generated agent planner runtime
Sep 14, 2026
87f6ee3
fix(studio): defer skill and mcp startup runtimes
Sep 14, 2026
0ed9a11
perf(studio): defer migration sandbox runtime
Sep 14, 2026
56d6c4d
perf(studio): defer sandbox session runtimes
Sep 15, 2026
79dda72
perf(studio): defer heavy builtin tool clients
Sep 15, 2026
a6a5834
perf(studio): defer source project sandbox runtime
Sep 15, 2026
f4ced5f
perf(studio): defer environment project runtime
Sep 15, 2026
2c60331
perf(studio): defer intelligent development sandbox runtime
Sep 15, 2026
84fed71
perf(studio): defer workspace sandbox transport
Sep 15, 2026
0fdf957
perf(studio): defer workspace project runtime
Sep 15, 2026
b045274
perf(studio): defer request-only sdk types
Sep 15, 2026
288876b
perf(studio): defer adk session startup
Sep 15, 2026
d4d1b13
perf(studio): defer genai request models
Sep 15, 2026
172decd
perf(studio): defer genai telemetry models
Sep 15, 2026
8eb5566
perf(studio): defer builtin tool execution runtime
Sep 15, 2026
40f6e2f
perf(studio): defer request-only runtimes
Sep 15, 2026
a7de8a2
perf(studio): defer cold-start request runtimes
Sep 15, 2026
d8c395a
fix(release): normalize staged runtime permissions
Sep 15, 2026
852c2df
fix(studio): defer transient identity startup failure
Sep 15, 2026
ba2b8b0
fix(ci): unblock release verification
Sep 15, 2026
4af48e7
fix(studio): normalize deferred schema compatibility
Sep 15, 2026
969923f
test(studio): await capability terminal response
Sep 15, 2026
c01cd8e
fix(studio): defer legacy identity initialization
Sep 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 85 additions & 13 deletions .github/workflows/harness-sidecar-release-gate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,32 @@ on:
- 'tests/cli/test_managed_sidecar_source.py'
- 'tests/cli/test_legacy_runtime_recovery.py'
- 'tests/cli/test_generated_agent_backend_codegen_extended.py'
- 'tests/cli/test_generated_agent_sidecar_runtime.py'
- 'tests/cli/test_generated_agent_mcp.py'
- 'tests/cli/test_studio_rbac.py'
- 'tests/cli/test_studio_release.py'
- 'tests/cli/test_studio_update.py'
- 'tests/cli/test_studio_startup_imports.py'
- 'tests/frontend/server/studio_tools/test_deferred_veadk_builtin_tools.py'
- 'tests/frontend/server/test_runtime_iam.py'
- 'tests/extensions/harness/**'
- 'tests/integrations/agentkit/test_app.py'
- 'tests/test_harness_sidecar_release_gate.py'
- 'tests/test_cloud.py'
- 'tests/test_studio_release_server.py'
- 'tests/test_studio_release_workflow.py'
- 'veadk/cli/generated_agent_codegen.py'
- 'veadk/cli/generated_agent_mcp.py'
- 'veadk/cli/generated_agent_sidecar_runtime.py'
- 'veadk/cli/cli_frontend.py'
- 'frontend/server/runtime_iam.py'
- 'veadk/cli/agentkit_cli.py'
- 'veadk/cli/managed_sidecar_source.py'
- 'veadk/cli/legacy_runtime_recovery.py'
- 'veadk/cli/studio_vpc_network.py'
- 'veadk/cli/studio_release.py'
- 'veadk/cli/studio_self_update.py'
- 'veadk/integrations/ve_faas/ve_faas.py'
- 'veadk/extensions/harness/**'
- 'veadk/integrations/agentkit/app.py'
- 'pyproject.toml'
Expand All @@ -30,15 +47,32 @@ on:
- 'tests/cli/test_managed_sidecar_source.py'
- 'tests/cli/test_legacy_runtime_recovery.py'
- 'tests/cli/test_generated_agent_backend_codegen_extended.py'
- 'tests/cli/test_generated_agent_sidecar_runtime.py'
- 'tests/cli/test_generated_agent_mcp.py'
- 'tests/cli/test_studio_rbac.py'
- 'tests/cli/test_studio_release.py'
- 'tests/cli/test_studio_update.py'
- 'tests/cli/test_studio_startup_imports.py'
- 'tests/frontend/server/studio_tools/test_deferred_veadk_builtin_tools.py'
- 'tests/frontend/server/test_runtime_iam.py'
- 'tests/extensions/harness/**'
- 'tests/integrations/agentkit/test_app.py'
- 'tests/test_harness_sidecar_release_gate.py'
- 'tests/test_cloud.py'
- 'tests/test_studio_release_server.py'
- 'tests/test_studio_release_workflow.py'
- 'veadk/cli/generated_agent_codegen.py'
- 'veadk/cli/generated_agent_mcp.py'
- 'veadk/cli/generated_agent_sidecar_runtime.py'
- 'veadk/cli/cli_frontend.py'
- 'frontend/server/runtime_iam.py'
- 'veadk/cli/agentkit_cli.py'
- 'veadk/cli/managed_sidecar_source.py'
- 'veadk/cli/legacy_runtime_recovery.py'
- 'veadk/cli/studio_vpc_network.py'
- 'veadk/cli/studio_release.py'
- 'veadk/cli/studio_self_update.py'
- 'veadk/integrations/ve_faas/ve_faas.py'
- 'veadk/extensions/harness/**'
- 'veadk/integrations/agentkit/app.py'
- 'pyproject.toml'
Expand All @@ -47,9 +81,10 @@ permissions:
contents: read

jobs:
python:
backend-gate:
name: Backend gate
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 3
steps:
- uses: actions/checkout@v4

Expand All @@ -68,15 +103,18 @@ jobs:
shell: bash
run: |
set -euo pipefail
checks=(coverage lifecycle credentials)
checks=(coverage lifecycle credentials release)
pids=()
(
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/cli/test_generated_agent_sidecar_runtime.py \
tests/cli/test_managed_sidecar_source.py \
tests/cli/test_studio_startup_imports.py \
tests/frontend/server/studio_tools/test_deferred_veadk_builtin_tools.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 \
Expand All @@ -88,19 +126,49 @@ jobs:
pids+=("$!")
(
python -m pytest -q \
tests/cli/test_legacy_runtime_recovery.py -k 'six_case_ or changed_unnamed_mcp_url'
tests/cli/test_legacy_runtime_recovery.py -k 'six_case_ or changed_unnamed_mcp_url or zero_mcp_servers_json' \
tests/extensions/harness/sidecar_runtime/test_sidecar.py::test_zero_structured_mcp_is_valid_and_does_not_reactivate_legacy_upstream
) > "$RUNNER_TEMP/sidecar-lifecycle.log" 2>&1 &
pids+=("$!")
(
python -m pytest -q \
tests/frontend/server/test_runtime_iam.py \
tests/cli/test_generated_agent_mcp.py \
tests/cli/test_generated_agent_backend_codegen_extended.py::test_generated_debug_applies_published_mcp_credential_contract_before_discovery \
tests/cli/test_studio_rbac.py::test_deployment_status_recovers_completed_update_from_fresh_instance \
tests/cli/test_studio_rbac.py::test_new_deployment_only_updates_non_default_instance_range \
tests/cli/test_studio_rbac.py::test_sidecar_deployment_uses_agentkit_cli_structured_release \
tests/cli/test_studio_rbac.py::test_source_preserving_output_repository_migrates_only_tagless_runtimes \
tests/cli/test_studio_rbac.py::test_source_preserving_update_ignores_browser_source_and_keeps_secrets_out_of_build \
tests/cli/test_studio_rbac.py::test_source_preserving_legacy_ops_update_migrates_output_repository_via_sdk \
tests/cli/test_studio_rbac.py::test_application_owned_mcp_update_routes_cover_reuse_and_additions \
tests/cli/test_studio_rbac.py::test_sidecar_update_resolves_or_explicitly_reuses_stored_mcp_credentials
) > "$RUNNER_TEMP/sidecar-credentials.log" 2>&1 &
pids+=("$!")
(
python -m pytest -q \
tests/test_studio_release_server.py::test_release_server_agentkit_cli_pin_matches_veadk \
tests/test_studio_release_server.py::test_publisher_repairs_missing_agentkit_cli_before_manifest \
tests/test_studio_release_server.py::test_release_server_zip_normalizes_runtime_file_permissions \
tests/test_studio_release_server.py::test_stage_deployment_uses_frontend_service_package \
tests/cli/test_studio_release.py::test_release_zip_normalizes_runtime_file_permissions \
tests/test_studio_release_workflow.py::test_smoke_gate_is_fresh_amd64_and_runs_before_import_validation \
tests/test_studio_release_workflow.py::test_smoke_gate_executes_bundle_as_low_privilege_user \
tests/test_studio_release_workflow.py::test_smoke_gate_survives_platform_entrypoint_mode_normalization \
tests/cli/test_studio_update.py::test_update_application_code_bundle_merges_only_explicit_environment \
tests/cli/test_studio_update.py::test_studio_update_preserves_custom_function_command \
tests/cli/test_studio_update.py::test_native_python_function_uses_mode_independent_bundle_entrypoint \
tests/test_cloud.py::test_vefaas_deploy_updates_existing_application_in_place \
tests/frontend/server/test_user_management.py::test_initialized_runtime_defers_transient_identity_directory_failure \
tests/frontend/server/test_user_management.py::test_initialized_runtime_deferred_identity_failure_remains_fail_closed \
tests/frontend/server/test_user_management.py::test_directory_normalizes_credential_resolver_failure \
tests/frontend/server/test_user_management.py::test_uninitialized_runtime_identity_failure_remains_fail_closed \
tests/frontend/server/test_user_management.py::test_uninitialized_runtime_retries_original_initialization_after_recovery \
tests/test_studio_release_server.py::test_tos_dependency_store_accepts_manifest_pinned_agentkit_cli_version \
tests/test_studio_release_server.py::test_tos_dependency_store_rejects_untrusted_agentkit_cli_url \
tests/test_harness_sidecar_release_gate.py
) > "$RUNNER_TEMP/sidecar-release.log" 2>&1 &
pids+=("$!")

status=0
for index in "${!pids[@]}"; do
Expand All @@ -113,9 +181,10 @@ jobs:
done
exit "$status"

frontend:
frontend-gate:
name: Frontend gate
runs-on: ubuntu-latest
timeout-minutes: 30
timeout-minutes: 3
steps:
- uses: actions/checkout@v4

Expand All @@ -138,15 +207,18 @@ jobs:
run: npm test

gate:
if: always()
needs: [python, frontend]
name: Gate
if: ${{ always() }}
needs:
- backend-gate
- frontend-gate
runs-on: ubuntu-latest
timeout-minutes: 5
timeout-minutes: 1
steps:
- name: Require every Sidecar check to pass
- name: Require both parallel gates
env:
PYTHON_RESULT: ${{ needs.python.result }}
FRONTEND_RESULT: ${{ needs.frontend.result }}
BACKEND_RESULT: ${{ needs.backend-gate.result }}
FRONTEND_RESULT: ${{ needs.frontend-gate.result }}
run: |
test "$PYTHON_RESULT" = success
test "$BACKEND_RESULT" = success
test "$FRONTEND_RESULT" = success
120 changes: 84 additions & 36 deletions .github/workflows/publish-studio-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -215,11 +215,63 @@ jobs:
VOLCENGINE_SECRET_KEY: smoke
run: |
set -euo pipefail
package_dir="$RUNNER_TEMP/studio-release-package"
runtime_venv="$RUNNER_TEMP/studio-release-runtime"
export package_dir runtime_venv
test "$(uname -s)" = "Linux"
test "$(uname -m)" = "x86_64"
test "$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')" = "3.12"
COLD_START_DEADLINE_SECONDS=60
STUDIO_MAX_BUNDLE_BYTES=$((256 * 1024 * 1024))
bundle=("$RUNNER_TEMP"/studio-release-output/studio-bundle-*.zip)
test "${#bundle[@]}" -eq 1
test "$(stat -c %s "${bundle[0]}")" -lt "$STUDIO_MAX_BUNDLE_BYTES"

permission_probe_root="$(mktemp -d)"
permission_probe="$permission_probe_root/package"
permission_probe_bin="$permission_probe_root/bin"
permission_probe_state="$permission_probe_root/state"
mkdir "$permission_probe" "$permission_probe_bin" "$permission_probe_state"
chmod 755 "$permission_probe_root" "$permission_probe" "$permission_probe_bin"
chmod 700 "$permission_probe_state"
sudo chown nobody "$permission_probe_state"
unzip -q "${bundle[0]}" -d "$permission_probe"
test "$(stat -c %a "$permission_probe/run.sh")" = "755"
test "$(stat -c %a "$permission_probe/agentkit-linux-x64.tar.gz")" = "644"
cat >"$permission_probe_bin/python3" <<'SH'
#!/bin/bash
set -eu
if [[ "$*" == *"veadk.cli.studio_companion"* ]]; then
test -r "$VEADK_STUDIO_AGENTKIT_CLI_ARCHIVE"
touch "$PERMISSION_PROBE_STATE/companion-started"
while [ ! -f "$PERMISSION_PROBE_STATE/studio-started" ]; do sleep 0.01; done
exit 0
fi
touch "$PERMISSION_PROBE_STATE/studio-started"
while [ ! -f "$PERMISSION_PROBE_STATE/companion-started" ]; do sleep 0.01; done
SH
chmod 755 "$permission_probe_bin/python3"
sudo -u nobody -H env \
PATH="$permission_probe_bin:/usr/bin:/bin" \
PERMISSION_PROBE_STATE="$permission_probe_state" \
"$permission_probe/run.sh"
sudo -u nobody -H rm \
"$permission_probe_state/companion-started" \
"$permission_probe_state/studio-started"
chmod 644 "$permission_probe/run.sh"
sudo -u nobody -H env \
PATH="$permission_probe_bin:/usr/bin:/bin" \
PERMISSION_PROBE_STATE="$permission_probe_state" \
bash "$permission_probe/run.sh"

uv run --frozen --group dev python - <<'PY'
smoke_studio() {
provider="$1"
port="$2"
package_dir="$RUNNER_TEMP/studio-release-package-${provider}"
runtime_venv="$RUNNER_TEMP/studio-release-runtime-${provider}"
log="$RUNNER_TEMP/studio-${provider}.log"
response="$RUNNER_TEMP/studio-${provider}-ui-config.json"
export package_dir
test ! -e "$package_dir"
test ! -e "$runtime_venv"
uv run --frozen --group dev python - <<'PY'
import os
from pathlib import Path

Expand All @@ -229,37 +281,11 @@ jobs:
bundle = next(output_dir.glob("studio-bundle-*.zip"))
extract_studio_bundle(bundle, Path(os.environ["package_dir"]))
PY

uv venv "$runtime_venv"
(
cd "$package_dir"
uv pip install --python "$runtime_venv/bin/python" -r requirements.txt
)

(
cd "$package_dir"
"$runtime_venv/bin/python" - <<'PY'
from pathlib import Path

import frontend
import veadk
import frontend.server.cronjobs
import frontend.service.studio_release_server
import frontend.service.studio_scheduler

runtime_root = Path(veadk.__file__).resolve().parents[1]
assert Path(frontend.__file__).resolve().is_relative_to(runtime_root)
webui = Path(veadk.__file__).resolve().parent / "webui" / "index.html"
assert webui.is_file()
print(f"Validated installed Studio packages from {runtime_root}")
PY
)

smoke_studio() {
provider="$1"
port="$2"
log="$RUNNER_TEMP/studio-${provider}.log"
response="$RUNNER_TEMP/studio-${provider}-ui-config.json"
uv venv --python 3.12 "$runtime_venv"
(
cd "$package_dir"
uv pip install --python "$runtime_venv/bin/python" -r requirements.txt
)
(
cd "$package_dir"
PATH="$runtime_venv/bin:$PATH" \
Expand All @@ -269,7 +295,8 @@ jobs:
./run.sh
) >"$log" 2>&1 &
pid=$!
for _ in {1..60}; do
started=$SECONDS
while (( SECONDS - started < COLD_START_DEADLINE_SECONDS )); do
if ! kill -0 "$pid" 2>/dev/null; then
cat "$log"
return 1
Expand Down Expand Up @@ -298,6 +325,27 @@ jobs:
smoke_studio byteplus 18877
smoke_studio volcengine 18878

package_dir="$RUNNER_TEMP/studio-release-package-volcengine"
runtime_venv="$RUNNER_TEMP/studio-release-runtime-volcengine"
(
cd "$package_dir"
"$runtime_venv/bin/python" - <<'PY'
from pathlib import Path

import frontend
import veadk
import frontend.server.cronjobs
import frontend.service.studio_release_server
import frontend.service.studio_scheduler

runtime_root = Path(veadk.__file__).resolve().parents[1]
assert Path(frontend.__file__).resolve().is_relative_to(runtime_root)
webui = Path(veadk.__file__).resolve().parent / "webui" / "index.html"
assert webui.is_file()
print(f"Validated installed Studio packages from {runtime_root}")
PY
)

release-context:
if: >-
github.event_name == 'workflow_dispatch' &&
Expand Down
9 changes: 6 additions & 3 deletions frontend/server/agent_reviews/repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
from collections.abc import Callable, Iterator
from typing import Any

from agentkit.sdk.runtime import types as sdk
from agentkit.sdk.runtime.client import AgentkitRuntimeClient

from frontend.server.agentkit_clients import create_agentkit_client
from frontend.server.storage import StudioProvider

Expand All @@ -38,6 +35,8 @@ def __init__(
self.credentials = credentials

def client(self, region: str) -> Any:
from agentkit.sdk.runtime.client import AgentkitRuntimeClient

access_key, secret_key, token = self.credentials()
return create_agentkit_client(
AgentkitRuntimeClient,
Expand All @@ -49,11 +48,15 @@ def client(self, region: str) -> Any:
)

def get(self, region: str, runtime_id: str) -> Any:
from agentkit.sdk.runtime import types as sdk

return self.client(region).get_runtime(
sdk.GetRuntimeRequest.model_validate({"RuntimeId": runtime_id})
)

def list(self, region: str) -> Iterator[Any]:
from agentkit.sdk.runtime import types as sdk

client = self.client(region)
token = ""
seen: set[str] = set()
Expand Down
2 changes: 1 addition & 1 deletion frontend/server/deployment_resources.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2026 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
# Copyright (c) 2025 Beijing Volcano Engine Technology Co., Ltd. and/or its affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down
Loading
Loading