diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts index 80e01512255b7..345219adbede8 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/doc-handler.ts @@ -181,7 +181,10 @@ function updateAIPanelConfig( config.errorStateConfig = buildErrorConfig(aiPanel); config.copy = buildCopyConfig(aiPanel); config.discardCallback = () => { - getTracker(host).discardAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'discard_button', + }); reportResponse('result:discard'); }; } @@ -202,7 +205,7 @@ export function actionToHandler( if (!blocks || blocks.length === 0) return; const block = blocks.at(-1); assertExists(block); - getTracker(host).startAction({ action: id }); + getTracker(host).action_panel.invokeAction({ action: id }); aiPanel.toggle(block, 'placeholder'); }; } diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-handler.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-handler.ts index 7134622b33860..1543248a7fd3b 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-handler.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-handler.ts @@ -1,4 +1,3 @@ -import track from '@affine/track'; import type { EditorHost } from '@blocksuite/affine/block-std'; import type { AffineAIPanelWidget, @@ -42,6 +41,7 @@ import { getSelectedNoteAnchor, getSelections, } from '../utils/selection-utils'; +import { getTracker } from '../utils/track'; import { EXCLUDING_COPY_ACTIONS, IMAGE_ACTIONS } from './consts'; import { bindTextStream } from './doc-handler'; import { @@ -394,7 +394,10 @@ function updateEdgelessAIPanelConfig< }, }; config.discardCallback = () => { - track.copilot.edgeless.$.discardAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'discard_button', + }); reportResponse('result:discard'); }; config.hideCallback = () => { @@ -513,7 +516,7 @@ export function actionToHandler( togglePanel() .then(isEmpty => { - track.copilot.edgeless.$.startAction({ action: id }); + getTracker(host).action_panel.invokeAction({ action: id }); aiPanel.toggle( referenceElement, isEmpty ? undefined : 'placeholder', diff --git a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts index 8bfcc5f4ab5dd..b7f9cefe2c1a3 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/actions/edgeless-response.ts @@ -97,7 +97,10 @@ export function retry( name: 'Retry', icon: ResetIcon, handler: () => { - getTracker(panel.host).retryAction({ action: id }); + getTracker(panel.host).action_panel.invokeAction({ + action: id, + retry: true, + }); reportResponse('result:retry'); panel.generate(); }, @@ -146,7 +149,10 @@ export function createInsertResp( ); }, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'insert', + }); reportResponse('result:insert'); handler(host, ctx); const panel = getAIPanel(host); @@ -168,7 +174,10 @@ export function asCaption( return id === 'generateCaption' && !!panel.answer; }, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'as_caption', + }); reportResponse('result:use-as-caption'); const panel = getAIPanel(host); const caption = panel.answer; @@ -586,7 +595,10 @@ export function actionToResponse( name: 'Continue in chat', icon: ChatWithAIIcon, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'continue_in_chat', + }); reportResponse('result:continue-in-chat'); const panel = getAIPanel(host); AIProvider.slots.requestOpenWithChat.emit({ host }); @@ -628,17 +640,26 @@ export function actionToErrorResponse< ): ErrorConfig { return { upgrade: () => { - getTracker(host).failureAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'paywall', + }); AIProvider.slots.requestUpgradePlan.emit({ host: panel.host }); panel.hide(); }, login: () => { - getTracker(host).failureAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'login_required', + }); AIProvider.slots.requestLogin.emit({ host: panel.host }); panel.hide(); }, cancel: () => { - getTracker(host).discardAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'paywall', + }); panel.hide(); }, responses: [ diff --git a/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts b/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts index 918ee4216ba92..f3d2033596c24 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/ai-panel.ts @@ -66,7 +66,10 @@ function asCaption( return id === 'generateCaption' && !!panel.answer; }, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'as_caption', + }); reportResponse('result:use-as-caption'); const panel = getAIPanel(host); const caption = panel.answer; @@ -96,7 +99,10 @@ function createNewNote( return !!panel.answer && isInsideEdgelessEditor(host); }, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'insert_note', + }); reportResponse('result:add-note'); // get the note block const { selectedBlocks } = getSelections(host); @@ -202,7 +208,10 @@ export function buildTextResponseConfig< showWhen: () => !!panel.answer && (!id || !INSERT_ABOVE_ACTIONS.includes(id)), handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'insert', + }); reportResponse('result:insert'); insertAnswerBelow(panel).catch(console.error); }, @@ -213,7 +222,10 @@ export function buildTextResponseConfig< showWhen: () => !!panel.answer && !!id && INSERT_ABOVE_ACTIONS.includes(id), handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'insert', + }); reportResponse('result:insert'); insertAnswerAbove(panel).catch(console.error); }, @@ -224,7 +236,10 @@ export function buildTextResponseConfig< icon: ReplaceIcon, showWhen: () => !!panel.answer, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'replace', + }); reportResponse('result:replace'); replaceWithAnswer(panel).catch(console.error); }, @@ -239,7 +254,10 @@ export function buildTextResponseConfig< name: 'Continue in chat', icon: ChatWithAIIcon, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'continue_in_chat', + }); reportResponse('result:continue-in-chat'); AIProvider.slots.requestOpenWithChat.emit({ host }); panel.hide(); @@ -249,7 +267,10 @@ export function buildTextResponseConfig< name: 'Regenerate', icon: RetryIcon, handler: () => { - getTracker(host).retryAction({ action: id }); + getTracker(host).action_panel.invokeAction({ + action: id, + retry: true, + }); reportResponse('result:retry'); panel.generate(); }, @@ -280,7 +301,10 @@ export function buildErrorResponseConfig< icon: ReplaceIcon, showWhen: () => !!panel.answer, handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'replace', + }); replaceWithAnswer(panel).catch(console.error); }, }, @@ -290,7 +314,10 @@ export function buildErrorResponseConfig< showWhen: () => !!panel.answer && (!id || !INSERT_ABOVE_ACTIONS.includes(id)), handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'insert', + }); insertAnswerBelow(panel).catch(console.error); }, }, @@ -300,7 +327,10 @@ export function buildErrorResponseConfig< showWhen: () => !!panel.answer && !!id && INSERT_ABOVE_ACTIONS.includes(id), handler: () => { - getTracker(host).finishAction({ action: id }); + getTracker(host).action_panel.acceptAction({ + action: id, + control: 'insert', + }); reportResponse('result:insert'); insertAnswerAbove(panel).catch(console.error); }, @@ -317,7 +347,10 @@ export function buildErrorResponseConfig< icon: RetryIcon, showWhen: () => true, handler: () => { - getTracker(host).retryAction({ action: id }); + getTracker(host).action_panel.invokeAction({ + action: id, + retry: true, + }); reportResponse('result:retry'); panel.generate(); }, @@ -353,17 +386,26 @@ export function buildErrorConfig( return { upgrade: () => { - getTracker(host).discardAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'paywall', + }); AIProvider.slots.requestUpgradePlan.emit({ host: panel.host }); panel.hide(); }, login: () => { - getTracker(host).discardAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'login_required', + }); AIProvider.slots.requestLogin.emit({ host: panel.host }); panel.hide(); }, cancel: () => { - getTracker(host).discardAction({ action: id }); + getTracker(host).action_panel.discardAction({ + action: id, + control: 'paywall', + }); panel.hide(); }, responses: buildErrorResponseConfig(panel, id), diff --git a/packages/frontend/core/src/blocksuite/presets/ai/utils/track.ts b/packages/frontend/core/src/blocksuite/presets/ai/utils/track.ts index 19fa738511b00..1d793829d74e3 100644 --- a/packages/frontend/core/src/blocksuite/presets/ai/utils/track.ts +++ b/packages/frontend/core/src/blocksuite/presets/ai/utils/track.ts @@ -3,5 +3,5 @@ import type { EditorHost } from '@blocksuite/affine/block-std'; import { isInsideEdgelessEditor } from '@blocksuite/affine/blocks'; export function getTracker(host: EditorHost) { - return track.copilot[isInsideEdgelessEditor(host) ? 'edgeless' : 'page'].$; + return track.copilot[isInsideEdgelessEditor(host) ? 'edgeless' : 'page']; } diff --git a/packages/frontend/track/src/events.ts b/packages/frontend/track/src/events.ts index ebd2622ce6006..58f30dfd0cfaa 100644 --- a/packages/frontend/track/src/events.ts +++ b/packages/frontend/track/src/events.ts @@ -113,14 +113,11 @@ type PaymentEvents = type CopilotEvents = | 'startChat' | 'resetChat' - | 'retryChat' - | 'failureChat' + | 'abortChat' | 'addChatAttachment' - | 'startAction' - | 'retryAction' + | 'invokeAction' | 'discardAction' - | 'failureAction' - | 'finishAction'; + | 'acceptAction'; // END SECTION type UserEvents = @@ -306,31 +303,17 @@ const PageEvents = { }, copilot: { chat: { - $: [ - 'startChat', - 'retryChat', - 'resetChat', - 'failureChat', - 'addChatAttachment', - ], + $: ['startChat', 'abortChat', 'resetChat', 'addChatAttachment'], }, page: { - $: [ - 'startAction', - 'retryAction', - 'discardAction', - 'failureAction', - 'finishAction', - ], + action_panel: ['invokeAction', 'discardAction', 'acceptAction'], + inline_panel: ['invokeAction', 'discardAction', 'acceptAction'], + chat: ['invokeAction', 'discardAction', 'acceptAction'], }, edgeless: { - $: [ - 'startAction', - 'retryAction', - 'discardAction', - 'failureAction', - 'finishAction', - ], + action_panel: ['invokeAction', 'discardAction', 'acceptAction'], + inline_panel: ['invokeAction', 'discardAction', 'acceptAction'], + chat: ['invokeAction', 'discardAction', 'acceptAction'], }, }, // remove when type added @@ -470,11 +453,30 @@ export type EventArgs = { editProperty: { type: string }; addProperty: { type: string; control: 'at menu' | 'property list' }; // copilot - startAction: { action: string }; - retryAction: { action: string }; - discardAction: { action: string }; - failureAction: { action: string }; - finishAction: { action: string }; + invokeAction: { + action: string; + retry?: boolean; + }; + discardAction: { + action: string; + control: + | 'stop_button' + | 'discard_button' + | 'paywall' + | 'backend_policy' + | 'backend_error' + | 'login_required' + | 'retry'; + }; + acceptAction: { + action: string; + control: + | 'insert' + | 'insert_note' + | 'replace' + | 'as_caption' + | 'continue_in_chat'; + }; }; // for type checking