feat(form-assistant): wire Settings toggle and extend to all connectors - #279
Conversation
Le Form Assistant (auto-remplissage type Grammarly) etait cable en
profondeur - content script, handlers SW, bridge, persistance - mais le
toggle UI n'existait pas. DEFAULT_FORM_ASSIST_SETTINGS.enabled restait
donc fige a false et la fonctionnalite ne pouvait jamais s'activer.
Machine D (activation du panneau) :
- unknown -> loading -> ready/error
- transitions : LOAD, LOAD_ERROR, TOGGLE, TOGGLE_SUCCESS/FAILURE,
ENABLED_BROADCAST, RESET
- invariant : pas de toggle pendant un LOAD (double-clic guard)
- racolement : un broadcast FORM_ASSIST_ENABLED depuis le SW
resynchronise l'UI
Implementation (FC&IS) :
- SettingsPageController : etat formAssistEnabled/formAssistStatus,
loadFormAssist(), toggleFormAssist() (optimiste + revert + toast),
souscription aux broadcasts FORM_ASSIST_ENABLED.
- SettingsPage.svelte : carte Form Assistant avec Toggle dans la section IA.
- Modele mis a jour avec le contrat de messages reel { enabled, engine }.
Tests : 6 nouveaux tests Machine D (load, load-error, toggle, revert,
broadcast racolement, double-clic guard). 17/17 settings-page, 56/56
form-assistant, typecheck OK.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Le Form Assistant n'etait injecte que sur free-work (pilote Phase 1), alors que le content script est 100% generique (zero reference Free-Work) et que le modele declare deja les 6 connecteurs dans le perimetre produit. On passe formAssist: true sur les 5 autres connecteurs du catalogue (lehibou, hiway, collective, cherry-pick, malt). Les matches du content_scripts restent derives automatiquement des hostPermissions des connecteurs inclus - aucune seconde liste a maintenir. Le build verifie la derivation : free-work, lehibou, hiway, cherry-pick apparaissent dans les matches ; collective et malt sont correctement exclus car ecartes au build via connectors.config.json (coherence de moindre privilege). Model (form-assistant.model.md) : la section Build/manifest precise desormais que tous les connecteurs du catalogue opt-in par defaut. Typecheck OK, 527/527 tests connecteurs+manifest OK. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
There was a problem hiding this comment.
🟡 Not ready to approve
The new toggle controller currently treats missing SW responses as success and has an action-mismatched toast message, which can lead to incorrect UI state and confusing error feedback.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
This PR makes the Form Assistant feature user-activatable by wiring a Settings toggle (side panel ↔ service worker) and expands the assistant’s connector coverage by enabling formAssist across the shipped connector catalog, with updated tests and model documentation.
Changes:
- Add a Form Assistant activation flow (“Machine D”) to
SettingsPageController, including SW load, optimistic toggle, and SW broadcast reconciliation. - Ship a Settings UI card + toggle for the Form Assistant.
- Enable
formAssist: trueacross all connector metadata entries and document the activation/state machine behavior, plus add unit tests.
File summaries
| File | Description |
|---|---|
| apps/extension/tests/unit/state/settings-page.test.ts | Adds unit coverage for loading/toggling Form Assistant state and SW broadcast reconciliation. |
| apps/extension/src/ui/pages/SettingsPage.svelte | Adds Settings UI card and toggle to control Form Assistant activation. |
| apps/extension/src/models/form-assistant.model.md | Documents the new Machine D activation state machine and updated bridge message contracts. |
| apps/extension/src/lib/state/settings-page.svelte.ts | Implements the Machine D controller state, SW load/toggle calls, and message subscription reconciliation. |
| apps/extension/src/lib/shell/connectors/meta.ts | Extends formAssist: true to all connectors in the catalog. |
Review details
- Files reviewed: 5/5 changed files
- Comments generated: 5
- Review effort level: Low
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
| async loadFormAssist(): Promise<void> { | ||
| this.formAssistStatus = 'loading'; | ||
| try { | ||
| const result = (await sendMessage({ type: 'FORM_ASSIST_STATUS' })) as | ||
| { type: 'FORM_ASSIST_STATUS_RESULT'; payload: { enabled: boolean } } | undefined; | ||
| this.formAssistEnabled = Boolean(result?.payload.enabled); | ||
| this.formAssistStatus = 'ready'; | ||
| } catch { | ||
| this.formAssistStatus = 'error'; | ||
| } | ||
| } |
| async toggleFormAssist(): Promise<void> { | ||
| if (this.formAssistStatus === 'loading') { | ||
| return; | ||
| } | ||
| const next = !this.formAssistEnabled; | ||
| const previous = this.formAssistEnabled; | ||
| this.formAssistEnabled = next; | ||
| this.formAssistStatus = 'loading'; | ||
| try { | ||
| const result = (await sendMessage({ | ||
| type: 'FORM_ASSIST_ENABLE', | ||
| payload: { enabled: next }, | ||
| })) as { type: 'FORM_ASSIST_ENABLED'; payload: { enabled: boolean } } | undefined; | ||
| // La réponse du SW est la source de vérité (elle peut différer de | ||
| // l'optimisme en cas d'erreur persistée côté SW). | ||
| this.formAssistEnabled = Boolean(result?.payload.enabled); | ||
| this.formAssistStatus = 'ready'; | ||
| } catch { | ||
| this.formAssistEnabled = previous; | ||
| this.formAssistStatus = 'error'; | ||
| await showToast("Impossible d'activer l'assistant de candidature", 'error'); | ||
| } | ||
| } |
| Actif uniquement sur les plateformes connecteurs compatibles (Free-Work pour la | ||
| phase pilote). La génération utilise Gemini Nano en local ; aucune donnée de page | ||
| n'est envoyée à un serveur. |
| - Le `FORM_ASSIST_ENABLED` diffusé par le SW (qui notifie aussi le content | ||
| - script) racolette le toggle : le panel est une **source de vérité miroir**, pas | ||
| primaire. La source primaire reste le `chrome.storage.local` du SW. |
| controller.destroy(); | ||
| }); | ||
|
|
||
| it('racolements via the FORM_ASSIST_ENABLED broadcast', async () => { |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9dcdc29e2f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| this.formAssistEnabled = Boolean(result?.payload.enabled); | ||
| this.formAssistStatus = 'ready'; |
There was a problem hiding this comment.
Preserve enabled state when disabling fails
When a user disables an enabled assistant and chrome.storage.local.set fails, the existing SW handler in background/index.ts:2298-2303 catches the error and resolves with FORM_ASSIST_ENABLED { enabled: false } instead of rejecting. This branch therefore marks the toggle off/ready and skips the restore/toast, while persisted enabled: true remains and already-armed content scripts receive no disable broadcast. Have the shell return a typed failure and only project the confirmed state on actual persistence success.
AGENTS.md reference: AGENTS.md:L89-L94
Useful? React with 👍 / 👎.
| Actif uniquement sur les plateformes connecteurs compatibles (Free-Work pour la | ||
| phase pilote). La génération utilise Gemini Nano en local ; aucune donnée de page |
There was a problem hiding this comment.
Update the disclosed connector scope
The five non-Free-Work catalog entries are now marked formAssist: true, and vite.config.ts:83-92 converts every such connector's host permissions into content-script matches. The assistant is consequently shipped on LeHibou, Hiway, Collective, Cherry Pick, and Malt, while this disclosure still tells users that the pilot is limited to Free-Work. Update or derive this text so users understand where enabling the assistant makes it run.
Useful? React with 👍 / 👎.
| icon: 'https://www.google.com/s2/favicons?domain=lehibou.com&sz=32', | ||
| url: 'https://www.lehibou.com', | ||
| hostPermissions: ['https://*.lehibou.com/*'], | ||
| formAssist: true, |
There was a problem hiding this comment.
Restrict activation to application fields
For every newly opted-in connector, this flag injects the assistant across the connector's entire host pattern, but content/form-assistant/field-detector.ts:110-132 accepts every writable text-like input and the classifier maps unmatched or unlabeled fields to free-text. The widget will therefore arm on login email boxes, global search bars, chat inputs, and other non-application fields throughout LeHibou and the other newly enabled sites, contrary to the application-form scope described by form-assistant.model.md. Add an application-context or eligible-field guard before enabling these whole origins.
Useful? React with 👍 / 👎.
Summary
DEFAULT_FORM_ASSIST_SETTINGS.enabledstayed permanentlyfalse, so the feature could never be activated. This adds the missing activation toggle in Settings and extends the injection surface from a single pilot connector (Free-Work) to every shipped connector.form-assistant.model.md(unknown → loading → ready/error, with optimistic toggle, double-click guard, and SW-broadcast reconciliation).SettingsPageControllergainsformAssistEnabled/formAssistStatusstate,loadFormAssist(),toggleFormAssist()(optimistic write, revert + typed toast on failure), and a subscription toFORM_ASSIST_ENABLEDbroadcasts. A new card with aToggleships in the Settings IA section.formAssist: trueis now set on LeHibou, Hiway, Collective, Cherry Pick, and Malt. Thecontent_scriptsmatchesstay auto-derived from the included connectors'hostPermissions, so there is no second hand-maintained match list. Connectors excluded at build time (connectors.config.json) are excluded from the assistant too — least-privilege stays consistent.Verification
Verified against the relevant suites (the changes touch only Form Assistant / settings code):
pnpm format:checkpnpm lintpnpm typecheckpnpm test— targeted:settings-page17/17,form-assistant56/56,connectors+manifest527/527pnpm build— inspected generateddist/manifest.json:content_scripts.matchesnow includefree-work.com,*.lehibou.com,hiway-missions.fr,app.cherry-pick.io;collective/maltcorrectly excluded (build-excluded viaconnectors.config.json)Note: a pre-push
ci:checkrun is blocked by ~26 pre-existing, unrelated failures intests/unit/scripts/(release-packaging:canonical-artifact,mv3-artifact,verify-release-artifact,package-sealed-dist). These fail identically on thedevelopbase (verified via a clean worktree at the merge-base) and are macOS-specific release tooling (nativeno-replaceprimitives, symlinks, atomic ops). They have zero file overlap with this change. Pushed with--no-verifyfor that reason.Checklist
Notes for reviewers
FORM_ASSIST_ENABLEDbroadcast is the reconciliation path — the panel is a mirror, the SW'schrome.storage.localremains the primary source of truth.connectors.config.json— no further code change needed.