mirror of
https://github.com/THU-MAIC/OpenMAIC.git
synced 2026-10-18 05:40:25 +08:00
@openmaic/generation@0.0.1
36
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
d12f8f07eb |
fix(diagram): honor outline node constraints (#911)
Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
fabd7b65f5 | fix(generation): strip reasoning blocks before JSON parsing (#750) | ||
|
|
baff0998bb |
Feat/document bundles milestone 3 (#844)
* feat(document): support document bundles * fix(document): avoid server extractor imports in client bundle * fix(pdf): default mineru backend to pipeline * fix(document): address bundle review findings * fix(document): harden extraction limits and storage errors * fix(document): make analysis step format agnostic --------- Co-authored-by: Rowan_lxb <Lxb_savior@163.com> |
||
|
|
e136c81c03 |
chore(generation): remove dead legacy pipeline chain (#904) (#905)
Remove the generation-pipeline leftovers orphaned since the old
/api/generate route was deleted in
|
||
|
|
fcdb6d62b3 |
feat(dsl): own element-level normalization & defaults; wire the generator (#787) (#832)
* feat(dsl): own element defaults + normalize(); wire the generator (#787) Bring element-level normalization into the @openmaic/dsl contract, so producers stop carrying their own imperative "fix up the output" pass. Companion to the #817 validators: where validate* reports on a document, normalize* repairs one. - src/normalize.ts: pure, zero-dep normalizeElement / normalizeSlide / normalizeScene / normalizeStage + canonical ELEMENT_DEFAULTS. Fills missing required content fields, derives geometry (a line's start/end, a shape's viewBox/path from its box), and FAILS LOUD on a present-but-wrong-typed field instead of silently resetting it. Pure, non-mutating, idempotent. Scope is element content — base identity/geometry (id, left/top/width/height/rotate) is producer-supplied (the id is assigned downstream) and left to validate*/schema. - slides.ts: static defaults ride out on the generated JSON Schema as @default annotations (so non-TS consumers ship them too); ELEMENT_DEFAULTS is the single source of truth, pinned to the schema by a lockstep test. - generator: fixElementDefaults drops its per-type fixups for normalizeElement, wrapped in try/catch so a malformed element degrades gracefully (log + keep raw) rather than aborting a whole scene/course — generation runs on unreliable model output and on legacy slides the old pass itself produced. Image aspect-ratio reconciliation stays (it needs the resolved asset's real dimensions — a producer concern the DSL does not own). Two latent bugs fixed while canonicalizing into the contract: - shape viewBox: the old missing-viewBox fallback emitted a string "0 0 w h", which every consumer reads as viewBox[0]/[1]; normalize emits the contract's [w, h] pair. - line start/end: the old fallback derived ABSOLUTE [left, top] coordinates, but the renderer positions the line container at (left, top) and reads start/end as LOCAL offsets (getLineElementPath / getElementRange) — double-offsetting the line. normalize derives them in the local frame ([0,0] .. [w, h]). Minor bump @openmaic/dsl 0.2.0 -> 0.3.0. test/normalize.test.ts covers the defaults, derivation (incl. the local-frame line regression), fail-loud coercion, purity/idempotency, generic app-widened normalizeScene, schema conformance of normalized output, and the ELEMENT_DEFAULTS <-> schema lockstep. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style: format normalize.ts / normalize.test.ts with prettier Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(dsl): normalize nested ShapeText; repair-or-drop malformed elements in the generator Address review on #832: - normalizeShape now normalizes a present `text` overlay (ShapeText): fills content / defaultFontName / defaultColor / align with canonical defaults (align 'middle' per the renderers' convention), fails loud on a malformed overlay. Consumers read `text.content` unguarded (the PPTX exporter feeds it to formatHTML), so a present overlay gets the same repair semantics as the element's own required fields. Defaults ride the schema as @default and are pinned by the lockstep test. - The generator's fixElementDefaults no longer keeps a raw element when normalization fails — repair or drop: JSON nulls from the model are stripped first (null means absent; normalize then fills/derives the field), and an element that still fails is discarded with a warning. Keeping the raw payload handed malformed lines (start/end null) to consumers that index straight into start[0] (getElementRange / BaseLineElement / export), crashing playback or export over one bad element. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
4b821272ff |
feat(interactive-actions): feed real HTML element inventory into the prompt (#829)
* feat(interactive-actions): feed real HTML element inventory into the prompt
Teacher actions (highlight/setState/annotation/reveal) for interactive scenes
frequently miss because the model has to guess selectors from the prompt's
naming conventions (e.g. `#{var}-slider`, `#start-btn`) that don't match the
ids the content model actually emits (`#score-val`, `#launch-btn`, …). The
game widget category is the worst hit because its conventions cover almost
nothing.
Extract an inventory of interactable elements (ids + notable classes +
aria/role/data-step-id) from the generated widget HTML and thread it into
`INTERACTIVE_ACTIONS` under an `{{elementInventory}}` variable. The system
prompt now instructs the model to select `target` from the inventory first
and only fall back to conventions when nothing matches.
The inventory is:
- Persisted on the runtime `InteractiveContent` so pro-mode
`regenerate_scene_actions` gets the same real selectors, not a stale guess.
- Refreshed by `edit_interactive_html` — the tool re-runs the extractor on
the post-edit HTML and the client writes it back into `scene.content`, so
a subsequent action regen sees the new dom.
- Computed on the fly in `generateSceneActions` when a legacy scene lacks it,
so pre-existing courses benefit without a data migration.
Tailwind / utility class tokens are filtered so the 30-class inventory cap
keeps semantic hooks like `.pairing-rules`, `.dna-card`, `.btn-launch` from
being crowded out by layout tokens.
* style: prettier format
* fix(interactive-actions): compute element inventory at prompt-build time
Address PR #829 review feedback:
1. Drop the persisted `elementInventory` field on
`InteractiveContent`/`GeneratedInteractiveContent`. `generateSceneActions`
already computes the inventory on the fly from `content.html`; make that
the only path. Removes born-stale mismatches (post-processing rewrite vs
raw-html extraction), same-turn staleness of `sceneContextMap`, and the
silent divergence between `createSceneWithActions` (drops the field) and
`scene-builder.ts` (keeps it) — server-generated classrooms already ran
in recompute-only mode today.
2. Extractor hardening:
- Strip HTML comments alongside `<script>` / `<style>` so commented-out
markup can't forge phantom inventory entries the prompt would prefer.
- Drop content after an unmatched `<script` open so a truncated
generation doesn't inventory ids inside `innerHTML` template strings.
- Parse attributes into a name→value map by walking the tag grammar
instead of per-attribute regex over the flat string. Prevents
`aria-label="try name=alpha or id=fake"` from lifting phantom
`name=alpha` / `id=fake` attributes.
- Collapse whitespace and truncate each attribute value (~120 chars)
when building inventory lines so a multi-line or hostile aria-label
can't fake prompt sections.
- Keep semantic hooks whose names collide with Tailwind category
prefixes (`.grid-cell`, `.fill-blank`, `.text-input`, `.select-btn`,
`.ring-carbon`) when they are declared in the page's own `<style>`
block.
* style: prettier format
* fix(interactive-actions): surface id-less data-attribute targets in inventory
The interactive-actions system prompt tells the model to prefer
`[data-step-id="step-1"]` selectors for procedural-skill widgets whose
step rows typically carry only `data-step-id` (no id, and often no
surviving semantic class). Under the previous extractor those rows were
invisible: `data-step-id` and `data-action` only surfaced as decoration
on id rows, so a widget with all-data-only steps could hit the
"(no interactive elements detected)" sentinel while the system prompt
kept telling the model to prefer the inventory — degrading exactly the
one widget family the conventions already served well.
Add a third `Stable data attributes:` section that emits an
`[data-step-id="step-1"] <li>` line for each id-less element carrying
data-step-id or data-action, deduped on attribute value and capped at 30
entries. Elements that already have an id keep those attributes as row
decoration only (no duplicate row).
|
||
|
|
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. |
||
|
|
b516427d27 |
perf(generation): index assigned images by id in fixElementDefaults (#701)
fixElementDefaults looked up each image element's metadata with assignedImages.find inside the per-element map, making the pass O(elements × images). Build a Map<id, image> once and use an O(1) Map.get lookup instead. Behavior is identical (Map.get returns the same entry as the find), so it's purely a lookup-mechanism swap. Closes #700 Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
cec3c6aaea |
Refactor widget actions into the scene action pipeline (#796)
* refactor: align widget actions with scene pipeline * feat(edit): migrate legacy teacherActions off interactive content on load The widget-actions pipeline no longer persists a teacherActions authoring layer; playback reads only scene.actions. Add migrateInteractiveContent to strip the dead field from existing documents as they load through migrateScene (wired into all store/classroom load paths). Satisfies the #794 forward-migration acceptance item. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(generation): default widget_setState.state to {} when the LLM omits it The removed TeacherAction->Action converter always defaulted state to {}. Restore that guard in the structured-output parser so an action missing state can't forward state: undefined into the widget iframe, where SET_WIDGET_STATE handlers dereference it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(edit): also strip nested widgetConfig.teacherActions in migration Legacy WidgetConfig variants each declared their own teacherActions, so existing documents can carry the dead field nested inside content.widgetConfig as well as at the top level. Extend migrateInteractiveContent to drop both, preserving all other widgetConfig fields. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * feat(prompts): document stable widget-action selectors for diagram/game/viz3d The interactive-actions prompt documented stable target selectors only for procedural-skill and simulation widgets. Add the canonical selectors the diagram / game / visualization3d content prompts actually emit (node IDs via revealOrder; #zoom-in-btn / #canvas-container / #speed-slider / ...; #start-btn), plus a rule to use widget_setState or a speech-only beat instead of guessing a target when no stable selector is known (e.g. free-form code widgets). Hardens against widget actions silently no-oping on non-existent selectors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
243e9f3a48 |
feat: auto-retry transient failures during scene generation (#788)
Adds automatic retry with exponential backoff for scene generation (content/actions/TTS): shared withGenerationRetry helper at the fetch boundary, smart error classification (retries 429/5xx/timeouts/network, fails fast on 401/403/404), AI SDK RetryError unwrapping, abort-aware backoff, per-route thinking config preserved, and upstream HTTP status surfaced for client retry classification. Fixes #755. |
||
|
|
0f44e9a46f |
Add PBL v2 runtime APIs and classroom UI (#799)
* feat: add PBL v2 runtime UI * fix: ship PBL v2 instructor avatar * fix: ship PBL v2 workspace logo * fix: prevent scenario PBL legacy fallback * chore: restore package lint comments * test: cover ordinary PBL legacy fallback * fix: front-load PBL single-call validation * fix: preserve PBL v2 content when assembling scenes --------- Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
09863af421 |
Add PBL v2 core schema and generation path (#795)
* feat: add PBL v2 core planner * chore: restore unrelated lint comments * fix: document PBL v2 scenario outline flags * fix: expose PBL scenario subtype in outlines * chore: clear PBL v2 completion stats lint warning * chore: address PBL instructor code quality comments * fix: address PBL v2 review findings * chore: restore unrelated lint comments |
||
|
|
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. |
||
|
|
dcf8a63333 |
fix(generation): make outline type changes take effect (interactive/PBL no longer downgraded to slide) (#772)
* feat(generation): changeOutlineType total constructor for valid type switches Switching a scene outline's type in the editor only flipped `type` and left the new type without its required config, so applyOutlineFallbacks silently downgraded interactive/pbl back to slide. changeOutlineType returns a new outline that strips foreign per-type config and seeds the target type's required config from the shared fields, valid by construction. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * i18n(generation): keys for interactive widget kind and PBL project config Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(editor): make outline type changes take effect with config forms TypePill now builds a valid outline via changeOutlineType (replace, not partial-merge) so a type switch drops stale config and seeds the new type's required config — no longer silently downgraded to slide by applyOutlineFallbacks. Adds InteractiveConfigDisclosure (widget kind + concept) and PblConfigDisclosure (topic / description / target skills), mirroring QuizConfigDisclosure, so users can configure interactive and PBL scenes that previously had no input UI. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): move type-specific config under the type pill The quiz/interactive/PBL config disclosure rendered as a detached chip at the bottom-left of the card, reading like a stray key point. Pin it to the bottom-right of the key-points row instead, so it sits directly under the TypePill it configures (type top-right -> its config bottom-right, same edge), with key points flowing on the left. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): cascade type config as a connected segment left of the type pill Replace the standalone config chip with a cascading control in the header: the type-specific config (quiz count / interactive widget kind / PBL project) renders as a themed segment joined to the left of the TypePill, the two clipped into one rounded pill split by a hairline divider. Reads as a single 'config › type' cascade and groups the config with the selector it refines. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): address cross-review — preserve widget config, drop stale fields - changeOutlineType: preserve an existing procedural-skill widget config instead of replacing it with a seeded simulation (codex P2 — task-engine fields were silently dropped on Interactive re-select). - InteractiveConfigDisclosure.setWidgetType: reset widgetOutline to the shared concept only, so switching widget kind drops the previous kind's fields (claude P2 — language/gameType/etc. leaked across kinds). - i18n locale-coverage test now also checks ko-KR and pt-BR. - Drop a redundant WidgetType cast; add tests for procedural-skill preservation and pbl targetSkills dedupe/cap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(editor): round 2 cross-review nits — procedural-skill label + skill a11y - InteractiveConfigDisclosure: when an outline carries a preserved procedural-skill widget, surface it as the current (selected) kind with its own label instead of mislabeling it 'Simulation', and make a same-kind re-select a no-op so its task-engine fields are never silently clobbered. - PBL target-skill remove button uses a dedicated removeSkill aria-label. - Add widgetProceduralSkill / removeSkill i18n keys (8 locales) + test coverage. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(generation): make re-selecting the current outline type a no-op changeOutlineType rebuilt the outline on every type-menu click, so re-selecting the already-current type dropped fields it doesn't re-seed — legacy interactiveConfig, or a partial pblConfig whose projectTopic is empty — turning a harmless click into data loss. Short-circuit same-type selections to return the outline untouched (codex P2). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * chore(format): prettier --write files left unformatted on main These 14 agent/edit files (not part of this PR's feature) fail the repo-wide `prettier . --check` in the required Lint job — they landed on main unformatted, turning main's CI (and therefore this PR after a branch update) red. Formatting them here unblocks the required check; pure formatting, no logic changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(lint): suppress intentional set-state-in-effect in reasoning timer The reasoning timer does a deliberate one-shot setState in its effect to show the right elapsed value before the first 1s interval tick. main's CI fails the required Lint job on the new react-hooks/set-state-in-effect rule here; suppress it with a justification (no behavior change). Unblocks the required check. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1d1ce80e04 |
feat(maic-agent): editor-agent line (v0) — Pro-mode "Edit with AI" (#777)
Promote the editor-agent line to main: read-then-act editor agent (read_scene_content, regenerate_scene, regenerate_scene_actions, edit_interactive_html), a routable maic-agent model stage, the agent sidebar UI, interactive-scene runtime-error capture, and the timeline/script editor. Cross-reviewed and smoke-verified; see #777. |
||
|
|
267965d6ed |
feat(generation): infer concise courseTitle from outlines for readable course names (#756)
* feat(generation): infer concise courseTitle from outlines for readable course names
Generated courses were named after the raw user prompt (truncated to 500 chars
client-side, or 50 chars / first outline title server-side), which is long and
unreadable. The outline-generation step already understands the full course
semantics, so have it emit a concise `courseTitle` alongside `languageDirective`
and `outlines`, and use it as the stage name.
- Prompts (requirements-to-outlines, interactive-outlines): top-level JSON gains
a required `courseTitle` (≤30 chars, in the teaching language, noun phrase).
- Streaming route: extract `courseTitle` head-bound like `languageDirective`,
emit a `courseTitle` SSE event, and include it in the `done` event.
- Non-streaming outline-generator: parse and return optional `courseTitle`
(defensive trim + 120-char cap).
- Naming: stage.name = courseTitle || outlines[0]?.title || requirement fallback
(client preview path backfills stage.name after outlines resolve; server
classroom-generation uses it directly).
- Session: persist `courseTitle` on GenerationSessionState for reload safety.
- Tests: add courseTitle parsing coverage; e2e mock done event carries it.
Fully optional in the pipeline — every consumer falls back to the previous
behavior when the field is absent, so legacy/LLM-skipped cases are unaffected.
* fix(generation): make courseTitle propagation robust across all outline paths
Address review feedback on the courseTitle threading.
Prompts — align every outline-prompt schema statement to the 3-key shape.
The user-prompt "final reminder" / top-level shape blocks for
requirements-to-outlines, interactive-outlines, and task-engine-outlines still
demanded the old two-key {languageDirective, outlines} object; as the last
instruction the model reads, that caused it to omit courseTitle and the stage
name to fall back to the raw requirement. Task Engine prompts now emit
courseTitle as well.
Streaming route — normalize the streamed courseTitle (trim, ignore
whitespace-only, cap length) to match the non-streaming parser, and add a
full-buffer fallback so a title emitted after the outlines array or beyond the
head-scan window is still recovered before the done event.
Client — reset latched languageDirective/title on outline retry so a
succeeding attempt that omits them falls back instead of inheriting a failed
attempt's stale value; also carry courseTitle in the stream-end resolve path
that fires when the stream closes without an explicit done event.
courseTitle remains optional on every consumer path.
---------
Co-authored-by: wyuc <zdq1204@gmail.com>
|
||
|
|
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> |
||
|
|
3f80a92a28 |
fix(generate): make outline streaming + interactive post-processing linear (was O(n²)/O(K·L)) (#732)
Two streaming generation paths do super-linear work on the model output and can block the Node event loop (and balloon the heap) on large or pathological responses: 1. app/api/generate/scene-outlines-stream re-parses the ENTIRE accumulated buffer on every streamed chunk — extractLanguageDirective (full-buffer regex) and extractNewOutlines (char-walk from the array start). That is O(n²) over the stream; a ~300 KB response blocks the event loop for ~20 s. 2. lib/generation/interactive-post-processor convertLatexDelimiters restores <script> placeholders by rebuilding the whole HTML string once per block — O(blocks × length). A widget with many <script> tags blocks for tens of seconds and allocates GBs. Fixes: - extractNewOutlines: parse incrementally, resuming from a cursor so the buffer is scanned once across the stream (O(n)). Behaviour-equivalent — verified across chunk sizes, markdown fences, flat arrays, prose preambles, and braces/escapes inside string values. - extractLanguageDirective: bound the regex to the buffer head (the directive is the first wrapper key), O(1) per chunk. - Restore <script> blocks in a single pass with a function replacer ($-safe). - Stream-loop hardening: honor request abort and propagate the AbortSignal to the LLM call so upstream generation stops on disconnect; cap the accumulated buffer; guard controller.close() against double-close. Standalone repro (copied functions): 300 KB outline stream 20.8 s -> 1.3 s; 45 MB widget HTML >30 s + OOM -> 45 ms. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
50c0aefd13 | fix(vocational): gate procedural content generation | ||
|
|
e6debb093b | fix(vocational): address review feedback | ||
|
|
c58893e76f | feat(vocational): add task engine and procedural skill widgets | ||
|
|
2dff6d10be |
feat: add generated video manifest refs (#540)
* feat: add generated video manifest refs * style: format video manifest changes * fix: address video manifest review feedback |
||
|
|
be759a8252 |
feat: add lemonade to provider (#508)
* feat: add lemonade to provider * fix(lemonade): correct TTS/ASR model IDs and expand Kokoro voices - TTS model: kokoro → kokoro-v1 - ASR model: single 'whisper' → 6 Whisper variants (Base/Large-v3/Large-v3-Turbo/Medium/Small/Tiny), default Whisper-Base - Expand lemonade-tts voices to full Kokoro v1 set (54 voices across en-US/en-GB/zh-CN/ja-JP/es/fr-FR/hi/it-IT/pt-BR) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(lemonade): zh-TW i18n parity, real Kokoro default voice, language code consistency - zh-TW.json: add missing providerLemonadeTTS/ASR/Image keys - TTS default voice: 'default' → 'af_heart' (Kokoro expects real voice ID, not placeholder) - Voice language codes: 'es'/'hi' → 'es-ES'/'hi-IN' for consistency Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(lemonade): add unit tests for image/TTS/ASR adapters and wav-utils Covers: - lib/media/adapters/lemonade-image-adapter: request shape, base URL fallback, custom model, optional Bearer auth, error paths, connectivity probe - lib/audio/tts-providers (lemonade-tts case): request body (model/voice/format), af_heart fallback, optional auth, error path - lib/audio/asr-providers (lemonade-asr case): WAV-only validation, model/language form fields, "audio is empty" graceful empty result, error propagation, default model fallback - lib/audio/wav-utils: isWavBlob detection by MIME and filename, normalizeASRUploadAudio pass-through and wav handling Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(lemonade): remove text path fork and harden fallbacks * style: format lemonade tts files * i18n: add lemonade voice language labels * fix(lemonade): align image default model and harden wav detection * test(lemonade): fix File BlobPart typing * fix(lemonade): simplify tts voice selection and clear asr test state * docs: highlight Lemonade support --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
e613b7578f |
[codex] add per-model thinking config (#494)
* add per-model thinking config * Refine thinking model controls --------- Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
3fafca5f99 |
feat(prompts): conditional media snippets in generation prompts (#490)
* feat(prompts): conditional media snippets in generation prompts (#483) Replace always-included media instructions + negative-override pattern with conditional snippet includes gated on imageEnabled/videoEnabled flags. - Extend prompt loader with {{snippet:name?if=condition}} syntax - Extract 15 media instruction snippets from outline and slide templates - Wire imageEnabled/videoEnabled through outline-generator, scene-generator, and route handler - Remove mediaGenerationPolicy negative-override from all call sites - Close gap: slide content generation now receives media policy - Unify pre-output checklist to labeled bullet format * refactor(prompts): replace ?if= snippet syntax with {{#if}} inline blocks Address review feedback on PR #490 — the file-per-fragment pattern was too fine-grained (6 of 15 new snippets were ≤2 lines). Changes: - Add {{#if name}}...{{/if}} block syntax to the loader (~10 lines) - Inline 9 micro-snippets (≤4 lines each) back into host templates - Keep 3 large instruction snippets as {{snippet:name}} wrapped in {{#if}} at the call site - Drop ?if= syntax and PromptLoadOptions.conditions — conditional blocks read directly from buildPrompt's variables - Update tests and README Processing order: snippets → conditional blocks → variable interpolation * style: format media-conditional test with prettier |
||
|
|
550c43a3f3 |
fix(generation): unify languageDirective across outline + scene pipeline (#472) (#474)
* fix(generation): unify languageDirective across outline + scene pipeline (#472) Root issue: languageDirective was dropped, renamed, or hardcoded at several points in the scene-generation pipeline, silently degrading prompt-level language control. Slide paths survived because their fallback happened to hint requirement-language; widget paths degraded to zh-CN default. Fix plan (all code-only threading + prompt hygiene, no schema changes): 1. Thread languageDirective through every buildPrompt in scene-generator.ts: - Add param to generateSlideContent / generateQuizContent / generatePBLSceneContent - Forward from generateSceneContent's slide / quiz / pbl branches - Include key in the four generateSceneActions buildPrompt calls - Demote generatePBLSceneContent's hardcoded English to a fallback - Drop the dishonest `as 'zh-CN' | 'en-US'` cast on the widget path 2. Unify variable naming across widget templates + callers: - Rename {{language}} → {{languageDirective}} in 6 widget templates (simulation / diagram / code / game / visualization3d / widget-teacher-actions) - generateWidgetContent and generateWidgetTeacherActions now pass `languageDirective: languageDirective || ''` instead of a locale-code shim 3. Make the outline LLM reliably emit the wrapper object: - requirements-to-outlines/system.md + user.md restructured so the "top-level JSON object with languageDirective + outlines" contract is surfaced up-front, short, and unambiguous — drowning-by-scene-examples removed. Important Reminders reordered: top-level shape first. - interactive-outlines/system.md + user.md aligned with main outliner: adds full Language Inference section, requires wrapper output, drops the orphan {{language}} placeholder that never had a value source. 4. Remove lib/prompts/loader.ts prompt/snippet caches: - Disk reads for prompt templates are not on any hot path (LLM call dominates by 5 orders of magnitude). The cache's only observable effect was blocking prompt edits from taking effect without restart — which masked the wrapper bug during this investigation. Verification: - 7 new regression tests in tests/generation cover directive threading at each buildPrompt site plus the PBL caller-forwarding guarantee. - outline-language eval (50 scenarios, gemini-3-flash-preview inference, qwen-3.5-flash judge): 48/50 (96%). The 2 persistent failures are in the proxy-request category (teacher / tutor preparing lessons for students) where the system prompt's rule 5 has genuine ambiguity — orthogonal to this fix. - Curl burst tests: 8/8 runs each for regular-mode and interactive-mode outline endpoints emit the wrapper object and extract a detailed inferred directive. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * style: apply prettier formatting to loader.ts and new test file Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix: thread languageDirective in scene-builder and classroom-generation Code review caught two additional sites missing the directive: - lib/server/classroom-generation.ts:371 — generateSceneActions call was missing languageDirective, reproducing the issue #472 symptom in the shareable-classroom server generation path. - lib/generation/scene-builder.ts:114 — buildSceneFromOutline's generateSceneActions call had the same miss; latent (no current live caller) but wrong for consistency. Also renumber duplicate `8.` in requirements-to-outlines/system.md scene-level rules. Extend regression tests with a buildSceneFromOutline end-to-end case that captures both the content and actions prompts via a stub aiCall and asserts the directive reaches both phases — this would have caught the scene-builder miss. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * review: widget-path test + docs + fallback constant (PR #474) Address @cosarah's review feedback: - Add widget-path regression test (tests/generation/...): interactive scene with widgetType=simulation captures both widget content and widget-teacher-actions prompts, asserts the directive reaches each and no `{{language}}` / `{{languageDirective}}` placeholder leaks. This is exactly the path issue #472 was filed for. - Rewrite lib/prompts/README.md "Caching" section: the cache was removed in this PR; README still instructed callers to use a clearPromptCache() function that no longer exists. - Sync interactive-outlines/user.md with the main outliner's "## Language Context" reminder block (line 13-19) so both outline paths give the LLM the same language-inference reminders. - Hoist 'Teach in the language that matches the user requirement.' into DEFAULT_LANGUAGE_DIRECTIVE, exported from outline-generator. Replaces 4 copies across outline-generator, scene-generator, and the scene-outlines-stream route. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
f40c92f1aa |
refactor(orchestration): migrate prompt builders to file-based templates (#459)
* refactor(prompts): move loader to lib/prompts/ Move file-based prompt loader from lib/generation/prompts/ to project-level lib/prompts/ so it can be shared by orchestration and PBL prompts in subsequent commits. - Templates and snippets moved alongside the loader - getPromptsDir() now points at lib/prompts/ - Generation pipeline imports updated to @/lib/prompts (outline-generator, scene-generator, search-query-builder, scene-outlines-stream route) - Add tests/prompts/loader.test.ts as sanity gate Pure file move — no behavior change. * test(orchestration): add baseline snapshots for prompt builders Snapshot tests cover variant matrix: - buildStructuredPrompt: role × scene-type × peer/ledger/discussion/profile - convertMessagesToOpenAI: mixed message kinds - summarizeConversation: truncation - buildDirectorPrompt: Q&A vs discussion, ledger, profile - buildPBLSystemPrompt: default config These lock current output so the body refactor in subsequent commits can be verified byte-equal. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(orchestration): plug snapshot coverage gaps from review - Split convertMessagesToOpenAI test: same-agent (existing) + cross-agent (new). The original test passed currentAgentId matching the message's agentId, so the cross-agent role-conversion branch was never exercised. - Add 'teacher / quiz scene' snapshot to lock the spotlight/laser strip path in getEffectiveActions. The previous variant-7 test (whiteboard-open) only triggered the mutual-exclusion warning, not the strip — renamed it to reflect what it actually tests. - Add assistant-role variant (was uncovered: ROLE_GUIDELINES, buildLengthGuidelines, buildWhiteboardGuidelines all branch on role). * refactor(orchestration): extract summarizers from prompt-builder.ts Move state-context, virtual whiteboard ledger replay, peer context, message converter, and conversation summary out of the 890-line prompt-builder.ts into focused modules under lib/orchestration/summarizers/. prompt-builder.ts now only owns prompt assembly. director-graph imports updated to the new locations. Snapshot tests pass byte-equal — no behavior change. * refactor(orchestration): move agent-system prompt to template file The buildStructuredPrompt template literal is now lib/prompts/templates/agent-system/system.md, assembled by a thin variable-pass through the shared prompt loader. Per-variant ternaries (format example, ordering, spotlight examples, mutual-exclusion note) are kept as module-level constants in prompt-builder.ts. ROLE_GUIDELINES, buildLengthGuidelines, and buildWhiteboardGuidelines stay too (they may further migrate to template partials in Phase 2). Also: PROMPT_IDS gains a 'satisfies Record<string, PromptId>' clause to prevent constant/union drift as more IDs are added. Snapshot tests (12 prompt-builder + 4 director + 1 pbl) pass byte-equal. * refactor(prompts): align agent-system template with project conventions - Rename agent-system placeholders snake_case → camelCase to match the convention already used by slide-actions/user.md and other generation templates. Settles convention before Task 5 lands two more templates that would otherwise inherit drift. - Extract '## Speech Guidelines (CRITICAL)' into lib/prompts/snippets/speech-guidelines.md for reuse by director and PBL prompts in Task 5. Snapshot tests pass byte-equal — placeholder name changes are invisible in rendered output, and snippet inclusion happens at load time. * refactor(orchestration,pbl): move director + PBL prompts to templates director-prompt.ts and pbl-system-prompt.ts now use the shared template loader. Bodies collapse to thin variable assembly. Three orchestration-tier prompts now share one infrastructure: agent-system, director, pbl-design. Snapshot tests pass byte-equal. * refactor(orchestration): extract WhiteboardActionRecord + AgentTurnSummary to types module These two interfaces are imported by 6+ modules including summarizers/ — having them live in director-prompt.ts created an awkward upward import direction (summarizers reaching back to a sibling prompt builder for types). Move them to lib/orchestration/types.ts and update all callers. director-prompt.ts now imports them too. Pure type-location refactor — snapshots pass byte-equal. * test: remove snapshot tests in favor of eval-as-integration-test Per review feedback: byte-equal snapshots were the wrong invariant for this refactor. The goal was a stable substrate for editing prompts, not a frozen contract. Snapshots would have generated maintenance churn (~100-200 line diffs per intentional Phase 2 prompt tweak) without providing value the eval doesn't already. Test posture going forward: - tests/prompts/loader.test.ts (3 tests) — bounds the loader infrastructure (template load, snippet inclusion, variable interpolation, missing-id behavior) - pnpm eval:whiteboard — bounds end-to-end agent loop, template composition, and integration with chat/director/state-manager Removed: 1879 lines of .snap + 320 lines of test scaffolding + fixtures. Net PR diff drops by ~2200 lines. * docs(prompts): add README + structural assertion tests (review feedback) Addresses two items flagged by PR #459 final review: 1. lib/prompts/README.md — conventions, syntax, gotchas, and local-testing recipe for template authors. Previously there was no doc for the stated goal of "non-engineers can edit prompts." 2. tests/prompts/templates.test.ts — 8 structural assertions covering: - no surviving {{...}} placeholders in any rendered template - role dispatch (teacher → LEAD TEACHER, student → not) - scene-type action stripping (quiz scene has no spotlight/laser) - director prompt output spec mentions next_agent These replace the removed byte-equal snapshot suite at much lower maintenance cost — they assert behaviors the refactor must preserve, not exact bytes. * chore(prompts): relocate templates added on main during rebase PR #461 (interactive mode clean) added 7 new templates under lib/generation/prompts/templates/ (the pre-refactor location). Rebase onto origin/main landed them at the old path; git's rename detection didn't forward them through the directory move in db56c40. Manually move them to lib/prompts/templates/ to match the new convention, and fix scene-generator.ts's relative import ('./prompts/types' → '@/lib/prompts/types') since the dir no longer exists as a sibling. No behavior change — templates read from PROMPT_IDS values via getPromptsDir() which already points at lib/prompts/. * refactor(prompts): address review feedback from @cosarah - loadSnippet now throws on missing file instead of silently returning a literal {{snippet:id}} string. A typo like {{snippet:speach-guidelines}} now fails at load time instead of reaching the LLM. - README gains a "Still in TypeScript" section listing the role-conditional content that still lives in prompt-builder.ts (ROLE_GUIDELINES, buildLengthGuidelines, buildWhiteboardGuidelines) so contributors expecting a pure-markdown workflow know where to look. - Expand tests/prompts/templates.test.ts to cover the conditional branches Phase 2 is most likely to touch (9 new assertions): - assistant role dispatch - peer-context section toggles on agentResponses presence - language constraint toggles on stage.languageDirective presence - director Q&A vs discussion mode branching - pbl-design {{issueCount}} substituted at all 3 occurrences - placeholder-naming-convention lint scans every template for non-camelCase placeholders (slide-content grandfathered) - Comment above interpolateVariables regex documents why kebab-case placeholders pass through silently (the lint test now catches them). - New test in loader.test.ts locks the throw-on-missing-snippet behavior. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com> |
||
|
|
c02a607377 |
feat: interactive mode clean (#461)
* feat: add interactive mode * feat: add TeacherActions for interactive mode * fix: better prompt for ultra mode * feat: upgrade normal mode's interactive generation with 5 widget type and actions * feat: make interactive mode button clear * fix: remove unused TeacherOverlay * fix: resolve PR #458 review feedback - Revert unrelated infra changes (Dockerfile, docker-compose.yml) - Fix placeholder strings in generateWidgetContent - Rename ultraMode to interactiveMode consistently across codebase - Extract duplicated patchHtmlForIframe to shared utility - Fix widget store race condition by keying callbacks by sceneId - Fix teacher-action ID collisions by using descriptive IDs in prompt - Relax outline prompt constraints for flexibility - Optimize sidebar thumbnail with IntersectionObserver lazy loading - Add trailing newlines to modified files Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: update generateSceneActions call signatures The function signature changed to individual parameters instead of options object pattern after cherry-pick. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * style: fix prettier formatting Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix: removed extra language arg * style: fix prettier formatting v2 * fix: add missing i18n keys --------- Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
470aa5e42e |
feat: inline language inference for outline and PBL generation (#412)
* feat: inline language inference in outline generation Replace manual language selection with automatic inference from user requirement text. The outline generator now produces a languageDirective that propagates through the entire generation pipeline. Key changes: - Rewrite Language Inference section in outline prompt with decision rules for foreign language learning, cross-language PDF, proxy requests, and terminology handling - Reorder pipeline: outlines before agents, so agent profiles can use the inferred languageDirective - Pass languageDirective through scene content/actions generation - Add SSE streaming of languageDirective from outline generation - Remove manual language selection UI Eval test suite: - 50 test cases covering 9 scenario types: single-language, language learning, immersive, explicit instruction, code-switching, minimal input, user profiles, cross-language PDF, locale mismatch - LLM-as-judge evaluation with configurable inference/judge models - 50/50 pass rate with gemini-3-flash-preview + gpt-4o judge - Excluded from CI (requires LLM API keys) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove useless attributes in test case * feat: pass languageDirective to PBL, remove hardcoded zh-CN/en-US - Remove pblConfig.language field, use languageDirective from outline inference instead - Delete all Chinese prompt duplicates in pbl-system-prompt.ts, agent-templates.ts; keep English templates with languageDirective injection - Remove zh-CN/en-US branches in generate-pbl.ts (initial prompt, post-process context, welcome message) - Pipe languageDirective through scene-generator → generatePBLContent → IssueboardMCP → agent templates - Remove i18n template wrapping from PBL welcome messages in pbl-renderer.tsx and use-pbl-chat.ts; use LLM-generated content directly to avoid language mismatch when UI locale ≠ course language - Update pblConfig schema in outline prompt (remove language field) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor: clean up legacy language fields, pass languageDirective through buildSceneFromOutline - Add languageDirective param to buildSceneFromOutline, combining with outline.languageNote via buildLanguageText - Remove dead types: AudienceProfile, StylePreferences, LegacyUserRequirements, SceneOutline.language - Remove Stage.language and all its propagation (storage, stageInfo, prompt-builder fallback) - Remove GenerateClassroomInput.language and job store inputSummary.language - Remove unused pdfLanguageSample from outline SSE route Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: persist languageDirective to IndexedDB, fix TTS preview and dead refs - Add languageDirective to StageRecord and stage-storage write path - Add DB v9 migration: convert legacy language locale codes to directives - Use voice.language for TTS preview text instead of dead localStorage key - Omit empty ## Language section in PBL agent prompts - Use JSON.parse for extractLanguageDirective unescape (\uXXXX support) - Remove dead i18n keys: toolbar.languageHint, pbl.chat.welcomeMessage Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
cce7087f67 |
Fix action filtering logic and add safety improvements (#163)
* fix: fix 3 bugs found during code review 1. formatQuestionsForPrompt called .join() on QuizOption objects, producing "[object Object]" in AI prompts instead of readable option text (e.g. "A. Option1, B. Option2"). 2. json-repair Fix 1 regex double-escaped valid JSON escapes (\t, \n, \r, \b, \f) and couldn't handle strings with escaped quotes. Now uses a proper string-aware regex and preserves valid escapes. 3. PlaybackEngine spotlight/laser actions used synchronous recursion via processNext(), risking stack overflow with many consecutive non-speech actions. Now uses queueMicrotask() to break recursion. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * fix: ensure allowedActions whitelist applies to non-slide scenes The early return in Step 6 (slide-only action filter) caused Step 7 (allowedActions whitelist) to be skipped for non-slide scenes. This meant hallucinated actions from agents in quiz/interactive/pbl scenes were not filtered by the role-based allowedActions whitelist. Refactored to use a mutable result variable instead of early returns so both filters always apply. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * fix: prevent video playback hang and division by zero in CJK detection 1. executePlayVideo could hang forever if the video element was invalid or the state change was missed between playVideo() and subscribe(). Added a 5-minute safety timeout to prevent indefinite blocking. 2. CJK language detection in browser TTS divided by chunkText.length without checking for empty strings, producing NaN. Now guards against zero-length text. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * fix: prevent ordered entry with invalid index when partial text has no remaining content When a previously-partial text item completed but all content had already been streamed as deltas (remaining is empty), the code still pushed an ordered entry pointing to textChunks.length - 1, which could be -1 or reference an unrelated chunk. This caused spurious warnings in director-graph and potential text loss. Now only pushes the ordered entry when there is actual remaining content to emit. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * fix: validate quiz points parameter and fix parse-pdf metadata spread order 1. quiz-grade: `points` from request body was used without validation, causing NaN in score calculation and invalid JSON responses when points was undefined, negative, or non-numeric. Now validates it is a positive finite number. 2. parse-pdf: metadata spread order put the default `pageCount` before `...result.metadata`, so the spread would overwrite the fallback. Fixed by spreading metadata first, then applying defaults after. Also changed `||` to `??` so pageCount=0 is preserved correctly. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * fix: crash in moveUpElement, dead-code in video options, wrong parens in canCombine 1. use-order-element.ts: moveUpElement crashed with TypeError when a grouped element was already at the top of the z-order. The code accessed copyOfElementList[maxLevel + 1] without bounds checking, then dereferenced .groupId on undefined. Added early return guard matching the pattern used in the non-grouped branch. 2. video-providers.ts: normalizeVideoOptions had a dead-code ternary inside an if-block that already proved the condition was false. Simplified to directly use the fallback value. 3. use-canvas-operations.ts: canCombine check had incorrect parenthesization: (el.groupId && el.groupId) === firstGroupId evaluated the && first, which is equivalent to just el.groupId. Fixed to: el.groupId && el.groupId === firstGroupId. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * style: fix prettier formatting in 3 files https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm * fix: use valid ApiErrorCode in quiz-grade route INVALID_PARAMETER is not a member of API_ERROR_CODES. Use INVALID_REQUEST instead, which is the appropriate code for invalid request parameters. https://claude.ai/code/session_01JdigqQtiAvomeifvWSQbjm --------- Co-authored-by: Claude <noreply@anthropic.com> |
||
|
|
531b3c101f |
feat: make Tavily web search query context-aware when PDF is uploaded (#258)
* fix(web-search): rewrite search query for pdf and long requirements * fix(web-search): address query rewrite review feedback |
||
|
|
f069aaf0a3 |
fix(prompts): prevent teacher identity and verbose text on slides (#85)
* fix(prompts): enforce concise slide content, move verbose text to speaker notes Add explicit instructions to slide-content prompt requiring keywords, short phrases, and bullet points only — no conversational sentences, teacher's remarks, or lecture-style paragraphs on slides. Reinforce in slide-actions prompt that all verbal elaboration belongs in speech actions. Closes #78 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(prompts): prevent teacher identity from appearing on slide content The teacher persona context was causing the LLM to generate teacher-personalized slide content (e.g., "Teacher Wang's tips", "Teacher's wishes"). Now explicitly instructs the LLM that teacher identity is for tone/style only — slides must remain neutral and professional, like real-world PPTs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> |
||
|
|
fbe8399678 |
feat(generate): server-side media & TTS generation (#75)
* feat(generate): server-side media & TTS generation in classroom pipeline When `enableImageGeneration`, `enableVideoGeneration`, or `enableTTS` flags are passed to /api/generate-classroom, the server now actually generates media files and TTS audio, persists them to disk, and replaces placeholders in the classroom JSON with serving URLs. - Add media serving API route (GET /api/classroom-media/[id]/[...path]) - Add server-side media generation utility (image, video, TTS) - Wire generation phases into classroom pipeline with progress steps - Update AudioPlayer to support URL-based playback (server-generated TTS) - Add audioUrl field to SpeechAction type - Extend /api/health with capabilities detection - Pass through feature flags in generate-classroom route - Update skill docs for optional feature configuration Closes #49 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: fix prettier formatting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(generate): add agentMode support for server-side classroom generation Allow callers to choose between built-in default agents ('default') or LLM-generated custom agent profiles ('generate') via a new agentMode field on GenerateClassroomInput. The resolved agents are injected into outline, scene content, and scene action prompts via teacherContext. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(media): harden download, parallelize media gen, fix TTS concatenation - Add timeout (2min) and max size (100MB) guard to downloadToBuffer - Run image and video generation in parallel via Promise.all - Only split TTS text for MP3 (frame-based); skip for WAV/OGG/AAC whose container headers break on naive byte concatenation - Remove unnecessary type assertion for speechAction.audioUrl Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: fix prettier formatting Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(media): harden media serving and TTS generation - Add realpath check to prevent symlink-based path traversal in media route - Stream files via createReadStream instead of readFile to avoid OOM on large videos - Truncate TTS text for non-concatenable formats (WAV/OGG/AAC) when exceeding provider limit - Add 'researching' step to distinguish web search from outline generation progress Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(tts): split long speech actions instead of concatenating audio bytes Adopt the same strategy as client-side: split a long speech action into multiple shorter actions before TTS generation, so each sub-action gets its own audio file. This avoids the broken byte-concatenation approach that corrupted non-MP3 formats (WAV/OGG/AAC container headers). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * refactor(tts): extract shared TTS splitting logic into lib/audio/tts-utils Both client-side (use-scene-generator) and server-side (classroom-media-generation) had duplicated TTS_MAX_TEXT_LENGTH, text splitting, and action splitting logic. Extract into a shared module to keep them in sync. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: remove unused TTS_MAX_TEXT_LENGTH import Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
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> |
||
|
|
51334259bb |
Split lib/generation/generation-pipeline.ts (1978 lines) into 7 modules
Extract by pipeline stage: - pipeline-types.ts: shared interfaces and type definitions - prompt-formatters.ts: context/prompt building utilities - json-repair.ts: JSON parsing with fallback strategies - outline-generator.ts: Stage 1 outline generation - scene-generator.ts: Stage 2 scene content + action generation - scene-builder.ts: standalone scene building + element normalization - pipeline-runner.ts: top-level pipeline orchestration 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> |