feat(web-app-ai-multi-doc-synthesizer): add multi-document synthesizer#466
feat(web-app-ai-multi-doc-synthesizer): add multi-document synthesizer#466LukasHirt wants to merge 11 commits into
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
dj4oC
left a comment
There was a problem hiding this comment.
Solid core idea and the Vue/composable logic + unit tests are decent. Commenting (draft) — there are a few blocker-class items beyond the failing gate.
What the +7511 lines are: ~76% (5742 lines) is a committed per-extension pnpm-lock.yaml. This is a single-root-lockfile monorepo; no other packages/* ships its own lockfile. Please delete it (and the local pnpm-workspace.yaml) and let the root lockfile manage deps. Real content is ~1770 lines.
Blockers
- [security] API key shipped to the browser + direct LLM calls, same as #465:
index.tsputsapiKeyin client config anduseLLM.tssends it as a Bearer token on directfetch(cfg.endpoint…). Route throughai-llm-proxywith the user's oCIS token; dropapiKeyfrom client config. - [CI integrity]
postinstall.cjsdefeats the hygiene gate. Its own comment states it symlinksnode_modules/.pnpmso the CI scan'sfind -type f"makes large binary artifacts invisible to the scan." That deliberately evades a CI control and mutates the shared virtual store (renameSync/rmSync), which can corrupt other packages' installs. Please remove this file and thepostinstallscript, and fix the underlying size issue honestly (the committed lockfile above).
Major
- Wrong directory (
extensions/…) — not registered/mounted/configured anywhere (no docker mount, noocis.apps.yamlkey, no CSP entry). Move topackages/web-app-ai-multi-doc-synthesizer/. - No
l10n/directory/translations (strings are correctly$gettext-wrapped). - Capability probe fires 4 unconditional requests (incl.
/v1/models, which the proxy doesn't expose) to whatever endpoint config holds.
Minor
- Unbounded
Promise.allover all selected docs (bounded to ≤10 byisVisible, so low risk) — consider a small concurrency cap on the per-file summary pass. - Per-file content silently truncated at 10k chars with no user signal.
- Hand-rolled modal/buttons + literal
✕glyph + ~170 lines custom CSS instead ofoc-modal/oc-button/oc-icon. synthesis-<date>.mdcan overwrite a same-day prior result.- PR title needs the Conventional Commits prefix.
Unit tests (useSynthesis.spec.ts, file-support.spec.ts) are good and salvageable once it's moved into packages/ and re-pointed at the proxy.
7896c02 to
5c5f21f
Compare
Changes made to address review feedbackAll review items have been addressed. Here is a summary of every change: Housekeeping (done first)
Blocker: Wrong directory
Blocker: API key shipped to browser
Major: No
|
cff8e49 to
24ffaa2
Compare
Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
…s/ and clean up housekeeping - Move from extensions/ai-multi-doc-synthesizer/ to packages/web-app-ai-multi-doc-synthesizer/ so pnpm-workspace.yaml's packages/* glob picks it up - Delete per-package pnpm-lock.yaml (monorepo uses single root lockfile) - Delete pnpm-workspace.yaml (not a nested workspace) - Delete postinstall.cjs and its npm script (evaded CI scan, corrupted virtual store) - Rename package to web-app-ai-multi-doc-synthesizer and vite config name to match - Add private:true and @ownclouders/web-test-helpers devDependency to align with other packages Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
… add l10n, fix minor issues Security (blocker): - Remove apiKey from LLMConfig entirely — provider auth belongs in ai-llm-proxy - useLLM.ts now sends Authorization: Bearer <accessToken> (user's oCIS token) via useAuthStore, not a provider API key - Add same-origin check matching chat-with-file pattern: reject requests to cross-origin endpoints to prevent oCIS token leakage - Remove 4 unconditional probe requests (capability probing on mount); calls are only made when the user triggers synthesis Tier selection: replaced capability-probe-based logic with a simple 8k-char combined-content heuristic; single-pass when small, two-pass otherwise Minor issues (from review): - Add concurrency cap: file fetches and per-file LLM calls run at most 3 at a time (runWithConcurrency helper) instead of unbounded Promise.all - Show truncationWarning when any file exceeds 10k chars; exposed in overlay - Fix filename uniqueness: synthesis-YYYY-MM-DD-HHMMSS.md (was date only, could silently overwrite same-day results) - Replace hand-rolled ✕ close button and plain <button> elements with oc-button + oc-icon + oc-spinner from @ownclouders/web-pkg - Add l10n/translations.json (empty skeleton) and wire translations into defineWebApplication return value Tests: - Update useSynthesis.spec.ts to match new UseLLMReturn API (no capabilities/stream) and new char-based tier logic; add truncationWarning tests - Update E2E acceptance tests to mock ai-llm-proxy route instead of direct LLM endpoint; add bearer-token assertion; fix save-path regex Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
…s.apps.yaml entries, CI matrix - docker-compose.yml: add dist/ volume mount (strips web-app- prefix per convention) - dev/docker/ocis.apps.yaml: add ai-multi-doc-synthesizer entry with proxy endpoint - support/actions/ocis.apps.yaml: add web-app-ai-multi-doc-synthesizer entry - .github/workflows/test.yml: add to test matrix so unit + E2E run in CI Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
…pe errors, clean up Architecture fix: - defineWebApplication does not support rootComponent; remove it - Adopt useModals().dispatchModal() pattern (same as ai-sensitive-data-scanner) so the synthesis UI is opened as a proper oc-modal dialog - Replace SynthesisOverlay.vue (custom backdrop + Teleport) with SynthesisPanel.vue (modal body content only, no backdrop/teleport — modal handles that) - Remove App.vue and state.ts (global ref state no longer needed with dispatchModal) - index.ts now passes resources + llmConfig as customComponentAttrs Type errors fixed: - Mock return values in tests now use `as any` (same as useChat.spec.ts reference) - File-support spec unchanged and still passes Tests: 22/22 passing, check:types clean Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
…v vars, and usage Add sections for: - Requirements and prerequisites - Configuration examples for both ocis.apps.yaml files - Proxy environment variable reference table - Local development setup instructions - Supported file types - Synthesis tier selection logic - Concurrency and truncation behavior - Privacy guarantees Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
…auth and file setup Signed-off-by: Lukas Hirt <info@hirt.cz>
…4.2 and vue to 3.5.x Signed-off-by: Lukas Hirt <info@hirt.cz>
24ffaa2 to
84ab913
Compare
…up E2E test Add missing public/manifest.json required for the extension build output. Remove the DAV PUT route stub in the E2E beforeEach — actual file uploads now work end-to-end, making the stub unnecessary and misleading. Also reformat the close-button locator for line-length compliance. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
- Wrong individual-row checkbox selector caused a 30 s timeout (the "[data-testid=resource-table-select]" attribute doesn't exist); use ".has-item-context-menu tr" nth(1) with force:true instead, skipping the <thead> row and bypassing hover-only visibility. - Modal close-button selector didn't match any element; replace with the proven ".oc-modal-body-actions-cancel" class used by other extensions. - clipboard-read/clipboard-write are not valid grantPermissions names on Firefox/WebKit; wrap in try/catch and mock navigator.clipboard.writeText via page.evaluate so the copy test passes on all three browsers. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
Summary
Adds the AI Multi-Document Synthesizer extension (`web-app-ai-multi-doc-synthesizer`) — a new ownCloud Web extension that lets users select 2–10 text documents and receive an LLM-generated synthesis covering shared themes, key differences, and action items.
What it does
Architecture decisions
Infrastructure
Test plan
🤖 Generated with Claude Code