mirror of
https://github.com/THU-MAIC/OpenMAIC.git
synced 2026-10-13 04:50:23 +08:00
@openmaic/generation@0.3.13
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
67584fe9e8 | fix(whiteboard): correct the inverted viewportRatio so boards render 16:9 landscape (#1257) | ||
|
|
0ae21aa559 |
refactor(pbl): retire v1 write path and dead UI, converge on v2 (#1060)
* refactor(pbl): retire v1 write path and dead UI (#1058) Remove the legacy generator, renderer branches, chat API, and compatibility mirror writes. Keep stored v1 scenes readable through documented legacy adapters, and surface ordinary PBL planner double failures instead of degrading. * fix(pbl): contain planner failure to the scene, support legacy scenes in action regeneration, tighten legacy guards - Contain typed planner failures per scene while preserving retry and skip behavior. - Upgrade legacy PBL content before regenerating scene actions. - Apply video-export import boundaries to legacy readers. - Harden legacy rendering and empty-state handling. - Restore legacy upgrade compatibility coverage. - Remove retired translations and refresh fallback narration and legacy cover documentation. * fix(pbl): keep tolerant legacy configs renderable, guard invalid chat timestamps * chore(dsl): bump to 0.6.3 for README accuracy fix The README no longer references the deleted PBLProjectConfig symbol; the version gate requires a bump for any publishable package input change. * fix(pbl): harden legacy upgrade and persistence contract * fix(pbl): align action prompt with v2 workflow and validate project containers * fix(i18n): remove retired PBL v1 keys from the new fr-FR locale The fr-FR locale landed on main after this branch removed the v1 UI key families; prune the same 38 keys so all 10 locales align with en-US. * fix(generation): sync packaged pbl-actions template with the v2 wording The generation package that landed on main carries a byte-identical copy of the app's pbl-actions template; sync the v2 rewording and bump the package version. * fix(pbl): normalize legacy content and preserve planner status * fix(pbl): propagate provider status and ground action prompts * fix(pbl): classify planner failures for retry, default the project summary prompt input * fix(pbl): fall back to legacy data when v2 payloads are damaged, harden summary building * refactor(pbl): resolve hybrid content through a validity-aware resolver * fix(pbl): keep one v2 acceptance criterion across validator, resolver and persistence Persistence gates on the same container predicate as the validator and the renderer's resolver: payloads the renderer will not treat as v2 are inert bytes everywhere, avoiding runtime side effects for documents the write barrier would reject. An explicit null proficiencyAssessment stays processable. * fix(pbl): require runnable projects and harden legacy fallback * test(pbl): exercise the real save reload and hydration chain * fix(pbl): require an instructor and usable microtasks before v2 takes precedence * fix(pbl): fall back to the loop planner unless the provider failed or the user cancelled * fix(pbl): require role and task identities before v2 takes precedence Runtime normalization can repair status and create the instructor thread, but it cannot synthesize the role id that binds the thread, the microtask ids used by lookup and update paths, or the labels the workspace renders. The runnable predicate and its video-export mirror now require them, so identity-less payloads fall back to usable legacy data. |
||
|
|
be3d313bc3 |
feat(document): dirty-set incremental saves + operation-level flush (#983)
* feat(document): dirty-set incremental saves + operation-level flush + unload protection Every store mutation used to trigger a debounced FULL aggregate rewrite — editing one word rewrote the whole document, scene switches during playback rewrote it for nothing, and concurrent editors clobbered each other at document granularity. Mutations now mark precise dirt (scene:<id> / structure / stage / outline / currentScene / chats): scene edits flush as version-gated putScene, stage metadata as putStage, structure and outline changes keep the full-save path, and currentScene/chats no longer touch the document at all. Dirt entries are revisioned so a mutation landing during a write is never accidentally cleared, and failed writes retain their dirt for retry. flushStageSave() drains the debounce single-flight; agent apply operations await it so each AI edit is durable before its tool result returns; hidden-page/unload kick a best-effort immediate flush. The PendingChange type stays neutral about the change unit so a future operation-log backend can replace the flush internals at one seam. Co-authored-by: Codex <codex@openai.com> * fix(document): incremental-persistence review round — bypass-proofing, true drain, no stranded dirt Structural mutations carry the cursor they changed (and cursor resolution validates membership on load, so a stale device cursor can never resurrect a deleted scene). The Stage API now wraps the real store in a guard that diffs pre/post state and centrally classifies every raw write — whiteboard, element, canvas, and action-engine mutations can no longer bypass dirty tracking, and new API namespaces inherit the guard by construction (with a lint-like inventory test). flushStageSave is a bounded true drain: an awaiter whose mutation landed mid-flight loops until its own dirt is durable. setStage hands the old document's dirt to a departing flush instead of discarding it, and a failed flush always reschedules. Mixed dirty batches (scene+stage/outline) use the atomic full save — the incremental fast path is homogeneous-only. Chat-half failures keep the chats dirt for retry without changing the tolerated-split outer semantics. Co-authored-by: Codex <codex@openai.com> * fix(document): reviewer round — drain covers caller dirt, full-path chat retry, stamping unification flushStageSave's early-return now only fires when the failing round's snapshot actually covered the caller's dirt — an agent edit landing beside an in-flight failing round is written before the promise resolves, keeping the tool-result durability guarantee unconditional. The full-save path reports chat failures the same way the incremental path does (chats dirt survives and reschedules; the tolerated-split semantics are unchanged). The departing-stage flush retries once and its doc-comment states the best-effort semantics honestly. Stage and scene stamping are extracted and shared — fixing the incremental putScene branch silently dropping the order ?? index normalization the full path applies — and the dead outline mark in setGenerationComplete is gone. Co-authored-by: Codex <codex@openai.com> --------- Co-authored-by: Codex <codex@openai.com> Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
7c19ab8f1e |
feat(dsl): JSON Schema artifacts + pure validators (#787 Part B-1) (#817)
* feat(dsl): add ACTION_TYPES set + isActionType guard A frozen set of every valid ActionType plus a pure membership guard, mirroring the PPT_ELEMENT_TYPES / isPPTElementType idiom in guards.ts. Used by the new validators; useful standalone for narrowing untrusted action.type values. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dsl): build-time JSON Schema codegen for stage/scene/action TS types stay the single source of truth; ts-json-schema-generator (a devDependency, build-only) emits dist/schema/{stage,scene,action}.schema.json, shipped under the new ./schema/* export. Serves non-TS / bring-your-own-validator consumers without adding a runtime dependency. JSON Schema is not generic, so schema-roots.ts provides a concrete Scene<Action, SceneContent> entry point (kept internal, not re-exported). schema.test.ts compiles the generated schema with ajv (devDep) to prove the artifact is real and self-contained on a clean checkout. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(dsl): add pure structural validators (stage/scene/action) validateStage / validateScene / validateAction: hand-written, zero-dependency, fail-loud structural checks layered on the existing guards. They verify discriminants, required fields, and known nested discriminants — a gate for untrusted input (LLM/agent output) and persistence boundaries. Exhaustive per-field validation is delegated to the shipped JSON Schema. Error-collecting ValidationResult reports every issue with a JSON-pointer-ish path. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(dsl): document the runtime schema + validator layer Add a Runtime layer section covering the two complementary consumption modes (schema-as-data via @openmaic/dsl/schema/* and the zero-dep validate* gate), the validate.ts module row, the build:schema step, and tick the JSON Schema roadmap box. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dsl): harden validators per cross-review (exhaustiveness, discriminant agreement) Addresses cross-review findings on the validator layer: - Add compile-time exhaustiveness assertions for ACTION_TYPES and SCENE_TYPES. `satisfies` only proved each entry is valid, not that the tuple covers the whole union — a newly-added Action/Scene variant could silently be rejected by the validators. The assertion now fails the build on drift. - validateScene cross-checks that scene.type agrees with content.type; a slide-typed scene carrying quiz content (or vice versa) is now rejected. - Move SCENE_TYPES + add an isSceneType guard to stage.ts, next to SceneType, matching the PPT_ELEMENT_TYPES / isPPTElementType idiom in guards.ts; validate.ts reuses them instead of re-encoding the union locally. - Make the validators' scope honest in the doc comment + README: they check the structural envelope, known discriminants, and scene/content agreement; they do NOT exhaustively check per-variant fields, and app-side interactive/pbl content is validated only at the envelope level (exhaustive checks → the JSON Schema). - Note the contract-owned content scope in schema-roots.ts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * perf(dsl): reuse one schema generator + harden direct-invocation guard Addresses cross-review findings on the codegen path: - gen-schema.mjs built a fresh ts-json-schema-generator (full TS program parse) per root type; build one generator over the tsconfig program and reuse it for every createSchema call — parses once, identical per-type output. - Harden the `invoked directly` check to compare realpaths, so a symlinked invocation (bin shim / pnpm link) still runs main() instead of silently emitting no schema. - schema.test.ts generates all roots once at module scope, then only compiles per case — no repeated heavy codegen. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dsl): bind scene schema discriminants + pin node-20-compatible generator Addresses round-2 cross-review (codex) findings: - scene.schema.json now ties scene `type` to the matching `content.type`. SerializedScene became a discriminated union (SlideScene | QuizScene via `Omit<Scene<…>, 'type'> & { type }`), so the generator emits a const-narrowed discriminant per branch. Previously the schema accepted e.g. { type: 'quiz', content: { type: 'slide', … } } even though validateScene rejects it — the schema is now consistent with the validator. Locked with a test. - Pin ts-json-schema-generator to ~2.4.0. ^2.3.0 resolved to 2.9.0, which declares `node >=22`, conflicting with the repo's `engines.node >=20.9.0`; 2.4.x supports node >=18, keeping the build runnable on every supported Node. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style(dsl): prettier formatting + drop unused ts-expect-error for green CI - Apply repo Prettier (`pnpm check`) formatting to the new/edited files. - Remove the `@ts-expect-error` on the gen-schema.mjs import: the root `tsc --noEmit` (which compiles test files; allowJs infers the .mjs exports) flagged it as an unused directive (TS2578). Plain comment retained. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(dsl): align validators + schema to the public Scene type (review) Addresses cosarah's review: the validator, the JSON Schema, and the public TS type had drifted into three different notions of a valid scene. Realign them so the TS types stay the single source of truth, and position the two runtime layers honestly. - schema-roots.ts: revert SerializedScene to the plain default Scene<Action, SceneContent>. The schema no longer encodes a stricter type/content binding that the public Scene type doesn't express (the constraint had effectively moved into a hidden internal type). - validate.ts: drop the scene.type<->content.type agreement check (the public Scene does not bind them, so neither does the validator); restrict content to the contract-owned kinds (slide/quiz), matching SceneContent and the schema, so validator and schema no longer disagree on interactive/pbl content. - Reposition docs (validate.ts header + README): the JSON Schema is the authoritative, exhaustive per-field validator (it checks variant fields like an action's elementId) for trust boundaries; validate* are a cheap, zero-dep structural pre-check and a strict subset of the schema — not a separate or stricter gate. - Tests updated to lock the realigned behavior. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(dsl): bind scene type<->content in the public Scene contract (review) cosarah's review showed the scene type<->content agreement is a real, load-bearing invariant: consumers branch on `scene.type` and then read `scene.content` as the matching shape (e.g. `stage-api-canvas` casts `content as SlideContent` after a `scene.type === 'slide'` check; `complete-summary` counts by `scene.type` and reads `content as QuizContent`). A validator/schema that blesses mismatched pairs is unsafe. So tighten the *exported* contract rather than loosening the runtime checks to match a hole — and make the pure validators the authoritative, relied-upon boundary. DSL contract: - `Scene` becomes a distributive discriminated type binding `type` to `content['type']` (`SceneCore<TAction> & { type: TContent['type']; content: TContent }` distributed over TContent). TS itself now rejects mismatched scenes; generic widening still works. Extract `SceneCore` for the kind-independent fields. - `validateScene` re-establishes the type<->content agreement check; scene `type` is the contract's slide/quiz; `scene.schema.json` (from the spelled-out discriminated `SerializedScene`) binds `type` to content per branch. Type, validator, and schema now describe the same thing. - `validateAction` checks each variant's required fields (e.g. spotlight.elementId, discussion.topic) — closes the false-positive gap. A test pins the hand map to the generated schema (the TS-derived source of truth) so it cannot drift. - Reposition docs: `validate*` is the zero-dep in-process boundary producers rely on; the JSON Schema is the cross-language mirror + exhaustive value checker. App consumers (the sites the discriminated Scene exposes): - Add `ScenePatch` (non-distributive partial) + `makeScene(core, content)` helper to lib/types/stage.ts — one isolated cast, type derived from content. Patch-typed signatures (`updateScene`, `applyScenePatchInSync`, regenerate plan) and scene rebuilds (`stage-api-scene`, store `updateScene`, `migrateScene`, stage-storage deserialize) route through these. Closes two latent desync foot-guns. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dsl): validate action field types + migrate scene.update; bidirectional drift-guard (review) Round-2 review of the contract-tightening change (codex + Claude): - validateAction now checks each variant-required field's TYPE, not just presence (`{ type:'spotlight', elementId: 123 }` is rejected — elementId must be a string). ACTION_REQUIRED_FIELDS carries a runtime kind per field. - The schema lockstep test is now bidirectional and type-aware: it asserts a fully-typed action is accepted (catches the map OVER-listing an optional field), every required field flags when missing (under-listing), and flags when present but mis-typed — all keyed off the generated schema's field names + types. - Migrate the public `stageApi.scene.update()` to ScenePatch + makeScene (the create() path was done last commit; update() still did a raw spread that could desync type<->content — masked from tsc only because StageStore.setState is typed `any`). Now both public scene-construction paths rebind type to content. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(api): keep scene.create's params.type authoritative over content.type (review) cosarah's review: `CreateSceneParams` exposes an independent `type` plus `content?: Partial<SceneContent>`, and after switching create() to makeScene() (which derives the scene kind from content.type), a call like `create({ type: 'slide', content: { type: 'interactive', ... } })` would silently become an interactive scene — params.type ignored — and mix slide defaults into it. Reject a `content.type` that disagrees with `params.type`, and pin the merged content's `type` to `params.type` so a partial content override can't flip the scene's discriminant. params.type stays authoritative. Adds a test both ways. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5daf3e5a6e |
fix(editor): keep emptied/zero-action scenes playable, bind outline by stable id, surface incomplete content (#814)
Editor empty-state robustness: dwell on zero-action scenes (engine + PlaybackChromeRoot) so emptied/blank slides stay playable; bind a scene's outline by stable outlineId (reorder/insert/duplicate-safe, allOutlines in scene order); clear the cue preview on glyph unmount; surface incomplete content calmly (amber dashed frame on clips, amber dot on blank outline titles + rail, neutral N/M-ready generate gate). Cross-reviewed (Codex + Claude), 5 rounds to a clean pass. |
||
|
|
7cb129183d |
chore(packages): publish the @openmaic/* SDK family to npm (#778) (#780)
* chore(packages): publish the @openmaic/* SDK family to npm (#778) Prepares the @openmaic/{dsl,renderer,importer} family for its first npm publish, and moves the SDK packages onto the @openmaic scope. Why the scope move: the @maic org name is unavailable on npm (an unscoped `maic` package already holds the name), so @maic/* is not claimable. @openmaic matches the project name, the scope is free, and the repo already ships an @openmaic/docs package — so the SDK family now lines up with that convention. - rename @maic/{dsl,renderer,importer} -> @openmaic/* across packages, the workspace glob, the package dir, and all import sites; lockfile regenerated - renderer: add publishConfig (public, registry.npmjs.org) — was missing, so a scoped publish would default to the wrong registry / restricted access - importer: add a files allowlist (dist, README, LICENSE) and drop the fragile .npmignore blacklist that shipped src; add an exports map so ESM consumers resolve dist/index.js instead of falling back to the .cjs main - all three: add a prepublishOnly build (+ test/typecheck) guard so a publish can never ship a stale or empty dist - add a tag-triggered publish workflow with npm provenance, pinned by name to the three @openmaic packages so the vendored forks (mathml2omml, pptxgenjs) are never published Refs #778, #720 (Phase 1). * fix(packages): address cross-review on the @openmaic publish prep Cross-review (Claude /code-review + codex) on this PR surfaced: - renderer's advertised CJS entry was broken: it keeps @openmaic/dsl external and imports a runtime enum from it, but dsl is ESM-only (no `require` condition), so `require('@openmaic/renderer')` would throw ERR_PACKAGE_PATH_NOT_EXPORTED. Make renderer ESM-only: drop the `.cjs` rollup output, `main` now points at the ESM build, and the `require` conditions are removed from `exports`. (importer is unaffected — it bundles dsl, so its CJS build still works.) - prepublishOnly re-ran the test suite during `pnpm -r publish`, so a flaky test after dsl had already published gave a non-atomic partial release. Reduce prepublishOnly to a build-only guard (never ship stale/empty dist) and move the real test/typecheck gate into the workflow, before any publish. - document that an @openmaic/* tag publishes the whole family via `pnpm -r` (pnpm skips already-published versions); the tag is a release marker, not a per-package gate. Verified: dsl + renderer + importer build; renderer emits ESM only (0 .cjs), all exports entries resolve; `npm pack` ships dist + README + LICENSE with no src leak; frozen-lockfile passes. Refs #778. * style: reflow @openmaic/dsl type imports past print-width after rename The @maic -> @openmaic rename lengthened two single-line type imports past prettier's 100-col width; prettier --check flagged them. Pure formatting. Refs #778. * docs(importer): mark @openmaic/importer browser-only (cr-loop accepted limitation) codex cross-review flagged that the published @openmaic/importer throws `XMLHttpRequest is not a constructor` when loaded in a pure Node process — its rollup build is browser-targeted (`nodeResolve({browser:true})` + a browser pdf.js build). The app only consumes it client-side ('use client'), so this is by design. Document it as an accepted limitation: prominent browser-only note in the README and a `browser` field in the manifest. Refs #778. |
||
|
|
4dce1f7414 |
refactor(types): import the slide DSL directly from @maic/dsl; drop the shim (#738)
#707 left lib/types/slides.ts as a thin `export * from '@maic/dsl'` shim so the ~100 existing `@/lib/types/slides` import sites kept working unchanged. Point them at `@maic/dsl` directly and delete the shim, so the app consumes the package contract with no indirection and the legacy module path is gone. Pure module-specifier migration — every symbol imported from `@/lib/types/slides` was already a re-export of the same `@maic/dsl` symbol, so behavior is identical. Also redirects the two `lib/types` relative importers (`./slides`), the e2e fixture's relative import, and the dynamic `import('../types/slides').Slide` type alias in stage-storage; merges the now same-module import pair in slide-edit-elements. Verified: tsc --noEmit clean, eslint clean, vitest 804/804, next build OK, e2e (Playwright) 19/19. Part of #720 (Phase 1). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
843d33e5cc |
chore: enforce Prettier formatting and fix lint issues
- Add .prettierignore to exclude vendor packages, lock files, markdown, and YAML - Update .prettierrc: printWidth 100, singleQuote, trailingComma "all" - Run Prettier across all source files for consistent formatting - Fix unused imports (UserRequirements, setTTSProvider) - Fix eslint-disable comment placement after Prettier reformat Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
e4e4743b3a |
Split lib/api/stage-api.ts (1587 lines) into namespace-based modules
Extract 8 focused modules from the monolithic stage-api: - stage-api-types.ts: interfaces and type definitions - stage-api-defaults.ts: utility functions and content factories - stage-api-scene.ts: scene CRUD operations - stage-api-element.ts: slide element operations - stage-api-canvas.ts: highlight/spotlight/laser/zoom effects - stage-api-navigation.ts: scene navigation - stage-api-whiteboard.ts: whiteboard operations - stage-api-mode.ts: mode and stage metadata Original file becomes a barrel re-export. All existing imports unchanged. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |
||
|
|
0d20abfed9 |
Initial commit: OpenMAIC AI classroom platform
Next.js 16 App Router application with: - AI-powered interactive classroom generation from PDF/text requirements - Multi-agent discussion system (teacher, students, assistant roles) - Provider abstraction for LLM, TTS, ASR, image, video, web search - Local-first data architecture (IndexedDB/Dexie) - i18n support (zh-CN/en-US) - Structured logger, SSRF guard, lint/build passing (0 errors) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> |