|
| 1 | +# Attach Tabs & Files in New Tab Page |
| 2 | + |
| 3 | +| | | |
| 4 | +|---|---| |
| 5 | +| **Feature** | Attach one or more open tabs (and PDF files) to a Duck.ai chat from the New Tab Page omnibar | |
| 6 | +| **Feature flag** | `enableAttachTabs` (tab attachment) · PDF attachment gated per-model by `supportedFileTypes` | |
| 7 | +| **Platform** | Desktop — macOS (primary), Windows (native bridge in progress) | |
| 8 | +| **Design** | [Figma: Desktop – Attach tabs (All inputs)](https://www.figma.com/design/c1D1uEZt217Y8Zbk2fcd16/Desktop---Attach-tabs--All-inputs-?node-id=1-877&m=dev) | |
| 9 | +| **Asana** | [Frontend: Attach 1 or more tabs in New Tab Page](https://app.asana.com/1/137249556945/project/72649045549333/task/1214227868283289) | |
| 10 | + |
| 11 | +## What Is This? |
| 12 | + |
| 13 | +The New Tab Page (NTP) omnibar already lets you start a Duck.ai chat from a fresh |
| 14 | +tab. This feature adds a way to bring extra context into that chat **before you |
| 15 | +send it**: |
| 16 | + |
| 17 | +- **Attach open tabs** — pick one or more of your currently open browser tabs, |
| 18 | + and their page content rides along with your prompt so Duck.ai can answer about |
| 19 | + them (e.g. "compare these two laptops"). |
| 20 | +- **Attach PDF files** — attach a PDF from your computer the same way, for models |
| 21 | + that support file input. |
| 22 | + |
| 23 | +Attachments show up as removable **chips** above the omnibar input. You can add |
| 24 | +several, remove any of them, and then submit the chat with everything attached. |
| 25 | + |
| 26 | +This brings the NTP omnibar in line with the other places Duck.ai already lives |
| 27 | +(the sidebar and the in-browser omnibar), so the attach experience feels the same |
| 28 | +everywhere. |
| 29 | + |
| 30 | +## Why? |
| 31 | + |
| 32 | +- As Duck.ai grows from single-page help toward multi-source tasks (comparison, |
| 33 | + synthesis, planning), the "current tab only" model is too limiting. |
| 34 | +- Users already think of their open tabs as a working set — this gives them a |
| 35 | + first-class way to express "use these." |
| 36 | +- Shipping it now establishes a consistent foundation across all desktop entry |
| 37 | + points before usage scales further. |
| 38 | + |
| 39 | +## User Flows |
| 40 | + |
| 41 | +### Flow A — Attach tabs via the paperclip menu |
| 42 | + |
| 43 | +1. User opens a New Tab Page and focuses the omnibar in AI/Duck.ai mode. |
| 44 | +2. User clicks the **paperclip** entry point. |
| 45 | +3. A picker opens listing the user's open tabs (most recent first; the NTP tab |
| 46 | + itself is not listed). |
| 47 | +4. User selects a tab. |
| 48 | +5. The page content for that tab is extracted and a **chip** (title + favicon) |
| 49 | + appears above the input. |
| 50 | +6. User repeats to attach more tabs. |
| 51 | +7. User types a prompt and submits — the chat is sent with all attached tab |
| 52 | + contexts. |
| 53 | + |
| 54 | +### Flow B — Attach tabs via `@` mention |
| 55 | + |
| 56 | +1. In the omnibar, user types the `@` character. |
| 57 | +2. A typeahead appears, filtering the same open-tab list as the user keeps typing. |
| 58 | +3. User picks a tab from the typeahead. |
| 59 | +4. A chip is added (same as Flow A), and the user continues their prompt and |
| 60 | + submits. |
| 61 | + |
| 62 | +### Flow C — Attach a PDF file |
| 63 | + |
| 64 | +1. User clicks the paperclip entry point (shown only when the active model accepts |
| 65 | + files). |
| 66 | +2. User chooses a PDF from the system file picker. |
| 67 | +3. A chip with the file name appears above the input. |
| 68 | +4. User submits — the chat is sent with the PDF attached. |
| 69 | + |
| 70 | +### Flow D — Remove an attachment |
| 71 | + |
| 72 | +1. User clicks the remove control on any chip (tab or file). |
| 73 | +2. The chip disappears and that context is dropped from the next submit. |
| 74 | + |
| 75 | +## Key Behaviors |
| 76 | + |
| 77 | +| Behavior | Expected outcome | |
| 78 | +|---|---| |
| 79 | +| Open the picker (paperclip or `@`) | Shows the list of open tabs, most-recently-used first | |
| 80 | +| The current NTP tab | Never appears in the tab list | |
| 81 | +| `@` typeahead | Filters the same tab list as the paperclip picker, on the client | |
| 82 | +| Select a tab | Extracts that tab's page content and renders a chip | |
| 83 | +| Submit with N tab chips | All N tab contexts are sent with the chat | |
| 84 | +| Select a PDF | Reads + encodes the file in the page and renders a named chip | |
| 85 | +| Submit with a PDF chip | The PDF is sent with the chat | |
| 86 | +| Remove a chip | That attachment is dropped from the next submit | |
| 87 | +| Multiple attachments | Tabs and files can be combined in a single submit | |
| 88 | + |
| 89 | +## Edge Cases & Error Handling |
| 90 | + |
| 91 | +| Scenario | Expected behavior | |
| 92 | +|---|---| |
| 93 | +| `enableAttachTabs` is off / absent | Paperclip and `@` typeahead for tabs are hidden; existing omnibar flows are unchanged | |
| 94 | +| Active model does not accept files | The file/paperclip entry for PDFs is hidden (driven by the model's `supportedFileTypes`) | |
| 95 | +| Selected tab is closed, restricted, or content can't be extracted | No content is returned for that tab; it does not produce a usable chip | |
| 96 | +| User switches to a model that can't handle an already-attached file type | The unsupported file attachment is cleared | |
| 97 | +| Switch between browser tabs while NTP is open | Attached chips persist (per-tab state) | |
| 98 | +| NTP tab is closed | Attached chips are cleared | |
| 99 | +| Submit with no attachments | Behaves exactly as today — no attachment data is added to the chat | |
| 100 | + |
| 101 | +## Platform Support |
| 102 | + |
| 103 | +| Platform | Status | |
| 104 | +|---|---| |
| 105 | +| Frontend (NTP web layer) | In scope — picker UI, chips, `@` typeahead, file read/encode | |
| 106 | +| macOS (native bridge) | In scope | |
| 107 | +| Windows (native bridge) | Planned / in progress | |
| 108 | +| iOS / Android | Not in scope (desktop NTP feature) | |
| 109 | + |
| 110 | +## What's NOT in Scope (v1) |
| 111 | + |
| 112 | +- Server-side / native-side tab filtering or search — all filtering (including the |
| 113 | + `@` typeahead) happens client-side over the returned tab list. |
| 114 | +- File types other than **PDF** — v1 only sends PDFs, though the design leaves room |
| 115 | + to add more types later. |
| 116 | +- A master on/off switch for PDF support — file attachment is enabled per-model, not |
| 117 | + via a single global flag. |
| 118 | +- Image attachment changes — images already work today and are unchanged here. |
| 119 | + |
| 120 | +## Testing Notes |
| 121 | + |
| 122 | +**Tabs (frontend):** |
| 123 | +- Picker populates the tab list on open. |
| 124 | +- `@`-typeahead filters the same list client-side. |
| 125 | +- Selecting a tab extracts content and renders a chip. |
| 126 | +- Removing a chip drops that context from the next submit. |
| 127 | +- A closed/broken tab yields no usable content. |
| 128 | +- Submitting with N chips includes N tab contexts in the submitted chat. |
| 129 | +- With `enableAttachTabs` absent/false, the paperclip and `@` typeahead are hidden |
| 130 | + and existing flows are unchanged. |
| 131 | +- Per-tab state: chips persist across browser-tab switches and clear when the NTP |
| 132 | + tab closes. |
| 133 | + |
| 134 | +**Files (frontend):** |
| 135 | +- The paperclip entry and file-picker `accept` are driven by the active model's |
| 136 | + supported file types; the entry is hidden when none are supported. |
| 137 | +- Selecting a file adds a chip; removing it drops the file from the next submit. |
| 138 | +- The submitted chat carries files matching the attached chips. |
| 139 | +- Switching to a model that doesn't support an attached file's type clears it. |
| 140 | + |
| 141 | +**Mock mode / dev tools:** |
| 142 | +- Testable through the existing NTP `mock-transport.js`. |
| 143 | +- Enable tab attachment with the query param `?omnibar.enableAttachTabs=true`. |
| 144 | +- Mock transport returns a set of mock tabs with a simulated extraction delay. |
| 145 | +- For files, any mock model declaring PDF support surfaces the file entry point. |
| 146 | + |
| 147 | +## Open Questions |
| 148 | + |
| 149 | +- **AL1** — Should the native layer enforce a size/count cap on attached files |
| 150 | + before forwarding to Duck.ai, and if so what limit? (Raised in the PDF tech |
| 151 | + design; unresolved.) |
| 152 | + |
| 153 | +## Analytics (TBD) |
| 154 | + |
| 155 | +No pixels/events are defined in the source tasks. The following are candidates that |
| 156 | +should be specified before launch: |
| 157 | + |
| 158 | +- Paperclip entry point opened. |
| 159 | +- Tab attached (via paperclip vs. `@` mention). |
| 160 | +- File (PDF) attached. |
| 161 | +- Attachment removed. |
| 162 | +- Chat submitted with N tab attachments / with a file attachment. |
0 commit comments