Detach and stop the active playback engine before asynchronous scene teardown so switching to a non-playable scene cannot leave narration, timers, or effects running.\n\nRecheck engine ownership after lecture-session creation in manual and auto-play paths, close stale sessions, and reject progress callbacks from detached engines. Add regression coverage for all three races.
Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn>
* feat(chat): add PPT element references to Pi
* fix(chat): include chart values in reference routing
* fix(chat): harden slide element reference evidence
* fix(playback): clear element reference on scene navigation
* fix(pi): preserve element grounding across child retries
---------
Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn>
* feat(agent): add edit_elements NL → EditIntent vertical (#895)
Give the editing surface its first real consumer: natural-language
per-element style/geometry edits flow through the same EditIntent
vocabulary as pointer gestures, with an all-or-nothing validation gate
and one undo entry per instruction.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(agent): harden edit_elements against CR findings (#895)
Re-validate intents at apply time (atomic refuse on missing/locked ids),
type-check prop values, require an open edit session for undo, clamp line
stroke width correctly, enforce group cohesion, nest shape text chrome,
and surface refuseReason on the tool card.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(agent): close remaining edit_elements CR residuals (#895)
Feed apply outcomes into next-turn history and post-run chat corrections,
phrase tool success as proposed-not-applied, and tighten gradient/filters/
enums/per-type value validation plus label-less shape text refusal.
Co-authored-by: Cursor <cursoragent@cursor.com>
* refactor(agent): derive edit_elements prop validation from the DSL schema (#895)
Three review rounds each found a hand-written validator disagreeing with
the DSL contract (a gradient pos range pinned at [0,1] against the
percent contract, a textType enum matching the DSL in neither direction,
per-type ownership gaps like vertical-on-shape and color-on-everything).
Replace the class instead of the instances:
- The gate now loads the dsl-generated JSON schema
(@openmaic/dsl/schema/scene.schema.json) and validates every proposed
prop value against the target element type's subschema via a compact
schema-subset checker — per-type ownership, enums, and structured
shapes (outline/shadow/gradient/filters) come from the single source
of truth and stay correct as the DSL evolves.
- Explicit policy layers stay on top: the content/identity blocklist
(schema would allow what policy forbids), geometry clamps (coords,
min sizes, line stroke width), and a numeric-range overlay for what
plain number types cannot express — gradient stop pos is a percent in
[0,100] (the previous [0,1] check refused canonical gradients and the
unit test pinned the wrong contract), fontSize/lineHeight/radius
bounds, filter value length, stop-count cap.
- Consequences: color is refused on types that do not render it, with
prompt guidance steering text color to defaultColor and shape body to
fill; fill on charts is now allowed (the schema has it; the inventory
already advertised it); textType accepts the full DSL enum.
- Apply-time revalidation also refuses element-type drift via a
gate-time targetElementTypes map carried in the tool details.
- Refusal reasons render as visible card text, not only a hover title.
- Test pins added for all of the above plus selection scoping, coord
bounds, non-finite rotate, and empty batch/props.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(agent): harden the schema-derived gate — fail closed, assert schema source, unify numeric clamping (#895)
- A schema construct the subset checker cannot judge (unresolved $ref,
malformed anyOf, unsupported keywords) now refuses instead of
accepting — the gate fails closed on the unknown.
- A module-load assertion verifies the loaded dsl schema carries every
definition the gate maps and a sane TextType enum, so a stale or
missing build artifact fails loudly with a rebuild hint instead of
validating an outdated contract silently.
- Numeric-overshoot convention unified and documented: structural,
enum, or ownership mismatches refuse (teaching the model the
contract); numeric overshoot on a valid prop clamps (matching gesture
behavior) — opacity now clamps like geometry.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(agent): localize edit element refusals (#895)
* fix(agent): preserve partial element edit semantics (#895)
* fix(agent): prevent stale element edit application (#895)
* fix(agent): preserve live canvas edit invariants (#895)
* fix(agent): close element style contract gaps (#895)
* fix(agent): reject non-persistent element styles (#895)
* fix(agent): preserve rigid group geometry (#895)
* fix(agent): tolerate decimal group translations (#895)
* fix(agent): constrain line height edits (#895)
* fix(agent): reject stale or shadowed element edits (#895)
* fix(agent): close renderer contract gaps (#895)
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com>