fix(deepseek): fall back to reasoning "搜索到 XX 个网页" panel for citations
When the standard search-results panel never opens, click the reasoning-chain "搜索到 N 个网页" affordance to reveal the citation source list, and prefer the revealed panel links over stale snapshot links so citations point at the right URLs. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,48 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
vi.mock("electron/main", () => ({
|
||||||
|
app: {
|
||||||
|
getPath: () => "/tmp/geo-rankly-deepseek-test",
|
||||||
|
getVersion: () => "0.0.0-test",
|
||||||
|
isPackaged: false,
|
||||||
|
on: vi.fn(),
|
||||||
|
whenReady: () => Promise.resolve(),
|
||||||
|
},
|
||||||
|
BrowserWindow: vi.fn(),
|
||||||
|
WebContentsView: vi.fn(),
|
||||||
|
ipcMain: {
|
||||||
|
handle: vi.fn(),
|
||||||
|
on: vi.fn(),
|
||||||
|
removeHandler: vi.fn(),
|
||||||
|
},
|
||||||
|
Menu: {
|
||||||
|
buildFromTemplate: vi.fn(() => ({ popup: vi.fn() })),
|
||||||
|
setApplicationMenu: vi.fn(),
|
||||||
|
},
|
||||||
|
Tray: vi.fn(),
|
||||||
|
nativeTheme: {
|
||||||
|
on: vi.fn(),
|
||||||
|
shouldUseDarkColors: false,
|
||||||
|
},
|
||||||
|
safeStorage: {
|
||||||
|
decryptString: vi.fn(),
|
||||||
|
encryptString: vi.fn(),
|
||||||
|
isEncryptionAvailable: () => false,
|
||||||
|
},
|
||||||
|
session: {
|
||||||
|
fromPartition: vi.fn(() => ({
|
||||||
|
cookies: {
|
||||||
|
get: vi.fn(),
|
||||||
|
remove: vi.fn(),
|
||||||
|
set: vi.fn(),
|
||||||
|
},
|
||||||
|
webRequest: {
|
||||||
|
onBeforeSendHeaders: vi.fn(),
|
||||||
|
onHeadersReceived: vi.fn(),
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
import { __deepseekTestUtils } from "./deepseek";
|
import { __deepseekTestUtils } from "./deepseek";
|
||||||
import { getMonitorAdapter } from "./index";
|
import { getMonitorAdapter } from "./index";
|
||||||
@@ -11,9 +55,11 @@ const {
|
|||||||
dedupeSourceItems,
|
dedupeSourceItems,
|
||||||
classifyDeepseekSources,
|
classifyDeepseekSources,
|
||||||
mergeDeepSeekRawSourceLinks,
|
mergeDeepSeekRawSourceLinks,
|
||||||
|
resolveDeepSeekCitationPanelLinks,
|
||||||
isObservationComplete,
|
isObservationComplete,
|
||||||
isDeepSeekToggleSelected,
|
isDeepSeekToggleSelected,
|
||||||
isDeepSeekWebpagesTriggerText,
|
isDeepSeekWebpagesTriggerText,
|
||||||
|
isDeepSeekReasoningSearchTriggerText,
|
||||||
} = __deepseekTestUtils;
|
} = __deepseekTestUtils;
|
||||||
|
|
||||||
describe("deepseek adapter helpers", () => {
|
describe("deepseek adapter helpers", () => {
|
||||||
@@ -67,6 +113,74 @@ describe("deepseek adapter helpers", () => {
|
|||||||
expect(classified.searchResults[0]?.url).toBe("https://example.com/search");
|
expect(classified.searchResults[0]?.url).toBe("https://example.com/search");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses revealed xx webpages panel links instead of stale snapshot links for citation sources", () => {
|
||||||
|
const citationPanelLinks = resolveDeepSeekCitationPanelLinks(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
url: "https://stale.example/from-snapshot",
|
||||||
|
title: "Stale snapshot result",
|
||||||
|
text: "Wrong result from the page snapshot",
|
||||||
|
siteName: "Stale",
|
||||||
|
kind: "search",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
url: "https://right.example/from-xx-webpages",
|
||||||
|
title: "Right side panel result",
|
||||||
|
text: "Correct result from DeepSeek search results",
|
||||||
|
siteName: "Right",
|
||||||
|
kind: "search",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
);
|
||||||
|
const classified = classifyDeepseekSources({
|
||||||
|
inlineLinks: [
|
||||||
|
{
|
||||||
|
url: "https://inline.example/body-link",
|
||||||
|
title: "Inline body link",
|
||||||
|
text: "[1]",
|
||||||
|
siteName: "Inline",
|
||||||
|
kind: "inline",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sourcePanelLinks: [],
|
||||||
|
searchPanelLinks: citationPanelLinks,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(citationPanelLinks.map((item) => item.url)).toEqual([
|
||||||
|
"https://right.example/from-xx-webpages",
|
||||||
|
]);
|
||||||
|
expect(classified.citations.map((item) => item.url)).toEqual([
|
||||||
|
"https://right.example/from-xx-webpages",
|
||||||
|
]);
|
||||||
|
expect(classified.searchResults.map((item) => item.url)).toEqual([
|
||||||
|
"https://right.example/from-xx-webpages",
|
||||||
|
]);
|
||||||
|
expect(classified.inlineCitationCandidates.map((item) => item.url)).toEqual([
|
||||||
|
"https://inline.example/body-link",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("falls back to snapshot search links when the revealed xx webpages panel is unavailable", () => {
|
||||||
|
const citationPanelLinks = resolveDeepSeekCitationPanelLinks(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
url: "https://snapshot.example/result",
|
||||||
|
title: "Snapshot result",
|
||||||
|
text: "Fallback result",
|
||||||
|
siteName: "Snapshot",
|
||||||
|
kind: "search",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(citationPanelLinks.map((item) => item.url)).toEqual([
|
||||||
|
"https://snapshot.example/result",
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("enriches numeric inline citations with source metadata from revealed search cards", () => {
|
it("enriches numeric inline citations with source metadata from revealed search cards", () => {
|
||||||
const classified = classifyDeepseekSources({
|
const classified = classifyDeepseekSources({
|
||||||
inlineLinks: [
|
inlineLinks: [
|
||||||
@@ -267,6 +381,12 @@ describe("deepseek adapter helpers", () => {
|
|||||||
expect(isDeepSeekWebpagesTriggerText("搜索到 39 个网页")).toBe(false);
|
expect(isDeepSeekWebpagesTriggerText("搜索到 39 个网页")).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("treats reasoning 搜索到 xx 个网页 as a separate citation-source fallback trigger", () => {
|
||||||
|
expect(isDeepSeekReasoningSearchTriggerText("搜索到 30 个网页")).toBe(true);
|
||||||
|
expect(isDeepSeekReasoningSearchTriggerText("57 个网页")).toBe(false);
|
||||||
|
expect(isDeepSeekReasoningSearchTriggerText("已阅读 57 个网页")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
it("normalizes DeepSeek model labels without mistaking search toggles for models", () => {
|
it("normalizes DeepSeek model labels without mistaking search toggles for models", () => {
|
||||||
const snapshot = {
|
const snapshot = {
|
||||||
url: "https://chat.deepseek.com/",
|
url: "https://chat.deepseek.com/",
|
||||||
|
|||||||
@@ -18,6 +18,9 @@ const DEEPSEEK_SEARCH_RESULTS_HEADING_PATTERN = /^(?:搜索结果|search results
|
|||||||
const DEEPSEEK_WEBPAGES_TRIGGER_ZH_PATTERN = /^(?:已阅读\s*)?\d+\s*个网页$/i
|
const DEEPSEEK_WEBPAGES_TRIGGER_ZH_PATTERN = /^(?:已阅读\s*)?\d+\s*个网页$/i
|
||||||
const DEEPSEEK_WEBPAGES_TRIGGER_EN_PATTERN =
|
const DEEPSEEK_WEBPAGES_TRIGGER_EN_PATTERN =
|
||||||
/^(?:(?:read|viewed)\s*)?\d+\s*(?:web\s*pages?|webpages?)$/i
|
/^(?:(?:read|viewed)\s*)?\d+\s*(?:web\s*pages?|webpages?)$/i
|
||||||
|
const DEEPSEEK_REASONING_SEARCH_TRIGGER_ZH_PATTERN = /^搜索到\s*\d+\s*个网页$/i
|
||||||
|
const DEEPSEEK_REASONING_SEARCH_TRIGGER_EN_PATTERN =
|
||||||
|
/^(?:found|searched)\s*\d+\s*(?:web\s*pages?|webpages?)$/i
|
||||||
const DEEPSEEK_BUSY_TEXT_PATTERN =
|
const DEEPSEEK_BUSY_TEXT_PATTERN =
|
||||||
/(searching|thinking|generating|please wait until the message is generated|搜索中|思考中|生成中|停止生成|stop generating)/i
|
/(searching|thinking|generating|please wait until the message is generated|搜索中|思考中|生成中|停止生成|stop generating)/i
|
||||||
const DEEPSEEK_BUSY_DESCRIPTOR_PATTERN =
|
const DEEPSEEK_BUSY_DESCRIPTOR_PATTERN =
|
||||||
@@ -354,6 +357,18 @@ function isDeepSeekWebpagesTriggerText(value: string | null | undefined): boolea
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isDeepSeekReasoningSearchTriggerText(value: string | null | undefined): boolean {
|
||||||
|
const normalized = normalizeText(value)
|
||||||
|
if (!normalized) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
DEEPSEEK_REASONING_SEARCH_TRIGGER_ZH_PATTERN.test(normalized) ||
|
||||||
|
DEEPSEEK_REASONING_SEARCH_TRIGGER_EN_PATTERN.test(normalized)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function buildSourceItem(source: DeepSeekSourceInput): MonitoringSourceItem | null {
|
function buildSourceItem(source: DeepSeekSourceInput): MonitoringSourceItem | null {
|
||||||
const url = normalizeUrl(getSourceNormalizedUrl(source) ?? source.url)
|
const url = normalizeUrl(getSourceNormalizedUrl(source) ?? source.url)
|
||||||
if (!url) {
|
if (!url) {
|
||||||
@@ -466,6 +481,16 @@ function classifyDeepseekSources(input: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveDeepSeekCitationPanelLinks(
|
||||||
|
snapshotSearchPanelLinks: DeepSeekRawSourceLink[],
|
||||||
|
revealedSearchPanelLinks: DeepSeekRawSourceLink[],
|
||||||
|
): DeepSeekRawSourceLink[] {
|
||||||
|
if (revealedSearchPanelLinks.length > 0) {
|
||||||
|
return mergeDeepSeekRawSourceLinks(revealedSearchPanelLinks)
|
||||||
|
}
|
||||||
|
return mergeDeepSeekRawSourceLinks(snapshotSearchPanelLinks)
|
||||||
|
}
|
||||||
|
|
||||||
function extractQuestionText(payload: Record<string, unknown>): string {
|
function extractQuestionText(payload: Record<string, unknown>): string {
|
||||||
const candidates = [
|
const candidates = [
|
||||||
payload.question_text,
|
payload.question_text,
|
||||||
@@ -1127,6 +1152,247 @@ async function maybeRevealDeepSeekSources(page: PlaywrightPage): Promise<void> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function maybeRevealDeepSeekReasoningSearchSources(page: PlaywrightPage): Promise<void> {
|
||||||
|
if (await hasDeepSeekSearchResultsPanel(page)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const reasoningSearchTrigger = await page
|
||||||
|
.evaluate(() => {
|
||||||
|
const normalize = (value: unknown): string | null => {
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const trimmed = value.trim().replace(/\s+/g, ' ')
|
||||||
|
return trimmed || null
|
||||||
|
}
|
||||||
|
const isVisible = (node: Element | null): node is HTMLElement => {
|
||||||
|
if (!(node instanceof HTMLElement)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const style = window.getComputedStyle(node)
|
||||||
|
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const rect = node.getBoundingClientRect()
|
||||||
|
return rect.width > 0 && rect.height > 0
|
||||||
|
}
|
||||||
|
const isTriggerText = (value: unknown): boolean => {
|
||||||
|
const text = normalize(value)
|
||||||
|
return Boolean(
|
||||||
|
text &&
|
||||||
|
(/^搜索到\s*\d+\s*个网页$/i.test(text) ||
|
||||||
|
/^(?:found|searched)\s*\d+\s*(?:web\s*pages?|webpages?)$/i.test(text)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const isReasoningNode = (node: HTMLElement): boolean => {
|
||||||
|
if (
|
||||||
|
node.closest(
|
||||||
|
".ds-think-content, [class*='think-content'], [class*='reasoning-content']",
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
let current: HTMLElement | null = node
|
||||||
|
for (let depth = 0; current && depth < 8; depth += 1) {
|
||||||
|
const text = normalize(current.textContent || '')
|
||||||
|
const className = String(current.className || '')
|
||||||
|
if (
|
||||||
|
/think|reason|analysis|思考/i.test(className) ||
|
||||||
|
Boolean(text && /已思考|思考过程|搜索到\s*\d+\s*个网页/.test(text))
|
||||||
|
) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
current = current.parentElement
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const isClickable = (node: HTMLElement): boolean => {
|
||||||
|
const tagName = node.tagName.toLowerCase()
|
||||||
|
const role = normalize(node.getAttribute('role'))
|
||||||
|
const style = window.getComputedStyle(node)
|
||||||
|
return (
|
||||||
|
tagName === 'button' ||
|
||||||
|
tagName === 'a' ||
|
||||||
|
role === 'button' ||
|
||||||
|
node.tabIndex >= 0 ||
|
||||||
|
style.cursor === 'pointer' ||
|
||||||
|
typeof (node as { onclick?: unknown }).onclick === 'function'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const findClickTarget = (node: HTMLElement): HTMLElement | null => {
|
||||||
|
let fallback: HTMLElement | null = null
|
||||||
|
const nextParent = (element: HTMLElement): HTMLElement | null =>
|
||||||
|
element.parentNode instanceof HTMLElement ? element.parentNode : null
|
||||||
|
let current: HTMLElement | null = node
|
||||||
|
for (let depth = 0; current !== null && depth < 10; depth += 1) {
|
||||||
|
const element: HTMLElement = current
|
||||||
|
if (!isVisible(element)) {
|
||||||
|
current = nextParent(element)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const currentText = normalize(
|
||||||
|
element.textContent || element.getAttribute('aria-label') || '',
|
||||||
|
)
|
||||||
|
if (!fallback && currentText && isTriggerText(currentText)) {
|
||||||
|
fallback = element
|
||||||
|
}
|
||||||
|
if (isClickable(element)) {
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
current = nextParent(element)
|
||||||
|
}
|
||||||
|
return fallback
|
||||||
|
}
|
||||||
|
|
||||||
|
let bestTarget: HTMLElement | null = null
|
||||||
|
let bestScore = -1
|
||||||
|
for (const node of Array.from(
|
||||||
|
document.querySelectorAll("span, div, button, a, [role='button']"),
|
||||||
|
).slice(0, 1600)) {
|
||||||
|
if (!(node instanceof HTMLElement) || !isVisible(node)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const text = normalize(node.textContent || node.getAttribute('aria-label') || '')
|
||||||
|
if (!isTriggerText(text) || !isReasoningNode(node)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = findClickTarget(node)
|
||||||
|
if (!(target instanceof HTMLElement)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = target.getBoundingClientRect()
|
||||||
|
let score = 0
|
||||||
|
if (isClickable(target)) {
|
||||||
|
score += 32
|
||||||
|
}
|
||||||
|
if (rect.left >= window.innerWidth * 0.18 && rect.left <= window.innerWidth * 0.75) {
|
||||||
|
score += 18
|
||||||
|
}
|
||||||
|
if (rect.top >= window.innerHeight * 0.2) {
|
||||||
|
score += 12
|
||||||
|
}
|
||||||
|
if (rect.width <= 360) {
|
||||||
|
score += 8
|
||||||
|
}
|
||||||
|
if (target.closest(".ds-think-content, [class*='think-content']")) {
|
||||||
|
score += 16
|
||||||
|
}
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score
|
||||||
|
bestTarget = target
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!bestTarget) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
bestTarget.scrollIntoView({ block: 'center', inline: 'center' })
|
||||||
|
const rect = bestTarget.getBoundingClientRect()
|
||||||
|
return {
|
||||||
|
x: rect.left + rect.width / 2,
|
||||||
|
y: rect.top + rect.height / 2,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => null)
|
||||||
|
|
||||||
|
if (!reasoningSearchTrigger || typeof reasoningSearchTrigger !== 'object') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await page.mouse.click(reasoningSearchTrigger.x, reasoningSearchTrigger.y).catch(() => undefined)
|
||||||
|
await page.waitForTimeout(500).catch(() => undefined)
|
||||||
|
if (await waitForDeepSeekSearchResultsPanel(page, 5_000)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
await page
|
||||||
|
.evaluate(() => {
|
||||||
|
const normalize = (value: unknown): string | null => {
|
||||||
|
if (typeof value !== 'string') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
const trimmed = value.trim().replace(/\s+/g, ' ')
|
||||||
|
return trimmed || null
|
||||||
|
}
|
||||||
|
const isVisible = (node: Element | null): node is HTMLElement => {
|
||||||
|
if (!(node instanceof HTMLElement)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const style = window.getComputedStyle(node)
|
||||||
|
if (style.display === 'none' || style.visibility === 'hidden' || style.opacity === '0') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const rect = node.getBoundingClientRect()
|
||||||
|
return rect.width > 0 && rect.height > 0
|
||||||
|
}
|
||||||
|
const isTriggerText = (value: unknown): boolean => {
|
||||||
|
const text = normalize(value)
|
||||||
|
return Boolean(text && /^搜索到\s*\d+\s*个网页$/i.test(text))
|
||||||
|
}
|
||||||
|
const isClickable = (node: HTMLElement): boolean => {
|
||||||
|
const tagName = node.tagName.toLowerCase()
|
||||||
|
const role = normalize(node.getAttribute('role'))
|
||||||
|
const style = window.getComputedStyle(node)
|
||||||
|
return (
|
||||||
|
tagName === 'button' ||
|
||||||
|
tagName === 'a' ||
|
||||||
|
role === 'button' ||
|
||||||
|
node.tabIndex >= 0 ||
|
||||||
|
style.cursor === 'pointer' ||
|
||||||
|
typeof (node as { onclick?: unknown }).onclick === 'function'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const dispatchClick = (target: HTMLElement): void => {
|
||||||
|
target.dispatchEvent(
|
||||||
|
new PointerEvent('pointerdown', { bubbles: true, cancelable: true, pointerId: 1 }),
|
||||||
|
)
|
||||||
|
target.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true }))
|
||||||
|
target.dispatchEvent(
|
||||||
|
new PointerEvent('pointerup', { bubbles: true, cancelable: true, pointerId: 1 }),
|
||||||
|
)
|
||||||
|
target.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true }))
|
||||||
|
target.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true }))
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const node of Array.from(
|
||||||
|
document.querySelectorAll("span, div, button, a, [role='button']"),
|
||||||
|
).slice(0, 1600)) {
|
||||||
|
if (!(node instanceof HTMLElement) || !isVisible(node)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const text = normalize(node.textContent || node.getAttribute('aria-label') || '')
|
||||||
|
if (!isTriggerText(text)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
let target: HTMLElement | null = node
|
||||||
|
let fallback: HTMLElement | null = node
|
||||||
|
for (let depth = 0; target && depth < 10; depth += 1) {
|
||||||
|
if (isVisible(target) && isClickable(target)) {
|
||||||
|
dispatchClick(target)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (isVisible(target)) {
|
||||||
|
fallback = target
|
||||||
|
}
|
||||||
|
target = target.parentElement
|
||||||
|
}
|
||||||
|
if (fallback) {
|
||||||
|
dispatchClick(fallback)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => undefined)
|
||||||
|
await page.waitForTimeout(500).catch(() => undefined)
|
||||||
|
await waitForDeepSeekSearchResultsPanel(page).catch(() => undefined)
|
||||||
|
}
|
||||||
|
|
||||||
async function maybeExpandDeepSeekReasoning(page: PlaywrightPage): Promise<void> {
|
async function maybeExpandDeepSeekReasoning(page: PlaywrightPage): Promise<void> {
|
||||||
await page
|
await page
|
||||||
.evaluate(() => {
|
.evaluate(() => {
|
||||||
@@ -2561,19 +2827,26 @@ export const deepseekAdapter: MonitorAdapter = {
|
|||||||
context.reportProgress('deepseek.reveal_sources')
|
context.reportProgress('deepseek.reveal_sources')
|
||||||
await maybeExpandDeepSeekReasoning(page).catch(() => undefined)
|
await maybeExpandDeepSeekReasoning(page).catch(() => undefined)
|
||||||
await maybeRevealDeepSeekSources(page).catch(() => undefined)
|
await maybeRevealDeepSeekSources(page).catch(() => undefined)
|
||||||
const revealedSearchPanelLinks = await collectDeepSeekSearchResultsPanelLinks(page).catch(
|
let revealedSearchPanelLinks = await collectDeepSeekSearchResultsPanelLinks(page).catch(
|
||||||
() => [],
|
() => [],
|
||||||
)
|
)
|
||||||
|
if (revealedSearchPanelLinks.length === 0) {
|
||||||
|
await maybeRevealDeepSeekReasoningSearchSources(page).catch(() => undefined)
|
||||||
|
revealedSearchPanelLinks = await collectDeepSeekSearchResultsPanelLinks(page).catch(
|
||||||
|
() => [],
|
||||||
|
)
|
||||||
|
}
|
||||||
const finalSnapshot = await readDeepSeekPageSnapshot(page, questionText).catch(
|
const finalSnapshot = await readDeepSeekPageSnapshot(page, questionText).catch(
|
||||||
() => waitResult.finalSnapshot,
|
() => waitResult.finalSnapshot,
|
||||||
)
|
)
|
||||||
const bestSnapshot = selectBetterSnapshot(waitResult.finalSnapshot, finalSnapshot)
|
const bestSnapshot = selectBetterSnapshot(waitResult.finalSnapshot, finalSnapshot)
|
||||||
|
const citationPanelLinks = resolveDeepSeekCitationPanelLinks(
|
||||||
|
bestSnapshot.searchPanelLinks,
|
||||||
|
revealedSearchPanelLinks,
|
||||||
|
)
|
||||||
const mergedSnapshot: DeepSeekPageSnapshot = {
|
const mergedSnapshot: DeepSeekPageSnapshot = {
|
||||||
...bestSnapshot,
|
...bestSnapshot,
|
||||||
searchPanelLinks: mergeDeepSeekRawSourceLinks(
|
searchPanelLinks: citationPanelLinks,
|
||||||
bestSnapshot.searchPanelLinks,
|
|
||||||
revealedSearchPanelLinks,
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
const classifiedSources = classifyDeepseekSources({
|
const classifiedSources = classifyDeepseekSources({
|
||||||
inlineLinks: mergedSnapshot.inlineLinks,
|
inlineLinks: mergedSnapshot.inlineLinks,
|
||||||
@@ -2639,7 +2912,9 @@ export const __deepseekTestUtils = {
|
|||||||
dedupeSourceItems,
|
dedupeSourceItems,
|
||||||
classifyDeepseekSources,
|
classifyDeepseekSources,
|
||||||
mergeDeepSeekRawSourceLinks,
|
mergeDeepSeekRawSourceLinks,
|
||||||
|
resolveDeepSeekCitationPanelLinks,
|
||||||
isObservationComplete,
|
isObservationComplete,
|
||||||
isDeepSeekToggleSelected,
|
isDeepSeekToggleSelected,
|
||||||
isDeepSeekWebpagesTriggerText,
|
isDeepSeekWebpagesTriggerText,
|
||||||
|
isDeepSeekReasoningSearchTriggerText,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user