-
-
Notifications
You must be signed in to change notification settings - Fork 53
feat: add initial Perplexity extension support #370
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
3fcda5d
c0e716c
2ee27fd
198b82a
59df35c
14db0f8
b2e9037
8328a01
ad8f654
81cb1ae
0372f28
f026ffb
c20c3a9
9cfa722
6203bb7
f400d7c
73850ad
71d37d7
c2e970c
c5c73ee
dc018a3
05de0e9
51ef432
ef714d6
3053fa5
dea0dba
158d5b6
7ca9c77
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,6 +35,12 @@ | |
| url?: string | ||
| } | ||
|
|
||
| export interface ConversationRenameTarget { | ||
| id: string | ||
| title?: string | ||
| url?: string | ||
| } | ||
|
|
||
| export interface SiteDeleteConversationResult { | ||
| id: string | ||
| success: boolean | ||
|
|
@@ -86,7 +92,10 @@ | |
| selector: string | ||
| shadow: boolean | ||
| extractInfo: (el: Element) => ConversationInfo | null | ||
| extractRemovedInfo?: (el: Element) => ConversationInfo | null | ||
| getTitleElement: (el: Element) => Element | null | ||
| enablePolling?: boolean | ||
| pollIntervalMs?: number | ||
| } | ||
|
|
||
| export interface AnchorData { | ||
|
|
@@ -204,6 +213,17 @@ | |
| if (!normalized) return "" | ||
|
|
||
| const lines = normalized.split("\n") | ||
|
|
||
| // Some sites wrap code blocks as: | ||
| // text\nflowchart TD ... | ||
| // Strip a leading plain-text language marker before Mermaid detection. | ||
| if (lines.length > 1) { | ||
| const firstLine = lines[0].trim().toLowerCase() | ||
| if (/^(text|plain(?:\s|-)?text|text\/plain|markdown|text\/markdown|md|txt)$/.test(firstLine)) { | ||
| return normalizeAssistantMermaidSource(lines.slice(1).join("\n")) | ||
| } | ||
| } | ||
|
|
||
| const firstMeaningfulLineIndex = getFirstMeaningfulMermaidLineIndex(lines) | ||
| if (firstMeaningfulLineIndex === -1) { | ||
| return normalized | ||
|
|
@@ -383,6 +403,14 @@ | |
| return [] | ||
| } | ||
|
|
||
| /** | ||
| * Whether getConversationList currently includes a complete enough remote snapshot | ||
| * to safely prune local conversations that disappeared from the site. | ||
| */ | ||
| hasAuthoritativeConversationList(): boolean { | ||
| return false | ||
| } | ||
|
|
||
| /** 获取当前页面会话的基础元数据 */ | ||
| getCurrentConversationInfo(): ConversationInfo | null { | ||
| const id = this.getSessionId() | ||
|
|
@@ -446,6 +474,17 @@ | |
| return results | ||
| } | ||
|
|
||
| async renameConversationOnSite( | ||
| _target: ConversationRenameTarget, | ||
| _newTitle: string, | ||
| ): Promise<{ success: boolean; method: "api" | "ui" | "none"; reason?: string }> { | ||
| return { | ||
| success: false, | ||
| method: "none", | ||
| reason: "not_supported", | ||
| } | ||
| } | ||
|
|
||
| async loadAllConversations(): Promise<void> { | ||
| const container = this.getSidebarScrollContainer() | ||
| if (!container) return | ||
|
|
@@ -500,6 +539,44 @@ | |
| return selectorBtn?.textContent || selectorBtn?.innerText || "" | ||
| } | ||
|
|
||
| /** | ||
| * Whether the site's model selector menu is currently open. | ||
| * Adapters can override this so the shared model locker avoids | ||
| * interfering with a manually opened model menu. | ||
| */ | ||
| isModelSelectorOpen(): boolean { | ||
| return false | ||
| } | ||
|
|
||
| /** | ||
| * Some sites need a persistent model-lock monitor rather than a short | ||
| * relock window after route changes. | ||
| */ | ||
| usesPersistentModelLockMonitor(): boolean { | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这些模型锁定相关 hook 暴露了一个更复杂的持续监控模型,但我不希望为 Perplexity 引入这种通用机制。当前需求更像“默认模型初始化”,不是强制锁定。 公共基类里可以保留一个简单的站点能力扩展点,但不应该把 persistent monitor、mutation debounce、UI ready 等一整套复杂机制变成通用抽象。这样会增加维护成本,也会让其它站点以后更容易误用。 |
||
| return false | ||
| } | ||
|
|
||
| getModelLockMonitorInterval(): number { | ||
| return 1000 | ||
| } | ||
|
|
||
| getModelLockMonitorRoot(): Node | null { | ||
| return typeof document !== "undefined" ? document.body : null | ||
| } | ||
|
|
||
| getModelLockMutationDebounce(): number { | ||
| return 120 | ||
| } | ||
|
|
||
| /** | ||
| * Whether the site's model-lock UI is currently available. | ||
| * Sites with temporary mode/tool menus instead of a model selector can | ||
| * return false so the shared locker waits for the selector to come back. | ||
| */ | ||
| isModelLockUiReady(): boolean { | ||
| return true | ||
| } | ||
|
|
||
| /** 获取网络监控配置 */ | ||
| getNetworkMonitorConfig(): NetworkMonitorConfig | null { | ||
| return null | ||
|
|
@@ -548,6 +625,10 @@ | |
| return null | ||
| } | ||
|
|
||
| onZenModeChanged(_enabled: boolean): void { | ||
| // Optional hook for site-specific layout calibration. | ||
| } | ||
|
|
||
| /** 返回净化模式配置(隐藏免责声明、广告、下载按钮等冗余元素) */ | ||
| getCleanModeConfig(): ZenModeConfig | null { | ||
| return null | ||
|
|
@@ -579,8 +660,18 @@ | |
| } | ||
|
|
||
| /** | ||
| * 精准查找提交按钮 | ||
| * 当站点存在多个相邻 icon button,且仅靠通用选择器/距离判断容易误判时使用 | ||
| * Provide a custom anchor for mounting the usage monitor. | ||
| * Override when the default placement near the editor would break layout. | ||
| */ | ||
| getUsageCounterMountAnchor( | ||
| _editor: HTMLElement, | ||
| _submitButton: HTMLElement | null, | ||
| ): HTMLElement | null { | ||
| return null | ||
| } | ||
|
|
||
| /** | ||
| * Precisely locate the submit button when generic selectors are ambiguous. | ||
| */ | ||
| findSubmitButton(_editor: HTMLElement | null): HTMLElement | null { | ||
| return null | ||
|
|
@@ -1066,7 +1157,7 @@ | |
| behavior: "instant", | ||
| block: "start", | ||
| __bypassLock: true, | ||
| } as any) | ||
| } | ||
|
|
||
| /** 是否支持滚动锁定功能 */ | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,6 +16,7 @@ import { GeminiEnterpriseAdapter } from "./gemini-enterprise" | |
| import { GrokAdapter } from "./grok" | ||
| import { ImaAdapter } from "./ima" | ||
| import { KimiAdapter } from "./kimi" | ||
| import { PerplexityAdapter } from "./perplexity" | ||
| import { QianwenAdapter } from "./qianwen" | ||
| import { QwenAiAdapter } from "./qwen-studio" | ||
| import { YuanbaoAdapter } from "./yuanbao" | ||
|
|
@@ -32,6 +33,7 @@ const adapters: SiteAdapter[] = [ | |
| new DeepSeekAdapter(), | ||
| new DoubaoAdapter(), | ||
| new ImaAdapter(), | ||
| new PerplexityAdapter(), | ||
|
Owner
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 这里把 建议先拆成最小可合并版本,或者把站点适配改成按 hostname 懒加载/按需动态导入;至少不能在没有体积控制方案的情况下直接把这么大的 adapter 放进公共入口。 |
||
| new ChatGLMAdapter(), | ||
| new KimiAdapter(), | ||
| new QwenAiAdapter(), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
新增 adapter capability 本身可以接受,但这里的能力要非常克制。
hasAuthoritativeConversationList()这个名字和语义会让公共 manager 相信“缺失即删除”,而 Perplexity 当前线程列表并不能保证完整。建议不要把 prune/delete 判断做成通用能力,至少默认公共逻辑不应据此删除本地数据;如果 Perplexity 需要处理 native sidebar 删除,应限制在 Perplexity adapter 自己的同步逻辑里,不能扩散到所有会话管理路径。