From 89e014afa1ced7b312be5a0c1ce3d76073791af9 Mon Sep 17 00:00:00 2001 From: AI Assistant Date: Thu, 3 Sep 2026 13:04:43 +1000 Subject: [PATCH] AI bridge: fix cross-realm reply drop + add diagnostics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit read_editor_buffer came back empty in testing: the reply to the chat iframe was dropped because event.source (the iframe's Window) is from another JS realm, so dyn_into::() returned None. - reply via unchecked_ref::() (postMessage works cross-realm even though instanceof Window does not), plus a DOM-query fallback that posts straight to the '#ai-assistant-editor-embed iframe' contentWindow. - console.log at each step ([cmms-ai-bridge] …); on-page command-line error if save_to_bytes fails. - Cargo.toml: web-sys HtmlIFrameElement. --- Cargo.toml | 1 + src/app/update/mod.rs | 33 +++++++++++-------- src/sys.rs | 73 ++++++++++++++++++++++++++++++------------- 3 files changed, 72 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 267e1e81..5929c968 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,6 +92,7 @@ web-sys = { version = "=0.3.85", features = [ "Document", "Element", "HtmlAnchorElement", + "HtmlIFrameElement", "Blob", "File", "FileSystemDirectoryHandle", diff --git a/src/app/update/mod.rs b/src/app/update/mod.rs index dfc7f9e5..ff942962 100644 --- a/src/app/update/mod.rs +++ b/src/app/update/mod.rs @@ -877,19 +877,26 @@ impl OpenCADStudio { // Reply with the active drawing as ASCII DXF (the editor's // export format regardless of the on-disk format). An empty // reply tells the CMMS read tool the buffer isn't ready. - let dxf = self - .tabs - .get(self.active_tab) - .and_then(|tab| { - crate::io::save_to_bytes( - &tab.scene.document, - "dxf", - tab.scene.document.version, - ) - .ok() - }) - .map(|bytes| String::from_utf8_lossy(&bytes).into_owned()) - .unwrap_or_default(); + let dxf = match self.tabs.get(self.active_tab).map(|tab| { + crate::io::save_to_bytes( + &tab.scene.document, + "dxf", + tab.scene.document.version, + ) + }) { + Some(Ok(bytes)) => String::from_utf8_lossy(&bytes).into_owned(), + Some(Err(e)) => { + self.command_line.push_error( + crate::tf!("AI Assistant: could not read the drawing: {e}").as_ref(), + ); + String::new() + } + None => String::new(), + }; + web_sys::console::log_1(&wasm_bindgen::JsValue::from_str(&format!( + "[cmms-ai-bridge] poll: want_read, replying {} bytes DXF", + dxf.len() + ))); crate::sys::reply_ai_editor_buffer(&dxf); } if let Some(dxf) = apply { diff --git a/src/sys.rs b/src/sys.rs index 30ee3c48..e80a947d 100644 --- a/src/sys.rs +++ b/src/sys.rs @@ -560,7 +560,11 @@ mod ai_editor_bridge { struct State { listener: Option>, - reply_to: Option, + // The chat iframe's Window, kept as a raw JsValue: it comes from + // another realm (the