Skip to content

refactor(mcp_env): 改进 before_launch 钩子处理逻辑 - #1

Closed
learningtostudy wants to merge 226 commits into
Timandes:masterfrom
learningtostudy:pr/refactor-mcp-env-before-launch
Closed

refactor(mcp_env): 改进 before_launch 钩子处理逻辑#1
learningtostudy wants to merge 226 commits into
Timandes:masterfrom
learningtostudy:pr/refactor-mcp-env-before-launch

Conversation

@learningtostudy

Copy link
Copy Markdown

变更内容

  • 自动调用所有 lifecycle 的 before_launch 方法
  • 再执行用户传入的 before_launch hook

相关 Commit

eb65220 refactor(mcp_env): 改进 before_launch 钩子处理逻辑

BCeZn and others added 30 commits March 31, 2026 16:26
* refactor: add method to merge session environment variables

* docs: add env vars for harbor demo script

* refactor: rename `_check_env` to `check_oss_env` in harbor demo script
…libaba#708)

* feat(sdk): add OssMirrorConfig and OSS artifact mirror support

- Add OssMirrorConfig to EnvironmentConfig for OSS artifact mirroring
- Add JobConfig.enable_oss_mirror() convenience method
- Add JobConfig.step field
- Update Job to call _autofill_sandbox_info() before writing config YAML
- Add unit tests in tests/unit/sdk/agent/test_oss_mirror.py

fixes alibaba#707

* feat: remove step param
…#716) (alibaba#717)

* feat: refine expr_id and namespace

* feat(sdk): add JobConfig enhancements and fix linting issues

Add job configuration improvements including experiment_id support,
OSS mirror config updates, and port validation changes. Fix ruff
lint and format issues across the codebase.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use urlparse for URL hostname validation in speedup tests

Replace substring-based URL checks with urlparse().hostname to
satisfy CodeQL's "Incomplete URL substring sanitization" rule.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: extract domain constants to avoid CodeQL URL substring warnings

CodeQL flags `"domain" in var` as incomplete URL sanitization regardless
of variable type. Extract hostnames to constants and use helper functions
to eliminate the flagged pattern entirely.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: 恢复CI请求触发工作流配置

* chore(CI-workflow): 更新CI触发脚本并添加任务开始时间戳

* chore(.github/scripts): 更新CI结果获取脚本中的FC应用地址

* chore(CI-request-trigger.yml): 移除多余的路径引用并修正脚本调用格式

* chore(.github/scripts): 更新CI结果获取脚本中的API地址为HTTP协议

* chore(CI-workflow): 在CI触发脚本前添加时间戳记录
Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>
…ibaba#747)

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>
* feat: wire DatabaseConfig into RockConfig YAML loading

Add DatabaseConfig dataclass (url field) to rock/config.py and wire it
into RockConfig both as a field and in the from_env() YAML parser.

* feat: implement SandboxRecord ORM model and async DatabaseProvider

- Add Base(DeclarativeBase) as the single SQLAlchemy declarative base
- Add SandboxRecord ORM model with all sandbox metadata columns
- Add LIST_BY_ALLOWLIST and _NOT_NULL_DEFAULTS class-level constants
- Add DatabaseProvider with async engine/session factory
- Add DatabaseConfig dataclass to RockConfig
- _convert_url handles sqlite://, postgresql://, and postgres:// (Heroku)
  shorthand; URLs with existing driver specifier pass through unchanged
- Default state column value uses string literal "pending" instead of
  State.PENDING enum instance for explicit column semantics

* feat: implement SandboxTable - strict insert, allowlist-based list_by

- Add SandboxTable with insert/get/update/delete/list_by/list_by_in
- _filter_data strips unknown keys; _NOT_NULL_DEFAULTS fills NOT NULL cols
- LIST_BY_ALLOWLIST prevents arbitrary column queries (injection guard)
- _record_to_sandbox_info uses lru_cache to avoid repeated get_type_hints
  calls in bulk list_by scenarios
