feat: configure canvas pages sent for note analysis

Canvas analysis previously sent every page. Add a Magic Notes setting for
1-8 canvas pages, defaulting to 1 for new and historical settings. Select
the first N pages in current canvas order before capture and use the same
text/image range for saved entries, drafts and canvas-source todos.

Keep full 50-page saving/export, expose the same setting through config
tools, and use the shared settings select with an inline help icon.
Include pagination, persistence, production IPC and isolated Electron
regressions, including text-only input and scaled page boundaries.

Validation: focused feature tests and isolated Electron regressions passed;
the final compact UI passed 14 tests. Typecheck and lint were reported
passing by the coordinating agent. No full-suite pass is claimed because
the completed full test command exposed no summary. No live model calls
were made for this commit preparation.

Release note: 魔法笔记新增“发送画布页数”设置,可选 1~8 页,默认 1 页,按当前画布顺序发送前 N 页的文字和图片;标题旁问号可查看说明,保存和导出完整画布不受影响。
This commit is contained in:
mesalogo
2026-09-20 00:07:07 +08:00
parent ecf09f4e95
commit bf1d34e897
39 changed files with 475 additions and 102 deletions
+5 -2
View File
@@ -61,8 +61,11 @@ changing saved content or export dimensions; see the
[canvas zoom reference](../../../src/renderer/src/magic-canvas/README.md#view-zoom).
Drafts, saved entries and todos sourced from canvases support AI comments using
the default model's image-input capability. Image-capable models receive complete
page captures and extracted text. Text-only models receive an explicitly labelled
the default model's image-input capability. The Canvas pages to send setting
selects the first 1-8 pages in current canvas order, defaulting to 1. It counts
pages in one canvas, not entries, and leaves full-canvas saving and export intact.
Image-capable models receive complete captures and extracted text for that prefix.
Text-only models receive the same page range as an explicitly labelled
text fallback; a purely visual canvas entry or draft reports that an image-capable
default model is required. Canvas comments are requested manually in `immediate`
mode, or after a manual save in `after-save-auto` mode. Analysis failure does not
+51
View File
@@ -1,5 +1,56 @@
# Magic Notes Progress
## 2026-09-19: Compact Page Count Setting
- The page-count select now uses the existing `.field` settings control styling.
A title-adjacent `CircleHelp` icon uses the shared `icon-button` and native
`title` hint; the full description is screen-reader-only and remains associated
with both controls through `aria-describedby`. The compact row uses flex and
keeps the label and help icon together with inline-flex, including at narrow
widths. Control styling and the native hint mechanism remain shared. Page
selection and persistence behavior are unchanged.
- `npx vitest run src/renderer/src/ApplicationCenter.test.tsx` passed 14 tests.
Focused ESLint and a temporary TypeScript configuration rooted at
`ApplicationCenter.tsx` with its imported dependencies passed. No full suite,
full typecheck, Electron/live-model test or model request was run in this UI pass.
- The commit preparation had only inspected status, diffs and history. The index
remained empty and HEAD remained `ecf09f4`; no staging or commit was performed.
The later same-line adjustment passed the same 14-test UI suite before commit.
- The coordinating agent subsequently reported full typecheck and lint passing.
The first full test command timed out at 200 seconds; the second completed but
exposed only the RUN banner without a summary. No full-suite pass is claimed.
## 2026-09-19: Canvas Pages to Send
- Implemented the page-count preference and input selection described in
[Canvas Analysis and Comments](./technical-design.md#canvas-analysis-and-comments).
Application settings and configuration tools persist the same field; historical
missing values read as 1. All three production analysis handlers use the saved
count for text and images. Saving retains the complete canvas.
- Focused verification passed **15 files / 271 tests**:
`npx vitest run src/main/application-settings-store.test.ts src/main/magic-notes/magic-note-analyzer.test.ts src/main/magic-notes/canvas-ipc.integration.test.ts src/renderer/src/ApplicationCenter.test.tsx src/renderer/src/MagicNotesWorkspace.test.tsx src/renderer/src/MagicCanvasEditor.test.tsx src/renderer/src/MagicCanvasThumbnail.test.tsx src/renderer/src/magic-canvas src/shared/goodbuddy-config-contracts.test.ts src/shared/magic-note-pages.test.ts src/main/goodbuddy-config-service.test.ts src/renderer/src/UpdateSettingsSection.test.tsx`.
Coverage includes 1/8 boundaries, invalid counts, missing historical fields,
restart persistence, settings events, config-tool writes, 50-page source
preservation, current page-array order, selected PDF/object/flow text, missing
flow text and selected pages with no readable text.
- `npx vitest run tests/magic-notes-analysis.electron.test.ts` passed **2 tests**,
one per image capability. The real settings form changes the default from 1 to
2 through production preload/IPC and the file-backed settings store. Workspace,
Quill and Fabric then analyze saved entries, edited saves, new drafts, new saves
and canvas-source todos through registered IPC/analyzer/SQLite. Explicit page
breaks and automatic overflow both exclude later-page text. Browsing page three
at 75% zoom still sends pages one and two. This exposed scaled DOMRect rounding
at column starts; the corrected boundary retains each page's first character.
- `npx vitest run src/renderer/src/App.test.tsx -t application` passed **5 tests**
with 279 unrelated cases filtered out. Focused ESLint and `git diff --check`
passed. Full `npm test`, typecheck and lint were not run, per user request.
- Electron uses an isolated feature window, real application code and temporary
data, with DOM actions/Quill edits and substituted model output. It does not
validate a packaged full App, physical input devices or a live provider.
Real model calls: **0**. Analysis uses desktop `createDefaultModelRuntime`;
deployed gbagent and desktop-to-Agent execution are unaffected. Existing user
changes were retained; no commits or user-data writes were made by this task.
## 2026-09-19: Canvas Content and History Preservation
- Page-break deletion now removes only the embed, retaining existing paragraph
+27 -7
View File
@@ -75,9 +75,8 @@ An abort listener calls core `destroy()` immediately: PDF render cancellation an
the Fabric abort happen synchronously, before waiting for capture to settle.
The `finally` path awaits the same destruction promise and removes the temporary
surface, without destroying twice or waiting for capture before cancellation.
AI capture retains its existing
all-page behavior. Main canvas page height, wheel handling and file storage are
unchanged.
AI capture uses the configured page prefix described under Canvas Analysis and
Comments. Main canvas page height, wheel handling and file storage are unchanged.
Background refresh preserves dirty editing content and its original optimistic
revision, including externally deleted entries. Clean editors adopt refreshed
@@ -249,18 +248,39 @@ model profile's `supportsImageInput` (or the resolved default setting when no
profile is selected). Main resolves settings again for the actual request. This
does not change an Agent runtime or desktop-to-Agent protocol.
`magicNoteCanvasPageCount` is an application preference: an integer from 1 to 8,
defaulting to 1 when absent in historical settings. The application center and
`goodbuddy_config` application.update/get share the settings schema, store and
change event. It counts pages within the canvas being analyzed, never entries.
The first N pages follow the current `content.pages` array order, independent of
the viewed page, page IDs or PDF source page numbers. Fewer than N pages selects
the whole canvas. Saving and PDF export retain the 50-page canvas limit.
Renderer and Main share `selectMagicNotePages`. The core selects the prefix before
compositing, so it never captures 50 pages just to discard 49. Analysis capture
returns the selected pages' Quill text measured from the actual CSS columns;
binary searches locate the character boundaries for explicit and automatic page
breaks. Text-only requests skip image compositing but still read page text.
The transient `canvasPageText` IPC field carries these page IDs and text, without
changing saved canvas content. Main reads the persisted page count for all three
handlers, selects page text, PDF text, objects and images in the same order, and
ignores captures outside the prefix. A partial canvas with flow requires matching
page text; missing data fails instead of including the full cross-page flow.
Prompts state the selected and total page counts. A changed setting applies to
the next analysis; existing comments are not automatically regenerated.
| Default model capability | Analysis input and result |
| --- | --- |
| Image input supported | Renderer captures all pages; Main checks page IDs and PNG/JPEG encoding. Images are ordered by page alongside flow, PDF and object text. Comments carry `inputMode: canvas-images`. |
| No image input | No page capture is required. Extracted text is used with an explicit instruction that handwriting, images and layout were not seen. Comments carry `inputMode: text-fallback`. |
| No image input and no extracted text in an entry/draft | Analysis fails with guidance to switch to an image-capable default model; no visual understanding is claimed. |
| Image input supported | Renderer captures the selected prefix; Main requires each selected page's PNG/JPEG capture and sends it alongside that page's flow, PDF and object text. Comments carry `inputMode: canvas-images`. |
| No image input | Only text from the selected prefix is sent, with an explicit instruction that handwriting, images and layout were not seen. Comments carry `inputMode: text-fallback`. |
| No image input and no extracted text in the selected entry/draft pages | Analysis fails with guidance to switch to an image-capable default model; no visual understanding is claimed. |
Todo analysis includes its title and instructions plus the source canvas context,
and uses the same capability and capture rules. Non-canvas content keeps the text
analysis path. All analysis remains read-only with no tool calls.
Saved-entry requests accept `expectedRevision`; todo requests accept
`sourceEntryRevision`. Nonempty `canvasImages` requires the corresponding revision,
`sourceEntryRevision`. Nonempty `canvasImages` or `canvasPageText` requires the corresponding revision,
even when the resolved model uses text fallback. Main loads the source after
resolving settings and checks the supplied revision before model invocation.
Existing rich-text callers may omit these fields. Entry writeback retains its