From 2171d1bfe2bb5d98f20a4f772edd27f7986c7a72 Mon Sep 17 00:00:00 2001 From: Wu Yue Date: Thu, 26 Jun 2025 17:04:57 +0800 Subject: [PATCH] feat(core): add ai playground feature flag and remove model switch feature flag (#12934) ## Summary by CodeRabbit * **New Features** * Added support for the "AI Playground" experimental feature, including new settings and localization entries. * **Refactor** * Renamed configuration and service references from "Model Switch" to "Playground" across the AI chat and playground interfaces. * Updated feature flag from "enable_ai_model_switch" to "enable_ai_playground" for consistency. * **Bug Fixes** * The "Model" submenu in AI chat preferences is now always visible, simplifying menu options. * **Chores** * Removed outdated Claude model options from the chat prompt. --- .../src/plugins/copilot/prompt/prompts.ts | 4 --- .../src/blocksuite/ai/chat-panel/index.ts | 10 +++--- .../ai-chat-composer/ai-chat-composer.ts | 5 --- .../components/ai-chat-input/ai-chat-input.ts | 5 --- .../ai-chat-input/preference-popup.ts | 36 ++++++++----------- .../ai/components/ai-chat-input/type.ts | 2 +- .../ai/components/playground/chat.ts | 6 ++-- .../ai/components/playground/content.ts | 6 ++-- .../hooks/affine/use-ai-chat-config.ts | 10 +++--- .../pages/workspace/detail-page/tabs/chat.tsx | 6 ++-- .../core/src/modules/ai-button/index.ts | 6 ++-- .../{model-switch.ts => playground.ts} | 4 +-- .../core/src/modules/feature-flag/constant.ts | 2 +- packages/frontend/core/src/modules/index.ts | 4 +-- packages/frontend/i18n/src/i18n.gen.ts | 8 +++++ packages/frontend/i18n/src/resources/en.json | 2 ++ 16 files changed, 52 insertions(+), 64 deletions(-) rename packages/frontend/core/src/modules/ai-button/services/{model-switch.ts => playground.ts} (84%) diff --git a/packages/backend/server/src/plugins/copilot/prompt/prompts.ts b/packages/backend/server/src/plugins/copilot/prompt/prompts.ts index 8695be5108..6858b1afd4 100644 --- a/packages/backend/server/src/plugins/copilot/prompt/prompts.ts +++ b/packages/backend/server/src/plugins/copilot/prompt/prompts.ts @@ -1650,10 +1650,6 @@ const CHAT_PROMPT: Omit = { 'gpt-4.1', 'o3', 'o4-mini', - 'claude-opus-4-20250514', - 'claude-sonnet-4-20250514', - 'claude-3-7-sonnet-20250219', - 'claude-3-5-sonnet-20241022', 'gemini-2.5-flash', 'gemini-2.5-pro', 'claude-opus-4@20250514', diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts index 1e32663af9..2b06f654cc 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts @@ -20,8 +20,8 @@ import type { SearchMenuConfig, } from '../components/ai-chat-chips'; import type { - AIModelSwitchConfig, AINetworkSearchConfig, + AIPlaygroundConfig, AIReasoningConfig, } from '../components/ai-chat-input'; import { @@ -224,7 +224,7 @@ export class ChatPanel extends SignalWatcher( accessor reasoningConfig!: AIReasoningConfig; @property({ attribute: false }) - accessor modelSwitchConfig!: AIModelSwitchConfig; + accessor playgroundConfig!: AIPlaygroundConfig; @property({ attribute: false }) accessor appSidebarConfig!: AppSidebarConfig; @@ -298,7 +298,7 @@ export class ChatPanel extends SignalWatcher( .doc=${this.doc} .networkSearchConfig=${this.networkSearchConfig} .reasoningConfig=${this.reasoningConfig} - .modelSwitchConfig=${this.modelSwitchConfig} + .playgroundConfig=${this.playgroundConfig} .appSidebarConfig=${this.appSidebarConfig} .searchMenuConfig=${this.searchMenuConfig} .docDisplayConfig=${this.docDisplayConfig} @@ -437,7 +437,7 @@ export class ChatPanel extends SignalWatcher( >` : 'AFFiNE AI'} - ${this.modelSwitchConfig.visible.value + ${this.playgroundConfig.visible.value ? html`
${CenterPeekIcon()} @@ -478,7 +478,7 @@ export class ChatPanel extends SignalWatcher( .isVisible=${this._isSidebarOpen} .networkSearchConfig=${this.networkSearchConfig} .reasoningConfig=${this.reasoningConfig} - .modelSwitchConfig=${this.modelSwitchConfig} + .playgroundConfig=${this.playgroundConfig} .docDisplayConfig=${this.docDisplayConfig} .searchMenuConfig=${this.searchMenuConfig} .trackOptions=${{ diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts index 61b813b523..5b5d8bfe33 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-composer/ai-chat-composer.ts @@ -29,7 +29,6 @@ import type { import { isCollectionChip, isDocChip, isTagChip } from '../ai-chat-chips'; import type { AIChatInputContext, - AIModelSwitchConfig, AINetworkSearchConfig, AIReasoningConfig, } from '../ai-chat-input'; @@ -93,9 +92,6 @@ export class AIChatComposer extends SignalWatcher( @property({ attribute: false }) accessor searchMenuConfig!: SearchMenuConfig; - @property({ attribute: false }) - accessor modelSwitchConfig!: AIModelSwitchConfig; - @property({ attribute: false }) accessor onChatSuccess: (() => void) | undefined; @@ -151,7 +147,6 @@ export class AIChatComposer extends SignalWatcher( .updateContext=${this.updateContext} .networkSearchConfig=${this.networkSearchConfig} .reasoningConfig=${this.reasoningConfig} - .modelSwitchConfig=${this.modelSwitchConfig} .docDisplayConfig=${this.docDisplayConfig} .onChatSuccess=${this.onChatSuccess} .trackOptions=${this.trackOptions} diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts index ae5dc52112..4ac380394f 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/ai-chat-input.ts @@ -27,7 +27,6 @@ import { import { MAX_IMAGE_COUNT } from './const'; import type { AIChatInputContext, - AIModelSwitchConfig, AINetworkSearchConfig, AIReasoningConfig, } from './type'; @@ -320,9 +319,6 @@ export class AIChatInput extends SignalWatcher( @property({ attribute: false }) accessor reasoningConfig!: AIReasoningConfig; - @property({ attribute: false }) - accessor modelSwitchConfig: AIModelSwitchConfig | undefined = undefined; - @property({ attribute: false }) accessor docDisplayConfig!: DocDisplayConfig; @@ -442,7 +438,6 @@ export class AIChatInput extends SignalWatcher(
void) | undefined; @@ -96,22 +90,20 @@ export class ChatInputPreference extends SignalWatcher( const searchItems = []; // model switch - if (this.modelSwitchConfig?.visible.value) { - modelItems.push( - menu.subMenu({ - name: 'Model', - prefix: AiOutlineIcon(), - options: { - items: (this.session?.optionalModels ?? []).map(modelId => { - return menu.action({ - name: modelId, - select: () => this._onModelChange(modelId), - }); - }), - }, - }) - ); - } + modelItems.push( + menu.subMenu({ + name: 'Model', + prefix: AiOutlineIcon(), + options: { + items: (this.session?.optionalModels ?? []).map(modelId => { + return menu.action({ + name: modelId, + select: () => this._onModelChange(modelId), + }); + }), + }, + }) + ); modelItems.push( menu.toggleSwitch({ diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/type.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/type.ts index 6d26d96152..22b09806b9 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/type.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-input/type.ts @@ -14,7 +14,7 @@ export interface AIReasoningConfig { setEnabled: (state: boolean) => void; } -export interface AIModelSwitchConfig { +export interface AIPlaygroundConfig { visible: Signal; } diff --git a/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts b/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts index 7372358d85..d68e4b81d2 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/playground/chat.ts @@ -18,8 +18,8 @@ import type { ChatPanelMessages } from '../../chat-panel/chat-panel-messages'; import { AIProvider } from '../../provider'; import type { DocDisplayConfig, SearchMenuConfig } from '../ai-chat-chips'; import type { - AIModelSwitchConfig, AINetworkSearchConfig, + AIPlaygroundConfig, AIReasoningConfig, } from '../ai-chat-input'; import { @@ -136,7 +136,7 @@ export class PlaygroundChat extends SignalWatcher( accessor reasoningConfig!: AIReasoningConfig; @property({ attribute: false }) - accessor modelSwitchConfig!: AIModelSwitchConfig; + accessor playgroundConfig!: AIPlaygroundConfig; @property({ attribute: false }) accessor appSidebarConfig!: AppSidebarConfig; @@ -320,7 +320,7 @@ export class PlaygroundChat extends SignalWatcher( .isVisible=${this._isVisible} .networkSearchConfig=${this.networkSearchConfig} .reasoningConfig=${this.reasoningConfig} - .modelSwitchConfig=${this.modelSwitchConfig} + .playgroundConfig=${this.playgroundConfig} .docDisplayConfig=${this.docDisplayConfig} .searchMenuConfig=${this.searchMenuConfig} > diff --git a/packages/frontend/core/src/blocksuite/ai/components/playground/content.ts b/packages/frontend/core/src/blocksuite/ai/components/playground/content.ts index 4afba1e4f1..d8daf09ec2 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/playground/content.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/playground/content.ts @@ -12,8 +12,8 @@ import type { AppSidebarConfig } from '../../chat-panel/chat-config'; import { AIProvider } from '../../provider'; import type { DocDisplayConfig, SearchMenuConfig } from '../ai-chat-chips'; import type { - AIModelSwitchConfig, AINetworkSearchConfig, + AIPlaygroundConfig, AIReasoningConfig, } from '../ai-chat-input'; @@ -66,7 +66,7 @@ export class PlaygroundContent extends SignalWatcher( accessor reasoningConfig!: AIReasoningConfig; @property({ attribute: false }) - accessor modelSwitchConfig!: AIModelSwitchConfig; + accessor playgroundConfig!: AIPlaygroundConfig; @property({ attribute: false }) accessor appSidebarConfig!: AppSidebarConfig; @@ -329,7 +329,7 @@ export class PlaygroundContent extends SignalWatcher( .doc=${this.doc} .networkSearchConfig=${this.networkSearchConfig} .reasoningConfig=${this.reasoningConfig} - .modelSwitchConfig=${this.modelSwitchConfig} + .playgroundConfig=${this.playgroundConfig} .appSidebarConfig=${this.appSidebarConfig} .searchMenuConfig=${this.searchMenuConfig} .docDisplayConfig=${this.docDisplayConfig} diff --git a/packages/frontend/core/src/components/hooks/affine/use-ai-chat-config.ts b/packages/frontend/core/src/components/hooks/affine/use-ai-chat-config.ts index 9f6784dba5..211b316a65 100644 --- a/packages/frontend/core/src/components/hooks/affine/use-ai-chat-config.ts +++ b/packages/frontend/core/src/components/hooks/affine/use-ai-chat-config.ts @@ -1,6 +1,6 @@ // packages/frontend/core/src/blocksuite/ai/hooks/useChatPanelConfig.ts -import { AIModelSwitchService } from '@affine/core/modules/ai-button/services/model-switch'; import { AINetworkSearchService } from '@affine/core/modules/ai-button/services/network-search'; +import { AIPlaygroundService } from '@affine/core/modules/ai-button/services/playground'; import { AIReasoningService } from '@affine/core/modules/ai-button/services/reasoning'; import { CollectionService } from '@affine/core/modules/collection'; import { DocsService } from '@affine/core/modules/doc'; @@ -22,7 +22,7 @@ export function useAIChatConfig() { const searchService = framework.get(AINetworkSearchService); const reasoningService = framework.get(AIReasoningService); - const modelSwitchService = framework.get(AIModelSwitchService); + const playgroundService = framework.get(AIPlaygroundService); const docDisplayMetaService = framework.get(DocDisplayMetaService); const workspaceService = framework.get(WorkspaceService); const searchMenuService = framework.get(SearchMenuService); @@ -42,8 +42,8 @@ export function useAIChatConfig() { setEnabled: reasoningService.setEnabled, }; - const modelSwitchConfig = { - visible: modelSwitchService.visible, + const playgroundConfig = { + visible: playgroundService.visible, }; const docDisplayConfig = { @@ -130,6 +130,6 @@ export function useAIChatConfig() { reasoningConfig, docDisplayConfig, searchMenuConfig, - modelSwitchConfig, + playgroundConfig, }; } diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx index da248cb401..ed599c1c56 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx @@ -47,7 +47,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel( searchMenuConfig, networkSearchConfig, reasoningConfig, - modelSwitchConfig, + playgroundConfig, } = useAIChatConfig(); useEffect(() => { @@ -74,7 +74,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel( chatPanelRef.current.searchMenuConfig = searchMenuConfig; chatPanelRef.current.networkSearchConfig = networkSearchConfig; chatPanelRef.current.reasoningConfig = reasoningConfig; - chatPanelRef.current.modelSwitchConfig = modelSwitchConfig; + chatPanelRef.current.playgroundConfig = playgroundConfig; chatPanelRef.current.extensions = editor.host.std .get(ViewExtensionManagerIdentifier) .get('preview-page'); @@ -109,7 +109,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel( networkSearchConfig, searchMenuConfig, reasoningConfig, - modelSwitchConfig, + playgroundConfig, ]); return
; diff --git a/packages/frontend/core/src/modules/ai-button/index.ts b/packages/frontend/core/src/modules/ai-button/index.ts index 1266fd028f..66403c8fa4 100644 --- a/packages/frontend/core/src/modules/ai-button/index.ts +++ b/packages/frontend/core/src/modules/ai-button/index.ts @@ -7,8 +7,8 @@ import { FeatureFlagService } from '../feature-flag'; import { GlobalStateService } from '../storage'; import { AIButtonProvider } from './provider/ai-button'; import { AIButtonService } from './services/ai-button'; -import { AIModelSwitchService } from './services/model-switch'; import { AINetworkSearchService } from './services/network-search'; +import { AIPlaygroundService } from './services/playground'; import { AIReasoningService } from './services/reasoning'; export const configureAIButtonModule = (framework: Framework) => { @@ -28,6 +28,6 @@ export function configureAIReasoningModule(framework: Framework) { framework.service(AIReasoningService, [GlobalStateService]); } -export function configureAIModelSwitchModule(framework: Framework) { - framework.service(AIModelSwitchService, [FeatureFlagService]); +export function configureAIPlaygroundModule(framework: Framework) { + framework.service(AIPlaygroundService, [FeatureFlagService]); } diff --git a/packages/frontend/core/src/modules/ai-button/services/model-switch.ts b/packages/frontend/core/src/modules/ai-button/services/playground.ts similarity index 84% rename from packages/frontend/core/src/modules/ai-button/services/model-switch.ts rename to packages/frontend/core/src/modules/ai-button/services/playground.ts index d2052c2369..5c82d7677d 100644 --- a/packages/frontend/core/src/modules/ai-button/services/model-switch.ts +++ b/packages/frontend/core/src/modules/ai-button/services/playground.ts @@ -6,7 +6,7 @@ import { Service } from '@toeverything/infra'; import type { FeatureFlagService } from '../../feature-flag'; -export class AIModelSwitchService extends Service { +export class AIPlaygroundService extends Service { constructor(private readonly featureFlagService: FeatureFlagService) { super(); @@ -22,5 +22,5 @@ export class AIModelSwitchService extends Service { visible: Signal; private readonly _visible$ = - this.featureFlagService.flags.enable_ai_model_switch.$; + this.featureFlagService.flags.enable_ai_playground.$; } diff --git a/packages/frontend/core/src/modules/feature-flag/constant.ts b/packages/frontend/core/src/modules/feature-flag/constant.ts index a57bbbef4e..4e57fe3b88 100644 --- a/packages/frontend/core/src/modules/feature-flag/constant.ts +++ b/packages/frontend/core/src/modules/feature-flag/constant.ts @@ -26,7 +26,7 @@ export const AFFINE_FLAGS = { configurable: false, defaultState: true, }, - enable_ai_model_switch: { + enable_ai_playground: { category: 'affine', displayName: 'com.affine.settings.workspace.experimental-features.enable-ai-model-switch.name', diff --git a/packages/frontend/core/src/modules/index.ts b/packages/frontend/core/src/modules/index.ts index 8a49b8d883..7140dd5108 100644 --- a/packages/frontend/core/src/modules/index.ts +++ b/packages/frontend/core/src/modules/index.ts @@ -3,8 +3,8 @@ import { type Framework } from '@toeverything/infra'; import { configureAIButtonModule, - configureAIModelSwitchModule, configureAINetworkSearchModule, + configureAIPlaygroundModule, configureAIReasoningModule, } from './ai-button'; import { configureAppSidebarModule } from './app-sidebar'; @@ -107,7 +107,7 @@ export function configureCommonModules(framework: Framework) { configureCommonGlobalStorageImpls(framework); configureAINetworkSearchModule(framework); configureAIReasoningModule(framework); - configureAIModelSwitchModule(framework); + configureAIPlaygroundModule(framework); configureAIButtonModule(framework); configureTemplateDocModule(framework); configureBlobManagementModule(framework); diff --git a/packages/frontend/i18n/src/i18n.gen.ts b/packages/frontend/i18n/src/i18n.gen.ts index f181f4d2a0..a626c9bb3e 100644 --- a/packages/frontend/i18n/src/i18n.gen.ts +++ b/packages/frontend/i18n/src/i18n.gen.ts @@ -5692,6 +5692,14 @@ export function useAFFiNEI18N(): { * `Enable or disable AI model switch feature.` */ ["com.affine.settings.workspace.experimental-features.enable-ai-model-switch.description"](): string; + /** + * `Enable AI Playground` + */ + ["com.affine.settings.workspace.experimental-features.enable-ai-playground.name"](): string; + /** + * `Enable or disable AI playground feature.` + */ + ["com.affine.settings.workspace.experimental-features.enable-ai-playground.description"](): string; /** * `Database Full Width` */ diff --git a/packages/frontend/i18n/src/resources/en.json b/packages/frontend/i18n/src/resources/en.json index 16c60e9e84..d9359f2982 100644 --- a/packages/frontend/i18n/src/resources/en.json +++ b/packages/frontend/i18n/src/resources/en.json @@ -1423,6 +1423,8 @@ "com.affine.settings.workspace.experimental-features.enable-ai-network-search.description": "Enable or disable AI Network Search feature.", "com.affine.settings.workspace.experimental-features.enable-ai-model-switch.name": "Enable AI Model Switch", "com.affine.settings.workspace.experimental-features.enable-ai-model-switch.description": "Enable or disable AI model switch feature.", + "com.affine.settings.workspace.experimental-features.enable-ai-playground.name": "Enable AI Playground", + "com.affine.settings.workspace.experimental-features.enable-ai-playground.description": "Enable or disable AI playground feature.", "com.affine.settings.workspace.experimental-features.enable-database-full-width.name": "Database Full Width", "com.affine.settings.workspace.experimental-features.enable-database-full-width.description": "The database will be displayed in full-width mode.", "com.affine.settings.workspace.experimental-features.enable-database-attachment-note.name": "Database Attachment Note",