- Add SandboxInfoField generated type and generation script

* feat: implement SandboxRepository - Redis hot-path with async DB replica

- Redis alive/timeout keys remain the source of truth for live state
- DB writes are fire-and-forget via asyncio.create_task + _safe_db_call
- batch_get: Redis hits served directly; DB fallback uses a single
  list_by_in("sandbox_id", miss_ids) query instead of N serial gets,
  leveraging the primary key index for O(1) lookup per row
- iter_alive_sandbox_ids queries DB by state IN (running, pending)
  instead of Redis scan_iter, enabling indexed filtering

* feat: wire SandboxRepository into sandbox lifecycle; rename meta_store to meta_repo

- Replace MetaStore with SandboxRepository throughout SandboxManager,
  GemManager, BaseManager, and SandboxProxyService
- Wire SandboxRepository (Redis + SandboxTable) in admin/main.py startup
- stop(): add early return after archive() in the ValueError except branch
  to prevent double archive when the Ray actor is already gone

Made-with: Cursor

* test: unit tests for SandboxTable and SandboxRepository

- Add TestSandboxTableWithSQLite: full CRUD coverage using SQLite
  in-memory database (no external dependencies, runs in fast CI)
  including list_by_in, NOT NULL defaults, and noop-on-missing-id cases
- Add TestSandboxTableWithPostgres: PostgreSQL-specific tests (JSONB,
  real container) marked need_docker + need_database
- Add comprehensive SandboxRepository tests: create/update/delete/archive/
  get/exists/batch_get/list_by/refresh_timeout/is_expired
- Consistent lowercase "stopped" state string throughout test data,
  matching the State enum value convention (running/pending)

* feat: add indexes to SandboxRecord and add DDL generation script

- Add single-column indexes on all commonly queried fields (user_id,
  state, namespace, experiment_id, cluster_name, image, host_ip,
  host_name, create_user_gray_flag)
- Add scripts/gen_ddl.py to emit CREATE TABLE / CREATE INDEX DDL
- Add *.db and ddl/ to .gitignore (generated artifacts)

* fix: inject redis_provider into RayOperator via OperatorContext

OperatorContext was missing redis_provider, leaving RayOperator._redis_provider
as None. This caused the use_rocklet get_status path to crash with
'NoneType object has no attribute get' because build_sandbox_from_redis
skips the lookup entirely when redis_provider is None.

* refactor: rename SandboxRepository to SandboxMetaStore

- Rename class SandboxRepository to SandboxMetaStore to better reflect its role
  as a coordinator for Redis (hot path) + DB (query path) dual-write
- Rename _meta_repo to _meta_store across all files
- Rename sandbox_repository.py to sandbox_meta_store.py
- Update all imports and references
- Use legacy states (_TERMINAL_STATES, _LIST_BY_BLACKLIST) from SandboxMetaStore
  as the authoritative source; removed duplicate definitions elsewhere

* refactor: extract sandbox timeout logic into SandboxTimeoutHelper

- Add rock/sandbox/utils/timeout.py with SandboxTimeoutHelper:
  pure calculation helpers (make_timeout_info, refresh_timeout, is_expired)
  with no I/O dependency
- Add SandboxMetaStore.update_timeout() for raw Redis set of timeout key;
  remove refresh_timeout() and is_expired() from MetaStore (not its responsibility)
- SandboxManager._refresh_timeout / _is_expired: own the I/O (get_timeout +
  update_timeout) and delegate calculation to SandboxTimeoutHelper
- SandboxProxyService._update_expire_time: same pattern
- Replace inline auto_clear_time_dict construction in start_async with
  SandboxTimeoutHelper.make_timeout_info()
- Update tests: replace TestRefreshTimeout/TestIsExpired in test_sandbox_meta_store
  with TestUpdateTimeout; add test_sandbox_timeout.py for pure unit tests

* feat: add spec/status columns to SandboxRecord; remove SandboxInfoField

Schema
- Add spec (JSONB): DockerDeploymentConfig.model_dump() snapshot, written
  once at creation, never updated
- Add status (JSONB): full SandboxInfo snapshot, overwritten on every update

SandboxRecordData
- New TypedDict in schema.py extending SandboxInfo with spec/status fields
- Used as the unified I/O type for SandboxTable (replaces plain SandboxInfo)

SandboxTable
- create(): writes spec from caller; auto-populates status from data
- update(): always overwrites status with latest SandboxInfo snapshot
- list_by / list_by_in / get return SandboxRecordData

SandboxMetaStore
- create() gains spec: dict | None parameter; constructs SandboxRecordData
  before passing to SandboxTable; Redis path unchanged

SandboxManager
- start_async passes spec=docker_deployment_config.model_dump() to meta_store

Cleanup
- Remove SandboxInfoField generated Literal type and its generation script
- Replace SandboxInfoField with plain str in SandboxTable / SandboxMetaStore
  (LIST_BY_ALLOWLIST already enforces valid column names at runtime)

* refactor: replace async_sessionmaker with direct AsyncSession(engine) in SandboxTable

- Remove async_sessionmaker, _session_factory, and session() factory from DatabaseProvider
- Add engine property that raises RuntimeError if not initialised
- Update all SandboxTable methods to use AsyncSession(self._db.engine) directly
- Simpler, more explicit session lifecycle with no factory indirection

* refactor: always-on DB+Redis providers; simplify SandboxMetaStore

- Fallback to sqlite-memory when database.url is not configured
- Fallback to FakeRedis when redis.host is not configured
- SandboxMetaStore now requires both providers (no more None checks)
- batch_get() returns only found sandboxes (no positional None slots)
- list_by() raises ValueError for non-allowlisted fields (no Redis fallback)
- list_sandboxes and batch_get_status expose use_legacy_states param
- Update tests to reflect new behaviour

* refactor: rename DatabaseProvider init_pool/close_pool to init/close; remove auto-create_all and verbose logging

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove use_legacy_states parameter; always filter non-RUNNING/PENDING sandboxes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: raise error in get_status when sandbox is already stopped

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: add sandbox_record DDL as sql/sandbox_record.sql

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: remove all _meta_store None checks; meta_store is always provided

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: add DatabaseProvider.create_tables() for explicit DDL creation in tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: auto-create tables for SQLite fallback in admin lifespan

When database.url is not configured, admin falls back to SQLite
in-memory which has no persistent schema. Call create_tables()
only in this case so integration tests and local dev work
out of the box. Production PostgreSQL relies on external DDL
(sql/sandbox_record.sql).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: refactor k8s api client informer

* fix: disable test test_rock_agent_run_langgraph
* feat: add skills for docs

* docs: 修改skills文档

* docs: fix docs deploy fail

* fix: pin webpack 5.105.4 in CI deploy workflow
* feat: add container mode and related fields to VerifierConfig

* refactor: update verifier config fields names and types

* feat: add NativeConfig for verifier mode settings
* feat(job-config): translate field descriptions to English and update job models

* fix: add missing experiment_id to tests and backfill sandbox experiment_id in _autofill_sandbox_info

* feat: modify job config field description

* fix: only set experiment_id on JobConfig level in _autofill_sandbox_info
- Change job_name type from str to str | None with default None
- Add _generate_default_job_name() method to generate meaningful names
- Format: {dataset_name}_{task_name}_{uuid} for single task, or {dataset_name}_{uuid} for multiple/no tasks
- Add comprehensive unit tests for job_name generation logic
* docs: add v1.5.x versioned docs with v1.5.0 release note

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* v1.5.0 Release Note

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Bump pyproject.toml version to 1.5.0

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>

* feat: update v1.5.0 release note

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>

---------

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: auto-create temp session for arun normal mode when session is None

Previously, calling arun(cmd, mode="normal") without a session would
raise a Pydantic ValidationError. Now it auto-creates a temporary
session, matching the behavior of nohup mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rename test_arun_nohup to test_arun

