diff --git a/README.md b/README.md index 3d74682..97234b0 100644 --- a/README.md +++ b/README.md @@ -117,12 +117,19 @@ typed ADS and AnsysEM work, a real generated-input Momentum solve, and a one-turn cross-EDA workflow. Sanitized acceptance evidence is maintained in [Acceptance](docs/ACCEPTANCE.md). +A separate 2026-09-01 ADS 2027 comparison tested the current Runtime MCP plus +current Runtime/ADS Skills against the official ADS MCP with three fresh runs +per Agent and case. Runtime passed 22/24 overall and all 18/18 knowledge runs; +the official surface passed 18/24 overall and all 6/6 execution runs. Runtime's +successful governed native batch had a 2.379 s median, but its Agent path was +materially heavier. See the [ADS adapter's audited method and data](https://github.com/cottman99/ads-agent-bridge/blob/main/docs/BENCHMARK_ADS2027_HEADLESS_AC.md). + ## Start with one Agent profile Install Runtime on the computer where the Agent runs: ```console -python -m pip install "eda-bridge-runtime==0.1.0a37" +python -m pip install "eda-bridge-runtime==0.1.0a38" eda-runtime doctor ``` diff --git a/README.zh-CN.md b/README.zh-CN.md index 79e73d0..4cfe8fe 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -104,12 +104,19 @@ AEDT 生命周期占主导的任务主要受 EDA 本身耗时限制。这是工 操作、真实 Momentum 求解,以及一次跨 EDA 协作。脱敏后的真实主机 验收记录见 [Acceptance](docs/ACCEPTANCE.md)。 +另一组 2026-09-01 ADS 2027 对比,把当前 Runtime MCP + Runtime/ADS Skills +与官方 ADS MCP 分别交给两个 Agent,每个任务重复三次。Runtime 总体通过 +22/24、知识任务通过 18/18;官方路径总体通过 18/24、执行任务通过 6/6。 +Runtime 成功的受治理原生批处理中位数为 2.379 秒,但 Agent 使用路径明显 +更重。方法与审计数据见 +[ADS adapter 对比报告](https://github.com/cottman99/ads-agent-bridge/blob/main/docs/BENCHMARK_ADS2027_HEADLESS_AC.md)。 + ## 从一个 Agent 配置开始 在 Agent 所在的电脑安装 Runtime: ```console -python -m pip install "eda-bridge-runtime==0.1.0a37" +python -m pip install "eda-bridge-runtime==0.1.0a38" eda-runtime doctor ``` diff --git a/docs/V0_1_SCOPE.md b/docs/V0_1_SCOPE.md index 690a072..d412a60 100644 --- a/docs/V0_1_SCOPE.md +++ b/docs/V0_1_SCOPE.md @@ -14,6 +14,15 @@ - Report knowledge, official API reach, generic execution, default support, and validated workflows as separate coverage dimensions. +## 0.1.0a38 — inspectable native-batch capability contract + +- Expose the common native-batch capability contract directly to Agents so + they can discover the accepted program, effect, validation, and promotion + boundaries without inventing vendor-specific routing layers. +- Package bounded wait guidance and an explicit native program contract for + Codex and Pi Agent, and link the audited ADS Runtime-versus-official-MCP + comparison. + ## 0.1.0a37 — shared supervised live-edit envelope - Add the vendor-neutral `eda.live-edit/v1` envelope for one idempotent patch, diff --git a/integrations/pi-eda-runtime/skills/eda-runtime-control/SKILL.md b/integrations/pi-eda-runtime/skills/eda-runtime-control/SKILL.md index 2f930f0..fedea87 100644 --- a/integrations/pi-eda-runtime/skills/eda-runtime-control/SKILL.md +++ b/integrations/pi-eda-runtime/skills/eda-runtime-control/SKILL.md @@ -45,6 +45,10 @@ For a new `eda_read` or `eda_submit`, request its bounded `wait` option when com avoiding a second Agent turn. Use `eda_job_wait` to resume a job already returned to the Agent. Use `eda_job_status` only for a single observation after reconnecting and `eda_job_events` only when event detail is needed for diagnosis. +Runtime `wait.timeout_ms` is 1,000..300,000 ms and `poll_interval_ms` is +100..5,000 ms. A vendor operation may declare a longer timeout; do not copy that +value into Runtime wait. Use a bounded wait and resume an accepted non-terminal +job with `eda_job_wait`. When only a prior `run_id` remains, use `eda_run_get` once to recover the compact worker-ledger receipt. It does not replay work and intentionally omits the stored raw customer result. diff --git a/plugins/eda-bridge-runtime/.codex-plugin/plugin.json b/plugins/eda-bridge-runtime/.codex-plugin/plugin.json index 4294e3c..ed09795 100644 --- a/plugins/eda-bridge-runtime/.codex-plugin/plugin.json +++ b/plugins/eda-bridge-runtime/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "eda-bridge-runtime", - "version": "0.1.0-alpha.37", + "version": "0.1.0-alpha.38", "description": "Stable local and SSH execution path for EDA agent bridges", "author": { "name": "Pengfei Li", diff --git a/plugins/eda-bridge-runtime/skills/eda-runtime-control/SKILL.md b/plugins/eda-bridge-runtime/skills/eda-runtime-control/SKILL.md index c0c751e..2d3cf78 100644 --- a/plugins/eda-bridge-runtime/skills/eda-runtime-control/SKILL.md +++ b/plugins/eda-bridge-runtime/skills/eda-runtime-control/SKILL.md @@ -68,6 +68,10 @@ Runtime merely because SSH is absent. observation after reconnecting and incremental `eda.job.events` only for diagnostic detail; never resubmit merely because SSH or the conversation disconnected. +- Runtime `wait.timeout_ms` is bounded to 1,000..300,000 ms and + `poll_interval_ms` to 100..5,000 ms. The vendor operation's own timeout may be + longer; do not copy that value into Runtime wait. Use the maximum bounded wait + when appropriate, then resume an accepted non-terminal job with `eda.job.wait`. - When only a prior `run_id` remains after reconnecting, use `eda.run.get` once to recover its compact worker-ledger receipt. Do not search chat history, scan raw ledgers, or resubmit the operation. The receipt intentionally omits the stored raw customer result. diff --git a/pyproject.toml b/pyproject.toml index 853c387..73e25e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "eda-bridge-runtime" -version = "0.1.0a37" +version = "0.1.0a38" description = "Agent-neutral execution runtime for local and remote EDA bridges" readme = "README.md" requires-python = ">=3.10" diff --git a/src/eda_bridge_runtime/__init__.py b/src/eda_bridge_runtime/__init__.py index 8459097..1fd74ea 100644 --- a/src/eda_bridge_runtime/__init__.py +++ b/src/eda_bridge_runtime/__init__.py @@ -20,6 +20,7 @@ from .native_batch import ( NATIVE_BATCH_SCHEMA, OPERATION_CLASSES, + native_batch_capability_contract, validate_native_batch, validate_python_program_policy, ) @@ -51,6 +52,7 @@ "project_run", "parse_experience_asset", "NATIVE_BATCH_SCHEMA", + "native_batch_capability_contract", "OPERATION_CLASSES", "validate_native_batch", "validate_compiled_shortcut_binding", diff --git a/src/eda_bridge_runtime/_version.py b/src/eda_bridge_runtime/_version.py index aac962d..c78c1f3 100644 --- a/src/eda_bridge_runtime/_version.py +++ b/src/eda_bridge_runtime/_version.py @@ -1 +1 @@ -__version__ = "0.1.0a37" +__version__ = "0.1.0a38" diff --git a/src/eda_bridge_runtime/native_batch.py b/src/eda_bridge_runtime/native_batch.py index e29350f..e480dc1 100644 --- a/src/eda_bridge_runtime/native_batch.py +++ b/src/eda_bridge_runtime/native_batch.py @@ -29,6 +29,82 @@ ) +def native_batch_capability_contract() -> dict[str, Any]: + """Return the exact public shape an Agent needs before its first submission. + + This is deliberately compact rather than a second validation path. The + validator below remains authoritative; adapters embed this description in + their existing ``native.batch`` capability so an Agent does not have to + discover required fields by submitting invalid mutations. + """ + + program = { + "required": ["language", "source"], + "optional": ["sha256"], + "allowed_fields": ["language", "source", "sha256"], + "source_must_define": "def run(api, context)", + "do_not_submit_fields": ["entrypoint"], + } + return { + "schema_version": NATIVE_BATCH_SCHEMA, + "required": [ + "schema_version", + "runtime", + "effect", + "program", + "scope", + "transaction", + "validation", + "limits", + ], + "optional": ["batch_id"], + "effect": ["observe", "staged_mutation"], + "program": program, + "scope": { + "required": [ + "resource_kind", + "selectors", + "read_paths", + "write_paths", + "artifacts", + ] + }, + "transaction": { + "required": [ + "strategy", + "source_fingerprints", + "fresh_reopen", + "promotion", + ], + "observe": { + "strategy": "none", + "source_fingerprints": {}, + "fresh_reopen": False, + "promotion": "none", + }, + "staged_mutation": { + "strategy": "adapter_staging", + "source_fingerprints": "one SHA-256 per declared source read path", + "fresh_reopen": True, + "promotion": "on_validation", + }, + }, + "validation": { + "required": ["program", "required_artifacts"], + "observe_program": None, + "staged_mutation_program": { + **program, + "source_must_define": "def validate(api, context)", + }, + }, + "limits": { + "required": ["timeout_seconds", "max_output_bytes"], + "timeout_seconds": [1, 86_400], + "max_output_bytes": [1_024, 16_777_216], + }, + } + + def validate_operation_class(value: Any) -> str: operation_class = str(value or "") if operation_class not in OPERATION_CLASSES: diff --git a/tests/test_native_batch.py b/tests/test_native_batch.py index 035f6c4..7b07aeb 100644 --- a/tests/test_native_batch.py +++ b/tests/test_native_batch.py @@ -6,12 +6,40 @@ import pytest from eda_bridge_runtime.native_batch import ( + native_batch_capability_contract, validate_native_batch, validate_operation_class, validate_python_program_policy, ) +def test_capability_contract_exposes_complete_first_submission_shape(): + contract = native_batch_capability_contract() + assert contract["schema_version"] == "eda.native-batch/v1" + assert set(contract["required"]) == { + "schema_version", + "runtime", + "effect", + "program", + "scope", + "transaction", + "validation", + "limits", + } + assert contract["program"]["source_must_define"] == "def run(api, context)" + assert contract["program"]["allowed_fields"] == ["language", "source", "sha256"] + assert contract["program"]["do_not_submit_fields"] == ["entrypoint"] + assert contract["validation"]["staged_mutation_program"]["source_must_define"] == ( + "def validate(api, context)" + ) + assert contract["transaction"]["staged_mutation"] == { + "strategy": "adapter_staging", + "source_fingerprints": "one SHA-256 per declared source read path", + "fresh_reopen": True, + "promotion": "on_validation", + } + + def _program(entrypoint: str, body: str = "return {'status': 'passed'}") -> dict[str, str]: source = f"def {entrypoint}(api, context):\n {body}\n" return { diff --git a/uv.lock b/uv.lock index 720e963..e127aee 100644 --- a/uv.lock +++ b/uv.lock @@ -145,7 +145,7 @@ toml = [ [[package]] name = "eda-bridge-runtime" -version = "0.1.0a37" +version = "0.1.0a38" source = { editable = "." } [package.optional-dependencies]