feat(core): make editor host optional (#12990)
Close [AI-260](https://linear.app/affine-design/issue/AI-260) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## 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. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -80,11 +80,11 @@ declare global {
|
|||||||
retry?: boolean;
|
retry?: boolean;
|
||||||
|
|
||||||
// action's context
|
// action's context
|
||||||
docId: string;
|
docId?: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
|
|
||||||
// internal context
|
// internal context
|
||||||
host: EditorHost;
|
host?: EditorHost;
|
||||||
models?: (BlockModel | GfxModel)[];
|
models?: (BlockModel | GfxModel)[];
|
||||||
control?: TrackerControl;
|
control?: TrackerControl;
|
||||||
where?: TrackerWhere;
|
where?: TrackerWhere;
|
||||||
@@ -142,6 +142,7 @@ declare global {
|
|||||||
docs: AIDocContextOption[];
|
docs: AIDocContextOption[];
|
||||||
files: AIFileContextOption[];
|
files: AIFileContextOption[];
|
||||||
};
|
};
|
||||||
|
postfix?: (text: string) => string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TranslateOptions extends AITextActionOptions {
|
interface TranslateOptions extends AITextActionOptions {
|
||||||
@@ -374,9 +375,9 @@ declare global {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface CreateSessionOptions {
|
interface CreateSessionOptions {
|
||||||
docId: string;
|
|
||||||
workspaceId: string;
|
|
||||||
promptName: PromptKey;
|
promptName: PromptKey;
|
||||||
|
workspaceId: string;
|
||||||
|
docId?: string;
|
||||||
sessionId?: string;
|
sessionId?: string;
|
||||||
retry?: boolean;
|
retry?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor item!: ChatMessage;
|
accessor item!: ChatMessage;
|
||||||
@@ -99,7 +99,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
|||||||
${streamObjects?.length
|
${streamObjects?.length
|
||||||
? this.renderStreamObjects(streamObjects)
|
? this.renderStreamObjects(streamObjects)
|
||||||
: this.renderRichText(content)}
|
: this.renderRichText(content)}
|
||||||
${shouldRenderError ? AIChatErrorRenderer(host, error) : nothing}
|
${shouldRenderError ? AIChatErrorRenderer(error, host) : nothing}
|
||||||
${this.renderEditorActions()}
|
${this.renderEditorActions()}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
@@ -152,9 +152,11 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
|||||||
? mergeStreamContent(streamObjects)
|
? mergeStreamContent(streamObjects)
|
||||||
: content;
|
: content;
|
||||||
|
|
||||||
const actions = isInsidePageEditor(host)
|
const actions = host
|
||||||
? PageEditorActions
|
? isInsidePageEditor(host)
|
||||||
: EdgelessEditorActions;
|
? PageEditorActions
|
||||||
|
: EdgelessEditorActions
|
||||||
|
: null;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<chat-copy-more
|
<chat-copy-more
|
||||||
@@ -167,7 +169,7 @@ export class ChatMessageAssistant extends WithDisposable(ShadowlessElement) {
|
|||||||
.withMargin=${true}
|
.withMargin=${true}
|
||||||
.retry=${() => this.retry()}
|
.retry=${() => this.retry()}
|
||||||
></chat-copy-more>
|
></chat-copy-more>
|
||||||
${isLast && !!markdown
|
${isLast && !!markdown && host
|
||||||
? html`<chat-action-list
|
? html`<chat-action-list
|
||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.host=${host}
|
.host=${host}
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ export class ChatPanelChips extends SignalWatcher(
|
|||||||
private _abortController: AbortController | null = null;
|
private _abortController: AbortController | null = null;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chips!: ChatChip[];
|
accessor chips!: ChatChip[];
|
||||||
@@ -407,6 +407,9 @@ export class ChatPanelChips extends SignalWatcher(
|
|||||||
if (!contextId || !AIProvider.context) {
|
if (!contextId || !AIProvider.context) {
|
||||||
throw new Error('Context not found');
|
throw new Error('Context not found');
|
||||||
}
|
}
|
||||||
|
if (!this.host) {
|
||||||
|
throw new Error('Host not found');
|
||||||
|
}
|
||||||
const blobId = await this.host.store.blobSync.set(chip.file);
|
const blobId = await this.host.store.blobSync.set(chip.file);
|
||||||
const contextFile = await AIProvider.context.addContextFile(chip.file, {
|
const contextFile = await AIProvider.context.addContextFile(chip.file, {
|
||||||
contextId,
|
contextId,
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export class ChatPanelDocChip extends SignalWatcher(
|
|||||||
accessor docDisplayConfig!: DocDisplayConfig;
|
accessor docDisplayConfig!: DocDisplayConfig;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
private chipName = new Signal<string>('');
|
private chipName = new Signal<string>('');
|
||||||
|
|
||||||
@@ -103,6 +103,9 @@ export class ChatPanelDocChip extends SignalWatcher(
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly processDocChip = async () => {
|
private readonly processDocChip = async () => {
|
||||||
|
if (!this.host) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const doc = this.docDisplayConfig.getDoc(this.chip.docId);
|
const doc = this.docDisplayConfig.getDoc(this.chip.docId);
|
||||||
if (!doc) {
|
if (!doc) {
|
||||||
|
|||||||
@@ -51,11 +51,14 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor workspaceId!: string;
|
accessor workspaceId!: string;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor docId: string | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor session!: CopilotSessionType | null | undefined;
|
accessor session!: CopilotSessionType | null | undefined;
|
||||||
|
|
||||||
@@ -124,8 +127,10 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
></chat-panel-chips>
|
></chat-panel-chips>
|
||||||
<ai-chat-input
|
<ai-chat-input
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
.chips=${this.chips}
|
.workspaceId=${this.workspaceId}
|
||||||
|
.docId=${this.docId}
|
||||||
.session=${this.session}
|
.session=${this.session}
|
||||||
|
.chips=${this.chips}
|
||||||
.createSession=${this.createSession}
|
.createSession=${this.createSession}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
.updateContext=${this.updateContext}
|
.updateContext=${this.updateContext}
|
||||||
@@ -224,13 +229,12 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
|
|
||||||
const fileChips: FileChip[] = await Promise.all(
|
const fileChips: FileChip[] = await Promise.all(
|
||||||
files.map(async file => {
|
files.map(async file => {
|
||||||
const blob = await this.host.store.blobSync.get(file.blobId);
|
|
||||||
return {
|
return {
|
||||||
file: new File(blob ? [blob] : [], file.name),
|
file: new File([], file.name),
|
||||||
blobId: file.blobId,
|
blobId: file.blobId,
|
||||||
fileId: file.id,
|
fileId: file.id,
|
||||||
state: blob ? file.status : 'failed',
|
state: file.status,
|
||||||
tooltip: blob ? file.error : 'File not found in blob storage',
|
tooltip: file.error,
|
||||||
createdAt: file.createdAt,
|
createdAt: file.createdAt,
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
@@ -302,7 +306,7 @@ export class AIChatComposer extends SignalWatcher(
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
await AIProvider.context?.pollEmbeddingStatus(
|
await AIProvider.context?.pollEmbeddingStatus(
|
||||||
this.host.std.workspace.id,
|
this.workspaceId,
|
||||||
(status: ContextWorkspaceEmbeddingStatus) => {
|
(status: ContextWorkspaceEmbeddingStatus) => {
|
||||||
if (!status) {
|
if (!status) {
|
||||||
this.embeddingCompleted = false;
|
this.embeddingCompleted = false;
|
||||||
|
|||||||
@@ -72,10 +72,10 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chatTitle!: TemplateResult<1>;
|
accessor chatTitle: TemplateResult<1> | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor session!: CopilotSessionType | null | undefined;
|
accessor session!: CopilotSessionType | null | undefined;
|
||||||
@@ -288,6 +288,8 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
<ai-chat-messages
|
<ai-chat-messages
|
||||||
${ref(this.chatMessagesRef)}
|
${ref(this.chatMessagesRef)}
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
|
.workspaceId=${this.workspaceId}
|
||||||
|
.docId=${this.docId}
|
||||||
.session=${this.session}
|
.session=${this.session}
|
||||||
.createSession=${this.createSession}
|
.createSession=${this.createSession}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
@@ -302,6 +304,7 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
<ai-chat-composer
|
<ai-chat-composer
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
.workspaceId=${this.workspaceId}
|
.workspaceId=${this.workspaceId}
|
||||||
|
.docId=${this.docId}
|
||||||
.session=${this.session}
|
.session=${this.session}
|
||||||
.createSession=${this.createSession}
|
.createSession=${this.createSession}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
|
|||||||
@@ -281,7 +281,13 @@ export class AIChatInput extends SignalWatcher(
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@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 })
|
@property({ attribute: false })
|
||||||
accessor session!: CopilotSessionType | null | undefined;
|
accessor session!: CopilotSessionType | null | undefined;
|
||||||
@@ -596,10 +602,9 @@ export class AIChatInput extends SignalWatcher(
|
|||||||
sessionId,
|
sessionId,
|
||||||
input: userInput,
|
input: userInput,
|
||||||
contexts,
|
contexts,
|
||||||
docId: this.host.store.id,
|
docId: this.docId,
|
||||||
attachments: images,
|
attachments: images,
|
||||||
workspaceId: this.host.store.workspace.id,
|
workspaceId: this.workspaceId,
|
||||||
host: this.host,
|
|
||||||
stream: true,
|
stream: true,
|
||||||
signal: abortController.signal,
|
signal: abortController.signal,
|
||||||
isRootSession: this.isRootSession,
|
isRootSession: this.isRootSession,
|
||||||
@@ -681,8 +686,8 @@ export class AIChatInput extends SignalWatcher(
|
|||||||
const last = messages[messages.length - 1] as ChatMessage;
|
const last = messages[messages.length - 1] as ChatMessage;
|
||||||
if (!last.id) {
|
if (!last.id) {
|
||||||
const historyIds = await AIProvider.histories.ids(
|
const historyIds = await AIProvider.histories.ids(
|
||||||
this.host.store.workspace.id,
|
this.workspaceId,
|
||||||
this.host.store.id,
|
this.docId,
|
||||||
{ sessionId }
|
{ sessionId }
|
||||||
);
|
);
|
||||||
if (!historyIds || !historyIds[0]) return;
|
if (!historyIds || !historyIds[0]) return;
|
||||||
|
|||||||
@@ -141,7 +141,13 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor avatarUrl = '';
|
accessor avatarUrl = '';
|
||||||
|
|
||||||
@property({ attribute: false })
|
@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 })
|
@property({ attribute: false })
|
||||||
accessor isHistoryLoading!: boolean;
|
accessor isHistoryLoading!: boolean;
|
||||||
@@ -305,7 +311,7 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
.retry=${() => this.retry()}
|
.retry=${() => this.retry()}
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
></chat-message-assistant>`;
|
></chat-message-assistant>`;
|
||||||
} else if (isChatAction(item)) {
|
} else if (isChatAction(item) && this.host) {
|
||||||
return html`<chat-message-action
|
return html`<chat-message-action
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
.item=${item}
|
.item=${item}
|
||||||
@@ -330,7 +336,6 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
override connectedCallback() {
|
override connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
const { disposables } = this;
|
const { disposables } = this;
|
||||||
const docModeService = this.host.std.get(DocModeProvider);
|
|
||||||
|
|
||||||
Promise.resolve(AIProvider.userInfo)
|
Promise.resolve(AIProvider.userInfo)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@@ -351,17 +356,25 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
disposables.add(
|
|
||||||
this.host.selection.slots.changed.subscribe(() => {
|
const selection$ = this.host?.selection.slots.changed;
|
||||||
this._selectionValue = this.host.selection.value;
|
if (selection$) {
|
||||||
})
|
disposables.add(
|
||||||
);
|
selection$.subscribe(() => {
|
||||||
disposables.add(
|
this._selectionValue = this.host?.selection.value ?? [];
|
||||||
docModeService.onPrimaryModeChange(
|
})
|
||||||
() => this.requestUpdate(),
|
);
|
||||||
this.host.store.id
|
}
|
||||||
)
|
|
||||||
);
|
const docModeService = this.host?.std.get(DocModeProvider);
|
||||||
|
if (docModeService && this.docId) {
|
||||||
|
disposables.add(
|
||||||
|
docModeService.onPrimaryModeChange(
|
||||||
|
() => this.requestUpdate(),
|
||||||
|
this.docId
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override updated(_changedProperties: PropertyValues) {
|
protected override updated(_changedProperties: PropertyValues) {
|
||||||
@@ -400,13 +413,11 @@ export class AIChatMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
abortController,
|
abortController,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { store } = this.host;
|
|
||||||
const stream = await AIProvider.actions.chat({
|
const stream = await AIProvider.actions.chat({
|
||||||
sessionId,
|
sessionId,
|
||||||
retry: true,
|
retry: true,
|
||||||
docId: store.id,
|
docId: this.docId,
|
||||||
workspaceId: store.workspace.id,
|
workspaceId: this.workspaceId,
|
||||||
host: this.host,
|
|
||||||
stream: true,
|
stream: true,
|
||||||
signal: abortController.signal,
|
signal: abortController.signal,
|
||||||
where: 'chat-panel',
|
where: 'chat-panel',
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor session!: CopilotSessionType | null | undefined;
|
accessor session!: CopilotSessionType | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor doc!: Store;
|
accessor doc!: Store;
|
||||||
@@ -52,18 +52,19 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sessionId = this.session.id;
|
const sessionId = this.session.id;
|
||||||
const notification = this.host.std.getOptional(NotificationProvider);
|
const notification = this.host?.std.getOptional(NotificationProvider);
|
||||||
if (!notification) return;
|
|
||||||
try {
|
try {
|
||||||
if (
|
const confirm = notification
|
||||||
await notification.confirm({
|
? await notification.confirm({
|
||||||
title: 'Clear History',
|
title: 'Clear History',
|
||||||
message:
|
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.',
|
'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',
|
confirmText: 'Confirm',
|
||||||
cancelText: 'Cancel',
|
cancelText: 'Cancel',
|
||||||
})
|
})
|
||||||
) {
|
: true;
|
||||||
|
|
||||||
|
if (confirm) {
|
||||||
const actionIds = this.chatContextValue.messages
|
const actionIds = this.chatContextValue.messages
|
||||||
.filter(item => 'sessionId' in item)
|
.filter(item => 'sessionId' in item)
|
||||||
.map(item => item.sessionId);
|
.map(item => item.sessionId);
|
||||||
@@ -72,11 +73,11 @@ export class AIHistoryClear extends WithDisposable(ShadowlessElement) {
|
|||||||
this.doc.id,
|
this.doc.id,
|
||||||
[...(sessionId ? [sessionId] : []), ...(actionIds || [])]
|
[...(sessionId ? [sessionId] : []), ...(actionIds || [])]
|
||||||
);
|
);
|
||||||
notification.toast('History cleared');
|
notification?.toast('History cleared');
|
||||||
this.onHistoryCleared?.();
|
this.onHistoryCleared?.();
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
notification.toast('Failed to clear history');
|
notification?.toast('Failed to clear history');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { createTextRenderer } from '../../components/text-renderer';
|
|||||||
|
|
||||||
export class ChatContentRichText extends WithDisposable(ShadowlessElement) {
|
export class ChatContentRichText extends WithDisposable(ShadowlessElement) {
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor text!: string;
|
accessor text!: string;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
import type { FeatureFlagService } from '@affine/core/modules/feature-flag';
|
||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
||||||
|
import { ImageProxyService } from '@blocksuite/affine/shared/adapters';
|
||||||
import type { EditorHost } from '@blocksuite/affine/std';
|
import type { EditorHost } from '@blocksuite/affine/std';
|
||||||
import { ShadowlessElement } from '@blocksuite/affine/std';
|
import { ShadowlessElement } from '@blocksuite/affine/std';
|
||||||
import type { ExtensionType } from '@blocksuite/affine/store';
|
import type { ExtensionType } from '@blocksuite/affine/store';
|
||||||
@@ -26,7 +27,7 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
accessor answer!: StreamObject[];
|
accessor answer!: StreamObject[];
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor state: AffineAIPanelState = 'finished';
|
accessor state: AffineAIPanelState = 'finished';
|
||||||
@@ -44,32 +45,28 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
if (streamObject.type !== 'tool-call') {
|
if (streamObject.type !== 'tool-call') {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
const imageProxyService = this.host?.store.get(ImageProxyService);
|
||||||
switch (streamObject.toolName) {
|
switch (streamObject.toolName) {
|
||||||
case 'web_crawl_exa':
|
case 'web_crawl_exa':
|
||||||
return html`
|
return html`
|
||||||
<web-crawl-tool
|
<web-crawl-tool
|
||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.host=${this.host}
|
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${imageProxyService}
|
||||||
></web-crawl-tool>
|
></web-crawl-tool>
|
||||||
`;
|
`;
|
||||||
case 'web_search_exa':
|
case 'web_search_exa':
|
||||||
return html`
|
return html`
|
||||||
<web-search-tool
|
<web-search-tool
|
||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.host=${this.host}
|
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${imageProxyService}
|
||||||
></web-search-tool>
|
></web-search-tool>
|
||||||
`;
|
`;
|
||||||
default: {
|
default: {
|
||||||
const name = streamObject.toolName + ' tool calling';
|
const name = streamObject.toolName + ' tool calling';
|
||||||
return html`
|
return html`
|
||||||
<tool-call-card
|
<tool-call-card .name=${name} .width=${this.width}></tool-call-card>
|
||||||
.name=${name}
|
|
||||||
.host=${this.host}
|
|
||||||
.width=${this.width}
|
|
||||||
></tool-call-card>
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,22 +76,22 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
if (streamObject.type !== 'tool-result') {
|
if (streamObject.type !== 'tool-result') {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
const imageProxyService = this.host?.store.get(ImageProxyService);
|
||||||
switch (streamObject.toolName) {
|
switch (streamObject.toolName) {
|
||||||
case 'web_crawl_exa':
|
case 'web_crawl_exa':
|
||||||
return html`
|
return html`
|
||||||
<web-crawl-tool
|
<web-crawl-tool
|
||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.host=${this.host}
|
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${imageProxyService}
|
||||||
></web-crawl-tool>
|
></web-crawl-tool>
|
||||||
`;
|
`;
|
||||||
case 'web_search_exa':
|
case 'web_search_exa':
|
||||||
return html`
|
return html`
|
||||||
<web-search-tool
|
<web-search-tool
|
||||||
.data=${streamObject}
|
.data=${streamObject}
|
||||||
.host=${this.host}
|
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${imageProxyService}
|
||||||
></web-search-tool>
|
></web-search-tool>
|
||||||
`;
|
`;
|
||||||
default: {
|
default: {
|
||||||
@@ -102,8 +99,8 @@ export class ChatContentStreamObjects extends WithDisposable(
|
|||||||
return html`
|
return html`
|
||||||
<tool-result-card
|
<tool-result-card
|
||||||
.name=${name}
|
.name=${name}
|
||||||
.host=${this.host}
|
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${imageProxyService}
|
||||||
></tool-result-card>
|
></tool-result-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ export class AIScrollableTextRenderer extends WithDisposable(
|
|||||||
accessor answer!: string;
|
accessor answer!: string;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host: EditorHost | null = null;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor state: AffineAIPanelState | undefined = undefined;
|
accessor state: AffineAIPanelState | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor textRendererOptions!: TextRendererOptions;
|
accessor textRendererOptions!: TextRendererOptions;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { SignalWatcher, WithDisposable } from '@blocksuite/affine/global/lit';
|
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 { 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 { ToggleDownIcon, ToolIcon } from '@blocksuite/icons/lit';
|
||||||
import { type Signal } from '@preact/signals-core';
|
import { type Signal } from '@preact/signals-core';
|
||||||
import { css, html, nothing, type TemplateResult } from 'lit';
|
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 })
|
@property({ attribute: false })
|
||||||
accessor name: string = 'Tool result';
|
accessor name: string = 'Tool result';
|
||||||
|
|
||||||
@@ -208,6 +205,9 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor width: Signal<number | undefined> | undefined;
|
accessor width: Signal<number | undefined> | undefined;
|
||||||
|
|
||||||
|
@property({ attribute: false })
|
||||||
|
accessor imageProxyService: ImageProxyService | null | undefined;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
private accessor isCollapsed = true;
|
private accessor isCollapsed = true;
|
||||||
|
|
||||||
@@ -276,9 +276,11 @@ export class ToolResultCard extends SignalWatcher(
|
|||||||
if (!icon) {
|
if (!icon) {
|
||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
const imageProxyService = this.host.store.get(ImageProxyService);
|
|
||||||
if (typeof icon === 'string') {
|
if (typeof icon === 'string') {
|
||||||
return html` <img src=${imageProxyService.buildUrl(icon)} /> `;
|
if (this.imageProxyService) {
|
||||||
|
return html`<img src=${this.imageProxyService.buildUrl(icon)} />`;
|
||||||
|
}
|
||||||
|
return html`<img src=${icon} />`;
|
||||||
}
|
}
|
||||||
return html`${icon}`;
|
return html`${icon}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
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 { WebIcon } from '@blocksuite/icons/lit';
|
||||||
import type { Signal } from '@preact/signals-core';
|
import type { Signal } from '@preact/signals-core';
|
||||||
import { html, nothing } from 'lit';
|
import { html, nothing } from 'lit';
|
||||||
@@ -37,10 +38,10 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor data!: WebCrawlToolCall | WebCrawlToolResult;
|
accessor data!: WebCrawlToolCall | WebCrawlToolResult;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor width: Signal<number | undefined> | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor width: Signal<number | undefined> | undefined;
|
accessor imageProxyService: ImageProxyService | null | undefined;
|
||||||
|
|
||||||
renderToolCall() {
|
renderToolCall() {
|
||||||
return html`
|
return html`
|
||||||
@@ -61,7 +62,6 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) {
|
|||||||
const { favicon, title, content } = result[0];
|
const { favicon, title, content } = result[0];
|
||||||
return html`
|
return html`
|
||||||
<tool-result-card
|
<tool-result-card
|
||||||
.host=${this.host}
|
|
||||||
.name=${'The reading is complete, and this webpage has been read'}
|
.name=${'The reading is complete, and this webpage has been read'}
|
||||||
.icon=${WebIcon()}
|
.icon=${WebIcon()}
|
||||||
.footerIcons=${favicon ? [favicon] : []}
|
.footerIcons=${favicon ? [favicon] : []}
|
||||||
@@ -73,6 +73,7 @@ export class WebCrawlTool extends WithDisposable(ShadowlessElement) {
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${this.imageProxyService}
|
||||||
></tool-result-card>
|
></tool-result-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { WithDisposable } from '@blocksuite/affine/global/lit';
|
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 { WebIcon } from '@blocksuite/icons/lit';
|
||||||
import type { Signal } from '@preact/signals-core';
|
import type { Signal } from '@preact/signals-core';
|
||||||
import { html, nothing } from 'lit';
|
import { html, nothing } from 'lit';
|
||||||
@@ -37,10 +38,10 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor data!: WebSearchToolCall | WebSearchToolResult;
|
accessor data!: WebSearchToolCall | WebSearchToolResult;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor width: Signal<number | undefined> | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor width: Signal<number | undefined> | undefined;
|
accessor imageProxyService: ImageProxyService | null | undefined;
|
||||||
|
|
||||||
renderToolCall() {
|
renderToolCall() {
|
||||||
return html`
|
return html`
|
||||||
@@ -69,12 +70,12 @@ export class WebSearchTool extends WithDisposable(ShadowlessElement) {
|
|||||||
|
|
||||||
return html`
|
return html`
|
||||||
<tool-result-card
|
<tool-result-card
|
||||||
.host=${this.host}
|
|
||||||
.name=${'The search is complete, and these webpages have been searched'}
|
.name=${'The search is complete, and these webpages have been searched'}
|
||||||
.icon=${WebIcon()}
|
.icon=${WebIcon()}
|
||||||
.footerIcons=${footerIcons}
|
.footerIcons=${footerIcons}
|
||||||
.results=${results}
|
.results=${results}
|
||||||
.width=${this.width}
|
.width=${this.width}
|
||||||
|
.imageProxyService=${this.imageProxyService}
|
||||||
></tool-result-card>
|
></tool-result-card>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
private get _selectionValue() {
|
private get _selectionValue() {
|
||||||
return this.host.selection.value;
|
return this.host?.selection.value ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _currentTextSelection(): TextSelection | undefined {
|
private get _currentTextSelection(): TextSelection | undefined {
|
||||||
@@ -105,7 +105,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
private _morePopper: ReturnType<typeof createButtonPopper> | null = null;
|
private _morePopper: ReturnType<typeof createButtonPopper> | null = null;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor actions: ChatAction[] = [];
|
accessor actions: ChatAction[] = [];
|
||||||
@@ -136,7 +136,8 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly _notifySuccess = (title: string) => {
|
private readonly _notifySuccess = (title: string) => {
|
||||||
const notificationService = this.host.std.getOptional(NotificationProvider);
|
const notificationService =
|
||||||
|
this.host?.std.getOptional(NotificationProvider);
|
||||||
notificationService?.notify({
|
notificationService?.notify({
|
||||||
title: title,
|
title: title,
|
||||||
accent: 'success',
|
accent: 'success',
|
||||||
@@ -174,7 +175,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<div class="copy-more">
|
<div class="copy-more">
|
||||||
${content
|
${content && host
|
||||||
? html`<div
|
? html`<div
|
||||||
class="button copy"
|
class="button copy"
|
||||||
@click=${async () => {
|
@click=${async () => {
|
||||||
@@ -199,19 +200,19 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
<affine-tooltip .autoShift=${true}>Retry</affine-tooltip>
|
<affine-tooltip .autoShift=${true}>Retry</affine-tooltip>
|
||||||
</div>`
|
</div>`
|
||||||
: nothing}
|
: nothing}
|
||||||
${isLast
|
${!isLast && host
|
||||||
? nothing
|
? html`<div
|
||||||
: html`<div
|
|
||||||
class="button more"
|
class="button more"
|
||||||
data-testid="action-more-button"
|
data-testid="action-more-button"
|
||||||
@click=${this._toggle}
|
@click=${this._toggle}
|
||||||
>
|
>
|
||||||
${MoreHorizontalIcon({ width: '20px', height: '20px' })}
|
${MoreHorizontalIcon({ width: '20px', height: '20px' })}
|
||||||
</div> `}
|
</div> `
|
||||||
|
: nothing}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="more-menu">
|
<div class="more-menu">
|
||||||
${this._showMoreMenu
|
${this._showMoreMenu && host
|
||||||
? repeat(
|
? repeat(
|
||||||
actions.filter(action => action.showWhen(host)),
|
actions.filter(action => action.showWhen(host)),
|
||||||
action => action.title,
|
action => action.title,
|
||||||
|
|||||||
@@ -298,6 +298,8 @@ export class PlaygroundChat extends SignalWatcher(
|
|||||||
<ai-chat-messages
|
<ai-chat-messages
|
||||||
${ref(this._chatMessagesRef)}
|
${ref(this._chatMessagesRef)}
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
|
.workspaceId=${this.doc.workspace.id}
|
||||||
|
.docId=${this.doc.id}
|
||||||
.isHistoryLoading=${this.isLoading}
|
.isHistoryLoading=${this.isLoading}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
.session=${this.session}
|
.session=${this.session}
|
||||||
@@ -311,6 +313,7 @@ export class PlaygroundChat extends SignalWatcher(
|
|||||||
<ai-chat-composer
|
<ai-chat-composer
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
.workspaceId=${this.doc.workspace.id}
|
.workspaceId=${this.doc.workspace.id}
|
||||||
|
.docId=${this.doc.id}
|
||||||
.session=${this.session}
|
.session=${this.session}
|
||||||
.createSession=${this._createSession}
|
.createSession=${this._createSession}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
|
|||||||
@@ -415,7 +415,7 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor answer!: string;
|
accessor answer!: string;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host: EditorHost | null = null;
|
accessor host: EditorHost | null | undefined;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor schema: Schema | null = null;
|
accessor schema: Schema | null = null;
|
||||||
@@ -428,7 +428,7 @@ export class TextRenderer extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const createTextRenderer = (
|
export const createTextRenderer = (
|
||||||
host: EditorHost,
|
host: EditorHost | null | undefined,
|
||||||
options: TextRendererOptions
|
options: TextRendererOptions
|
||||||
) => {
|
) => {
|
||||||
return (answer: string, state?: AffineAIPanelState) => {
|
return (answer: string, state?: AffineAIPanelState) => {
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ export class AIErrorWrapper extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
accessor testId = 'ai-error';
|
accessor testId = 'ai-error';
|
||||||
}
|
}
|
||||||
|
|
||||||
const PaymentRequiredErrorRenderer = (host: EditorHost) => html`
|
const PaymentRequiredErrorRenderer = (host?: EditorHost | null) => html`
|
||||||
<ai-error-wrapper
|
<ai-error-wrapper
|
||||||
.text=${"You've reached the current usage cap for AFFiNE AI. You can subscribe to AFFiNE AI(with free 7-day-trial) to continue the AI experience!"}
|
.text=${"You've reached the current usage cap for AFFiNE AI. You can subscribe to AFFiNE AI(with free 7-day-trial) to continue the AI experience!"}
|
||||||
.actionText=${'Upgrade'}
|
.actionText=${'Upgrade'}
|
||||||
@@ -194,7 +194,7 @@ const PaymentRequiredErrorRenderer = (host: EditorHost) => html`
|
|||||||
></ai-error-wrapper>
|
></ai-error-wrapper>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const LoginRequiredErrorRenderer = (host: EditorHost) => html`
|
const LoginRequiredErrorRenderer = (host?: EditorHost | null) => html`
|
||||||
<ai-error-wrapper
|
<ai-error-wrapper
|
||||||
.text=${'You need to login to AFFiNE Cloud to continue using AFFiNE AI.'}
|
.text=${'You need to login to AFFiNE Cloud to continue using AFFiNE AI.'}
|
||||||
.actionText=${'Login'}
|
.actionText=${'Login'}
|
||||||
@@ -227,7 +227,7 @@ const GeneralErrorRenderer = (props: ErrorProps = {}) => {
|
|||||||
></ai-error-wrapper>`;
|
></ai-error-wrapper>`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AIChatErrorRenderer(host: EditorHost, error: AIError) {
|
export function AIChatErrorRenderer(error: AIError, host?: EditorHost | null) {
|
||||||
if (error instanceof PaymentRequiredError) {
|
if (error instanceof PaymentRequiredError) {
|
||||||
return PaymentRequiredErrorRenderer(host);
|
return PaymentRequiredErrorRenderer(host);
|
||||||
} else if (error instanceof UnauthorizedError) {
|
} else if (error instanceof UnauthorizedError) {
|
||||||
|
|||||||
@@ -471,7 +471,7 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
.message=${message}
|
.message=${message}
|
||||||
.textRendererOptions=${this._textRendererOptions}
|
.textRendererOptions=${this._textRendererOptions}
|
||||||
></ai-chat-block-message>
|
></ai-chat-block-message>
|
||||||
${shouldRenderError ? AIChatErrorRenderer(host, error) : nothing}
|
${shouldRenderError ? AIChatErrorRenderer(error, host) : nothing}
|
||||||
${shouldRenderCopyMore
|
${shouldRenderCopyMore
|
||||||
? html` <chat-copy-more
|
? html` <chat-copy-more
|
||||||
.host=${host}
|
.host=${host}
|
||||||
@@ -590,6 +590,7 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
<ai-chat-composer
|
<ai-chat-composer
|
||||||
.host=${host}
|
.host=${host}
|
||||||
.workspaceId=${this.rootWorkspaceId}
|
.workspaceId=${this.rootWorkspaceId}
|
||||||
|
.docId=${this.rootDocId}
|
||||||
.session=${this.forkSession ?? this.session}
|
.session=${this.forkSession ?? this.session}
|
||||||
.createSession=${this.createForkSession}
|
.createSession=${this.createForkSession}
|
||||||
.chatContextValue=${chatContext}
|
.chatContextValue=${chatContext}
|
||||||
|
|||||||
@@ -139,8 +139,8 @@ export class AIProvider {
|
|||||||
template: string;
|
template: string;
|
||||||
mode: 'page' | 'edgeless';
|
mode: 'page' | 'edgeless';
|
||||||
}>(),
|
}>(),
|
||||||
requestLogin: new Subject<{ host: EditorHost }>(),
|
requestLogin: new Subject<{ host?: EditorHost | null }>(),
|
||||||
requestUpgradePlan: new Subject<{ host: EditorHost }>(),
|
requestUpgradePlan: new Subject<{ host?: EditorHost | null }>(),
|
||||||
// stream of AI actions triggered by users
|
// stream of AI actions triggered by users
|
||||||
actions: new Subject<{
|
actions: new Subject<{
|
||||||
action: keyof BlockSuitePresets.AIActions;
|
action: keyof BlockSuitePresets.AIActions;
|
||||||
|
|||||||
@@ -42,24 +42,26 @@ const processTypeToPromptName = new Map<string, PromptKey>(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
interface CreateSessionOptions {
|
||||||
|
promptName: PromptKey;
|
||||||
|
workspaceId: string;
|
||||||
|
docId?: string;
|
||||||
|
sessionId?: string;
|
||||||
|
retry?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export function setupAIProvider(
|
export function setupAIProvider(
|
||||||
client: CopilotClient,
|
client: CopilotClient,
|
||||||
globalDialogService: GlobalDialogService,
|
globalDialogService: GlobalDialogService,
|
||||||
authService: AuthService
|
authService: AuthService
|
||||||
) {
|
) {
|
||||||
async function createSession({
|
async function createSession({
|
||||||
|
promptName,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
docId,
|
docId,
|
||||||
promptName,
|
|
||||||
sessionId,
|
sessionId,
|
||||||
retry,
|
retry,
|
||||||
}: {
|
}: CreateSessionOptions) {
|
||||||
workspaceId: string;
|
|
||||||
docId: string;
|
|
||||||
promptName: PromptKey;
|
|
||||||
sessionId?: string;
|
|
||||||
retry?: boolean;
|
|
||||||
}) {
|
|
||||||
if (sessionId) return sessionId;
|
if (sessionId) return sessionId;
|
||||||
if (retry) return AIProvider.LAST_ACTION_SESSIONID;
|
if (retry) return AIProvider.LAST_ACTION_SESSIONID;
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type AIActionEventName =
|
|||||||
| 'AI result accepted';
|
| 'AI result accepted';
|
||||||
|
|
||||||
type AIActionEventProperties = {
|
type AIActionEventProperties = {
|
||||||
page: 'doc' | 'edgeless';
|
page: 'doc' | 'edgeless' | 'unknown';
|
||||||
segment:
|
segment:
|
||||||
| 'AI action panel'
|
| 'AI action panel'
|
||||||
| 'right side bar'
|
| 'right side bar'
|
||||||
@@ -58,7 +58,7 @@ type AIActionEventProperties = {
|
|||||||
| 'other';
|
| 'other';
|
||||||
category: string;
|
category: string;
|
||||||
other: Record<string, unknown>;
|
other: Record<string, unknown>;
|
||||||
docId: string;
|
docId?: string;
|
||||||
workspaceId: string;
|
workspaceId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -231,7 +231,9 @@ const toTrackedOptions = (
|
|||||||
|
|
||||||
if (!eventName) return null;
|
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 otherProperties = omit(event.options, defaultActionOptions);
|
||||||
const type = inferObjectType(event);
|
const type = inferObjectType(event);
|
||||||
const segment = inferSegment(event);
|
const segment = inferSegment(event);
|
||||||
|
|||||||
Reference in New Issue
Block a user