fix: reliable answer capture + auth lifecycle hardening - #45
Open
jengchakhrit-ck wants to merge 3 commits into
Open
fix: reliable answer capture + auth lifecycle hardening#45jengchakhrit-ck wants to merge 3 commits into
jengchakhrit-ck wants to merge 3 commits into
Conversation
Three issues made ask_question.py non-functional against current NotebookLM:
1. human_type cached one ElementHandle then typed char-by-char; the Angular
chat panel re-renders the textarea during hydration, detaching the handle
("Element is not attached to the DOM"). Replaced with a Locator retry-loop +
atomic fill() + value verification.
2. Submit used keyboard Enter, which inserts a newline after a programmatic
fill() and does not send. Now clicks the send button (aria-label/type),
Enter only as fallback.
3. Answer poll locked onto the previous chat message (NotebookLM persists chat
history) and returned it instantly. Now baselines the pre-submit answer and
accepts only a new, stable response.
Known limit: multiple questions in one notebook session share chat context and
return RAG-anchored repeats; ask one question per session for distinct answers.
Submit failed silently on a non-English NotebookLM UI. The send-button
selector list was English-only ('Send'/'Submit'), but the live button is
localized (e.g. Thai 'ส่ง', icon arrow_forward). No match -> the
button[type=submit] fallback clicked the WRONG element -> message never
sent -> 120s answer timeout. Replaced with a locale-agnostic finder
(aria-label /send|submit|ส่ง/i OR mat-icon send/arrow_forward/arrow_upward)
that nudges a real keystroke until the Angular send button enables.
Also fixed stale-answer capture: NotebookLM persists the chat thread across
sessions, so the text-baseline raced the thread render and returned the
previous query's answer. Now settle the thread, then gate acceptance on a
NEW answer container appearing (count increase) + reject loading placeholders.
Verified live: PONG smoke + real query both return fresh, source-grounded answers.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Three compounding failures found while testing a live query:
1. ask_question answer-capture timed out though the answer rendered.
- texts[-1] is not reliably the newest answer (NotebookLM renders the
thread non-chronologically), and the len()>pre_count gate never fired
because the persisted thread does not grow the container count.
- Fix: identify the answer by Counter-delta novelty (a text whose
occurrence count now exceeds the pre-submit snapshot) at any index,
picking the longest candidate. Robust to duplicate answers too.
2. auth_manager validate gave a false-positive when the session was stale.
- It only loaded the home page; a near-dead session still passes that
while a real /notebook/<id> load bounces to accounts.google.com.
- Fix: add a notebook-level gate that loads the first library notebook
and requires the query input to render (the actual usage surface).
3. Session decayed even under continuous use.
- The state.json session cookies (Playwright #36139 workaround) were
frozen at login and never refreshed by the read path, so Google
rotation eventually forced a manual reauth regardless of usage.
- Fix: persist browser state after every successful query (best-effort;
a save failure does not drop the captured answer).
Verified: full source-grounded answers returned; validate now reports
STALE correctly; state.json mtime advances on each successful ask.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three fixes that make
ask_question.pyreliable across persisted browser sessions and harden the auth lifecycle. All changes are confined toscripts/(ask_question.py,auth_manager.py,browser_utils.py) — no config or dependency changes.Problems fixed
1. Answer capture timed out even when the answer rendered.
NotebookLM persists the chat thread across browser sessions, so the poll locked onto the previous answer (returning it instantly) or never detected the new one. The fresh answer is not reliably the DOM-last container (NotebookLM does not render the thread strictly chronologically) and the container count does not always grow — so neither
texts[-1]norlen() > pre_countdetects it. An answer can also be textually identical to an earlier one (same question asked twice), so plain set-membership novelty rejects it.collections.Counter) of existing answers before submit, then accept the text whose occurrence count is now higher (novel by occurrence delta, found at any index) and pick the longest such candidate before waiting for it to stop streaming.2. Send button missed on non-English UIs.
The send button is locale-dependent (e.g. Thai "ส่ง", icon
arrow_forward) and only enables once real key events land. The old English-only['Send'/'Submit']text match missed the localized button, and thebutton[type=submit]fallback clicked the wrong element → silent no-send → the answer poll then hit its full timeout.aria-label/icon across languages, nudge it with a real keystroke until it is clickable, and fall back toEnter.3.
validate_auth()false-positive + slow session decay.Validation only loaded the home page, so a near-dead session passed while the actual notebook load bounced to the Google login screen. Separately, the read path never re-saved browser state, so the
state.jsonsession cookies (the playwright#36139 workaround) stayed frozen at login time — even daily use eventually forced a manual re-auth once Google rotated them.validate_auth()(load the first library notebook, let the SSO bounce settle, require the query input to actually render), plus_save_browser_state()on every successful query so continuous use extends the session instead of letting it decay.Notes