Skip to content

Store Page Context when received from JS#7997

Merged
YoussefKeyrouz merged 1 commit intodevelopfrom
feature/youssef/store_tab_content
Mar 20, 2026
Merged

Store Page Context when received from JS#7997
YoussefKeyrouz merged 1 commit intodevelopfrom
feature/youssef/store_tab_content

Conversation

@YoussefKeyrouz
Copy link
Collaborator

@YoussefKeyrouz YoussefKeyrouz commented Mar 17, 2026

Task/Issue URL: https://app.asana.com/1/137249556945/project/1212810093780571/task/1213484200004108?focus=true

Description

Adds the ability to store tab content which will be used later for attaching tabs to ai chat prompts. It will be gated by a new feature flag storePageContext and currently only hooked to the existing PAGE_CONTEXT_FEATURE_NAME handler.
So at this point it will only be triggered by opening the contextual ai chat. This will allow us to test the storage without impact on existing logic.

  • Add TabPageContextRepository API for caching page content extracted by the JS PageContext layer, stored per tab in Room
  • Create tab_page_context table with FK to tabs (DB migration 60→61)
  • Wire caching into BrowserTabViewModel's existing PAGE_CONTEXT_FEATURE_NAME handler

Steps to test this PR (See video below)

  1. Enable the storePageContext feature flag (under androidBrowserConfig)
  2. Open a tab and visit any website
  3. Click on the duck.ai icon in the address bar to bring up the contextual ai sheet
  4. Validate in Android Studio's App Inspection (View -> Tool Windown -> App inspection) that the database is storing the tab context correctly
  5. Open more tabs and store more page context. Validate all of them are stored properly
  6. Navigate to another URL in an existing tab -> Validate that the database storage replaced the tab context (and not added a new one). This is tied to the Tab ID
  7. Close tabs, and validate that the context is deleted properly
  8. Use Fire button and validate that all tab context were deleted

Notes:

  • When you close a tab, the tab is soft deleted (allow undo) the page context is not deleted at that point. It's only deleted once the Tab entity is gone.
  • I decided to gate it behind a new feature flag as this is a browser level feature and don’t want to tie it directly to the chat attachment project.

Database Demo Video

Store.Page.Context.DB.demo.mov

Note

Medium Risk
Introduces a new Room table and migration (60→61) plus new write-path in BrowserTabViewModel, so there’s some risk of migration issues and additional on-device storage of page content when the flag is enabled.

Overview
Adds a new androidBrowserConfig.storePageContext toggle to optionally persist the JS PAGE_CONTEXT_FEATURE_NAME payload for a tab.

Bumps Room DB to v61 and introduces tab_page_context (FK to tabs, cascade delete) with a new TabPageContextRepository/DAO/entity implementation, wired into BrowserTabViewModel with failure logging and updated DI + tests.

Written by Cursor Bugbot for commit 889ab10. This will update automatically on new commits. Configure here.

Copy link
Collaborator Author

YoussefKeyrouz commented Mar 17, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Wrong URL source used for storing page context
    • The PAGE_CONTEXT handler now reads the current WebView URL on the main dispatcher via getWebViewUrl() before storing page context, and the related test now asserts that exact URL is persisted.

Create PR

Or push these changes by commenting:

@cursor push 7cf6c97f91
Preview (7cf6c97f91)
diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
--- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
@@ -4225,9 +4225,10 @@
                     val pageContext = pageContextJSHelper.processPageContext(featureName, method, data, tabId)
                     if (pageContext != null) {
                         if (androidBrowserConfig.storePageContext().isEnabled()) {
+                            val webViewUrl = withContext(dispatchers.main()) { getWebViewUrl() }
                             tabPageContextRepository.storePageContext(
                                 tabId = tabId,
-                                url = url.orEmpty(),
+                                url = webViewUrl.orEmpty(),
                                 serializedPageContext = pageContext,
                             )
                         }

diff --git a/app/src/test/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt b/app/src/test/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt
--- a/app/src/test/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt
+++ b/app/src/test/java/com/duckduckgo/app/browser/BrowserTabViewModelTest.kt
@@ -5601,7 +5601,7 @@
 
             verify(mockTabPageContextRepository).storePageContext(
                 eq("abc"),
-                anyString(),
+                eq("someUrl"),
                 eq(serializedContext),
             )
         }

@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/store_tab_content branch from 9572e9e to e3a463f Compare March 17, 2026 02:02
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Unhandled storage exception breaks existing page context flow
    • Wrapped page-context persistence in runCatching with error logging so storage failures no longer interrupt enrichment and PageContextReceived dispatch.

Create PR

Or push these changes by commenting:

@cursor push dedaca5dd7
Preview (dedaca5dd7)
diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
--- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
@@ -4226,11 +4226,15 @@
                     if (pageContext != null) {
                         if (androidBrowserConfig.storePageContext().isEnabled()) {
                             val pageContextUrl = JSONObject(pageContext).optString("url", "")
-                            tabPageContextRepository.storePageContext(
-                                tabId = tabId,
-                                url = pageContextUrl,
-                                serializedPageContext = pageContext,
-                            )
+                            runCatching {
+                                tabPageContextRepository.storePageContext(
+                                    tabId = tabId,
+                                    url = pageContextUrl,
+                                    serializedPageContext = pageContext,
+                                )
+                            }.onFailure {
+                                logcat(ERROR) { "Failed to store page context: ${it.asLog()}" }
+                            }
                         }
 
                         val enrichedContext = enrichPageContextIfPossible(pageContext)

@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/store_tab_content branch from e3a463f to 539ebce Compare March 17, 2026 02:20
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: runCatching swallows CancellationException from suspend call
    • I kept the existing runCatching behavior but re-throw CancellationException in onFailure so coroutine cancellation now propagates correctly.

Create PR

Or push these changes by commenting:

@cursor push bef3344a41
Preview (bef3344a41)
diff --git a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
--- a/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
+++ b/app/src/main/java/com/duckduckgo/app/browser/BrowserTabViewModel.kt
@@ -4232,6 +4232,8 @@
                                     url = pageContextUrl,
                                     serializedPageContext = pageContext,
                                 )
+                            }.onFailure { throwable ->
+                                if (throwable is kotlinx.coroutines.CancellationException) throw throwable
                             }
                         }

@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/store_tab_content branch from 539ebce to 1da0f1f Compare March 17, 2026 03:15
@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/store_tab_content branch 2 times, most recently from 3801308 to 6b66f7c Compare March 19, 2026 17:11
Copy link
Contributor

@malmstein malmstein left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

works as expected, nice work!

@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/store_tab_content branch from 6b66f7c to 889ab10 Compare March 20, 2026 08:18
@YoussefKeyrouz YoussefKeyrouz merged commit 9e34974 into develop Mar 20, 2026
11 checks passed
@YoussefKeyrouz YoussefKeyrouz deleted the feature/youssef/store_tab_content branch March 20, 2026 08:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants