Repository navigation
release: 0.4.0 — fix missing SDK names in PyPI 0.3.0, control serve + HIL, localized labels - #12
Merged
Merged
Conversation
Run a project's ONNX models on a Linux target while the browser keeps MuJoCo, the signal graph and project Python — model-service HIL, not full-controller deployment or hard real-time scheduling. - hil/: SSH target discovery, inspection and provisioning (generic-linux and rdk-x5 profiles), a versioned build → deploy → load → run lifecycle over verified SSH forwarding, and the target-side inference agent; new `botlab-agent` entry point and a `target` extra (numpy + onnxruntime only) - CLI: `botlab target list/add/inspect/remove/discover/identity/ provision/projects`, `botlab deploy --target`, `botlab agent`, and `botlab run --hil <target>`; HIL runs pin the host to loopback and require a browser runtime advertising hilProtocol v1 - server: HIL endpoints behind a per-session token with Host and origin checks - browser adapters: `botlab run --browser-adapter MODULE:FUNCTION --inference-endpoint HOST:PORT` runs a project-supplied launcher (BrowserRunContext) with the SDK-managed web runtime; physics stays in the browser - hardening: browser runs bind 127.0.0.1 by default (--host 0.0.0.0 for LAN disables HIL), UI asset traversal checks, dot-files and tmp/ excluded from local-project payloads and debug watches, project loads serialized under a lock for asynchronous HIL builds - README: browser-first run flow (--native opt-in) and the HIL guide Co-Authored-By: Claude Code <noreply@anthropic.com>
`botlab control` is a robot-independent client: a project supplies its own loopback middleware, capability declarations and execution backend, and the CLI discovers it, binds instances and sessions, and submits identity-preserving commands — without importing project code or any robot adapter. The first adapter ships in the MicroDuck example project. - control/: stdlib-only HTTP transport, private project-scoped middleware discovery, durable request receipts for retries, and capability-driven subcommands (instances, capabilities, sessions, state, connection, call, move, action, wait, retry, stop) - dispatch `botlab control` ahead of argparse so REMAINDER arguments reach the project CLI untouched - docs/control-protocol.md is the canonical protocol spec; the contract test runs against an unrelated joint-only stdlib middleware to prove the API is not MicroDuck-shaped Co-Authored-By: Claude Code <noreply@anthropic.com>
The protocol core now owns the frozen envelope field set, command statuses, project_key and strict envelope validation with injectable errors; the client consumes these instead of local duplicates. /info declares the extension negotiation surface (empty for local v1). docs/control-hosting.md freezes the M0 hosting decisions: eight-field envelope, extension negotiation, restart and deduplication semantics, dependency rules and the HIL acceptance split. Co-Authored-By: Claude Code <noreply@anthropic.com>
Endpoints now accept HTTPS origins (loopback HTTP keeps its explicit-port rule; plaintext HTTP never leaves the loopback). `botlab control enroll` probes a remote middleware, pins its reported identity and instance into a private remote descriptor, and every later command - including wait/retry - reuses the existing descriptor, receipt and restart-refusal semantics. Remote identity comparison uses the enrollment pin instead of the local checkout path; re-enrollment replaces an endpoint's previous descriptor and instance reuse across endpoints fails with instance_conflict. Tokens arrive via BOTLAB_CONTROL_TOKEN or a hidden prompt, never argv; private CAs are supported through BOTLAB_CONTROL_CA_BUNDLE. Acceptance runs over real TLS with a generated dev CA in tests/test_control_remote.py. Co-Authored-By: Claude Code <noreply@anthropic.com>
Board agents gain an outbound mode: botlab-agent connect dials a device gateway (ws:// loopback, wss:// anywhere) and serves the same dispatch loop as TCP mode, redialing after lease termination or link loss. The gateway relays opaque HIL v1 frames between /agent/<id> and /device/<id> and never parses them, so the inference path inherits no Control-command semantics — no receipts, no retry, no task table. - gateway: one shared bearer token (operator channel, no tokenless mode), exclusive coordinator pairing (device busy), takeover on re-registration closing the displaced pairing, either side dropping releases the HIL lease like a TCP disconnect; compression off, links dial directly (no ambient proxy). - agent connect + serve_stream extraction: TCP handler and outbound mode share one loop; the lease owner is the stream, fixing release identity. - host: transport "gateway" targets via a shared _open_stream helper; token only from BOTLAB_HIL_TOKEN, never in target settings. - endpoint rule mirrors Control M1: ws:// stays loopback with an explicit port, wss:// accepts any host (gateway_endpoint). - botlab target bench: serial-inference latency report (RTT percentiles, effective Hz, budget verdict) for the real-time acceptance tier; the functional tier is covered by tests/test_hil_gateway.py (loopback and real-TLS e2e, exclusive pairing, takeover, stale-session rejection). Co-Authored-By: Claude Code <noreply@anthropic.com>
`botlab control connection` (and remote enroll) now include an `agent_prompt` field: ready-to-paste instructions for the user's AI. Written for an already-prepared environment (botlab-python installed, middleware running) so it teaches no install steps, pins the working directory and --project discipline, and encodes the operational rules proven out on MicroDuck: terminal-state sequencing, parse failure != not sent, capabilities-bounded args, timeout/retry-id semantics, and hidden/pause readiness. The pairing token is never embedded; it stays behind `connection --show-token`, and the new test asserts both that and the absence of install instructions. Co-Authored-By: Claude Code <noreply@anthropic.com>
Remote descriptors pin the serving host's project path from /info; the AI assistant the prompt addresses runs botlab from this checkout, so both connection() and enroll() now pass self.project. Co-Authored-By: Claude Code <noreply@anthropic.com>
Browsers cannot set Authorization headers on a WebSocket handshake, so the
gateway now accepts the same shared bearer credential as one leading
{"type": "gateway-auth", "token": ...} text control frame on both channels
before the binary relay begins. The header path is unchanged; any text frame
after authentication remains a protocol error, and the relay still never
parses HIL frames. Bad or malformed frames fail exactly like a bad header
(1008), a silent client times out after 5 s.
Co-Authored-By: Claude Code <noreply@anthropic.com>
…pairing guidance agent_prompt() now lives in botlab.control.prompts (stdlib-pure, like the protocol core) so third-party middleware can serve byte-identical text to the browser panel. The copy gains an unpaired branch: when state shows the browser not paired, the AI relays the websocket URL and token from `connection --show-token` through chat only — never files, logs or commits. Also documents the optional Origin-gated `agent-prompt` extension endpoint. Co-Authored-By: Claude Code <noreply@anthropic.com>
The browser panel ships the handoff prompt as fixed UI copy instead of fetching it from the middleware; remove the endpoint convention until something actually serves it. Co-Authored-By: Claude Code <noreply@anthropic.com>
The handoff prompt now lives only as fixed copy in the browser's CLI-control panel, so connection/enroll stop carrying an agent_prompt field and the shared prompts module has no consumer left. Co-Authored-By: Claude Code <noreply@anthropic.com>
…panel prompt Co-Authored-By: Claude Code <noreply@anthropic.com>
The board runs gateway + agent on its own loopback and the host forwards port 50060 with a single ssh -N -L; both ws:// legs stay loopback and the cross-machine hop rides SSH. The domain-server runbook shrinks to a pointer to hil.md "Gateway targets" for remote boards. Co-Authored-By: Claude Code <noreply@anthropic.com>
Boards in scenario B often have no egress at all; sharing the assistant host's network or finding Wi-Fi is not worth it. The runbook now builds the wheel on the assistant host, downloads dependency wheels tagged for the board venv's exact Python, scps both over, and installs with --no-index --find-links. Also record the real floor: HIL needs Python >=3.11 because websockets>=17.1 declares Requires-Python >=3.11 and the dial passes the 17.1-only legacy=True flag (16.x raises TypeError). Boards with older system Pythons (or without ensurepip) get a standalone CPython instead. New pitfalls indexed: cp/ABI tag mismatch surfaces as "from versions: none", and downgrading websockets to 16.x is not a fix. Co-Authored-By: Claude Code <noreply@anthropic.com>
A coordinator can compile for minutes before its first frame; the 120s read timeout is not a lease failure. Keep waiting for traffic instead of dropping the gateway link and the device registration while the browser still works. Co-Authored-By: Claude Code <noreply@claude-code>
与 BotLab 85a71b6 逐字节同步:新增 _config.py(read_config 受限 YAML 解析)、 _run_end.py,_declaration/_robot/_resources 等更新;sync_sdk.py --botlab 显式路径重同步后 20 模块 cmp 校验一致。 Co-Authored-By: Claude Code <noreply@anthropic.com>
含 AI 助手 HIL 部署 runbook 文档、control serve 服务与描述符、wheel 校验 及 CI 更新等并行工作线的未提交改动。 Co-Authored-By: Claude Code <noreply@anthropic.com>
# Conflicts: # src/botlab/sdk/_robot.py # tests/test_host.py # tests/test_project.py
- sync src/botlab/sdk from BotLab main (adds _localized_text, imu-sensor observation data already in the WIP merge) and refresh _presets.py - bump version to 0.4.0 and lock metadata - fix ruff findings inherited from the WIP branch (import order, UP035/UP022)
# Conflicts: # tests/test_host.py
carlvon17
added a commit
that referenced
this pull request
Nov 5, 2026
release/0.4.0 was squash-merged as #12 (62 files, 14418+/526-); the remaining tree delta vs this branch is exactly #13 (68+/46-) plus the v3 SDK sync (1034+/217-), i.e. 1102+/263- with zero drift. Recorded with -s ours so the branch history is reachable from main and the ref can be retired; also covers merge/local-wip-20261028 and feat/localized-labels (both ancestors of this branch). Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
变更
发布 botlab-python 0.4.0,修掉 PyPI 上 0.3.0 的最高优先问题:
pip install botlab-python后跑任何内置模板都会ImportError,因为 0.3.0 缺read_config/declare_control/control_profile/action。merge/local-wip-20261028(control serve/descriptor、Control v1 协议、HIL 设备链与 gateway、打包面、docs)。main(bfaade5)重新镜像src/botlab/sdk与src/botlab/_presets.py,逐字节一致(仅_runtime按约定不镜像)。镜像带上了 BotLab 侧的{en, zh}标签支持。{en, zh}文本表)。BotLabmain的内置模板已经用本地化标签,0.4.0 必须同时接受它们,否则模板在 CLI 里报label must be a non-empty string。0.4.0(pyproject.toml、src/botlab/__init__.py、uv.lock),README 中的发布示例同步到 0.4.0。验证
uv run ruff check .→ All checks passeduv run pytest→ 1201 passed, 10 skipped, 2 deselected(含跨语言 digest 夹具PINNED_DIGEST_HEX = cf149d18…,与 BotLabpythonRelease.test.ts同一 pin)uv run python -m botlab._runtime.golden_check tests/fixtures/processors.json→ 54 cases replayedmain的public/templates):botlab validate全通的:g1-gmtrack、microduck(read_config+control_profile+declare_control+ 本地化标签全链路)models/…、templates/…需要站点根,与本次 SDK 无关)read_config/declare_control/control_profile/action均在botlab.__all__中可导入发布前置(未包含在本 PR)
src/botlab/ui快照:需在 BotLabmain上npm run build+npm run build:viewer后botlab ui sync、botlab ui export,再过scripts/verify_wheel.py与浏览器验收。TWINE_*),需人工twine upload/uv publish。v0.4.0release 需附botlab-browser-runtime-0.4.0.zip,否则botlab run拉不到浏览器运行时。