fix(ai-plugin): writeMacro family no-ops on web Document Server — nes…#596
Open
zhaokaige wants to merge 1 commit into
Open
fix(ai-plugin): writeMacro family no-ops on web Document Server — nes…#596zhaokaige wants to merge 1 commit into
zhaokaige wants to merge 1 commit into
Conversation
…ted eval shadowed by sandbox
On a web-deployed Document Server, writeMacro (and generateDocx /
changeParagraphStyle, same pattern) silently fail: WRITE requests report
success but never modify the document; READ requests return no data.
(1) WRITE: the macro code is passed to Asc.Editor.callCommand as a nested
eval inside the function body. Asc.plugin.callCommand serializes the function
via toString(), and the editor core executes it through _safe_eval_closure
(sdk-all-min.js), which wraps the string with Function.apply(... return eval(…))
and shadows the window formal parameter — a deliberate plugin sandbox. A side
effect is that a nested eval() inside the function body returns undefined and
never runs, so the macro silently no-ops. Verified by four probes:
new Function(code) and executeCommand("command", code) mutate; nested
eval(code) and nested new Function(code)() do not. The macro code must be the
function body, not runtime-eval'd data.
(2) READ: replacing eval with new Function fixes WRITE, but a new Function
body discards the last expression's value. The prompts and tool descriptions
were built on eval's auto-return semantics, so a READ macro returned nothing.
Fix:
- helpers.js (3 sites): dual-form new Function wrapper. Expression form
captures an IIFE / single expression; if new Function throws (multi-statement
or has return), fall back to the statement form which captures a top-level
return. try/catch + onlyoffice_id_result / onlyoffice_id_error_message
contract preserved (safePluginEval swallows thrown errors).
- helperFuncs.js + helpers.js: align prompts and tool descriptions to the new
execution model — read examples use explicit return; "last expression" ->
"explicit return"; add READ/WRITE/CHAT decision rule (mutate only on explicit
modify; reading never mutates), GENERATIVE rule (ask first on ambiguous
"write content" requests), and SELF-CHECK rule (verify top-level return on
READ macros).
Sandbox untouched; plugin isolation unchanged.
Co-Authored-By: Claude <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.
On a web-deployed Document Server, writeMacro (and generateDocx / changeParagraphStyle, same pattern) silently fail: WRITE requests report success but never modify the document; READ requests return no data.
(1) WRITE: the macro code is passed to Asc.Editor.callCommand as a nested eval inside the function body. Asc.plugin.callCommand serializes the function via toString(), and the editor core executes it through _safe_eval_closure (sdk-all-min.js), which wraps the string with Function.apply(... return eval(…)) and shadows the window formal parameter — a deliberate plugin sandbox. A side effect is that a nested eval() inside the function body returns undefined and never runs, so the macro silently no-ops. Verified by four probes: new Function(code) and executeCommand("command", code) mutate; nested eval(code) and nested new Function(code)() do not. The macro code must be the function body, not runtime-eval'd data.
(2) READ: replacing eval with new Function fixes WRITE, but a new Function body discards the last expression's value. The prompts and tool descriptions were built on eval's auto-return semantics, so a READ macro returned nothing.
Fix:
Sandbox untouched; plugin isolation unchanged.