feat(core): apply model tracking (#13128)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added user interaction tracking for document editing and diff review
actions, including accepting, rejecting, applying, and copying changes.
* Introduced tracking for "Accept all" and "Reject all" actions in block
diff views.

* **Chores**
* Enhanced event tracking system with new event types and payloads to
support detailed analytics for editing and review actions.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
德布劳外 · 贾贵
2025-07-10 17:25:05 +08:00
committed by GitHub
parent 3538c78a8b
commit 6b7d1e91e0
4 changed files with 61 additions and 8 deletions
@@ -1,3 +1,4 @@
import track from '@affine/track';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { type EditorHost, ShadowlessElement } from '@blocksuite/affine/std';
@@ -203,24 +204,33 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
}
private async _handleApply(markdown: string) {
if (!this.host) {
if (!this.host || this.data.type !== 'tool-result') {
return;
}
track.applyModel.chat.$.apply({
instruction: this.data.args.instructions,
});
await this.blockDiffService?.apply(this.host.store, markdown);
}
private async _handleReject(changedMarkdown: string) {
if (!this.host) {
if (!this.host || this.data.type !== 'tool-result') {
return;
}
track.applyModel.chat.$.reject({
instruction: this.data.args.instructions,
});
this.blockDiffService?.setChangedMarkdown(changedMarkdown);
this.blockDiffService?.rejectAll();
}
private async _handleAccept(changedMarkdown: string) {
if (!this.host) {
if (!this.host || this.data.type !== 'tool-result') {
return;
}
track.applyModel.chat.$.accept({
instruction: this.data.args.instructions,
});
await this.blockDiffService?.apply(this.host.store, changedMarkdown);
await this.blockDiffService?.acceptAll(this.host.store);
}
@@ -233,6 +243,7 @@ export class DocEditTool extends WithDisposable(ShadowlessElement) {
if (!this.host) {
return;
}
track.applyModel.chat.$.copy();
const success = await copyText(removeMarkdownComments(changedMarkdown));
if (success) {
this.notificationService.notify({
@@ -1,3 +1,4 @@
import track from '@affine/track';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine/shared/theme';
import { CloseIcon, DoneIcon } from '@blocksuite/icons/lit';
@@ -50,12 +51,12 @@ export class BlockDiffOptions extends WithDisposable(LitElement) {
accessor onReject!: (op: PatchOp) => void;
private readonly _handleAcceptClick = () => {
console.log('accept', this.op);
track.applyModel.widget.block.accept();
this.onAccept(this.op);
};
private readonly _handleRejectClick = () => {
console.log('reject', this.op);
track.applyModel.widget.block.reject();
this.onReject(this.op);
};
@@ -1,3 +1,4 @@
import { track } from '@affine/track';
import { WidgetComponent, WidgetViewExtension } from '@blocksuite/affine/std';
import { unsafeCSSVar, unsafeCSSVarV2 } from '@blocksuite/affine-shared/theme';
import {
@@ -82,6 +83,16 @@ export class AffineBlockDiffWidgetForPage extends WidgetComponent {
diffs[this.currentIndex].scrollIntoView({ behavior: 'smooth' });
}
async _handleAcceptAll() {
track.applyModel.widget.page.acceptAll();
await this.diffService.acceptAll(this.std.store);
}
_handleRejectAll() {
track.applyModel.widget.page.rejectAll();
this.diffService.rejectAll();
}
get diffService() {
return this.std.get(BlockDiffProvider);
}
@@ -112,7 +123,7 @@ export class AffineBlockDiffWidgetForPage extends WidgetComponent {
</div>
<div
class="ai-block-diff-all-option"
@click=${() => this.diffService.rejectAll()}
@click=${() => this._handleRejectAll()}
>
${CloseIcon({
style: `color: ${unsafeCSSVarV2('icon/secondary')}`,
@@ -121,7 +132,7 @@ export class AffineBlockDiffWidgetForPage extends WidgetComponent {
</div>
<div
class="ai-block-diff-all-option"
@click=${() => this.diffService.acceptAll(this.std.store)}
@click=${() => this._handleAcceptAll()}
>
${DoneIcon({
style: `color: ${unsafeCSSVarV2('icon/activated')}`,
+31 -1
View File
@@ -207,6 +207,16 @@ type CommentEvents =
| 'resolveComment';
// END SECTION
// SECTION: apply model
type ApplyModelEvents =
| 'acceptAll'
| 'rejectAll'
| 'accept'
| 'reject'
| 'apply'
| 'copy';
// END SECTION
type UserEvents =
| GeneralEvents
| AppEvents
@@ -231,7 +241,8 @@ type UserEvents =
| IntegrationEvents
| MeetingEvents
| MentionEvents
| WorkspaceEmbeddingEvents;
| WorkspaceEmbeddingEvents
| ApplyModelEvents;
interface PageDivision {
[page: string]: {
@@ -564,6 +575,15 @@ interface PageEvents extends PageDivision {
$: ['createDoc'];
};
};
applyModel: {
widget: {
page: ['acceptAll', 'rejectAll'];
block: ['accept', 'reject'];
};
chat: {
$: ['apply', 'accept', 'reject', 'copy'];
};
};
}
type OrganizeItemType = 'doc' | 'folder' | 'collection' | 'tag' | 'favorite';
@@ -635,6 +655,13 @@ type RecordingEventArgs = {
option?: 'Auto transcribing' | 'handle transcribing' | 'on' | 'off';
};
type ApplyModelArgs = {
/* User's complete instruction */
instruction?: string;
/* Split individual semantic change requests */
operation?: string;
};
export type EventArgs = {
createWorkspace: { flavour: string };
signIn: AuthArgs;
@@ -829,6 +856,9 @@ export type EventArgs = {
};
editComment: { type: 'root' | 'node' };
deleteComment: { type: 'root' | 'node' };
accept: ApplyModelArgs;
reject: ApplyModelArgs;
apply: ApplyModelArgs;
};
// for type checking