Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion packages/ai-native/src/browser/ai-core.contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,11 @@ import {
} from '@opensumi/ide-core-common';
import { DESIGN_MENU_BAR_RIGHT } from '@opensumi/ide-design';
import { IEditor, WorkbenchEditorService } from '@opensumi/ide-editor';
import { BrowserEditorContribution, IEditorFeatureRegistry } from '@opensumi/ide-editor/lib/browser';
import {
BrowserEditorContribution,
EditorComponentRegistry,
IEditorFeatureRegistry,
} from '@opensumi/ide-editor/lib/browser';
import { WorkbenchEditorServiceImpl } from '@opensumi/ide-editor/lib/browser/workbench-editor.service';
import { IMainLayoutService } from '@opensumi/ide-main-layout';
import { ISettingRegistry, SettingContribution } from '@opensumi/ide-preferences';
Expand Down Expand Up @@ -100,6 +104,7 @@ import {
AIRightTabRenderer,
} from './layout/tabbar.view';
import { AIChatLogoAvatar } from './layout/view/avatar/avatar.view';
import { BaseApplyService } from './mcp/base-apply.service';
import {
AINativeCoreContribution,
IChatFeatureRegistry,
Expand All @@ -116,13 +121,16 @@ import {
import { InlineChatEditorController } from './widget/inline-chat/inline-chat-editor.controller';
import { InlineChatFeatureRegistry } from './widget/inline-chat/inline-chat.feature.registry';
import { InlineChatService } from './widget/inline-chat/inline-chat.service';
import { InlineDiffManager } from './widget/inline-diff/inline-diff-manager';
import { InlineDiffController } from './widget/inline-diff/inline-diff.controller';
import { InlineHintController } from './widget/inline-hint/inline-hint.controller';
import { InlineInputController } from './widget/inline-input/inline-input.controller';
import { InlineInputService } from './widget/inline-input/inline-input.service';
import { InlineStreamDiffService } from './widget/inline-stream-diff/inline-stream-diff.service';
import { SumiLightBulbWidget } from './widget/light-bulb';

export const INLINE_DIFF_MANAGER_WIDGET_ID = 'inline-diff-manager-widget';

@Domain(
ClientAppContribution,
BrowserEditorContribution,
Expand Down Expand Up @@ -237,6 +245,9 @@ export class AINativeBrowserContribution
@Autowired(IChatInternalService)
private readonly chatInternalService: ChatInternalService;

@Autowired(BaseApplyService)
private readonly applyService: BaseApplyService;

constructor() {
this.registerFeature();
}
Expand Down Expand Up @@ -524,6 +535,19 @@ export class AINativeBrowserContribution
});
}

registerEditorComponent(registry: EditorComponentRegistry): void {
registry.registerEditorSideWidget({
id: INLINE_DIFF_MANAGER_WIDGET_ID,
component: InlineDiffManager,
displaysOnResource: (resource) => {
if (this.applyService.getUriPendingCodeBlock(resource.uri)) {
return true;
}
return false;
},
});
}

