From 9c11ea3b041f30f71c307530d58e2ec691078c07 Mon Sep 17 00:00:00 2001 From: Yang Cao Date: Thu, 5 Nov 2026 05:08:32 +0000 Subject: [PATCH] docs: bring agent and API docs up to date with placement, park and position_bed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agent guide: the gateway now moves the A1's bed; routing follows the amended §1.3 (position_bed included, lab-skills #98 pending); a one-line A1 agent loop; position_bed as its own step before the snapshot; a Bed positioning section (request/response, arm-clear statement, gates and refusal codes, hardware result, no retry); the park position and when to return the bed for pickup; bed.moved in the event list; refusal table. - API reference: correct routing statement (no merged SDK skill yet); position_bed request, response and refusals; bed.moved event. - README: lab-skills status, bed.moved, end-to-end steps with placement, inspect and park, agent-mode scope. - Generated reference intro, AGENTS.md and AGENT_RULES.md rule 4 wording. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 3 +- AGENT_RULES.md | 4 +- README.md | 37 +++++--- docs/API_REFERENCE.md | 32 +++++-- src/bambu_server/docs/AGENT_GUIDE.md | 124 +++++++++++++++++++-------- src/bambu_server/documentation.py | 5 +- 6 files changed, 148 insertions(+), 57 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 745771c..6806ebf 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,7 +19,8 @@ telemetry into one STATUS_SPEC v1.0 HTTP surface per configured printer. Monitoring is the default. A human approved (2026-10-04) a narrow, human-in-the-loop control plane, enabled per deployment by `dispatch.enabled`: -STATUS_SPEC v1.1 claims plus exactly four verbs -- camera snapshot, chamber +STATUS_SPEC v1.1 claims plus exactly four verbs (and, since 2026-11-05, a +fifth on the A1 only; see below) -- camera snapshot, chamber light (added 2026-10-05), `start_print` for an approved job after a person confirms the plate is empty, and `stop_print`. On 2026-10-20 a human approved the external spool (`vt_tray`) as a `start_print` mapping target for printers diff --git a/AGENT_RULES.md b/AGENT_RULES.md index afdf23b..1edf585 100644 --- a/AGENT_RULES.md +++ b/AGENT_RULES.md @@ -46,7 +46,9 @@ the Bambu printer gateway. decide the plate is empty from a camera snapshot it took under its claim (`plate_check_method: agent_camera`, frame at most `dispatch.agent_snapshot_max_age_s` old, deciding agent and rationale - recorded, frame archived with its SHA-256). The switch is off by default, + recorded, frame archived with its SHA-256). Under the same switch, approved + 2026-11-05, it may also move the bed with `position_bed` as rule 1 allows + (`AGENTIC_LAB_DESIGN.md` §1.3, *Bambu A1 bed positioning*). The switch is off by default, only an admin can flip it, and every flip is audited. Nothing else changes: on every other printer, and on the A1 with the switch off, the rule above holds in full, and no agent ever retries a failed or uncertain dispatch. diff --git a/README.md b/README.md index 681d808..b11d545 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,9 @@ confirms the plate is empty before every start, except on a printer whose **agent mode** an admin has switched on — approved 2026-11-02 for the Bambu A1 (`bambu_a1_01`) only — where an agent may decide from a claimed camera snapshot ([Agent mode](#agent-mode-bambu-a1-only)). The third-party library's -other command methods remain unreachable. Control is not yet exposed as -`lab-skills` skills. +other command methods remain unreachable. Control is not yet exposed as merged +`lab-skills` skills (ac-organic-lab PR #98 adds the A1's); until then the lab +rules let agents use the A1 agent-mode workflow on this API directly. Every job keeps a durable, schema-versioned **result bundle** and its exact artifact on the gateway's disk. Filing a record in the ELN is optional and goes @@ -182,7 +183,8 @@ sliced) plate is reported. **Events.** `GET /events?after=` (or the webhooks in `agent_workflow.event_webhook_urls`) delivers `job.started`, one event per terminal state (`job.finished`, `job.failed`, `job.rejected`, -`job.cancelled`), `job.cooled`, and `gateway.restarted`. Each event carries +`job.cancelled`), `job.cooled`, `bed.moved` (A1 `position_bed`), and +`gateway.restarted`. Each event carries `schema_version`, `event_id`, `gateway_id`, `boot_id`, `submission_id`, `printer_id`, `state`, `updated_at`, `eln_project` and `note`. Event ids are zero-padded decimals that keep increasing across restarts (they are kept in @@ -201,18 +203,26 @@ logged and never affect a job. **End-to-end for an agent:** -1. `POST /submissions` (sliced `.3mf`, `target_machine`, optional `eln_project`). +1. `POST /submissions` (sliced `.3mf`, or an `.stl` with `material` and + optionally `placement=front_left`; `target_machine`; optional `eln_project`). 2. Approval: a person approves — or, on the A1 in agent mode, the agent. 3. `POST /printers/{id}/control/claim`, then keep it alive with `heartbeat`. -4. Plate check: a person confirms (`in_person` / `printer_camera`) — or, in +4. On the A1, `POST /printers/bambu_a1_01/control/position_bed` + `{"position": "inspect", "bed_path_clear": true}` once the arm is confirmed + clear, because the last print left the bed parked forward out of the + camera's view. +5. Plate check: a person confirms (`in_person` / `printer_camera`) — or, in agent mode, the agent takes `POST /printers/{id}/control/snapshot`, judges the returned `image_base64` itself, and keeps the `token`. -5. `POST /printers/{id}/control/start_print` (see [Agent mode](#agent-mode-bambu-a1-only)). -6. Wait for `job.finished` (or `job.failed`) on `/events` or a webhook. -7. Wait for cool-down: `job.cooled`, or poll +6. `POST /printers/{id}/control/start_print` (see [Agent mode](#agent-mode-bambu-a1-only)), + then release the claim. +7. Wait for `job.finished` (or `job.failed`) on `/events` or a webhook. The + A1's end gcode parks the bed at `end_bed_y_mm` (Y 250 here) for pickup. +8. Wait for cool-down: `job.cooled`, or poll `GET /submissions/{id}/pickup-targets` until `ready`. -8. Hand the bed-frame `objects` to the arm agent, which applies its own - calibration. The bundle at `/submissions/{id}/result` keeps the record. +9. Hand the bed-frame `objects` and `bed_park_y_mm` to the arm agent, which + applies its own calibration. The bundle at `/submissions/{id}/result` keeps + the record. `agent_workflow.vision_enabled` adds an optional, dependency-light advisory check, `POST /printers/{id}/bed-check`, that compares a claimed snapshot with an @@ -224,7 +234,8 @@ decision. ### Agent mode (Bambu A1 only) Approved by Yang on 2026-11-02. With the switch on, an agent may submit, -approve and start jobs on the Bambu A1, deciding itself that the plate is empty. +approve and start jobs on the Bambu A1, deciding itself that the plate is empty, +and (approved 2026-11-05) move its bed with `position_bed`. Everywhere else, and on the A1 with the switch off, agents are refused and the human-in-the-loop path is unchanged. @@ -245,8 +256,8 @@ human-in-the-loop path is unchanged. verified identity and the agent id are both recorded (`requested_by_agent`, `approved_by_agent`, `dispatch.dispatched_by_agent`). - **Refusals** are 403 with `agent_mode: "not_eligible"` (any printer but the - A1) or `agent_mode: "off"` (switch off), for agent submissions, approvals and - starts. + A1) or `agent_mode: "off"` (switch off), for agent submissions, approvals, + bed moves and starts. An agent's start, on the A1 with the switch on: diff --git a/docs/API_REFERENCE.md b/docs/API_REFERENCE.md index 1ae9e96..b324017 100644 --- a/docs/API_REFERENCE.md +++ b/docs/API_REFERENCE.md @@ -35,9 +35,13 @@ the routes enabled in a deployment. | Optional vision advisory | `POST /printers/{id}/bed-check` (dispatch and vision enabled) | | Documentation | `GET /docs`, `/openapi.json`, `/agent-docs`, `/agent-docs/api-reference`, `/docs/agent`, `/llms.txt` | -Agents use the SDK for printer I/O. An occupied or unclear claimed snapshot -means release the claim and stop; never send a start request to test the gate. -Failed or uncertain dispatches require human reconciliation, without retries. +Until `lab-skills` merges its Bambu skills (ac-organic-lab PR #98), the lab +rules (`AGENTIC_LAB_DESIGN.md` §1.3) let an agent drive only the A1 agent-mode +workflow, `position_bed` included, directly on this API through the +authenticated edge; see the [agent guide](../src/bambu_server/docs/AGENT_GUIDE.md). +An occupied or unclear claimed snapshot means release the claim and stop; +never send a start request to test the gate. Failed or uncertain dispatches +and undelivered bed moves require human reconciliation, without retries. ## Printer inventory @@ -115,6 +119,20 @@ failed gate; `allowed_actions` on `/status` mirrors them, and the camera frame a start was confirmed against. Without dispatch enabled the control routes are absent; the stored plate-evidence route remains registered. +**Bed positioning (Bambu A1 only).** `POST /printers/bambu_a1_01/control/position_bed` +with the claim token and `{"position": "inspect" | "pickup", "bed_path_clear": true, +"reason"?: "..."}` moves the bed along Y only to the configured position +(`bed_positions` on the printer: `inspect_y_mm`, where the camera sees the +whole plate, and `pickup_y_mm`, kept equal to the slicer's `end_bed_y_mm`). +It returns `{printer_id, position, y_mm, requested_at, moved_by, +moved_by_verified, agent_id, note}`. Refusals: 423 without the claim; 412 when +the printer is not idle, reports an error, has a gateway job in flight, or has +no `bed_positions` (every printer but the A1); 403 for an unverified caller, or +an agent while agent mode is off; 422 when `bed_path_clear` is not `true` or +the position is unknown; 502 when the command was not delivered (never retry). +The printer does not report bed position, so confirm with a snapshot. A +delivered move emits `bed.moved`. + **Camera snapshot for a plate check.** `POST /printers/{id}/control/snapshot` with the claim token returns `{token, printer_id, captured_at, sha256, content_type: "image/jpeg", image_base64}`. The token is valid for that printer @@ -132,7 +150,8 @@ authenticated surface. Never send secrets or printer addresses in submissions. Approved 2026-11-02 for `bambu_a1_01`. An agent is a request carrying `X-Agent-Id`, or whose edge-verified role is in `dispatch.agent_roles` -(default `agent`). Agents may submit, approve and start only on a printer with +(default `agent`). Agents may submit, approve, move the bed (`position_bed`) +and start only on a printer with `agent_mode_eligible: true` (config accepts it on a Bambu A1 only) whose switch is on; otherwise 403 with `agent_mode: "not_eligible"` or `"off"`. @@ -195,8 +214,9 @@ parking at Y 250 instead of the stock Y 180 puts every object 70 mm further toward the front of the printer. `GET /events?after=` is a pollable lifecycle feed: `job.started`, -`job.finished`, `job.failed`, `job.rejected`, `job.cancelled`, `job.cooled` -and `gateway.restarted`, each with `schema_version`, `event_id`, +`job.finished`, `job.failed`, `job.rejected`, `job.cancelled`, `job.cooled`, +`bed.moved` (printer id and a note naming the position, Y, who and why) and +`gateway.restarted`, each with `schema_version`, `event_id`, `gateway_id`, `boot_id`, `submission_id`, `printer_id`, `state`, `updated_at`, `eln_project`, `note`, and for job events the bed-frame `object_positions`; `job.finished` and `job.cooled` add `pickup`. Ids persist diff --git a/src/bambu_server/docs/AGENT_GUIDE.md b/src/bambu_server/docs/AGENT_GUIDE.md index ccb715c..514efd0 100644 --- a/src/bambu_server/docs/AGENT_GUIDE.md +++ b/src/bambu_server/docs/AGENT_GUIDE.md @@ -1,10 +1,12 @@ # Bambu gateway: operating guide for agents This gateway monitors multiple Bambu printers and, where enabled, provides -claimed camera snapshots, chamber-light control, print starts and print stops. -Each printer's primary operation is printing a job; the aggregate gateway -has no physical operation of its own. It does not home, jog, heat on demand, -calibrate a robot or move a robot. Monitoring never starts or stops a print. +claimed camera snapshots, chamber-light control, print starts and print stops, +and on the Bambu A1 only, moving the bed between two named positions +(`position_bed`). Each printer's primary operation is printing a job; the +aggregate gateway has no physical operation of its own. It does not home, jog, +move any other axis, heat on demand, calibrate a robot or move a robot. +Monitoring never starts or stops a print. [API reference]({{root}}agent-docs/api-reference) · [OpenAPI]({{root}}openapi.json) · [Read-only Swagger]({{root}}docs) · @@ -17,13 +19,22 @@ to execute hardware actions. Agents respect live claims and preconditions and never bypass a refusal. Registration in the lab plan executor is a separate approval; these endpoints do not add it. -**How printer I/O is routed.** `lab-skills` has no Bambu skill yet. Until it -does, the lab rules (`AGENTIC_LAB_DESIGN.md` §1.3, *Bambu A1 agent mode*) -allow exactly one route: the A1 agent-mode workflow below, called directly on -this gateway's HTTP API through the authenticated edge. No other printer may -be driven by an agent, and nothing beyond that workflow is allowed on the A1. -When a Bambu skill lands in `lab-skills`, this exemption ends and the same -steps go through the SDK. +**How printer I/O is routed.** `lab-skills` has no merged Bambu skill yet +(ac-organic-lab PR #98 adds `snapshot`, `position_bed` and `start_print` for +the A1). Until it is merged, the lab rules (`AGENTIC_LAB_DESIGN.md` §1.3, +*Bambu A1 agent mode* and *Bambu A1 bed positioning*, the latter added +2026-11-05) allow exactly one route: the A1 agent-mode workflow below, +including `position_bed`, called directly on this gateway's HTTP API through +the authenticated edge. No other printer may be driven by an agent, and +nothing beyond that workflow is allowed on the A1. When the Bambu skill lands +in `lab-skills`, this exemption ends and the same steps go through the SDK. + +**The A1 agent loop at a glance.** Submit (optionally an `.stl` with +`placement=front_left`) → check the validation and object positions → approve +→ claim → `position_bed` to `inspect` → claimed snapshot → your plate decision +→ `start_print` → release → wait for `job.finished` (the print's own end gcode +parks the bed at the pickup position) → wait for `job.cooled` → hand +`pickup-targets` to the arm agent. Each step is described below. ## Find the printer and establish identity @@ -43,7 +54,8 @@ For the dashboard assistant's SDK documentation discovery, request session or manufacture edge identity headers. 4. Read `/printers/{id}/agent-mode`. Eligibility is static configuration; `enabled` is the audited admin switch. Only the approved Bambu A1 workflow - (`bambu_a1_01`) may use agent submission, approval and autonomous plate checks. + (`bambu_a1_01`) may use agent submission, approval, bed positioning and + autonomous plate checks. H2D and P1S keep their human-in-the-loop rules. An agent cannot flip the switch, even if its request carries an admin role. @@ -97,34 +109,34 @@ stop command for a running print. 1. Acquire `/printers/{id}/control/claim` (see *How printer I/O is routed*) and keep the claim alive with `heartbeat`. Send its `X-Claim-Token` on every control request. - Never take over another session's claim; release yours on exit. + Never take over another session's claim; release yours on exit. Hold one + claim for the whole sequence: a snapshot is valid only under the claim it + was taken with. 2. Read the printer's status and `allowed_actions`. These are current device preconditions, not a complete job-specific authorization. A listed `start_print` does not mean that the build plate is clear. - On the A1 the previous print leaves the bed parked forward for pickup, - where the camera cannot see the front of the plate. Before the snapshot, - move it into view: `POST /printers/bambu_a1_01/control/position_bed` with - `{"position": "inspect", "bed_path_clear": true}`. Send - `bed_path_clear: true` only after confirming the robot arm is parked clear - of the bed's travel and nothing stands above the plate. If the move is - refused or returns 502, stop and ask a person; never retry it. For pickup, - `{"position": "pickup", ...}` returns the bed to where the arm expects it - (`bed_park_y_mm` on `pickup-targets`). -3. Take `POST /printers/{id}/control/snapshot` under that claim. Inspect the +3. On the A1, move the bed into the camera's view first (see *Bed + positioning* below): a finished print leaves the bed parked forward for + pickup, where the camera cannot see the front of the plate, and + front-left parts sit exactly there. Send `position_bed` with + `{"position": "inspect", "bed_path_clear": true, "reason": "..."}`, then + wait a few seconds for the move to finish before the snapshot. +4. Take `POST /printers/{id}/control/snapshot` under that claim. Inspect the returned image itself and retain its token. If an object is present, the plate is obscured, or the image is unclear, record occupied/unknown, release the claim and stop. Do not send a start request to test a known occupied plate. Ask a person to inspect/remove the object, then obtain fresh evidence before any later attempt. -4. Only after a clear decision, call `/printers/{id}/control/start_print` with the +5. Only after a clear decision, call `/printers/{id}/control/start_print` with the approved submission, `plate_check_method: agent_camera`, that snapshot token, an affirmative empty-plate decision, its rationale, and an explicit mapping for every filament. The snapshot must be from the same printer and claim, normally no older than 120 seconds (deployment-configurable). -5. Inspect the returned job state. A successful HTTP response can carry a +6. Inspect the returned job state. A successful HTTP response can carry a failed job if running could not be confirmed. Never automatically repeat a failed, timed-out, disconnected or uncertain dispatch. Preserve the evidence and ask a person to reconcile the printer first. +7. Release the claim. The print runs without it. The gateway still requires a reachable, observable, idle, cold printer; a declared matching build plate; successful artifact revalidation; suitable @@ -140,6 +152,44 @@ The optional `/bed-check` compares an existing claimed snapshot with an operator reference. Its output is advisory and never substitutes for the agent's own visual decision. +## Bed positioning (Bambu A1 only) + +`POST /printers/bambu_a1_01/control/position_bed` moves the bed along Y only, +in absolute mode (`G90` / `G1 Y F`), to one of two positions the +deployment configures. Approved by Yang on 2026-11-05 (bambu-server PR #12) +and allowed for agents by `AGENTIC_LAB_DESIGN.md` §1.3 (ac-organic-lab #103). + +| Position | Use | +|---|---| +| `inspect` | The camera sees the whole plate. Use it before the plate-check snapshot. | +| `pickup` | Where the robot arm takes parts off. A finished print already parks the bed here through its end gcode, so call it only to return the bed after an `inspect`. | + +Request body: `position` (`inspect` or `pickup`), `bed_path_clear` (must be +literally `true`) and an optional `reason`, which is recorded. You name a +position, never a coordinate. The response gives `position`, the configured +`y_mm`, `requested_at`, `moved_by`, `moved_by_verified`, `agent_id` and a +`note`. + +- **Before you send it:** `bed_path_clear: true` states that the robot arm is + parked clear of the bed's travel and nothing stands above the plate. Send it + only after confirming that from the arm's own reported state, or from a + person's statement for that specific move. If you cannot confirm it, do not + move the bed. The A1 camera shows the bed, not the arm. +- **Gates:** the claim (423); an idle printer reporting no error and no + gateway job in flight (412, and `position_bed` is missing from + `allowed_actions`); an edge-verified identity (403); for an agent, A1 agent + mode on (403 with `agent_mode`). Any other printer answers 412: the verb is + configured on the A1 only. +- **After it:** the printer does not report bed position. Confirm the move + with a claimed snapshot before relying on it. On 2026-11-05 the A1 accepted + the move straight after a finished print, without homing, and `inspect` + showed the whole plate. +- **Failure:** a refusal or a 502 (command not delivered) means stop and ask a + person. Never retry the move, never "fix" it by homing or any other command, + and never use it as a recovery step. +- Each delivered move emits a `bed.moved` event naming the position, the Y, + who moved it and the reason. + ## External spool and color labels An AMS assignment uses the observed `(ams_id, tray_id)` pair. For a @@ -158,7 +208,9 @@ is an estimate or unknown; approval does not prove sufficient quantity. ## Observe completion, cooling and records -Use the job record and `/events?after=` for lifecycle changes. +Use the job record and `/events?after=` for lifecycle changes: +`job.started`, `job.finished`, `job.failed`, `job.rejected`, `job.cancelled`, +`job.cooled`, `bed.moved` and `gateway.restarted`. `job.started` is not completion; wait for `job.finished` or a terminal failure. Event IDs persist across restarts. Save the event cursor; do not turn event delivery into an automatic command retry. @@ -172,9 +224,12 @@ never commands the arm. Unknown positions are an empty list, never a guess. On the A1 the bed itself moves in Y, so bed coordinates do not fix a world position on their own: `bed_park_y_mm` says where the job's end gcode parked the bed (`null` when unknown, e.g. the stock Y 180 end move). A larger value -puts the plate, and every object on it, that much further toward the front. -After the print the bed motors are released, so the bed can be pushed; check -it has not moved before relying on it. +puts the plate, and every object on it, that much further toward the front; +on this deployment the park is Y 250, 70 mm forward of stock. After the print +the bed motors are released, so the bed can be pushed. If anything moved the +bed since the print (an `inspect` move, a person), return it with +`position_bed` `pickup` and check it with a snapshot before the arm relies on +it. A front-left part is out of the camera's view at the pickup position. `/submissions/{id}/artifact` returns the exact stored bytes and SHA-256 ETag. `/result` returns the durable versioned bundle; `final: false` means the job is @@ -200,11 +255,11 @@ with `last_error.code: print_failed`. `activity` separately reports `idle`, | 403 | Identity/admin requirement or agent mode refused the action. Do not impersonate a person or flip the switch. | | 404 | Unknown job/printer/resource, or a route disabled in this deployment. Inspect OpenAPI. | | 409 | Claim/job state conflict or ineligible admin toggle. Respect the holder/state. | -| 412 | A dispatch precondition failed; the body names the gate, and may include Retry-After. Do not change parameters to evade it. | +| 412 | A dispatch or bed-move precondition failed; the body names the gate, and may include Retry-After. Do not change parameters to evade it. | | 423 | Missing, stale or wrong claim token on a hard-enforced control action. | | 422 | Invalid request or failed slicing; inspect the response. | | 501 | Unsupported snapshot model, including H2D. | -| 502 / 503 | Camera/upstream failure or a service component unavailable. A failed camera check is not a clear plate. | +| 502 / 503 | Camera/upstream failure, an undelivered bed move or printer command, or a service component unavailable. A failed camera check is not a clear plate; an undelivered move is never retried. | Refusal envelopes can carry gate-specific fields alongside `detail`; FastAPI request validation uses its standard structured `detail` list. OpenAPI names @@ -215,6 +270,7 @@ Background monitoring reconnects independently of HTTP reads. Gateway shutdown does not stop the physical printer. A restart loses active claims and can record an interrupted dispatch as failed/uncertain; it never authorizes replay. Cooldown event watching does not resume after restart, so poll pickup readiness. -Turning agent mode off blocks subsequent agent submissions, approvals and -starts; it does not stop an already-running print. Operator inspection resolves -ambiguous outcomes; never home or move the bed as a recovery step. +Turning agent mode off blocks subsequent agent submissions, approvals, bed +moves and starts; it does not stop an already-running print. Operator +inspection resolves ambiguous outcomes; never home or move the bed as a +recovery step (`position_bed` is for the plate check and pickup only). diff --git a/src/bambu_server/documentation.py b/src/bambu_server/documentation.py index 7b52026..8182b24 100644 --- a/src/bambu_server/documentation.py +++ b/src/bambu_server/documentation.py @@ -48,8 +48,9 @@ def api_reference(schema: dict[str, Any], root: str = "../") -> str: "", "Paths are relative to the gateway. Browser clients use the authenticated `/bambu` " "edge prefix. The dashboard documentation proxy is read-only and cannot execute " - "these operations. lab-skills has no Bambu skill yet; until it does, agents may " - "drive only the A1 agent-mode workflow here, as the operating guide describes.", + "these operations. lab-skills has no merged Bambu skill yet; until it does, agents " + "may drive only the A1 agent-mode workflow here (position_bed included), as the " + "operating guide describes.", "", "## Endpoints", "",