feat(core): add reasoning icon button (#11941)

Close [AI-58](https://linear.app/affine-design/issue/AI-58).

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

## Summary by CodeRabbit

- **New Features**
  - Introduced a toggleable AI reasoning feature in the chat interface, allowing users to enable or disable advanced reasoning during AI chat interactions.
  - Added a new reasoning button to the chat input for quick access and control.
- **Enhancements**
  - Improved chat configuration options to include reasoning settings, providing more flexibility for AI responses.
  - Streamlined network search and image upload interactions for a smoother user experience.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
akumatus
2025-04-24 14:32:54 +00:00
parent fd90b2541e
commit 807cba03ee
14 changed files with 175 additions and 38 deletions

View File

@@ -8,6 +8,7 @@ import { GlobalStateService } from '../storage';
import { AIButtonProvider } from './provider/ai-button';
import { AIButtonService } from './services/ai-button';
import { AINetworkSearchService } from './services/network-search';
import { AIReasoningService } from './services/reasoning';
export const configureAIButtonModule = (framework: Framework) => {
framework.service(AIButtonService, container => {
@@ -21,3 +22,7 @@ export function configureAINetworkSearchModule(framework: Framework) {
FeatureFlagService,
]);
}
export function configureAIReasoningModule(framework: Framework) {
framework.service(AIReasoningService, [GlobalStateService]);
}

View File

@@ -0,0 +1,34 @@
import {
createSignalFromObservable,
type Signal,
} from '@blocksuite/affine/shared/utils';
import { LiveData, Service } from '@toeverything/infra';
import type { GlobalStateService } from '../../storage';
const AI_REASONING_KEY = 'AIReasoning';
export class AIReasoningService extends Service {
constructor(private readonly globalStateService: GlobalStateService) {
super();
const { signal: enabled, cleanup: enabledCleanup } =
createSignalFromObservable<boolean | undefined>(
this._enabled$,
undefined
);
this.enabled = enabled;
this.disposables.push(enabledCleanup);
}
enabled: Signal<boolean | undefined>;
private readonly _enabled$ = LiveData.from(
this.globalStateService.globalState.watch<boolean>(AI_REASONING_KEY),
undefined
);
setEnabled = (enabled: boolean) => {
this.globalStateService.globalState.set(AI_REASONING_KEY, enabled);
};
}

View File

@@ -4,6 +4,7 @@ import { type Framework } from '@toeverything/infra';
import {
configureAIButtonModule,
configureAINetworkSearchModule,
configureAIReasoningModule,
} from './ai-button';
import { configureAppSidebarModule } from './app-sidebar';
import { configAtMenuConfigModule } from './at-menu-config';
@@ -101,6 +102,7 @@ export function configureCommonModules(framework: Framework) {
configureDndModule(framework);
configureCommonGlobalStorageImpls(framework);
configureAINetworkSearchModule(framework);
configureAIReasoningModule(framework);
configureAIButtonModule(framework);
configureTemplateDocModule(framework);
configureBlobManagementModule(framework);

View File

@@ -14,16 +14,29 @@ export const AIChatBlockPeekView = ({
model,
host,
}: AIChatBlockPeekViewProps) => {
const { docDisplayConfig, searchMenuConfig, networkSearchConfig } =
useAIChatConfig();
const {
docDisplayConfig,
searchMenuConfig,
networkSearchConfig,
reasoningConfig,
} = useAIChatConfig();
return useMemo(() => {
const template = AIChatBlockPeekViewTemplate(
model,
host,
docDisplayConfig,
searchMenuConfig,
networkSearchConfig
networkSearchConfig,
reasoningConfig
);
return toReactNode(template);
}, [model, host, docDisplayConfig, searchMenuConfig, networkSearchConfig]);
}, [
model,
host,
docDisplayConfig,
searchMenuConfig,
networkSearchConfig,
reasoningConfig,
]);
};