mirror of
https://github.com/THU-MAIC/OpenMAIC.git
synced 2026-10-19 05:49:27 +08:00
@openmaic/editor@0.0.2
32
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
c38da84ef6 |
feat(renderer): decouple editor UI from the app (#1072)
* docs: define renderer editor task 1 integration * docs: plan renderer editor task 1 * feat: gate renderer slide editor * feat: adapt renderer editor intents * feat: connect renderer editor to slide surface * test: complete renderer intent shape fixture * fix: restore renderer editor action previews * fix: render editor alignment guides * perf: smooth renderer element dragging * feat: align renderer hidden element behavior * feat: add renderer canvas host commands * feat: add renderer canvas context interactions * test: cover renderer context menu interaction * fix: preserve renderer canvas interaction semantics * docs: design renderer text editing * docs: plan renderer text editing * feat(renderer): add ProseMirror text core * feat(renderer): add rich text editor controller * feat(renderer): render editable text in place * feat(renderer): enter text editing on click * feat: connect renderer rich text editing * feat: finalize renderer text edit lifecycle * fix: stabilize renderer text edit commits * fix(renderer): move elements from selected borders * docs: design renderer editing UI text toolbar * feat(renderer): publish editing UI contracts * feat(renderer): add controlled text format toolbar * style(renderer): format editing UI contracts * fix(renderer): address Task 2 review findings * fix(renderer): handle zero font sizes in toolbar * feat(renderer): add editing UI color picker * fix(renderer): address Task 3 color picker review * fix(renderer): commit native color input changes * fix(renderer): coordinate native color picker interaction * feat(renderer): anchor text toolbar to canvas elements * feat(renderer): compose editable canvas with text UI * feat(editor): use renderer text toolbar UI * fix(renderer): make editing UI tests type-safe * fix(renderer): harden editing UI integration * feat(renderer): add editable text UI * feat(renderer): add image and shape editing * feat(editor): extend renderer editing controls * feat(editor): add renderer chart insertion * docs: design renderer latex editor * docs: plan renderer latex editor * feat(renderer): add latex editor contract * feat(renderer): add latex editor dialog * feat(renderer): compose latex insert and edit UI * feat(editor): integrate renderer latex editing * fix(editor): consolidate latex toolbar actions * fix(renderer): show toolbar hover labels * test(renderer): cover localized latex tooltips * chore(renderer): hide latex sample palette * feat(renderer): add video editing controls * docs: define renderer audio editing * feat(renderer): render audio elements * feat(renderer): add audio editing UI * feat(renderer): add preview audio controls * feat(editor): add renderer element clipboard * feat(renderer): decouple editor UI from app * chore(renderer): release 0.0.6 * fix(renderer): clear editor CI gates * fix(editor): adapt renderer canvas to media resolution API * fix(i18n): complete French editor labels * fix(renderer): hide toolbar vertical overflow * chore(renderer): address review cleanup * chore(docs): remove planning artifacts from pr * feat(editor): add transactional core package * chore(editor): ignore local test cache * build(editor): publish core entrypoint * refactor(editor): route renderer changes through transactions * refactor(editor): split renderer editing into editor package * ci(editor): register editor package for release * docs(editor): document package dependencies * ci: rerun validation after editor release registration * test(editor): validate deletion against existing element * fix(editor): address transaction and package review findings * fix(editor): validate transactions and restore editor styles * fix(editor): protect required updates and react styles * fix(editor): validate required transaction fields * fix(editor): prevent insert popovers shifting canvas * refactor(editor): own renderer editing capabilities * fix(editor): harden editing transaction boundaries * refactor(editor): modularize editor UI integration * docs(editor): harden third-party integration * fix(editor): preserve video resize aspect ratio * fix(editor): discard text draft before deletion * fix(editor): preserve renderer picking and line presets * chore(editor): remove unused pick-layer import |
||
|
|
5d5acd6215 |
feat: claude search (#393)
* Added search tool support for Claude * New locales for i18n * Updated translations * Prevent default web search base URLs from being prepopulated * fixed coding style issues * fixed coding style issues * fixing lint errors * fix: add SSRF protection to fetchPageContent in claude.ts Agent-Logs-Url: https://github.com/joseph-mpo-yeti/OpenMAIC/sessions/099e53fb-e1db-49f4-af7f-4f17cb3d364a Co-authored-by: joseph-mpo-yeti <55380155+joseph-mpo-yeti@users.noreply.github.com> * fix: address all remaining review feedback from PR review thread Agent-Logs-Url: https://github.com/joseph-mpo-yeti/OpenMAIC/sessions/e1ab8fe2-fe0d-45a5-a0af-30945b99c268 Co-authored-by: joseph-mpo-yeti <55380155+joseph-mpo-yeti@users.noreply.github.com> * fix: rename ambiguous variable names in settings store for clarity Agent-Logs-Url: https://github.com/joseph-mpo-yeti/OpenMAIC/sessions/e1ab8fe2-fe0d-45a5-a0af-30945b99c268 Co-authored-by: joseph-mpo-yeti <55380155+joseph-mpo-yeti@users.noreply.github.com> * fixing lint errors * fix: address 5 items from second PR review thread Agent-Logs-Url: https://github.com/joseph-mpo-yeti/OpenMAIC/sessions/09469d80-8e91-449b-8bc2-9c11f83555df Co-authored-by: joseph-mpo-yeti <55380155+joseph-mpo-yeti@users.noreply.github.com> * fixing model verification error * fix: address 3 items from third PR review thread Agent-Logs-Url: https://github.com/joseph-mpo-yeti/OpenMAIC/sessions/0aa49d19-df5b-4a08-a7e1-2295ae9cfc38 Co-authored-by: joseph-mpo-yeti <55380155+joseph-mpo-yeti@users.noreply.github.com> * fixing lint errors * fix: resolved Copilot review comments * fix: returning string promise for ssrf-guard * fix: returning string promise for ssrf-guard * fix: updated locales, added allowed_callers for claude search tools, handle duplicated claude model keys * fix: updated locales, added allowed_callers for claude search tools, handle duplicated claude model keys * updated tests * using Anthropic SDK for search and connection test in search settings. * uses @ai-sdk with a custom fetch including allowed_callers in payload instead of adding Anthropic SDK as a direct dependency * fixed format * removed @anthropic-ai/sdk as direct dependency * fix: resolve TypeScript errors in claude web-search tests Cast mock.calls through unknown to avoid tuple-index type errors on Vitest mock objects whose parameter types are inferred as empty tuples. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add Claude as a web-search provider on the multi-provider framework Forward-port of the original Claude web-search work onto main's searchWeb dispatcher, per review guidance on #393: - lib/web-search/claude.ts: searchWithClaude via the AI SDK Anthropic provider and Anthropic's native web_search server tool, called through callLLM for usage accounting. Returns the model's answer plus cited sources deduplicated by URL. The page-content enrichment fetch from the original PR is removed entirely, resolving the P1 SSRF finding (no server-side fetches of attacker-influenced result URLs remain). - allowed_callers: ["direct"] is still injected at the fetch layer; the AI SDK's provider-defined web_search tools do not emit it. - Tool version picked from the model: web_search_20260209 for 4.6+ Opus/Sonnet, basic web_search_20250305 for Haiku/older; maxResults maps to the tool's max_uses. - Registry/dispatcher/route wiring: claude provider entry, claudeModelId passthrough (web-search route, classroom generation, generation preview), WEB_SEARCH_CLAUDE_* env config with server-pinned model via WEB_SEARCH_CLAUDE_MODELS, and client base-URL allowlisting for api.anthropic.com. - Settings: per-provider modelId with a model selector in the Claude panel; locale keys added to all ten languages. - Tests: new adapter suite plus claude cases in the dispatcher, constants, route, provider-config, web-search-config, and settings store suites. Closes #392 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01E9KqAGmKCtBwMC4HtT4JKE * fix(web-search): trim whitespace around the Claude API key and base URL Keys are pasted by hand into Settings, and nothing in the client key path trimmed them: a trailing newline or space was sent verbatim as the x-api-key header value and came back from Anthropic as 'invalid x-api-key', with nothing in the message pointing at whitespace. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * fix(web-search): correct Claude adapter tool selection, base URL, and timing Addresses the four P2 review findings on #393: - Route dated Claude 4.0 ids (claude-sonnet-4-20250514, claude-opus-4-20250514) to the basic web_search_20250305 tool. The blocklist regex missed them, so they were sent web_search_20260209, which pre-4.6 models reject. Replaced with an allowlist of the models that have dynamic filtering, so unrecognized ids also fall back to the basic tool -- the safe direction, since 4.6+ models accept both. - Pin allowed_callers: ["direct"] only on web_search_20250305. Injecting it into every request disabled the code-execution caller that provides dynamic filtering on web_search_20260209. - Normalize the bare Anthropic root to /v1 before handing the base URL to the SDK, which appends /messages verbatim and would otherwise 404. The adapter is the single choke point for the client allowlist, the server env var, YAML, and the default; other hosts pass through untouched. - Return responseTime in seconds, matching every sibling adapter's WebSearchResult contract instead of exposing milliseconds for Claude. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
2b3f2eaa37 |
feat(asr): add local FunASR provider (#1044)
Signed-off-by: LauraGPT <199134975+LauraGPT@users.noreply.github.com> Co-authored-by: LauraGPT <199134975+LauraGPT@users.noreply.github.com> |
||
|
|
de95350516 |
feat(video-export): deterministic Quiz/PBL cover cards (#985) (#995)
* feat(video-export): add deterministic Quiz/PBL cover cards Replace unsupported placeholders with authored-metadata cover cards that stay independent of learner progress, and pin dense-layout evidence for 720p/480p. Co-authored-by: Cursor <cursoragent@cursor.com> * feat(video-export): add configurable localized cover CTA Replace the inert Start Quiz affordance with a destination-configurable CTA (NEXT_PUBLIC_VIDEO_EXPORT_CTA_DESTINATION), including Unicode/bidi display guards. Co-authored-by: Cursor <cursoragent@cursor.com> * test(ci): require Hyperframes video-export gates Lock CI/Docker contracts so cover materialization and Hyperframes sample lint stay required for export changes. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(ci): move HF_E2E_DIR onto e2e steps GitHub rejects runner.* in job-level env, which aborted the CI workflow with zero jobs. Keep the sample dir on the materialize/lint steps only. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(video-export): tidy CI invoke and panel-box export Run the Hyperframes materialize step through pnpm exec vitest like the cover-card guardrail above it; the e2e job already pins Node 22. Stop re-exporting PBL_PANEL_DESIGN_BOX from the public barrel — only the layout browser test needs it, and it can import the emitter module directly. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
3d85525665 |
[codex] Add Amazon Bedrock LLM provider support (#538)
* Enable AWS-hosted text models without exposing ambient credentials Rebase the Bedrock provider onto current main and close the review-requested security, credential lifecycle, usage attribution, configuration, and metadata gaps. Constraint: Bedrock may use ambient AWS credentials only when explicitly enabled by the server operator Rejected: Trust client-supplied provider types | permits built-in keyless IDs to reach Bedrock credentials Confidence: high Scope-risk: moderate Directive: Keep provider ID/type validation at both request resolution and model construction boundaries Tested: targeted Bedrock/resolver/config/usage tests; TypeScript; ESLint; i18n alignment; production build Not-tested: Full suite has 27 failures in unchanged quiz/runtime and runtime/chat-storage tests * Give Bedrock a recognizable provider identity Use the official AWS architecture service icon so Bedrock no longer falls back to the generic provider cube in settings and model selection. Constraint: Preserve the AWS-provided artwork without redesigning the service mark Confidence: high Scope-risk: narrow Tested: SVG XML validation; provider unit test; TypeScript; ESLint; production build --------- Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
12ccd315ea |
Add Atlas Cloud LLM provider (#948)
* Add Atlas Cloud provider * Account for Atlas Cloud non-thinking model metadata * test: verify Atlas Cloud thinking payloads * style: format Atlas Cloud payload test * test: type Atlas Cloud fetch mock --------- Co-authored-by: binyangzhu000-sudo <224954946+binyangzhu000-sudo@users.noreply.github.com> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
61a7154f07 |
feat(pi): add evidence-aware Director context runtime (#971)
* feat(pi): add evidence-aware Director context runtime * fix(web-search): require completed native search * fix(orchestration): preserve whiteboard across agent handoffs * fix(pi): remove wrap-up turn bypass |
||
|
|
ff95e6683d |
feat(renderer): add optional playback canvas (#958)
* feat(renderer): add optional playback canvas * style(renderer): format playback tests * fix(renderer): center text by default * fix(renderer): address playback review feedback * docs(renderer): align playback canvas API docs --------- Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
84b1907255 |
feat(video-export): service-backed MP4 render + in-app one-click export (#866) (#937)
* feat(video-export): service-backed MP4 render + in-app one-click export (#866)
Adds the last mile of classroom video export: turning the self-contained
Hyperframes project ZIP (#865) into an MP4 via an isolated render service,
one-click in-app.
- render-service/: standalone Node 22 + Chromium + FFmpeg container wrapping
@hyperframes/producer's library API. Async job model (POST /render -> 202
jobId, GET poll, GET download, DELETE cancel). Swappable JobStore /
ArtifactStore seams (in-memory + local-disk now; Redis/S3 + presigned-302
download later) so it scales horizontally without changing the HTTP contract.
Concurrency + per-user guards are config knobs.
- App integration: thin Next proxy routes under app/api/export-video/* (forward
only, no rendering) + capability probe. use-render-video.ts uploads the ZIP,
polls via runPolledTask, downloads the MP4; shared buildExportZip prefix with
the existing ZIP path. Export menu gains resolution/fps/quality selectors and
a progress bar; degrades to ZIP download when RENDER_SERVICE_URL is unset.
- docker-compose: render-service under an opt-in "video-export" profile.
- Entry is main.ts (not server.ts): the producer auto-starts its own server on
:9847 when the process entry path ends with /src/server.ts.
Verified end-to-end in the container: rendered a real 640s (10.7 min) classroom
ZIP to a valid H.264 720p + AAC MP4 (duration matches source) in ~9.6 min
(~0.9x realtime, 4-worker frame capture). Degrade path, queued-cancel + cleanup,
and per-user 429 guard all exercised. pnpm check / lint / tsc / i18n pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat(video-export): global render progress store, percent+ETA UI, ring on export button (#866)
Addresses two UX issues found while driving the in-app MP4 export:
1. Progress display was raw and unfriendly (showed producer's English stage
strings like "Capturing frame 5130/19220") and had no time estimate. Now the
menu shows only "<percent>% · about <remaining> left". ETA is computed from a
recent-speed estimate (percent-per-ms over the last sample), EMA-smoothed —
which tracks the render's non-uniform pace (prep -> frame capture with a
4->1 worker drop -> encode) far better than a whole-run average, and never
shows a stale/rising ETA.
2. Switching scenes mid-render unmounted the export menu and lost the progress
(and reset the local "already rendering" ref, allowing a duplicate submit).
The whole render lifecycle now lives in a global store
(lib/store/video-render.ts), so progress survives menu close / scene switch
and duplicate submits are guarded by status. A persistent CircularProgress
ring on the export button shows live progress whether or not the menu is open.
Also fixes the progress scale: the producer reports progress as 0..100, but our
HTTP contract (and success path) is 0..1 — the service now normalizes it, so the
client no longer showed "2000%".
- lib/store/video-render.ts: new global store owning submit->poll->download,
recent-speed ETA, duplicate-submit guard.
- lib/video-export-app/use-render-video.ts: thin facade over the store.
- components/ui/circular-progress.tsx: lightweight SVG progress ring.
- components/stage/{header-controls,video-export-menu}.tsx: ring on the export
button; menu shows percent + ETA, subscribes to the store.
- render-service/src/render-manager.ts: normalize producer progress 0..100 -> 0..1.
- i18n: percent/ETA strings across all 8 locales (drops the stage-based string).
- render-service/package-lock.json: complete integrity hashes (reproducible npm ci).
Verified: ETA logic checked against the real segmented render curve (worker drop
raises ETA, encode speedup drives it to ~0); progress scale fix confirmed live
against the container (0.2 -> 20%). tsc / lint / prettier / i18n pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(video-export): persist render options in the store, not the menu component
Selecting 720p/24fps/draft, switching scenes, and reopening the export menu
showed the defaults again (1080p/30/standard). The selections lived in the
VideoExportMenu component's local state, which reset when the menu unmounted on
a scene switch — the running render still used the chosen options, but the UI
misrepresented them.
Move resolution/fps/quality into the global video-render store (with a
setOptions action). The menu now reads/writes the store, so selections survive
menu close / scene switch, and while a render runs the selectors reflect the
options that render is actually using. startRender() reads options from the
store instead of taking them as an argument.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(video-export): deployment correctness + resource/isolation controls (PR #937 review)
Addresses the blocking findings from wyuc's review. Output fidelity was fine;
these harden deployment and production resource/isolation boundaries.
#1 Compose advertised MP4 but couldn't render in prod:
- Capability now probes the service's /health (checkRenderServiceHealth), so a
configured-but-absent service reports disabled and the UI degrades to ZIP
instead of 502-ing.
- RENDER_SERVICE_URL is operator-supplied trusted config, so the proxy no longer
runs it through the SSRF guard — the one-command `docker compose --profile
video-export up` now works without globally weakening SSRF via
ALLOW_LOCAL_NETWORKS. resolveRenderServiceUrl() is now synchronous.
- Client degrades to ZIP on any failed submit (not only 501).
#2 Unbounded upload/queue (ZIP-bomb / DoS):
- unzip.ts bounds the archive via fflate's filter BEFORE decompression: entry
count, per-entry and total expanded size, and compression ratio.
- Proxy rejects oversized uploads (413) by Content-Length before forwarding.
- RenderManager enforces a global queue-depth cap (RENDER_MAX_QUEUE).
- All limits are env-tunable knobs in config.ts.
#3 Per-user guard was ineffective + admission ran after extraction:
- Identity is derived server-side (client IP) and forwarded as x-openmaic-client;
the service ignores any client-supplied userId, and the proxy strips it.
- Admission is split into reserve()/submit()/release(): the slot is reserved
BEFORE extraction, so a rejected caller never triggers a decompression.
Additional risks:
- Per-job wall-clock watchdog (RENDER_JOB_DEADLINE_MS) aborts + fails a hung
render so it can't hold a slot/scratch forever.
- Download proxy bounds only the time-to-headers, not the body stream, so large
MP4s over slow links no longer truncate.
- Client cancels the server job (DELETE) when a started render fails/times out.
- Compose puts render-service on an internal:true network (no host/internet
route), sandboxing the Chromium that runs the uploaded HTML; the export ZIP is
self-contained so no outbound is needed. README documents the standalone caveat.
Not closing #866: the smoke/golden-render CI acceptance criterion remains a
follow-up (see PR description).
Verified in-container: legal render 202; ZIP-bomb (entry-count + compression-
ratio) rejected 400 before any decompression; per-identity guard 429 with a
spoofed multipart userId ignored; reserve-before-extract leaves no scratch dir
on rejection; watchdog aborts an overrunning job and frees the slot. tsc / lint /
prettier / i18n pass; render-service tsc passes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(video-export): real audio durations + burned-in subtitles (PR #937 review)
Two export-fidelity issues found in wyuc's deeper E2E:
A. Narration was scheduled from estimated durations, cutting audio off mid-
sentence and advancing the timeline early. The scheduler trusted
AudioFileRecord.duration (recorded only since #861), so the many existing
classrooms without it fell back to text-length estimates — measured 4.35s
average / 10.23s max underestimate across 47 clips. timeline-deps now probes
the real duration from each narration blob via an off-document <audio>
(symmetric to the existing video probe), preferring it over the stored
duration, then the estimate only when no audio asset exists. Everything
downstream (narration starts, scene/total duration, subtitle cues) re-derives
from the corrected value in the pure compiler — no compiler change needed.
B. The final MP4 had no subtitles (only H.264+AAC), and the ZIP's SRT/VTT used
the same estimated boundaries. The emitter now renders a burned-in subtitle
overlay: one caption box + a hidden div per cue, revealed/hidden by the paused
GSAP timeline at each cue's start/end (corrected timings from A), so Chromium's
frame capture bakes them in. The producer has no subtitle track of its own, so
burn-in is the v1 approach.
Verified: emitter unit tests + snapshot updated (subtitle overlay + toggle
statements, escaped text, hidden-by-default); 82 video-export tests pass incl.
the determinism red-line proxy. Rendered a synthetic subtitle project through the
container and confirmed by pixel analysis that captions appear only within their
cue window (2429 near-white px in the caption band at t=1.5s vs 0 at t=0.05s).
tsc / lint / prettier / i18n pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(video-export): subtitle layout + upload/admission hardening (PR #937 review)
Address the three P1 blockers plus actionable P2s from the
|
||
|
|
bb8d4f30e7 |
feat(chat): add experimental Pi classroom runtime behind a flag (#914)
* feat(chat): add experimental Pi classroom runtime * fix(chat): harden Pi whiteboard action sequencing * style(chat): format session retirement flow * style(playback): format async scene transition * fix(chat): retire actions on session errors * fix(chat): close Pi runtime lifecycle gaps * fix(chat): avoid replaying historical whiteboard actions * fix(chat): prevent Pi structured-output residue from leaking and inflating turns Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(chat): expose whiteboard element/line ids and bound code-line context Surface each element's id (and code line ids) in the Pi whiteboard context so later child agents can target wb_delete / wb_edit_code, and cap the rendered code lines with a shared character budget so a code-heavy board cannot grow the prompt without bound. Return only the current turn's whiteboard ledger from the Pi director loop instead of carrying history forward across requests. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(chat): bound Pi whiteboard code context Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(chat): prioritize newer persisted whiteboard code in budget Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * fix(chat): enforce whiteboard boundaries across Pi sessions * feat(chat): refine soft-closing discussion controls * fix(chat): make whiteboard clearing model-directed --------- Co-authored-by: apple <apple@GigideMacBook-Air.local> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> Co-authored-by: LING-6150 <duan.lin@northeastern.edu> |
||
|
|
c56929510c |
feat(web-search): add SearXNG provider support (#842)
* feat(web-search): add SearXNG provider support Enable self-hosted SearXNG via SEARXNG_BASE_URL, with server-side provider fallback, settings sync, and tests. Co-authored-by: Cursor <cursoragent@cursor.com> * style: fix Prettier formatting in web-search files Restore pnpm check by applying Prettier to imports, headers, and test assertions. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web-search): keep SearXNG base URLs server-managed only Close the SSRF primitive by ignoring client-supplied SearXNG URLs at the route boundary and rejecting them in resolveSafeClientWebSearchBaseUrl. Add negative route/config tests and an opt-in live smoke test for the JSON API. Co-authored-by: Cursor <cursoragent@cursor.com> * style: fix Prettier formatting for SearXNG web-search changes Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: 徐松 <song.xu@aieshanghai.com> Co-authored-by: Cursor <cursoragent@cursor.com> |
||
|
|
3b63710376 |
feat(ai): add Azure OpenAI provider (#916)
* feat(ai): add Azure OpenAI provider Add deployment-based Azure OpenAI configuration for both client and server-managed setups, normalize Azure portal endpoints, and expose the provider in settings. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b0d3a94f-089a-470e-9987-608f1506ca6f * style: format Azure provider type Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b0d3a94f-089a-470e-9987-608f1506ca6f --------- Co-authored-by: MarshellOnMoon <121332425+MarshellOnMoon@users.noreply.github.com> |
||
|
|
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> |
||
|
|
25cf58d19f |
feat(model): optional per-stage LLM model routing (#745) (#747)
* feat(model): optional per-stage LLM model routing (#745) Add a config-only stage -> model map consulted during model resolution, falling back to DEFAULT_MODEL when unset (zero behavior change unless opted in). - lib/server/model-routes.ts: parse/validate/cache MODEL_ROUTES env JSON; LLM_STAGES registry of routable stages; getStageModel(stage). - resolveModel: resolution order x-model > stage route > DEFAULT_MODEL > builtin; thread optional `stage` through resolveModelFromHeaders/FromRequest. - Wire each route's resolveModel call site to its stage; classroom-generation resolves generate-classroom and web-search-query-rewrite independently. - .env.example: document MODEL_ROUTES; unit tests for both modules. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(model): address cross-review findings for per-stage routing (#745) - classroom-generation: resolve the web-search-query-rewrite model lazily, only when explicitly routed and inside the web-search branch, with try/catch fallback to the classroom model. Fixes a regression where a misconfigured optional route (keyless/invalid provider) threw and aborted ALL classroom generation even with web search disabled; also avoids wasted resolution on the common no-search path and preserves classroom-model inheritance when unrouted. - resolve-model: type the stage param as LlmStage across resolveModel/ resolveModelFromHeaders/resolveModelFromRequest so a mistyped stage literal is a compile error instead of silently falling through to DEFAULT_MODEL. - model-routes: simplify the cache to a process singleton (matching provider-config), dropping the raw-string-keyed cache and redundant STAGE_SET. - .env.example: clarify x-model precedence and that a route to an unconfigured provider fails at request time (no startup validation), like a bad DEFAULT_MODEL. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(model): stage route takes precedence over client x-model (#745) Cross-review (codex P2 + Claude tracer) found that the browser UI always sends its saved model as x-model, so the previous x-model > stage order made MODEL_ROUTES inert for normal UI traffic on exactly the heavy stages the RFC targets (scene-content, quiz, pbl-chat, chat). Flip resolution to stage route > x-model > DEFAULT_MODEL: a configured route is the operator's deliberate per-stage choice and wins, while unrouted stages still honor the client's x-model. Update docs and tests accordingly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * style(model): prettier-format changed files for #745 CI Run the repo formatter (pnpm check / prettier) on the changed routes, the new model-routes module, and the new tests so `prettier . --check` (CI) passes; also correct a stale precedence comment in the resolve-model test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(model): isolate routed model from client connection params (#745) When a stage route overrides the client's x-model and points at a different provider, the client-sent apiKey/baseUrl/providerType (for the client's model) must not bleed onto the routed provider — otherwise a routed Anthropic model would be constructed with the client's OpenAI providerType/key and fail. A routed model now resolves its connection params purely from server config, as if no x-model was sent. Unrouted stages still honor the client params. Adds tests covering both the drop (routed) and keep (unrouted) cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs(model): correct graceful-degradation comment in classroom (#745) resolveModel does not throw on a missing key; clarify that a keyless route surfaces later in callLLM (degraded by the outer try/catch), while only a resolution-time failure is caught at the rewrite re-resolve. Comment-only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(model): route scene-content per scene type (#745) Extend MODEL_ROUTES with composite keys scene-content:<type> for the four core scene types (slide/quiz/interactive/pbl). getStageModel now resolves composite `a:b` stages most-specific-first, trimming `:` segments, so scene-content:<type> falls back to the base scene-content route, then x-model, then DEFAULT_MODEL. The scene-content route derives its stage from outline.type. Backward compatible: with no composite key configured, behavior is unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(model): per-stage thinking effort + drop hardcoded gpt fallback (#745) MODEL_ROUTES values may now be {model, effort} (not just a model string) to pin the thinking effort per stage. Arbitration mirrors model routing: a routed stage with effort set wins over the client's thinking (effort "none" disables); routed with no effort uses the model's default and drops client thinking; unrouted stages keep the client thinking. resolveModel is the single arbiter — body thinking is threaded in via resolveModelFromRequest. classroom-generation passes the resolved thinking into its callLLM calls so generate-classroom and web-search-query-rewrite honor route effort too. Also: removed the hardcoded `|| 'gpt-5.4-mini'` fallback in resolveModel — if no model resolves (no route / x-model / DEFAULT_MODEL) it now throws instead of silently picking a vendor default. model-routes: getStageRoute returns {model, effort?}; getStageModel delegates to it. Docs + tests updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(model): route value carries full ThinkingConfig (#745) Per-stage routing accepts the full unified ThinkingConfig in the route value ({model, thinking:{mode,effort,level,enabled,budgetTokens,excludeReasoningOutput}}) instead of just an effort string. The route's thinking is passed through resolveModel and normalized per the model's capability by callLLM, so budgetTokens (qwen), level (Gemini), enabled/mode, etc. all work. (qwen3.7-plus/max thinking capability now comes from upstream #753, so this no longer registers them.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(model): honor routed thinking for chat-adapter; doc fixes (#745) Cross-review (codex P2 + Claude) found chat-adapter was the only routable stage that ignored the route's thinking: it took the routed model but built its own thinkingConfig from the request body, so operator-pinned thinking never applied and client thinking still leaked onto a routed model. Now pass the client thinking into resolveModel and use the resolved thinkingConfig (route-pinned for a routed stage, client otherwise; defaults to disabled for low-latency chat). Also: clarify DEFAULT_MODEL is now required for server-side stages (the hardcoded gpt-5.4-mini fallback was removed → resolveModel throws if nothing resolves), and fix a stale {model,effort}→{model,thinking} doc comment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
3ccd5da6da |
feat(generation): opt-in parallel scene-content generation (#660)
* feat(generation): opt-in parallel scene-content generation Scene generation was strictly serial — content -> actions -> TTS, one outline at a time — so an N-scene classroom paid N x (content + actions + TTS) of wall-clock latency, which dominates the post-outline wait. Add an opt-in hybrid two-phase path (#572): - Phase 1 fetches scene *content* concurrently (bounded). Content is the only per-scene step independent of cross-scene state, so it is safe to parallelise; a content failure marks just that outline and does not pause the batch. - Phase 2 keeps the existing in-order actions + TTS loop, so previousSpeeches threading, ordered addScene, the abort/epoch guards, and the pause-on-failure UX are all unchanged. Gated by a server-side PARALLEL_SCENE_CONCURRENCY (default 0 = off, clamped to 10), surfaced to the client through the existing /api/server-providers response. With it unset the content map is null and the loop is byte-for-byte the original serial path, so out-of-box behaviour is unchanged. The bounded worker pool is extracted to lib/utils/concurrency.ts (mapWithConcurrency, with an early-stop hook for abort/epoch) and unit-tested; getParallelSceneConcurrency env parsing/clamping is tested too. Closes #572 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * refactor(generation): pipeline content fetches instead of a barrier Address @wyuc's review on #660. The previous version awaited the whole bounded content pool before Phase 2, so for N > C scenes the user saw the first scene, then a stall on a single page for the entire content phase, then a burst — perceived as worse than serial despite the wall-clock win (the gap scales with ceil((N-1)/C)). Pipeline instead: lazyBoundedMap starts the content fetches (<= C in flight) and returns one promise per outline immediately; the serial loop awaits them in order, so each resolves as soon as its own content is ready (usually already done, hidden behind the previous scene's actions/TTS). The first scene now paints after content(1)+actions(1)+TTS(1) — same as serial — with the full concurrency benefit and no stall. Also from the review: - a content fetch can no longer take its siblings down: an unexpected throw is caught and returned as a failure result, routed through the same mark-failed path as the serial loop (symmetric); - drop the cosmetic Phase-1 setCurrentGeneratingOrder — the loop already sets it per outline; - note the intentional belt-and-suspenders clamp; - concurrency.test.ts asserts <= limit (not == limit), and gains lazyBoundedMap tests including the no-barrier property. mapWithConcurrency is kept as a thin await-all wrapper over lazyBoundedMap. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: ly-wang19 <ly-wang19@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
2165e55bac | feat: add MiniMax web search provider (#634) | ||
|
|
07115dff17 |
feat(asr): add Azure STT (Fast Transcription) provider (#175)
* add Azure ASR config and localization * add transcribeAzureASR func * fix(settings): prevent Azure STT crash in ASR modal * feat(i18n): add Azure STT provider support in language locales |
||
|
|
679130a6b9 | feat(ai): add Xiaomi MiMo Token Plan support (#578) | ||
|
|
47cc2a510c |
feat: add Brave Search and Baidu Search integration
Add Brave Search and Baidu Search providers with Baidu sub-source support, provider configuration updates, tests, and docs links. |
||
|
|
46b61dedfd |
feat: add HappyHorse video adapter (#509)
Add Alibaba Cloud DashScope HappyHorse text-to-video support as an OpenMAIC video generation provider. Co-authored-by: xuruiray <15962843+xuruiray@users.noreply.github.com> |
||
|
|
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> |
||
|
|
dbe1d2ec76 |
[codex] Add Bocha web search provider (#524)
* Add Bocha web search provider * Address Bocha web search review feedback |
||
|
|
4754bbae6d | support gpt-5.5 api (#487) | ||
|
|
a95aa87bf1 | support recent model providers (#481) | ||
|
|
c071e02d83 |
feat: ACCESS_CODE site-level authentication (#407) (#411)
* feat(access-code): add status API endpoint Returns whether ACCESS_CODE is enabled and whether the current user is authenticated via cookie, to support the frontend access gate. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(access-code): add verify API endpoint Creates POST /api/access-code/verify that validates ACCESS_CODE env var and sets an HttpOnly 7-day cookie on success. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(access-code): add Next.js middleware to gate API routes Intercepts all requests when ACCESS_CODE env var is set. API routes return 401 without the openmaic_access cookie; page requests pass through so the frontend can render the access-code modal. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(i18n): add accessCode translations for all 4 locales Add accessCode top-level key to en-US, zh-CN, ja-JP, and ru-RU locale files with title, placeholder, submit, and error strings. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs: add ACCESS_CODE documentation to .env.example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat: add AccessCodeGuard component and integrate into root layout Wraps page children with an access-code gate that checks /api/access-code/status on mount and renders AccessCodeModal when authentication is required. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(access-code): add AccessCodeModal component Adds the modal dialog component that prompts users for an access code, using existing Dialog/Button/Input UI components and i18n translation keys. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(access-code): fix lint error and format files - Fix useEffect setState pattern in access-code-guard.tsx - Format middleware.ts and layout.tsx with Prettier Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style(access-code): redesign modal as full-screen gate Replace generic Radix Dialog with a custom full-screen gate: - Mesh gradient background with noise texture - Frosted glass card with backdrop-blur - Staggered motion animations on mount - Inline submit button inside input field - Success state animation before dismissal - Proper dark mode support Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(access-code): address code review findings Critical: - Middleware now validates HMAC-signed cookie tokens, not just existence - Verify endpoint uses timingSafeEqual for constant-time comparison - Cookie value is now `timestamp.HMAC(ACCESS_CODE, timestamp)` instead of UUID Important: - Middleware 401 response includes `errorCode` matching apiError shape - Status endpoint uses apiSuccess wrapper for consistency - Remove unused `accessCode.submit` i18n key from all 4 locales Suggestions: - Guard renders children during loading (overlay on top, not blocking) - Network error defaults to enabled=true (safer than silently disabling) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(access-code): use Web Crypto API in middleware for Edge Runtime Node.js crypto module is not available in Next.js Edge Runtime. Replace createHmac/timingSafeEqual with crypto.subtle HMAC and manual constant-length XOR comparison. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
2c26e3a461 |
feat: Ollama local LLM support (#94)
* feat: Ollama local LLM support - Ollama as a built-in provider (OpenAI-compatible, no API key needed) - 8 default models: llama3.3, llama3.2, qwen2.5, qwen2.5:32b, mistral, gemma3, deepseek-r1, phi4 - Keyless provider activation: providers with only a baseUrl (no API key) now activate correctly - isProviderKeyRequired() helper for consistent key validation across routes - i18n strings for Ollama (zh-CN + en-US) and missing Doubao strings - SSRF guard documentation clarifying server-configured URLs bypass safely Previously, clients could send `x-requires-api-key: false` (header) or `requiresApiKey: false` (body) to skip API key validation for ANY provider, including ones like OpenAI that require keys. This meant a client could consume server-configured credentials without authorization. Fix: the server now derives requiresApiKey exclusively from its own provider registry. The client header and body field are removed from all server-side parsing. For Ollama, the registry says `requiresApiKey: false` so it works keyless. For OpenAI, the registry says `true` so the check is enforced regardless of what a client sends. * fix: address reviewer feedback on Ollama integration - Fix env-var activation so OLLAMA_BASE_URL alone activates the provider - Move SSRF bypass comment from ssrf-guard.ts to resolve-model.ts - Add ollama and doubao provider names to i18n locale files Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * Fixed issues from reviewer notes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * style: format provider-config.ts with Prettier 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: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
7474290ad6 |
fix(ssrf): add ALLOW_LOCAL_NETWORKS env var for self-hosted deployments (#366)
Self-hosted users need to access local network services (Ollama, local TTS/ASR endpoints, etc.) but the SSRF guard blocks all private addresses. Add ALLOW_LOCAL_NETWORKS env var that skips private-IP checks when set to "true" or "1", while still validating URL format and protocol. Fixes #310 Fixes #311 Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Co-authored-by: 杨慎 <117187635+cosarah@users.noreply.github.com> |
||
|
|
9badd59856 |
feat: add and expand MiniMax provider support (#182)
Add MiniMax LLM models (M2–M2.7), TTS provider (speech-2.8/2.6/02/01), image generation (image-01), and video generation (Hailuo 2.3/02, T2V-01). Unify base URLs to api.minimaxi.com and add MiniMax-specific base URL normalization for the Anthropic-compatible endpoint. Co-authored-by: Hi-Jiajun <3138947285@qq.com> |
||
|
|
3a3e27bac0 |
feat: add ElevenLabs TTS provider (#134)
* feat: add ElevenLabs TTS provider * fix(tts): wire ElevenLabs provider config Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> --------- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai> Co-authored-by: wyuc <wang-yc24@mails.tsinghua.edu.cn> |
||
|
|
e92d1958a6 |
feat: add Grok (xAI) support as an LLM, image generation, and video generation provider (#113)
* feat: add Grok (xAI) provider support for LLM, Image and Video generation - Add Grok as LLM provider (OpenAI-compatible, 11 models including grok-4.20, grok-4, grok-3) - Add Grok Image generation provider (grok-imagine-image, grok-imagine-image-pro) - Add Grok Video generation provider with async polling (grok-imagine-video) - Add env vars: GROK_*, IMAGE_GROK_*, VIDEO_GROK_* - Add web search note: Grok search is via chat completions, not standalone API - Update README/README-zh with Grok in supported providers Closes #87 * fix: ensure new image/video providers are auto-added to persisted settings Add ensureBuiltInImageProviders and ensureBuiltInVideoProviders functions that run on every store rehydrate, mirroring the existing LLM provider sync logic. Without this, Grok Image/Video providers would not appear for users with existing localStorage settings. * fix: add missing English translation for providerGrokVideo * style: fix prettier formatting for grok video provider * fix: remove unsupported grok multi-agent model and improve video error |
||
|
|
631bedfa2d | refactor: replace openclaw plugin with guided skill | ||
|
|
9c5550674f | chore: add vercel deploy settings |