From 3e03599d11955f91558e75c29b085c8d72636ea1 Mon Sep 17 00:00:00 2001 From: Wu Yue Date: Thu, 3 Jul 2025 08:49:07 +0800 Subject: [PATCH] feat(core): make editor host optional (#12990) Close [AI-260](https://linear.app/affine-design/issue/AI-260) ## Summary by CodeRabbit * **New Features** * Added support for passing workspace and document identifiers directly to chat components, enabling improved context handling in AI chat features. * **Bug Fixes** * Improved null safety and error handling across AI chat components to prevent issues when certain properties are missing. * Enhanced defensive checks to avoid runtime errors related to missing or undefined properties. * **Refactor** * Simplified and standardized property types and data flow in AI chat components, reducing reliance on certain objects and making properties optional where appropriate. * Streamlined error messaging and tool integration by updating property and parameter structures. * Updated tool components to use image proxy services directly, removing dependency on host objects. * **Chores** * Updated type definitions and interfaces for better flexibility and maintainability. * Added new interfaces to clarify session creation parameters. --- .../core/src/blocksuite/ai/actions/types.ts | 9 ++-- .../ai/chat-panel/message/assistant.ts | 14 +++--- .../ai-chat-chips/chat-panel-chips.ts | 5 +- .../ai/components/ai-chat-chips/doc-chip.ts | 5 +- .../ai-chat-composer/ai-chat-composer.ts | 18 ++++--- .../ai-chat-content/ai-chat-content.ts | 7 ++- .../components/ai-chat-input/ai-chat-input.ts | 17 ++++--- .../ai-chat-messages/ai-chat-messages.ts | 47 ++++++++++++------- .../ai-history-clear/ai-history-clear.ts | 29 ++++++------ .../ai-message-content/rich-text.ts | 2 +- .../ai-message-content/stream-objects.ts | 23 ++++----- .../components/ai-scrollable-text-renderer.ts | 4 +- .../components/ai-tools/tool-result-card.ts | 16 ++++--- .../ai/components/ai-tools/web-crawl.ts | 9 ++-- .../ai/components/ai-tools/web-search.ts | 9 ++-- .../src/blocksuite/ai/components/copy-more.ts | 19 ++++---- .../ai/components/playground/chat.ts | 3 ++ .../blocksuite/ai/components/text-renderer.ts | 4 +- .../core/src/blocksuite/ai/messages/error.ts | 6 +-- .../ai/peek-view/chat-block-peek-view.ts | 3 +- .../src/blocksuite/ai/provider/ai-provider.ts | 4 +- .../blocksuite/ai/provider/setup-provider.tsx | 18 +++---- .../src/blocksuite/ai/provider/tracker.ts | 8 ++-- 23 files changed, 161 insertions(+), 118 deletions(-) diff --git a/packages/frontend/core/src/blocksuite/ai/actions/types.ts b/packages/frontend/core/src/blocksuite/ai/actions/types.ts index 9904cf3a5..9fd8fb98d 100644 --- a/packages/frontend/core/src/blocksuite/ai/actions/types.ts +++ b/packages/frontend/core/src/blocksuite/ai/actions/types.ts @@ -80,11 +80,11 @@ declare global { retry?: boolean; // action's context - docId: string; + docId?: string; workspaceId: string; // internal context - host: EditorHost; + host?: EditorHost; models?: (BlockModel | GfxModel)[]; control?: TrackerControl; where?: TrackerWhere; @@ -142,6 +142,7 @@ declare global { docs: AIDocContextOption[]; files: AIFileContextOption[]; }; + postfix?: (text: string) => string; } interface TranslateOptions extends AITextActionOptions { @@ -374,9 +375,9 @@ declare global { }; interface CreateSessionOptions { - docId: string; - workspaceId: string; promptName: PromptKey; + workspaceId: string; + docId?: string; sessionId?: string; retry?: boolean; } diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/message/assistant.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/message/assistant.ts index afa7ba80b..c174ffe7c 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/message/assistant.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/message/assistant.ts @@ -33,7 +33,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) { `; @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor item!: ChatMessage; @@ -99,7 +99,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) { ${streamObjects?.length ? this.renderStreamObjects(streamObjects) : this.renderRichText(content)} - ${shouldRenderError ? AIChatErrorRenderer(host, error) : nothing} + ${shouldRenderError ? AIChatErrorRenderer(error, host) : nothing} ${this.renderEditorActions()} `; } @@ -152,9 +152,11 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) { ? mergeStreamContent(streamObjects) : content; - const actions = isInsidePageEditor(host) - ? PageEditorActions - : EdgelessEditorActions; + const actions = host + ? isInsidePageEditor(host) + ? PageEditorActions + : EdgelessEditorActions + : null; return html` this.retry()} > - ${isLast && !!markdown + ${isLast && !!markdown && host ? html`(''); @@ -103,6 +103,9 @@ export class ChatPanelDocChip extends SignalWatcher( }; private readonly processDocChip = async () => { + if (!this.host) { + return; + } try { const doc = this.docDisplayConfig.getDoc(this.chip.docId); if (!doc) { diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts index 93a840bbf..d145f909f 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts @@ -51,11 +51,14 @@ export class AIChatComposer extends SignalWatcher( `; @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor workspaceId!: string; + @property({ attribute: false }) + accessor docId: string | undefined; + @property({ attribute: false }) accessor session!: CopilotSessionType | null | undefined; @@ -124,8 +127,10 @@ export class AIChatComposer extends SignalWatcher( > { - const blob = await this.host.store.blobSync.get(file.blobId); return { - file: new File(blob ? [blob] : [], file.name), + file: new File([], file.name), blobId: file.blobId, fileId: file.id, - state: blob ? file.status : 'failed', - tooltip: blob ? file.error : 'File not found in blob storage', + state: file.status, + tooltip: file.error, createdAt: file.createdAt, }; }) @@ -302,7 +306,7 @@ export class AIChatComposer extends SignalWatcher( try { await AIProvider.context?.pollEmbeddingStatus( - this.host.std.workspace.id, + this.workspaceId, (status: ContextWorkspaceEmbeddingStatus) => { if (!status) { this.embeddingCompleted = false; diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts index 55f7da834..aa9eaf53e 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts @@ -72,10 +72,10 @@ export class AIChatContent extends SignalWatcher( `; @property({ attribute: false }) - accessor chatTitle!: TemplateResult<1>; + accessor chatTitle: TemplateResult<1> | undefined; @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor session!: CopilotSessionType | null | undefined; @@ -288,6 +288,8 @@ export class AIChatContent extends SignalWatcher( this.retry()} .width=${this.width} >`; - } else if (isChatAction(item)) { + } else if (isChatAction(item) && this.host) { return html` { @@ -351,17 +356,25 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) { } }) ); - disposables.add( - this.host.selection.slots.changed.subscribe(() => { - this._selectionValue = this.host.selection.value; - }) - ); - disposables.add( - docModeService.onPrimaryModeChange( - () => this.requestUpdate(), - this.host.store.id - ) - ); + + const selection$ = this.host?.selection.slots.changed; + if (selection$) { + disposables.add( + selection$.subscribe(() => { + this._selectionValue = this.host?.selection.value ?? []; + }) + ); + } + + const docModeService = this.host?.std.get(DocModeProvider); + if (docModeService && this.docId) { + disposables.add( + docModeService.onPrimaryModeChange( + () => this.requestUpdate(), + this.docId + ) + ); + } } protected override updated(_changedProperties: PropertyValues) { @@ -400,13 +413,11 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) { abortController, }); - const { store } = this.host; const stream = await AIProvider.actions.chat({ sessionId, retry: true, - docId: store.id, - workspaceId: store.workspace.id, - host: this.host, + docId: this.docId, + workspaceId: this.workspaceId, stream: true, signal: abortController.signal, where: 'chat-panel', diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-history-clear/ai-history-clear.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-history-clear/ai-history-clear.ts index 06a6d0581..fb05a6f7e 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-history-clear/ai-history-clear.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-history-clear/ai-history-clear.ts @@ -19,7 +19,7 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) { accessor session!: CopilotSessionType | null | undefined; @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor doc!: Store; @@ -52,18 +52,19 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) { return; } const sessionId = this.session.id; - const notification = this.host.std.getOptional(NotificationProvider); - if (!notification) return; + const notification = this.host?.std.getOptional(NotificationProvider); try { - if ( - await notification.confirm({ - title: 'Clear History', - message: - 'Are you sure you want to clear all history? This action will permanently delete all content, including all chat logs and data, and cannot be undone.', - confirmText: 'Confirm', - cancelText: 'Cancel', - }) - ) { + const confirm = notification + ? await notification.confirm({ + title: 'Clear History', + message: + 'Are you sure you want to clear all history? This action will permanently delete all content, including all chat logs and data, and cannot be undone.', + confirmText: 'Confirm', + cancelText: 'Cancel', + }) + : true; + + if (confirm) { const actionIds = this.chatContextValue.messages .filter(item => 'sessionId' in item) .map(item => item.sessionId); @@ -72,11 +73,11 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) { this.doc.id, [...(sessionId ? [sessionId] : []), ...(actionIds || [])] ); - notification.toast('History cleared'); + notification?.toast('History cleared'); this.onHistoryCleared?.(); } } catch { - notification.toast('Failed to clear history'); + notification?.toast('Failed to clear history'); } }; diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/rich-text.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/rich-text.ts index 0204d4ccb..cd2403c62 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/rich-text.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/rich-text.ts @@ -10,7 +10,7 @@ import { createTextRenderer } from '../../components/text-renderer'; export class ChatContentRichText extends WithDisposable(ShadowlessElement) { @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor text!: string; diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/stream-objects.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/stream-objects.ts index 0e9a27789..938881e45 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/stream-objects.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-message-content/stream-objects.ts @@ -1,5 +1,6 @@ import type { FeatureFlagService } from '@affine/core/modules/feature-flag'; import { WithDisposable } from '@blocksuite/affine/global/lit'; +import { ImageProxyService } from '@blocksuite/affine/shared/adapters'; import type { EditorHost } from '@blocksuite/affine/std'; import { ShadowlessElement } from '@blocksuite/affine/std'; import type { ExtensionType } from '@blocksuite/affine/store'; @@ -26,7 +27,7 @@ export class ChatContentStreamObjects extends WithDisposable( accessor answer!: StreamObject[]; @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor state: AffineAIPanelState = 'finished'; @@ -44,32 +45,28 @@ export class ChatContentStreamObjects extends WithDisposable( if (streamObject.type !== 'tool-call') { return nothing; } - + const imageProxyService = this.host?.store.get(ImageProxyService); switch (streamObject.toolName) { case 'web_crawl_exa': return html` `; case 'web_search_exa': return html` `; default: { const name = streamObject.toolName + ' tool calling'; return html` - + `; } } @@ -79,22 +76,22 @@ export class ChatContentStreamObjects extends WithDisposable( if (streamObject.type !== 'tool-result') { return nothing; } - + const imageProxyService = this.host?.store.get(ImageProxyService); switch (streamObject.toolName) { case 'web_crawl_exa': return html` `; case 'web_search_exa': return html` `; default: { @@ -102,8 +99,8 @@ export class ChatContentStreamObjects extends WithDisposable( return html` `; } diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-scrollable-text-renderer.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-scrollable-text-renderer.ts index 492a1030b..743e5f155 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-scrollable-text-renderer.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-scrollable-text-renderer.ts @@ -83,10 +83,10 @@ export class AIScrollableTextRenderer extends WithDisposable( accessor answer!: string; @property({ attribute: false }) - accessor host: EditorHost | null = null; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) - accessor state: AffineAIPanelState | undefined = undefined; + accessor state: AffineAIPanelState | undefined; @property({ attribute: false }) accessor textRendererOptions!: TextRendererOptions; diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/tool-result-card.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/tool-result-card.ts index 6870c8e60..088f878b5 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/tool-result-card.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/tool-result-card.ts @@ -1,7 +1,7 @@ import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit'; -import { ImageProxyService } from '@blocksuite/affine/shared/adapters'; +import { type ImageProxyService } from '@blocksuite/affine/shared/adapters'; import { unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme'; -import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std'; +import { ShadowlessElement } from '@blocksuite/affine/std'; import { ToggleDownIcon, ToolIcon } from '@blocksuite/icons/lit'; import { type Signal } from '@preact/signals-core'; import { css, html, nothing, type TemplateResult } from 'lit'; @@ -190,9 +190,6 @@ export class ToolResultCard extends SignalWatcher( } `; - @property({ attribute: false }) - accessor host!: EditorHost; - @property({ attribute: false }) accessor name: string = 'Tool result'; @@ -208,6 +205,9 @@ export class ToolResultCard extends SignalWatcher( @property({ attribute: false }) accessor width: Signal | undefined; + @property({ attribute: false }) + accessor imageProxyService: ImageProxyService | null | undefined; + @state() private accessor isCollapsed = true; @@ -276,9 +276,11 @@ export class ToolResultCard extends SignalWatcher( if (!icon) { return nothing; } - const imageProxyService = this.host.store.get(ImageProxyService); if (typeof icon === 'string') { - return html` `; + if (this.imageProxyService) { + return html``; + } + return html``; } return html`${icon}`; } diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-crawl.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-crawl.ts index 233d8b249..f75960e8a 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-crawl.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-crawl.ts @@ -1,5 +1,6 @@ import { WithDisposable } from '@blocksuite/affine/global/lit'; -import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std'; +import type { ImageProxyService } from '@blocksuite/affine/shared/adapters'; +import { ShadowlessElement } from '@blocksuite/affine/std'; import { WebIcon } from '@blocksuite/icons/lit'; import type { Signal } from '@preact/signals-core'; import { html, nothing } from 'lit'; @@ -37,10 +38,10 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) { accessor data!: WebCrawlToolCall | WebCrawlToolResult; @property({ attribute: false }) - accessor host!: EditorHost; + accessor width: Signal | undefined; @property({ attribute: false }) - accessor width: Signal | undefined; + accessor imageProxyService: ImageProxyService | null | undefined; renderToolCall() { return html` @@ -61,7 +62,6 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) { const { favicon, title, content } = result[0]; return html` `; } diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-search.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-search.ts index 0e4318af2..7307cff20 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-search.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/web-search.ts @@ -1,5 +1,6 @@ import { WithDisposable } from '@blocksuite/affine/global/lit'; -import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std'; +import type { ImageProxyService } from '@blocksuite/affine/shared/adapters'; +import { ShadowlessElement } from '@blocksuite/affine/std'; import { WebIcon } from '@blocksuite/icons/lit'; import type { Signal } from '@preact/signals-core'; import { html, nothing } from 'lit'; @@ -37,10 +38,10 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) { accessor data!: WebSearchToolCall | WebSearchToolResult; @property({ attribute: false }) - accessor host!: EditorHost; + accessor width: Signal | undefined; @property({ attribute: false }) - accessor width: Signal | undefined; + accessor imageProxyService: ImageProxyService | null | undefined; renderToolCall() { return html` @@ -69,12 +70,12 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) { return html` `; } diff --git a/packages/frontend/core/src/blocksuite/ai/components/copy-more.ts b/packages/frontend/core/src/blocksuite/ai/components/copy-more.ts index e1a847d70..a63fc575c 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/copy-more.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/copy-more.ts @@ -82,7 +82,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) { `; private get _selectionValue() { - return this.host.selection.value; + return this.host?.selection.value ?? []; } private get _currentTextSelection(): TextSelection | undefined { @@ -105,7 +105,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) { private _morePopper: ReturnType | null = null; @property({ attribute: false }) - accessor host!: EditorHost; + accessor host: EditorHost | null | undefined; @property({ attribute: false }) accessor actions: ChatAction[] = []; @@ -136,7 +136,8 @@ export class ChatCopyMore extends WithDisposable(LitElement) { } private readonly _notifySuccess = (title: string) => { - const notificationService = this.host.std.getOptional(NotificationProvider); + const notificationService = + this.host?.std.getOptional(NotificationProvider); notificationService?.notify({ title: title, accent: 'success', @@ -174,7 +175,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) { }
- ${content + ${content && host ? html`
{ @@ -199,19 +200,19 @@ export class ChatCopyMore extends WithDisposable(LitElement) { Retry
` : nothing} - ${isLast - ? nothing - : html`
${MoreHorizontalIcon({ width: '20px', height: '20px' })} -
`} +
` + : nothing}
- ${this._showMoreMenu + ${this._showMoreMenu && host ? repeat( actions.filter(action => action.showWhen(host)), action => action.title, diff --git a/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts b/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts index bab4d1260..c6b573016 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts @@ -298,6 +298,8 @@ export class PlaygroundChat extends SignalWatcher( { return (answer: string, state?: AffineAIPanelState) => { diff --git a/packages/frontend/core/src/blocksuite/ai/messages/error.ts b/packages/frontend/core/src/blocksuite/ai/messages/error.ts index e155b94b9..4b7190493 100644 --- a/packages/frontend/core/src/blocksuite/ai/messages/error.ts +++ b/packages/frontend/core/src/blocksuite/ai/messages/error.ts @@ -186,7 +186,7 @@ export class AIErrorWrapper extends SignalWatcher(WithDisposable(LitElement)) { accessor testId = 'ai-error'; } -const PaymentRequiredErrorRenderer = (host: EditorHost) => html` +const PaymentRequiredErrorRenderer = (host?: EditorHost | null) => html` html` > `; -const LoginRequiredErrorRenderer = (host: EditorHost) => html` +const LoginRequiredErrorRenderer = (host?: EditorHost | null) => html` { >`; }; -export function AIChatErrorRenderer(host: EditorHost, error: AIError) { +export function AIChatErrorRenderer(error: AIError, host?: EditorHost | null) { if (error instanceof PaymentRequiredError) { return PaymentRequiredErrorRenderer(host); } else if (error instanceof UnauthorizedError) { diff --git a/packages/frontend/core/src/blocksuite/ai/peek-view/chat-block-peek-view.ts b/packages/frontend/core/src/blocksuite/ai/peek-view/chat-block-peek-view.ts index 91ced56ad..f4e992f44 100644 --- a/packages/frontend/core/src/blocksuite/ai/peek-view/chat-block-peek-view.ts +++ b/packages/frontend/core/src/blocksuite/ai/peek-view/chat-block-peek-view.ts @@ -471,7 +471,7 @@ export class AIChatBlockPeekView extends LitElement { .message=${message} .textRendererOptions=${this._textRendererOptions} > - ${shouldRenderError ? AIChatErrorRenderer(host, error) : nothing} + ${shouldRenderError ? AIChatErrorRenderer(error, host) : nothing} ${shouldRenderCopyMore ? html` (), - requestLogin: new Subject<{ host: EditorHost }>(), - requestUpgradePlan: new Subject<{ host: EditorHost }>(), + requestLogin: new Subject<{ host?: EditorHost | null }>(), + requestUpgradePlan: new Subject<{ host?: EditorHost | null }>(), // stream of AI actions triggered by users actions: new Subject<{ action: keyof BlockSuitePresets.AIActions; diff --git a/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx b/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx index c72463740..55af3946c 100644 --- a/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx +++ b/packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx @@ -42,24 +42,26 @@ const processTypeToPromptName = new Map( }) ); +interface CreateSessionOptions { + promptName: PromptKey; + workspaceId: string; + docId?: string; + sessionId?: string; + retry?: boolean; +} + export function setupAIProvider( client: CopilotClient, globalDialogService: GlobalDialogService, authService: AuthService ) { async function createSession({ + promptName, workspaceId, docId, - promptName, sessionId, retry, - }: { - workspaceId: string; - docId: string; - promptName: PromptKey; - sessionId?: string; - retry?: boolean; - }) { + }: CreateSessionOptions) { if (sessionId) return sessionId; if (retry) return AIProvider.LAST_ACTION_SESSIONID; diff --git a/packages/frontend/core/src/blocksuite/ai/provider/tracker.ts b/packages/frontend/core/src/blocksuite/ai/provider/tracker.ts index 75eaef5ce..5d5530139 100644 --- a/packages/frontend/core/src/blocksuite/ai/provider/tracker.ts +++ b/packages/frontend/core/src/blocksuite/ai/provider/tracker.ts @@ -16,7 +16,7 @@ type AIActionEventName = | 'AI result accepted'; type AIActionEventProperties = { - page: 'doc' | 'edgeless'; + page: 'doc' | 'edgeless' | 'unknown'; segment: | 'AI action panel' | 'right side bar' @@ -58,7 +58,7 @@ type AIActionEventProperties = { | 'other'; category: string; other: Record; - docId: string; + docId?: string; workspaceId: string; }; @@ -231,7 +231,9 @@ const toTrackedOptions = ( if (!eventName) return null; - const pageMode = inferPageMode(event.options.host); + const pageMode = event.options.host + ? inferPageMode(event.options.host) + : 'unknown'; const otherProperties = omit(event.options, defaultActionOptions); const type = inferObjectType(event); const segment = inferSegment(event);