Files
webmail/lib/plugin-sandbox/assistant
Linus Rath bda99e1df8 feat: let plugins read the text of attachments
api.email.getAttachmentText reads PDF (pdf.js), Word, Excel, PowerPoint
and OpenDocument files (own reader over fflate and DOMParser, unpacking
capped at 50 MB), text, CSV, HTML, calendar and address files, and
answers with a status for what it can't read. The extraction lives in
lib/attachment-text so Files can use it too.

The sandbox runtime now copies every flag the host sends into
api.host.features; before, it kept only the three core flags, so the
assistant's flags never reached a plugin. The host bridge assertions in
plugin-host-features.test.ts compare against the core flags plus the
assistant's (withAssistant), since the init payload and host-change now
carry attachmentText too.
2026-11-02 21:53:05 +01:00
..

Host APIs for the AI assistant (2.2)

Host calls the assistant plugin needs, one set of files per area, so the areas can be built side by side without editing the same lines:

Area What Files
b More context: attachment text and images, threads, the list selection b.types.ts, b.ts, b.runtime.ts
c More actions: invitations, filters, batches, out-of-office, settings c.types.ts, c.ts, c.runtime.ts
d Files: find, read, attach, save, create d.types.ts, d.ts, d.runtime.ts
f The panel in every view f.types.ts, f.ts, f.runtime.ts

Each area fills its own three files:

  • <area>.types.ts (pure, no imports from the app): PERMISSIONS, the permissions the area adds (they join ALL_PERMISSIONS), and <Area>HostFeatures, the flags it adds to api.host.features.
  • <area>.ts (host side): PERMS (method → permission, joins PERM_PER_METHOD), dispatch(plugin, method, args) (returns NOT_MINE for methods it doesn't own) and features() (its flags right now).
  • <area>.runtime.ts (inside the sandbox): runtime(callApi), the methods it adds to the plugin's api, by namespace ({ email: { getThread } }).

index.ts, runtime.ts and types.ts merge the areas; host-api.ts, host-features.ts, runtime.tsx and plugin-types.ts read only those. A new permission needs a check (a method in PERMS, a slot or a hook), its texts in every locale under plugins.permissions.<key>, and docs.