feat(plugins): add managed runtime SDK and release 2.4.5

This commit is contained in:
chenmingxuan committed 2026-10-30 14:39:21 +08:00
1 parent 506e3bf1c5
commit 2a3bbaa3fb
45 files changed
+3348 -98

No files matched your search

@@ -0,0 +1,69 @@
"""Run with the current ARTEMIS Python; no pytest/device/service/config needed."""
import asyncio
import hashlib
import json
from pathlib import Path
import sys
import tempfile
from artemis.plugins.evidence import persist_attachments, validate_tools
from artemis.plugins.models import PluginManifest, PluginProfile
from artemis.plugins.sdk_checks import run_checks
from artemis.plugins.session import PluginSession, resolve_server
async def run_contract():
directory = Path(__file__).resolve().parent
manifest = PluginManifest.model_validate_json((directory / "plugin.json").read_text("utf-8"))
with tempfile.TemporaryDirectory(prefix="artemis-template-contract-") as temporary:
trace = Path(temporary).resolve()
artifacts = trace / "artifacts" / "plugins" / manifest.id
artifacts.mkdir(parents=True)
content = "synthetic local sample\n中文\x00".encode()
(artifacts / "样例.txt").write_bytes(content)
server = resolve_server(
manifest, PluginProfile(values={"python": sys.executable}), directory
)
server.env["ARTEMIS_ARTIFACTS_DIR"] = str(artifacts)
server.env["PYTHONDONTWRITEBYTECODE"] = "1"
session = await PluginSession(server, directory).start()
try:
validate_tools(manifest, session.tools)
success = await session.call(
"verify_note", {"name": "样例.txt", "sha256": hashlib.sha256(content).hexdigest()}
)
if success.isError:
raise AssertionError("MCP 校验入口失败")
receipt = success.structuredContent["artemis"]
attachments = persist_attachments(trace, manifest.id, receipt["attachments"])
if len(attachments) != 1:
raise AssertionError("宿主未回读到校验回执")
for name, digest in (("样例.txt", "0" * 64), ("../outside.txt", "0" * 64)):
denied = await session.call("verify_note", {"name": name, "sha256": digest})
if (
not denied.isError
or denied.structuredContent["artemis"]["execution"] != "not_started"
):
raise AssertionError("无效输入没有在工具启动前拒绝")
finally:
await session.aclose()
return {
"status": "passed",
"scope": "template_offline_contract",
"mcp_calls": 3,
"host_attachments_verified": 1,
"real_device_actions": False,
}
async def main():
print(
json.dumps(
{"sdk": await run_checks(), "template": await run_contract()}, ensure_ascii=False
)
)
if __name__ == "__main__":
asyncio.run(main())