registerCommands(commands: CommandRegistry): void {
commands.registerCommand(AI_INLINE_CHAT_VISIBLE, {
execute: (value: boolean) => {
Expand Down
12 changes: 12 additions & 0 deletions packages/ai-native/src/browser/chat/chat-manager.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
IStorage,
STORAGE_NAMESPACE,
StorageProvider,
debounce,
} from '@opensumi/ide-core-common';
import { ChatMessageRole, IChatMessage, IHistoryChatMessage } from '@opensumi/ide-core-common/lib/types/ai-native';

Expand Down Expand Up @@ -89,6 +90,7 @@ export class ChatManagerService extends Disposable {
const savedSessions = this.fromJSON(sessionsModelData);
savedSessions.forEach((session) => {
this.#sessionModels.set(session.sessionId, session);
this.listenSession(session);
});
await this.storageInitEmitter.fireAndAwait();
}
Expand All @@ -100,6 +102,7 @@ export class ChatManagerService extends Disposable {
startSession() {
const model = new ChatModel();
this.#sessionModels.set(model.sessionId, model);
this.listenSession(model);
return model;
}

Expand Down Expand Up @@ -196,6 +199,15 @@ export class ChatManagerService extends Disposable {
}
}

protected listenSession(session: ChatModel) {
this.addDispose(
session.history.onMessageAdditionalChange(() => {
this.saveSessions();
}),
);
}

@debounce(1000)
protected saveSessions() {
this._chatStorage.set('sessionModels', this.getSessions());
}
Expand Down
4 changes: 4 additions & 0 deletions packages/ai-native/src/browser/chat/chat.internal.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ export class ChatInternalService extends Disposable {
return this.chatManagerService.getSessions();
}

getSession(sessionId: string) {
return this.chatManagerService.getSession(sessionId);
}

activateSession(sessionId: string) {
const targetSession = this.chatManagerService.getSession(sessionId);
if (!targetSession) {
Expand Down
36 changes: 21 additions & 15 deletions packages/ai-native/src/browser/components/ChatHistory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import cls from 'classnames';
import React, { FC, memo, useCallback, useEffect, useRef, useState } from 'react';

import { Icon, Input, Loading, Popover, PopoverPosition, PopoverTriggerType, getIcon } from '@opensumi/ide-components';
import './chat-history.css';
import { localize } from '@opensumi/ide-core-browser';
import { EnhanceIcon } from '@opensumi/ide-core-browser/lib/components/ai-native';

import styles from './chat-history.module.less';

export interface IChatHistoryItem {
id: string;
title: string;
Expand Down Expand Up @@ -162,22 +163,25 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
(item: IChatHistoryItem) => (
<div
key={item.id}
className={cls('dm-chat-history-item', item.id === currentId ? 'dm-chat-history-item-selected' : '')}
className={cls(
styles['dm-chat-history-item'],
item.id === currentId ? styles['dm-chat-history-item-selected'] : '',
)}
onClick={() => handleHistoryItemSelect(item)}
>
<div className='dm-chat-history-item-content'>
<div className={styles['dm-chat-history-item-content']}>
{item.loading ? (
<Loading />
) : (
<Icon icon='message' style={{ width: '16px', height: '16px', marginRight: 4 }} />
)}
{!historyTitleEditable?.[item.id] ? (
<span id={`dm-chat-history-item-title-${item.id}`} className='dm-chat-history-item-title'>
<span id={`dm-chat-history-item-title-${item.id}`} className={styles['dm-chat-history-item-title']}>
{item.title}
</span>
) : (
<Input
className='dm-chat-history-item-title'
className={styles['dm-chat-history-item-title']}
defaultValue={item.title}
ref={inputRef}
onPressEnter={(e: any) => {
Expand All @@ -187,7 +191,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
/>
)}
</div>
<div className='dm-chat-history-item-actions'>
<div className={styles['dm-chat-history-item-actions']}>
{/* <EditOutlined
title={localize('aiNative.operate.chatHistory.edit')}
style={{ marginRight: 8 }}
Expand All @@ -198,7 +202,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
}}
/> */}
<EnhanceIcon
className={cls('dm-chat-history-item-actions-delete', getIcon('delete'))}
className={cls(styles['dm-chat-history-item-actions-delete'], getIcon('delete'))}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
Expand Down Expand Up @@ -237,10 +241,10 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
value={searchValue}
onChange={handleSearchChange}
/>
<div className='dm-chat-history-list'>
<div className={styles['dm-chat-history-list']}>
{groupedHistoryList.map((group) => (
<div key={group.key} style={{ padding: '4px' }}>
<div className='dm-chat-history-time'>{group.key}</div>
<div className={styles['dm-chat-history-time']}>{group.key}</div>
{group.items.map(renderHistoryItem)}
</div>
))}
Expand All @@ -253,11 +257,11 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
const getPopupContainer = useCallback((triggerNode: HTMLElement) => triggerNode.parentElement!, []);

return (
<div className={cls('dm-chat-history-header', className)}>
<div className='dm-chat-history-header-title'>
<div className={cls(styles['dm-chat-history-header'], className)}>
<div className={styles['dm-chat-history-header-title']}>
<span>{title}</span>
</div>
<div className='dm-chat-history-header-actions'>
<div className={styles['dm-chat-history-header-actions']}>
<Popover
id='dm-chat-history-header-actions-history'
content={renderHistory()}
Expand All @@ -267,10 +271,12 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
getPopupContainer={getPopupContainer}
>
<div
className='dm-chat-history-header-actions-history'
className={styles['dm-chat-history-header-actions-history']}
title={localize('aiNative.operate.chatHistory.title')}
>
<EnhanceIcon className={cls('dm-chat-history-header-actions-history', 'codicon codicon-history')} />
<EnhanceIcon
className={cls(styles['dm-chat-history-header-actions-history'], 'codicon codicon-history')}
/>
</div>
</Popover>
<Popover
Expand All @@ -279,7 +285,7 @@ const ChatHistory: FC<IChatHistoryProps> = memo(
title={localize('aiNative.operate.newChat.title')}
>
<EnhanceIcon
className={cls('dm-chat-history-header-actions-new', getIcon('plus'))}
className={cls(styles['dm-chat-history-header-actions-new'], getIcon('plus'))}
onClick={handleNewChat}
/>
</Popover>
Expand Down
Loading