app
Altium - the Altium Bridge
Public Made by Adomby adom
Adom Bridge for Altium Designer: a resident DelphiScript agent gives the AI eval, the 1,100-command process launcher, all 8 EDA surfaces with screenshots, compile/ERC, DRC, OutJob outputs, native SchLib/PcbLib authoring with STEP 3D bodies, and dialog handling by PID.
← Commit history
0.2.24 source: selftest_script_error reports halted_and_recovered vs contained_by_agent
6 files changed
+25−13
bridge-rs/Cargo.lock+1−1@@ -10,7 +10,7 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "altium-bridge"-version = "0.2.23"+version = "0.2.24" dependencies = [ "getrandom", "serde",
bridge-rs/Cargo.toml+1−1@@ -1,6 +1,6 @@ [package] name = "altium-bridge"-version = "0.2.23"+version = "0.2.24" edition = "2021" description = "Adom altium-bridge — the bridge process, in Rust. Calls ab's verbs for the desktop; speaks file IPC to the resident DelphiScript agent inside Altium." license = "MIT"
bridge-rs/src/main.rs+1−1@@ -25,7 +25,7 @@ mod win32; use std::time::Instant; use tiny_http::{Header, Method, Response, Server}; -pub const BRIDGE_VERSION: &str = "0.2.23";+pub const BRIDGE_VERSION: &str = "0.2.24"; fn json_response(status: u16, body: &serde_json::Value) -> Response<std::io::Cursor<Vec<u8>>> { let data = serde_json::to_vec(body).unwrap_or_else(|_| b"{}".to_vec());
bridge-rs/src/verbs.rs+20−8@@ -111,7 +111,7 @@ fn describe() -> Value { json!({"libraryPath": "path (.PcbLib)", "footprintName": "string (optional filter)"}), json!({"holes": "int", "plated": "int", "fixed": "Fp:Pad;..."}), 90, "altium_save the PcbLib afterwards; footprint_primitives on a placed part should then report layerId 74 for the vias.", &["normalize_bodies", "footprint_primitives", "save"], &["Read-modify in place: run once per library install."], json!({"libraryPath": "C:/lib/Adom_ToF.PcbLib"})), verb_doc("selftest_script_error", "Regression test for the script-error safety net (from 0.2.23): makes the agent raise a REAL DelphiScript runtime error on purpose and checks that the bridge photographs Altium's Error box, stops the halted script itself and leaves no dialog behind. Flashes one error box for under a second. Run it after any change to agent.rs / dialogs.rs and once on every new Altium build.",- json!({}), json!({"netWorks": "bool", "errorShot": "base64 png", "autoRecovered": "bool", "dialogsLeft": "int"}), 60,+ json!({}), json!({"netWorks": "bool", "outcome": "halted_and_recovered | contained_by_agent | unhandled", "errorShot": "base64 png (halted outcome only)", "autoRecovered": "bool", "dialogsLeft": "int"}), 60, "netWorks:true is the pass. The agent is stopped afterwards by design; the next verb restarts it.", &["agent_recover", "dialog_log", "agent_status"], &["It really does halt the engine for a moment: do not run it while a user is mid-edit in Altium."], json!({})), verb_doc("symbol_prims", "Read a SchLib component's drawing: primitive counts by kind, body rectangle, polyline bounding box, display mode and the footprint models. Read-only, use it to verify add_symbol_art / set_models.", json!({"libraryPath": "path (.SchLib)", "symbolName": "string", "models": "bool, default false (the model walk halts the engine on some builds)"}), json!({"pins": "int", "rectangles": "int", "lines": "int", "polylines": "int", "bodyRectMil": "[..]", "polyBboxMil": "[..]", "models": "[\"PCBLIB:NAME\"]"}), 60,@@ -496,17 +496,29 @@ pub fn dispatch(command: &str, args: &Value, _forwarded: &[(String, String)]) -> "place_on_sch" => library::place_on_sch(args), "add_symbol_art" => library::add_symbol_art(args), "selftest_script_error" => {+ // Two SAFE outcomes exist, and which one you get depends on the Altium build:+ // halted - AD 26.9.1: an Error box, the script parks on a breakpoint; the bridge must+ // photograph it and send EditScript:Stop (agent_script_error + autoRecovered).+ // contained - Altium Develop: the engine raises a catchable exception, the agent's own+ // Try/Except answers ok:false in ~2 s and the loop never stops.+ // Anything else (a timeout, a dialog left on screen) is the failure this test exists for. let mut r = agent::call("selftest_halt", &[], None, Duration::from_secs(45));- let caught = r.get("errorCode").and_then(|c| c.as_str()) == Some("agent_script_error");- let recovered = r.get("autoRecovered").and_then(|b| b.as_bool()).unwrap_or(false);+ let halted_ok = r.get("errorCode").and_then(|c| c.as_str()) == Some("agent_script_error")+ && r.get("autoRecovered").and_then(|b| b.as_bool()).unwrap_or(false);+ let contained_ok = r.get("data").and_then(|d| d.get("error")).and_then(|e| e.as_str())+ .map(|e| e.starts_with("exception in agent")).unwrap_or(false) && agent::is_alive(); let dialogs_left = crate::dialogs::scan().len();- r["netWorks"] = json!(caught && recovered && dialogs_left == 0);+ let pass = (halted_ok || contained_ok) && dialogs_left == 0;+ r["netWorks"] = json!(pass);+ r["outcome"] = json!(if halted_ok { "halted_and_recovered" } else if contained_ok { "contained_by_agent" } else { "unhandled" }); r["dialogsLeft"] = json!(dialogs_left);- r["success"] = json!(caught && recovered && dialogs_left == 0);- r["_hint"] = json!(if caught && recovered && dialogs_left == 0 {- "PASS: the deliberate runtime error was caught, photographed (errorShot), the halted script was stopped (EditScript:Stop) and nothing is left on the user's screen. The next verb restarts the agent."+ r["success"] = json!(pass);+ r["_hint"] = json!(if pass && halted_ok {+ "PASS (halted_and_recovered): this Altium build halts on a script error; the bridge photographed the Error box (errorShot), sent EditScript:Stop and left nothing on screen. The next verb restarts the agent."+ } else if pass {+ "PASS (contained_by_agent): this Altium build raises a catchable exception, so the agent's own handler answered and the loop never stopped. No box, no halt." } else {- "FAIL: the safety net did not fully handle a deliberate script error. altium_agent_recover, then fix agent.rs/dialogs.rs before shipping."+ "FAIL: a deliberate script error was neither contained by the agent nor recovered by the bridge, or it left a dialog up. altium_agent_recover, then fix agent.rs/dialogs.rs before shipping." }); r }
bridge.json+1−1@@ -2,7 +2,7 @@ "manifest_version": 1, "name": "altium", "displayName": "Altium Designer",- "version": "0.2.23",+ "version": "0.2.24", "description": "Drive Altium Designer from Adom: a resident DelphiScript agent (eval + the 1,100-command process launcher), the X2 -R command line, UIA over the VCL shell, dialogs by PID, screenshots of every Altium window, and Altium 365.", "homepage": "https://wiki.adom.inc/adom/altium-bridge", "docs": "https://wiki.adom.inc/adom/altium-bridge",
page.json+1−1@@ -140,4 +140,4 @@ "skills/altium-wiki-import/SKILL.md", "uninstall.sh" ]-}+}