* [AI Chat] Add deep research event parsing and UI rendering
Parse 12 deep research streaming event types from OAI response deltas
(queries, analyzing, thinking, answer, progress, blindspots, complete,
error, search/fetch/analysis status, iteration complete) and render them
in the assistant response as an animated single-line progress indicator
with elapsed timer, culminating in a final answer with inline citation
links and a sources section.
Implements: https://github.com/brave/brave-browser/issues/53022
* [AI Chat] Address review feedback (#34082)
- Move deep research parsing out of oai_parsing.cc into its own file,
using the brave-chat.deepResearch.* custom object pattern
- Add unit tests for all deep research event parsing
- Consolidate deep research event types into a single mojom union
- Use mojom enums for status fields instead of raw strings
- Use uint32 with _count suffixes for count fields
- Add DeepResearchUrlInfo struct for url/favicon pairs
- Use constexpr key constants instead of inline string literals
- Pass model_key by value instead of const optional ref
- Extract frontend deep research logic into deep_research_utils.ts
- Add Storybook stories for the deep research component
- Add localized UI strings
- Fix copyright year in new files
* [AI Chat] Address second round of review feedback (#34082)
- Remove model_key parameter from ParseDeepResearchEvent; return
mojom::ConversationEntryEventPtr directly and wrap at call site so
model_key remains available for tool call handling
- Replace static_cast<uint32_t> with base::saturated_cast<uint32_t> to
clamp negative server values instead of wrapping
- Match "started" status explicitly in ParseSearchStatusEvent and
ParseAnalysisStatusEvent; return nullopt with VLOG(1) for unrecognized
values instead of silently defaulting to kStarted
- Fix alphabetical ordering of deep_research_parsing entries in BUILD.gn
- Revert unrelated cosmetic changes in oai_parsing.cc
- Add JSDoc to exported interfaces in deep_research_utils.ts
- Add unit tests for unknown status rejection
* [AI Chat] Address third round of review feedback (#34082)
- Remove disableLinkRestrictions bypass for deep research; use the same
allowedLinks-based link validation as regular search since
WebSourcesContentBlock is already emitted and extracted for deep
research tools
- Scope deep research event extraction to events after the last deep
research ToolUseEvent to handle multiple runs in a single response
- Memoize extractDeepResearchEvents with React.useMemo
- Remove redundant nonDeepResearchEvents filter since AssistantEvent
returns null for unhandled types
- Use {...props} spread for DeepResearchProgressLine
- Rename ambiguous `e` variables to descriptive names (search, analysis,
thinking, etc.)
- Fix stale "Memoize" comment
* [AI Chat] Return nullptr instead of nullopt from ParseDeepResearchEvent
mojom::ConversationEntryEventPtr is already nullable, so wrapping it
in std::optional is redundant. Return nullptr for parse failures instead.
* [AI Chat] Add missing deepResearchEvent to event templates
* Presubmit code formatting fix
* [AI Chat] Fix deep research progress hiding too early
The deep research progress panel was hidden as soon as the
completeEvent arrived, but the synthesis answer hasn't started
streaming yet at that point. Track whether a completionEvent
(the synthesis answer) has arrived after the tool call and use
that to decide when to hide the progress panel instead.
* [AI Chat] Address review feedback (#34082)
- Add GURL::is_valid() checks for parsed URLs in deep_research_parsing.cc
- Remove duplicate mojom include already present in header
- Pass deepResearch as single prop instead of 10 individual props
- Simplify startTimeRef useEffect logic per reviewer suggestion
- Type-safe iconName using IconName from @brave/leo/icons/meta
- Replace hardcoded spacing/radius/font values with design system
variables (--leo-spacing-*, --leo-radius-*, --leo-font-*)
- Add TODO for elapsed timer inaccuracy on re-render
- Add unit tests for extractDeepResearchEvents (21 tests)
- Add unit tests for DeepResearchEvent component (8 tests)
- Add DynamicProgress story with timed event sequence for animation
* [AI Chat] Recalibrate elapsed timer on progressEvent updates (#34082)
Recalibrate startTimeRef on every progressEvent instead of only on
first render, so the timer stays accurate when the UI re-mounts
mid-research (e.g. sidebar toggle, move to new tab).
* [AI Chat] Simplify elapsed timer to count from component mount (#34082)
Replace progressEvent-based time calibration with a simple counter
that starts from when DeepResearchProgressLine mounts. Removes the
startTimeRef recalibration logic and progressEvent dependency from
ElapsedTimeCounter.