The test file now covers both normal and nohup mode, so rename
to reflect the broader scope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* add bash demo

* install rl-rock firstly

* log sandbox id

* add log for bash demo

* demo show variables

* add workspace

* add vitabench

* add job command

* make local-path optional

* add token params

* refine simple_bash_job_demo

* fix vitabench_demo

* add simple_bash dir

* delete vita
* Bump version to 1.5.1 (alibaba#769)

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>
(cherry picked from commit d76bf55)
Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>

* Release note v1.5.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: update 1.5.0 release note title

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>

---------

Signed-off-by: Jiachen Zhang <zjc462490@alibaba-inc.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
alibaba#779) (alibaba#780)

* feat: add docs

* feat(job): add result models (TaskResult, JobResult)

Add TaskStatus, TaskResult, JobStatus, and JobResult Pydantic models
for the new Job system. Includes computed properties for score, success,
n_completed, n_failed, and Harbor backward-compatible trial_results.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(job): add config hierarchy (JobConfig, BashJobConfig, HarborJobConfig)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(job): JobResult generic over T, JobStatus stays in agent module

* docs(job): rename Task concept to Trial in README.md and plan.md

* feat: refine config

* refactor(job): agent JobConfig inherits base JobConfig, remove HarborJobConfig from rock/sdk/job

* rename sdk/agent to sdk/bench

* rename sdk/agent to sdk/bench

* feat(job): add AbstractTrial and trial registry

* fix(job): check upload_dir exit_code, tighten registry types

* feat(job): add BashTrial with auto-registration

* feat(job): add Operator ABC and ScatterOperator

* feat(job): add JobExecutor with TrialClient/JobClient

* feat(job): add Job facade

* feat(job): add HarborTrial (extracted from bench/job.py)

* feat(job): update CLI with --type bash/harbor routing

* feat(job): integration wiring and public exports

- Wire rock/sdk/job/__init__.py to export Job, configs, results, operator,
  executor, trial; auto-register BashTrial.
- Wire rock/sdk/job/trial/__init__.py to export AbstractTrial and registry.
- Register HarborTrial at the end of rock/sdk/bench/__init__.py (after
  bench.models.trial.result is fully loaded) to avoid a circular import
  when rock.sdk.job is loaded mid-bench init.
- Pre-import rock.sdk.bench in rock.sdk.job.__init__ so that a cold
  `import rock.sdk.job` triggers bench-side registration too.
- Add tests/unit/sdk/job/test_integration.py covering public imports,
  trial auto-registration, and rock.sdk.bench backward compat.
- Minor ruff format fixup in trial/registry.py (merged adjacent f-strings).

* refactor(job): extract _job_tmp_prefix helper in JobExecutor

* refactor(job): make _job_tmp_prefix a method on JobExecutor

* refactor(job): rename job.py to facade.py to avoid package-module name collision

* rename facada.py to api.py

* fix(test): make test_ray_get resilient to leaked detached actors

- Use UUID-based actor name to avoid collisions from prior runs/reruns
- Specify namespace at creation time to match the lookup namespace
- Wrap in try/finally with ray.kill() to ensure cleanup on failure
- Fixes CI flakiness: 'name test (namespace=None) is already taken'

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
pg_isready can succeed before PostgreSQL fully accepts application
connections, causing CannotConnectNowError / ConnectionResetError
under parallel test workers (pytest-xdist). Follow up with a real
SQL query to close the startup race window.
…aba#788) (alibaba#789)

* rename JobConfig and HarborTrialResult

* fix(job): close G1-G7 gaps between bench/job.py and rock.sdk.job (alibaba#784)

* docs(job): clarify G1 approach as union+isinstance in bench-replacement

Align docs/dev/job/bench-replacement.md with the design decision for
Task 1: AbstractTrial.collect returns TrialResult | list[TrialResult],
and Job._build_result uses isinstance to decide extend vs append.
BashTrial stays unchanged (single), HarborTrial returns list.

* chore: baseline for bench-replacement gap fixes (222 passing)

* fix(job/G1a): HarborTrial.collect returns all sub-trial results as list

* fix(job/G1b): flatten list-returning collect() into JobResult.trial_results

* refactor(job/G1): drop BaseTrialResult alias in harbor.py, use TrialResult directly

Per user request: remove the local import alias
'from rock.sdk.job.result import TrialResult as BaseTrialResult'
and use TrialResult directly. No behavior change.

* test(job/G1): add multi-trial timeout exception-injection coverage

Addresses code review I1: exception-injection loop on multi-sub-trial
timeout previously untested. New test asserts:
- every sub-trial without its own exception_info gets ProcessTimeout
- pre-existing exception_info on a sub-trial is preserved

* fix(job/G5): populate JobResult.raw_output and exit_code from sandbox obs

* fix(job/G6): write script/nohup output under USER_DEFINED_LOGS, not /tmp

* fix(job/G7): sync HarborJobConfig.auto_stop with environment.auto_stop

OR semantics: if either the top-level HarborJobConfig.auto_stop or the
nested environment.auto_stop is True, both become True. Preserves legacy
'environment.auto_stop=True' usage while letting new code set auto_stop
at the top level.

* fix(job/G3): HarborJobConfig auto-generates job_name from dataset/task + uuid

* fix(job/G2): HarborJobConfig derives effective timeout from agent + multiplier

* fix(job/G4): AbstractTrial.on_sandbox_ready hook + HarborTrial backfills ns/exp_id

* test(job): blue-green equivalence tests for G1-G7 gap fixes

* chore(job): mark rock.sdk.bench.Job as deprecated; point users to rock.sdk.job.Job

G1-G7 gaps all closed and validated by blue-green equivalence tests.
Emits DeprecationWarning (stacklevel=2) from Job.__init__ so callers
see their own site. Scheduled for removal in 1.7.x.

Refs alibaba#783

* fix(job): pass job_name to harbor YAML and migrate demo to new Job path (alibaba#785)

Harbor was using timestamp-based directory names because job_name was
excluded from the serialized YAML config. Re-inject job_name in
to_harbor_yaml() so harbor uses it as the job directory name, allowing
result collection via {jobs_dir}/{job_name} to work correctly.

Also migrate harbor_demo.py from deprecated rock.sdk.bench.Job to
rock.sdk.job.Job.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* refactor(job): move on_sandbox_ready backfill to AbstractTrial

Hoist the namespace/experiment_id backfill + consistency check from
HarborTrial up into AbstractTrial.on_sandbox_ready so BashTrial (and any
future JobConfig-based trial) inherits the same behavior. The error
message uses type(self._config).__name__ instead of a hardcoded class
name. _make_mock_sandbox() in test_job.py now sets _namespace /
_experiment_id to None so the auto-mock children don't trip the default
backfill when two trials share one config.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs(job): update G4 description after hoisting on_sandbox_ready

on_sandbox_ready is no longer a HarborTrial override — the backfill +
consistency check now lives on AbstractTrial and is shared across
HarborTrial and BashTrial.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: ShixinPeng <58160712+BCeZn@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
)

Add TemplateConfig model with name/revision fields for referencing
Agent-Bench templates. Add optional template field to NativeConfig.
When dataset_name or task_name contains '/', only use the last segment
after the final '/' for job_name generation. This prevents path separators
from appearing in job names and keeps them concise.

Example:
- Before: 'swe_bench/verified/task1_abc12345'
- After: 'task1_abc12345'
Timandes and others added 29 commits June 15, 2026 16:22
此提交改进了 `_compose_before_launch` 方法中的钩子处理逻辑,确保所有生命周期对象的 `before_launch` 方法被正确调用,并且用户自定义的 `before_launch` 钩子也能按预期执行。

Co-developed-by: Aone Copilot <noreply@alibaba-inc.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.