refactor(core): lazy create copilot session and context (#10170)
This commit is contained in:
@@ -83,7 +83,7 @@ export class ChatActionList extends LitElement {
|
|||||||
accessor content: string = '';
|
accessor content: string = '';
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chatSessionId: string | undefined = undefined;
|
accessor getSessionId!: () => Promise<string | undefined>;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor messageId: string | undefined = undefined;
|
accessor messageId: string | undefined = undefined;
|
||||||
@@ -100,7 +100,7 @@ export class ChatActionList extends LitElement {
|
|||||||
return nothing;
|
return nothing;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { host, content, chatSessionId, messageId, layoutDirection } = this;
|
const { host, content, messageId, layoutDirection } = this;
|
||||||
const classes = classMap({
|
const classes = classMap({
|
||||||
'actions-container': true,
|
'actions-container': true,
|
||||||
horizontal: layoutDirection === 'horizontal',
|
horizontal: layoutDirection === 'horizontal',
|
||||||
@@ -138,11 +138,12 @@ export class ChatActionList extends LitElement {
|
|||||||
blocks: this._currentBlockSelections,
|
blocks: this._currentBlockSelections,
|
||||||
images: this._currentImageSelections,
|
images: this._currentImageSelections,
|
||||||
};
|
};
|
||||||
|
const sessionId = await this.getSessionId();
|
||||||
const success = await action.handler(
|
const success = await action.handler(
|
||||||
host,
|
host,
|
||||||
content,
|
content,
|
||||||
currentSelections,
|
currentSelections,
|
||||||
chatSessionId,
|
sessionId,
|
||||||
messageId
|
messageId
|
||||||
);
|
);
|
||||||
if (success) {
|
if (success) {
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
accessor content!: string;
|
accessor content!: string;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chatSessionId: string | undefined = undefined;
|
accessor getSessionId!: () => Promise<string | undefined>;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor messageId: string | undefined = undefined;
|
accessor messageId: string | undefined = undefined;
|
||||||
@@ -162,7 +162,7 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override render() {
|
override render() {
|
||||||
const { host, content, isLast, messageId, chatSessionId, actions } = this;
|
const { host, content, isLast, messageId, actions } = this;
|
||||||
return html`<style>
|
return html`<style>
|
||||||
.copy-more {
|
.copy-more {
|
||||||
margin-top: ${this.withMargin ? '8px' : '0px'};
|
margin-top: ${this.withMargin ? '8px' : '0px'};
|
||||||
@@ -217,11 +217,12 @@ export class ChatCopyMore extends WithDisposable(LitElement) {
|
|||||||
};
|
};
|
||||||
return html`<div
|
return html`<div
|
||||||
@click=${async () => {
|
@click=${async () => {
|
||||||
|
const sessionId = await this.getSessionId();
|
||||||
const success = await action.handler(
|
const success = await action.handler(
|
||||||
host,
|
host,
|
||||||
content,
|
content,
|
||||||
currentSelections,
|
currentSelections,
|
||||||
chatSessionId,
|
sessionId,
|
||||||
messageId
|
messageId
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export class ChatPanelChips extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor chatContextValue!: ChatContextValue;
|
accessor chatContextValue!: ChatContextValue;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chatContextId!: string | undefined;
|
accessor getContextId!: () => Promise<string | undefined>;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor updateContext!: (context: Partial<ChatContextValue>) => void;
|
accessor updateContext!: (context: Partial<ChatContextValue>) => void;
|
||||||
@@ -196,34 +196,36 @@ export class ChatPanelChips extends WithDisposable(ShadowlessElement) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _addToContext = async (chip: ChatChip) => {
|
private readonly _addToContext = async (chip: ChatChip) => {
|
||||||
if (!AIProvider.context || !this.chatContextId) {
|
const contextId = await this.getContextId();
|
||||||
|
if (!contextId || !AIProvider.context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDocChip(chip)) {
|
if (isDocChip(chip)) {
|
||||||
await AIProvider.context.addContextDoc({
|
await AIProvider.context.addContextDoc({
|
||||||
contextId: this.chatContextId,
|
contextId,
|
||||||
docId: chip.docId,
|
docId: chip.docId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await AIProvider.context.addContextFile({
|
await AIProvider.context.addContextFile({
|
||||||
contextId: this.chatContextId,
|
contextId,
|
||||||
fileId: chip.fileId,
|
fileId: chip.fileId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly _removeFromContext = async (chip: ChatChip) => {
|
private readonly _removeFromContext = async (chip: ChatChip) => {
|
||||||
if (!AIProvider.context || !this.chatContextId) {
|
const contextId = await this.getContextId();
|
||||||
|
if (!contextId || !AIProvider.context) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (isDocChip(chip)) {
|
if (isDocChip(chip)) {
|
||||||
await AIProvider.context.removeContextDoc({
|
await AIProvider.context.removeContextDoc({
|
||||||
contextId: this.chatContextId,
|
contextId,
|
||||||
docId: chip.docId,
|
docId: chip.docId,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await AIProvider.context.removeContextFile({
|
await AIProvider.context.removeContextFile({
|
||||||
contextId: this.chatContextId,
|
contextId,
|
||||||
fileId: chip.fileId,
|
fileId: chip.fileId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
accessor chatContextValue!: ChatContextValue;
|
accessor chatContextValue!: ChatContextValue;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chatSessionId!: string | undefined;
|
accessor getSessionId!: () => Promise<string | undefined>;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor updateContext!: (context: Partial<ChatContextValue>) => void;
|
accessor updateContext!: (context: Partial<ChatContextValue>) => void;
|
||||||
@@ -300,11 +300,9 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
private async _updatePromptName() {
|
private async _updatePromptName() {
|
||||||
if (this._lastPromptName !== this._promptName) {
|
if (this._lastPromptName !== this._promptName) {
|
||||||
this._lastPromptName = this._promptName;
|
this._lastPromptName = this._promptName;
|
||||||
if (this.chatSessionId) {
|
const sessionId = await this.getSessionId();
|
||||||
await AIProvider.session?.updateSession(
|
if (sessionId) {
|
||||||
this.chatSessionId,
|
await AIProvider.session?.updateSession(sessionId, this._promptName);
|
||||||
this._promptName
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,6 +557,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
if (status === 'loading' || status === 'transmitting') return;
|
if (status === 'loading' || status === 'transmitting') return;
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
|
|
||||||
|
try {
|
||||||
const { images } = this.chatContextValue;
|
const { images } = this.chatContextValue;
|
||||||
const { doc } = this.host;
|
const { doc } = this.host;
|
||||||
|
|
||||||
@@ -570,8 +569,6 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
markdown: '',
|
markdown: '',
|
||||||
});
|
});
|
||||||
|
|
||||||
await this._updatePromptName();
|
|
||||||
|
|
||||||
const attachments = await Promise.all(
|
const attachments = await Promise.all(
|
||||||
images?.map(image => readBlobAsURL(image))
|
images?.map(image => readBlobAsURL(image))
|
||||||
);
|
);
|
||||||
@@ -596,8 +593,10 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
await this._updatePromptName();
|
||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
|
const sessionId = await this.getSessionId();
|
||||||
const docs: DocContext[] = chips
|
const docs: DocContext[] = chips
|
||||||
.filter(isDocChip)
|
.filter(isDocChip)
|
||||||
.filter(chip => !!chip.markdown?.value && chip.state === 'success')
|
.filter(chip => !!chip.markdown?.value && chip.state === 'success')
|
||||||
@@ -606,7 +605,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
markdown: chip.markdown?.value || '',
|
markdown: chip.markdown?.value || '',
|
||||||
}));
|
}));
|
||||||
const stream = AIProvider.actions.chat?.({
|
const stream = AIProvider.actions.chat?.({
|
||||||
sessionId: this.chatSessionId,
|
sessionId,
|
||||||
input: userInput,
|
input: userInput,
|
||||||
docs: docs,
|
docs: docs,
|
||||||
docId: doc.id,
|
docId: doc.id,
|
||||||
@@ -638,7 +637,7 @@ export class ChatPanelInput extends SignalWatcher(WithDisposable(LitElement)) {
|
|||||||
const historyIds = await AIProvider.histories?.ids(
|
const historyIds = await AIProvider.histories?.ids(
|
||||||
doc.workspace.id,
|
doc.workspace.id,
|
||||||
doc.id,
|
doc.id,
|
||||||
{ sessionId: this.chatSessionId }
|
{ sessionId }
|
||||||
);
|
);
|
||||||
if (!historyIds || !historyIds[0]) return;
|
if (!historyIds || !historyIds[0]) return;
|
||||||
last.id = historyIds[0].messages.at(-1)?.id ?? '';
|
last.id = historyIds[0].messages.at(-1)?.id ?? '';
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor chatContextValue!: ChatContextValue;
|
accessor chatContextValue!: ChatContextValue;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor chatSessionId!: string | undefined;
|
accessor getSessionId!: () => Promise<string | undefined>;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor updateContext!: (context: Partial<ChatContextValue>) => void;
|
accessor updateContext!: (context: Partial<ChatContextValue>) => void;
|
||||||
@@ -415,7 +415,8 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
retry = async () => {
|
retry = async () => {
|
||||||
const { doc } = this.host;
|
const { doc } = this.host;
|
||||||
try {
|
try {
|
||||||
if (!this.chatSessionId) return;
|
const sessionId = await this.getSessionId();
|
||||||
|
if (!sessionId) return;
|
||||||
|
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const items = [...this.chatContextValue.items];
|
const items = [...this.chatContextValue.items];
|
||||||
@@ -427,7 +428,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
this.updateContext({ items, status: 'loading', error: null });
|
this.updateContext({ items, status: 'loading', error: null });
|
||||||
|
|
||||||
const stream = AIProvider.actions.chat?.({
|
const stream = AIProvider.actions.chat?.({
|
||||||
sessionId: this.chatSessionId,
|
sessionId,
|
||||||
retry: true,
|
retry: true,
|
||||||
docId: doc.id,
|
docId: doc.id,
|
||||||
workspaceId: doc.workspace.id,
|
workspaceId: doc.workspace.id,
|
||||||
@@ -482,7 +483,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.content=${content}
|
.content=${content}
|
||||||
.isLast=${isLast}
|
.isLast=${isLast}
|
||||||
.chatSessionId=${this.chatSessionId}
|
.getSessionId=${this.getSessionId}
|
||||||
.messageId=${messageId}
|
.messageId=${messageId}
|
||||||
.withMargin=${true}
|
.withMargin=${true}
|
||||||
.retry=${() => this.retry()}
|
.retry=${() => this.retry()}
|
||||||
@@ -492,7 +493,7 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
|
|||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.host=${host}
|
.host=${host}
|
||||||
.content=${content}
|
.content=${content}
|
||||||
.chatSessionId=${this.chatSessionId}
|
.getSessionId=${this.getSessionId}
|
||||||
.messageId=${messageId ?? undefined}
|
.messageId=${messageId ?? undefined}
|
||||||
.withMargin=${true}
|
.withMargin=${true}
|
||||||
></chat-action-list>`
|
></chat-action-list>`
|
||||||
|
|||||||
@@ -63,8 +63,8 @@ export class ChatPanelDocChip extends SignalWatcher(
|
|||||||
super.updated(changedProperties);
|
super.updated(changedProperties);
|
||||||
if (
|
if (
|
||||||
changedProperties.has('chip') &&
|
changedProperties.has('chip') &&
|
||||||
changedProperties.get('chip')?.state === 'candidate' &&
|
this.chip.state === 'processing' &&
|
||||||
this.chip.state === 'processing'
|
!this.chip.markdown
|
||||||
) {
|
) {
|
||||||
this.processDocChip().catch(console.error);
|
this.processDocChip().catch(console.error);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,17 @@ import type {
|
|||||||
import type { ChatPanelMessages } from './chat-panel-messages';
|
import type { ChatPanelMessages } from './chat-panel-messages';
|
||||||
import { isDocContext } from './components/utils';
|
import { isDocContext } from './components/utils';
|
||||||
|
|
||||||
|
const DEFAULT_CHAT_CONTEXT_VALUE: ChatContextValue = {
|
||||||
|
quote: '',
|
||||||
|
images: [],
|
||||||
|
abortController: null,
|
||||||
|
items: [],
|
||||||
|
chips: [],
|
||||||
|
status: 'idle',
|
||||||
|
error: null,
|
||||||
|
markdown: '',
|
||||||
|
};
|
||||||
|
|
||||||
export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
||||||
static override styles = css`
|
static override styles = css`
|
||||||
chat-panel {
|
chat-panel {
|
||||||
@@ -156,14 +167,22 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly _updateChips = async () => {
|
private readonly _updateChips = async () => {
|
||||||
if (!this._chatSessionId || !this._chatContextId) return;
|
|
||||||
|
|
||||||
const candidateChip: DocChip = {
|
const candidateChip: DocChip = {
|
||||||
docId: this.doc.id,
|
docId: this.doc.id,
|
||||||
state: 'candidate',
|
state: 'candidate',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// context not initialized, show candidate chip
|
||||||
|
if (!this._chatSessionId || !this._chatContextId) {
|
||||||
|
this.chatContextValue = {
|
||||||
|
...this.chatContextValue,
|
||||||
|
chips: [candidateChip],
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// context initialized, show the chips
|
||||||
let chips: (DocChip | FileChip)[] = [];
|
let chips: (DocChip | FileChip)[] = [];
|
||||||
if (this._chatContextId) {
|
|
||||||
const { docs = [], files = [] } =
|
const { docs = [], files = [] } =
|
||||||
(await AIProvider.context?.getContextDocsAndFiles(
|
(await AIProvider.context?.getContextDocsAndFiles(
|
||||||
this.doc.workspace.id,
|
this.doc.workspace.id,
|
||||||
@@ -191,14 +210,37 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
}
|
}
|
||||||
return chip;
|
return chip;
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
this.chatContextValue = {
|
this.chatContextValue = {
|
||||||
...this.chatContextValue,
|
...this.chatContextValue,
|
||||||
chips: chips.length === 0 ? [candidateChip] : chips,
|
chips: chips.length === 0 ? [candidateChip] : chips,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly _getSessionId = async () => {
|
||||||
|
if (this._chatSessionId) {
|
||||||
|
return this._chatSessionId;
|
||||||
|
}
|
||||||
|
this._chatSessionId = await AIProvider.session?.createSession(
|
||||||
|
this.doc.workspace.id,
|
||||||
|
this.doc.id
|
||||||
|
);
|
||||||
|
return this._chatSessionId;
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly _getContextId = async () => {
|
||||||
|
if (this._chatContextId) {
|
||||||
|
return this._chatContextId;
|
||||||
|
}
|
||||||
|
const sessionId = await this._getSessionId();
|
||||||
|
if (sessionId) {
|
||||||
|
this._chatContextId = await AIProvider.context?.createContext(
|
||||||
|
this.doc.workspace.id,
|
||||||
|
sessionId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return this._chatContextId;
|
||||||
|
};
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
accessor host!: EditorHost;
|
accessor host!: EditorHost;
|
||||||
|
|
||||||
@@ -221,20 +263,11 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
accessor isLoading = false;
|
accessor isLoading = false;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor chatContextValue: ChatContextValue = {
|
accessor chatContextValue: ChatContextValue = DEFAULT_CHAT_CONTEXT_VALUE;
|
||||||
quote: '',
|
|
||||||
images: [],
|
|
||||||
abortController: null,
|
|
||||||
items: [],
|
|
||||||
chips: [],
|
|
||||||
status: 'idle',
|
|
||||||
error: null,
|
|
||||||
markdown: '',
|
|
||||||
};
|
|
||||||
|
|
||||||
private _chatSessionId: string | undefined;
|
private _chatSessionId: string | null | undefined = null;
|
||||||
|
|
||||||
private _chatContextId: string | undefined;
|
private _chatContextId: string | null | undefined = null;
|
||||||
|
|
||||||
private readonly _scrollToEnd = () => {
|
private readonly _scrollToEnd = () => {
|
||||||
this._chatMessages.value?.scrollToEnd();
|
this._chatMessages.value?.scrollToEnd();
|
||||||
@@ -272,26 +305,29 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
const userId = (await AIProvider.userInfo)?.id;
|
const userId = (await AIProvider.userInfo)?.id;
|
||||||
if (!userId) return;
|
if (!userId) return;
|
||||||
|
|
||||||
try {
|
const sessionIds = await AIProvider.session?.getSessionIds(
|
||||||
this._chatSessionId = await AIProvider.session?.createSession(
|
|
||||||
this.doc.workspace.id,
|
this.doc.workspace.id,
|
||||||
this.doc.id
|
this.doc.id
|
||||||
);
|
);
|
||||||
|
if (sessionIds?.length) {
|
||||||
|
this._chatSessionId = sessionIds[0];
|
||||||
|
await this._updateHistory();
|
||||||
|
}
|
||||||
if (this._chatSessionId) {
|
if (this._chatSessionId) {
|
||||||
this._chatContextId = await AIProvider.context?.createContext(
|
this._chatContextId = await AIProvider.context?.getContextId(
|
||||||
this.doc.workspace.id,
|
this.doc.workspace.id,
|
||||||
this._chatSessionId
|
this._chatSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.error('init panel error', e);
|
|
||||||
}
|
|
||||||
await this._updateHistory();
|
|
||||||
await this._updateChips();
|
await this._updateChips();
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override updated(_changedProperties: PropertyValues) {
|
protected override updated(_changedProperties: PropertyValues) {
|
||||||
if (_changedProperties.has('doc')) {
|
if (_changedProperties.has('doc')) {
|
||||||
|
this._chatSessionId = null;
|
||||||
|
this._chatContextId = null;
|
||||||
|
this.chatContextValue = DEFAULT_CHAT_CONTEXT_VALUE;
|
||||||
|
|
||||||
requestAnimationFrame(async () => {
|
requestAnimationFrame(async () => {
|
||||||
await this._initPanel();
|
await this._initPanel();
|
||||||
});
|
});
|
||||||
@@ -376,7 +412,7 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
<chat-panel-messages
|
<chat-panel-messages
|
||||||
${ref(this._chatMessages)}
|
${ref(this._chatMessages)}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
.chatSessionId=${this._chatSessionId}
|
.getSessionId=${this._getSessionId}
|
||||||
.updateContext=${this.updateContext}
|
.updateContext=${this.updateContext}
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
.isLoading=${this.isLoading}
|
.isLoading=${this.isLoading}
|
||||||
@@ -385,14 +421,14 @@ export class ChatPanel extends WithDisposable(ShadowlessElement) {
|
|||||||
<chat-panel-chips
|
<chat-panel-chips
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
.chatContextId=${this._chatContextId}
|
.getContextId=${this._getContextId}
|
||||||
.updateContext=${this.updateContext}
|
.updateContext=${this.updateContext}
|
||||||
.docDisplayConfig=${this.docDisplayConfig}
|
.docDisplayConfig=${this.docDisplayConfig}
|
||||||
.docSearchMenuConfig=${this.docSearchMenuConfig}
|
.docSearchMenuConfig=${this.docSearchMenuConfig}
|
||||||
></chat-panel-chips>
|
></chat-panel-chips>
|
||||||
<chat-panel-input
|
<chat-panel-input
|
||||||
.chatContextValue=${this.chatContextValue}
|
.chatContextValue=${this.chatContextValue}
|
||||||
.chatSessionId=${this._chatSessionId}
|
.getSessionId=${this._getSessionId}
|
||||||
.networkSearchConfig=${this.networkSearchConfig}
|
.networkSearchConfig=${this.networkSearchConfig}
|
||||||
.updateContext=${this.updateContext}
|
.updateContext=${this.updateContext}
|
||||||
.host=${this.host}
|
.host=${this.host}
|
||||||
|
|||||||
@@ -131,6 +131,10 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private readonly _getSessionId = async () => {
|
||||||
|
return this.chatContext.currentSessionId ?? undefined;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new AI chat block based on the current session and history messages
|
* Create a new AI chat block based on the current session and history messages
|
||||||
*/
|
*/
|
||||||
@@ -408,7 +412,7 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.content=${message.content}
|
.content=${message.content}
|
||||||
.isLast=${isLastReply}
|
.isLast=${isLastReply}
|
||||||
.chatSessionId=${this.chatContext.currentSessionId ?? undefined}
|
.getSessionId=${this._getSessionId}
|
||||||
.messageId=${message.id ?? undefined}
|
.messageId=${message.id ?? undefined}
|
||||||
.retry=${() => this.retry()}
|
.retry=${() => this.retry()}
|
||||||
></chat-copy-more>`
|
></chat-copy-more>`
|
||||||
@@ -418,7 +422,7 @@ export class AIChatBlockPeekView extends LitElement {
|
|||||||
.host=${host}
|
.host=${host}
|
||||||
.actions=${actions}
|
.actions=${actions}
|
||||||
.content=${message.content}
|
.content=${message.content}
|
||||||
.chatSessionId=${this.chatContext.currentSessionId ?? undefined}
|
.getSessionId=${this._getSessionId}
|
||||||
.messageId=${message.id ?? undefined}
|
.messageId=${message.id ?? undefined}
|
||||||
.layoutDirection=${'horizontal'}
|
.layoutDirection=${'horizontal'}
|
||||||
></chat-action-list>`
|
></chat-action-list>`
|
||||||
|
|||||||
@@ -30,30 +30,6 @@ export type ToImageOptions = TextToTextOptions & {
|
|||||||
seed?: string;
|
seed?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function createChatSession({
|
|
||||||
client,
|
|
||||||
workspaceId,
|
|
||||||
docId,
|
|
||||||
promptName = 'Chat With AFFiNE AI',
|
|
||||||
}: {
|
|
||||||
client: CopilotClient;
|
|
||||||
workspaceId: string;
|
|
||||||
docId: string;
|
|
||||||
promptName?: string;
|
|
||||||
}) {
|
|
||||||
const sessionId = await client.createSession({
|
|
||||||
workspaceId,
|
|
||||||
docId,
|
|
||||||
promptName,
|
|
||||||
});
|
|
||||||
// always update the prompt name
|
|
||||||
await client.updateSession({
|
|
||||||
sessionId,
|
|
||||||
promptName,
|
|
||||||
});
|
|
||||||
return sessionId;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function resizeImage(blob: Blob | File): Promise<Blob | null> {
|
async function resizeImage(blob: Blob | File): Promise<Blob | null> {
|
||||||
let src = '';
|
let src = '';
|
||||||
try {
|
try {
|
||||||
@@ -90,7 +66,7 @@ async function createSessionMessage({
|
|||||||
client,
|
client,
|
||||||
docId,
|
docId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
promptName,
|
promptName = 'Chat With AFFiNE AI',
|
||||||
content,
|
content,
|
||||||
sessionId: providedSessionId,
|
sessionId: providedSessionId,
|
||||||
attachments,
|
attachments,
|
||||||
@@ -102,11 +78,10 @@ async function createSessionMessage({
|
|||||||
}
|
}
|
||||||
const hasAttachments = attachments && attachments.length > 0;
|
const hasAttachments = attachments && attachments.length > 0;
|
||||||
const sessionId = await (providedSessionId ??
|
const sessionId = await (providedSessionId ??
|
||||||
createChatSession({
|
client.createSession({
|
||||||
client,
|
|
||||||
workspaceId,
|
workspaceId,
|
||||||
docId,
|
docId,
|
||||||
promptName: promptName as string,
|
promptName,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const options: Parameters<CopilotClient['createMessage']>[0] = {
|
const options: Parameters<CopilotClient['createMessage']>[0] = {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { z } from 'zod';
|
|||||||
|
|
||||||
import type { CopilotClient } from './copilot-client';
|
import type { CopilotClient } from './copilot-client';
|
||||||
import type { PromptKey } from './prompt';
|
import type { PromptKey } from './prompt';
|
||||||
import { createChatSession, textToText, toImage } from './request';
|
import { textToText, toImage } from './request';
|
||||||
import { setupTracker } from './tracker';
|
import { setupTracker } from './tracker';
|
||||||
|
|
||||||
const filterStyleToPromptName = new Map(
|
const filterStyleToPromptName = new Map(
|
||||||
@@ -37,13 +37,6 @@ export function setupAIProvider(
|
|||||||
) {
|
) {
|
||||||
//#region actions
|
//#region actions
|
||||||
AIProvider.provide('chat', options => {
|
AIProvider.provide('chat', options => {
|
||||||
const sessionId =
|
|
||||||
options.sessionId ??
|
|
||||||
createChatSession({
|
|
||||||
client,
|
|
||||||
workspaceId: options.workspaceId,
|
|
||||||
docId: options.docId,
|
|
||||||
});
|
|
||||||
const { input, docs, ...rest } = options;
|
const { input, docs, ...rest } = options;
|
||||||
const params = docs?.length
|
const params = docs?.length
|
||||||
? {
|
? {
|
||||||
@@ -58,7 +51,6 @@ export function setupAIProvider(
|
|||||||
...rest,
|
...rest,
|
||||||
client,
|
client,
|
||||||
content: input,
|
content: input,
|
||||||
sessionId,
|
|
||||||
params,
|
params,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -408,10 +400,9 @@ Could you make a new website based on these notes and send back just the html fi
|
|||||||
createSession: async (
|
createSession: async (
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
docId: string,
|
docId: string,
|
||||||
promptName?: string
|
promptName = 'Chat With AFFiNE AI'
|
||||||
) => {
|
) => {
|
||||||
return createChatSession({
|
return client.createSession({
|
||||||
client,
|
|
||||||
workspaceId,
|
workspaceId,
|
||||||
docId,
|
docId,
|
||||||
promptName,
|
promptName,
|
||||||
|
|||||||
@@ -104,12 +104,14 @@ const clearChat = async (page: Page) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const collectChat = async (page: Page) => {
|
const collectChat = async (page: Page) => {
|
||||||
|
await page.waitForTimeout(ONE_SECOND);
|
||||||
const chatPanel = await page.waitForSelector('.chat-panel-messages');
|
const chatPanel = await page.waitForSelector('.chat-panel-messages');
|
||||||
if (await chatPanel.$('.chat-panel-messages-placeholder')) {
|
if (await chatPanel.$('.chat-panel-messages-placeholder')) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
// wait ai response
|
// wait ai response
|
||||||
await page.waitForSelector('.chat-panel-messages .message chat-copy-more');
|
await page.waitForSelector('.chat-panel-messages .message chat-copy-more');
|
||||||
|
await page.waitForTimeout(ONE_SECOND);
|
||||||
const lastMessage = await chatPanel.$$('.message').then(m => m[m.length - 1]);
|
const lastMessage = await chatPanel.$$('.message').then(m => m[m.length - 1]);
|
||||||
await lastMessage.waitForSelector('chat-copy-more');
|
await lastMessage.waitForSelector('chat-copy-more');
|
||||||
await page.waitForTimeout(ONE_SECOND);
|
await page.waitForTimeout(ONE_SECOND);
|
||||||
@@ -489,7 +491,6 @@ test.describe('chat panel', () => {
|
|||||||
await page.getByTestId('chat-network-search').click();
|
await page.getByTestId('chat-network-search').click();
|
||||||
await typeChatSequentially(page, 'What is the weather in Shanghai today?');
|
await typeChatSequentially(page, 'What is the weather in Shanghai today?');
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
await page.waitForTimeout(3000);
|
|
||||||
let history = await collectChat(page);
|
let history = await collectChat(page);
|
||||||
expect(history[0]).toEqual({
|
expect(history[0]).toEqual({
|
||||||
name: 'You',
|
name: 'You',
|
||||||
@@ -505,7 +506,6 @@ test.describe('chat panel', () => {
|
|||||||
await page.getByTestId('chat-network-search').click();
|
await page.getByTestId('chat-network-search').click();
|
||||||
await typeChatSequentially(page, 'What is the weather in Shanghai today?');
|
await typeChatSequentially(page, 'What is the weather in Shanghai today?');
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
await page.waitForTimeout(3000);
|
|
||||||
history = await collectChat(page);
|
history = await collectChat(page);
|
||||||
expect(history[0]).toEqual({
|
expect(history[0]).toEqual({
|
||||||
name: 'You',
|
name: 'You',
|
||||||
@@ -859,7 +859,6 @@ test.describe('chat with doc', () => {
|
|||||||
|
|
||||||
await typeChatSequentially(page, 'What is AFFiNE AI?');
|
await typeChatSequentially(page, 'What is AFFiNE AI?');
|
||||||
await page.keyboard.press('Enter');
|
await page.keyboard.press('Enter');
|
||||||
await page.waitForTimeout(3000);
|
|
||||||
const history = await collectChat(page);
|
const history = await collectChat(page);
|
||||||
expect(history[0]).toEqual({
|
expect(history[0]).toEqual({
|
||||||
name: 'You',
|
name: 'You',
|
||||||
|
|||||||
Reference in New Issue
Block a user