瀏覽代碼

feat(chrome-extension): 更新图标并添加对 DeepSeek 模型的支持

- 更新扩展图标为 icon.png
- 在 LLM 提供商中添加 DeepSeek 模型
- 修改搜索功能以支持百度
- 优化提示模板以使用中文
- 更新设置界面翻译
chd 3 月之前
父節點
當前提交
d789171a17

+ 3 - 3
chrome-extension/manifest.js

@@ -47,10 +47,10 @@ const manifest = withSidePanel({
     type: 'module',
   },
   action: {
-    default_icon: 'icon-32.png',
+    default_icon: 'icon.png',
   },
   icons: {
-    128: 'icon-128.png',
+    128: 'icon.png',
   },
   content_scripts: [
     {
@@ -60,7 +60,7 @@ const manifest = withSidePanel({
   ],
   web_accessible_resources: [
     {
-      resources: ['*.js', '*.css', '*.svg', 'icon-128.png', 'icon-32.png'],
+      resources: ['*.js', '*.css', '*.svg', 'icon-128.png', 'icon-32.png', 'icon.png'],
       matches: ['*://*/*'],
     },
   ],

二進制
chrome-extension/public/icon.png


+ 18 - 18
chrome-extension/src/background/agent/actions/builder.ts

@@ -142,12 +142,12 @@ export class ActionBuilder {
 
     const searchGoogle = new Action(async (input: z.infer<typeof searchGoogleActionSchema.schema>) => {
       const context = this.context;
-      const intent = input.intent || `Searching for "${input.query}" in Google`;
+      const intent = input.intent || `在百度中搜索"${input.query}"`;
       context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_START, intent);
 
-      await context.browserContext.navigateTo(`https://www.google.com/search?q=${input.query}`);
+      await context.browserContext.navigateTo(`https://www.baidu.com/s?wd=${input.query}`);
 
-      const msg2 = `Searched for "${input.query}" in Google`;
+      const msg2 = `在百度中搜索"${input.query}"`;
       context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_OK, msg2);
       return new ActionResult({
         extractedContent: msg2,
@@ -157,11 +157,11 @@ export class ActionBuilder {
     actions.push(searchGoogle);
 
     const goToUrl = new Action(async (input: z.infer<typeof goToUrlActionSchema.schema>) => {
-      const intent = input.intent || `Navigating to ${input.url}`;
+      const intent = input.intent || `导航至${input.url}`;
       this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_START, intent);
 
       await this.context.browserContext.navigateTo(input.url);
-      const msg2 = `Navigated to ${input.url}`;
+      const msg2 = `已导航到${input.url}`;
       this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_OK, msg2);
       return new ActionResult({
         extractedContent: msg2,
@@ -172,12 +172,12 @@ export class ActionBuilder {
 
     // eslint-disable-next-line @typescript-eslint/no-unused-vars
     const goBack = new Action(async (input: z.infer<typeof goBackActionSchema.schema>) => {
-      const intent = input.intent || 'Navigating back';
+      const intent = input.intent || '正在返回';
       this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_START, intent);
 
       const page = await this.context.browserContext.getCurrentPage();
       await page.goBack();
-      const msg2 = 'Navigated back';
+      const msg2 = '已返回';
       this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_OK, msg2);
       return new ActionResult({
         extractedContent: msg2,
@@ -188,10 +188,10 @@ export class ActionBuilder {
 
     const wait = new Action(async (input: z.infer<typeof waitActionSchema.schema>) => {
       const seconds = input.seconds || 3;
-      const intent = input.intent || `Waiting for ${seconds} seconds`;
+      const intent = input.intent || `正在等待${seconds}秒`;
       this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_START, intent);
       await new Promise(resolve => setTimeout(resolve, seconds * 1000));
-      const msg = `${seconds} seconds elapsed`;
+      const msg = `已等待${seconds}秒`;
       this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_OK, msg);
       return new ActionResult({ extractedContent: msg, includeInMemory: true });
     }, waitActionSchema);
@@ -200,7 +200,7 @@ export class ActionBuilder {
     // Element Interaction Actions
     const clickElement = new Action(
       async (input: z.infer<typeof clickElementActionSchema.schema>) => {
-        const intent = input.intent || `Click element with index ${input.index}`;
+        const intent = input.intent || `点击索引元素 ${input.index}`;
         this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_START, intent);
 
         const page = await this.context.browserContext.getCurrentPage();
@@ -208,12 +208,12 @@ export class ActionBuilder {
 
         const elementNode = state?.selectorMap.get(input.index);
         if (!elementNode) {
-          throw new Error(`Element with index ${input.index} does not exist - retry or use alternative actions`);
+          throw new Error(`索引为${input.index}的元素不存在-请重试或使用其他操作`);
         }
 
         // Check if element is a file uploader
         if (page.isFileUploader(elementNode)) {
-          const msg = `Index ${input.index} - has an element which opens file upload dialog. To upload files please use a specific function to upload files`;
+          const msg = `索引${input.index}-包含一个打开文件上传对话框的元素。要上传文件,请使用特定功能来上传文件`;
           logger.info(msg);
           return new ActionResult({
             extractedContent: msg,
@@ -224,13 +224,13 @@ export class ActionBuilder {
         try {
           const initialTabIds = await this.context.browserContext.getAllTabIds();
           await page.clickElementNode(this.context.options.useVision, elementNode);
-          let msg = `Clicked button with index ${input.index}: ${elementNode.getAllTextTillNextClickableElement(2)}`;
+          let msg = `点击了索引为${input.index}的按钮: ${elementNode.getAllTextTillNextClickableElement(2)}`;
           logger.info(msg);
 
           // TODO: could be optimized by chrome extension tab api
           const currentTabIds = await this.context.browserContext.getAllTabIds();
           if (currentTabIds.size > initialTabIds.size) {
-            const newTabMsg = 'New tab opened - switching to it';
+            const newTabMsg = '新标签页已打开 - 正在切换到该标签页';
             msg += ` - ${newTabMsg}`;
             logger.info(newTabMsg);
             // find the tab id that is not in the initial tab ids
@@ -242,7 +242,7 @@ export class ActionBuilder {
           this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_OK, msg);
           return new ActionResult({ extractedContent: msg, includeInMemory: true });
         } catch (error) {
-          const msg = `Element no longer available with index ${input.index} - most likely the page changed`;
+          const msg = `索引为${input.index}的元素不再可用 - 可能页面已经改变`;
           this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_FAIL, msg);
           return new ActionResult({
             error: error instanceof Error ? error.message : String(error),
@@ -256,7 +256,7 @@ export class ActionBuilder {
 
     const inputText = new Action(
       async (input: z.infer<typeof inputTextActionSchema.schema>) => {
-        const intent = input.intent || `Input text into index ${input.index}`;
+        const intent = input.intent || `在索引为${input.index}的元素中输入文本`;
         this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_START, intent);
 
         const page = await this.context.browserContext.getCurrentPage();
@@ -264,11 +264,11 @@ export class ActionBuilder {
 
         const elementNode = state?.selectorMap.get(input.index);
         if (!elementNode) {
-          throw new Error(`Element with index ${input.index} does not exist - retry or use alternative actions`);
+          throw new Error(`索引为${input.index}的元素不存在 - 请重试或使用其他操作`);
         }
 
         await page.inputTextElementNode(this.context.options.useVision, elementNode, input.text);
-        const msg = `Input ${input.text} into index ${input.index}`;
+        const msg = `在索引为${input.index}的元素中输入了 ${input.text}`;
         this.context.emitEvent(Actors.NAVIGATOR, ExecutionState.ACT_OK, msg);
         return new ActionResult({ extractedContent: msg, includeInMemory: true });
       },

+ 2 - 1
chrome-extension/src/background/agent/prompts/planner.ts

@@ -47,7 +47,8 @@ NOTE:
   - Ignore the output structures of other AI messages.
 
 REMEMBER:
-  - Keep your responses concise and focused on actionable insights.`);
+  - Keep your responses concise and focused on actionable insights.
+  - 用中文回答.`);
   }
 
   async getUserMessage(context: AgentContext): Promise<HumanMessage> {

+ 2 - 0
chrome-extension/src/background/agent/prompts/templates/navigator.ts

@@ -114,4 +114,6 @@ Common action sequences:
 - Plan is a json string wrapped by the <plan> tag
 - If a plan is provided, follow the instructions in the next_steps exactly first
 - If no plan is provided, just continue with the task
+REMEMBER:
+-用中文回答.
 `;

+ 3 - 1
chrome-extension/src/background/agent/prompts/validator.ts

@@ -91,7 +91,9 @@ ANSWER FORMATTING GUIDELINES:
 </example_output>
 
 TASK TO VALIDATE: 
-${this.tasksToValidate()}`);
+${this.tasksToValidate()}
+REMEMBER:
+- 用中文回答.`);
   }
 
   /**

+ 2 - 2
packages/i18n/locales/en/messages.json

@@ -1,11 +1,11 @@
 {
   "extensionDescription": {
     "description": "Extension description",
-    "message": "Automate web tasks with AI! NanoBrowser is an open-source Chrome extension that lets you extract data, fill forms, and more."
+    "message": "使用 AI 自动执行网络任务!允许您提取数据、填写表单等。"
   },
   "extensionName": {
     "description": "Extension name",
-    "message": "Nanobrowser: AI Web Agent & Automation"
+    "message": "派维斯智能体: AI Web Agent & Automation"
   },
   "toggleTheme": {
     "message": "Toggle theme"

+ 28 - 0
packages/storage/lib/settings/agentModels.ts

@@ -102,3 +102,31 @@ export const agentModelStore: AgentModelStorage = {
     return data.agents;
   },
 };
+async function initClient() {
+  await agentModelStore.setAgentModel('navigator' as any, {
+    modelName: 'deepseek-chat',
+    parameters: {
+      temperature: 0.1,
+      topP: 0.1,
+    },
+    provider: 'deepseek',
+  });
+  await agentModelStore.setAgentModel('planner' as any, {
+    modelName: 'deepseek-chat',
+    parameters: {
+      temperature: 0.1,
+      topP: 0.1,
+    },
+    provider: 'deepseek',
+  });
+  await agentModelStore.setAgentModel('validator' as any, {
+    modelName: 'deepseek-chat',
+    parameters: {
+      temperature: 0.1,
+      topP: 0.1,
+    },
+    provider: 'deepseek',
+  });
+}
+
+initClient();

+ 11 - 1
packages/storage/lib/settings/llmProviders.ts

@@ -203,7 +203,12 @@ function ensureBackwardCompatibility(providerId: string, config: ProviderConfig)
   // console.log(`[ensureBackwardCompatibility] Output for ${providerId}:`, JSON.stringify(updatedConfig));
   return updatedConfig;
 }
-
+// {
+//   apiKey: 'sk-3f91d3517b3648e8b4414f34de0696ea',
+//     modelNames: ['deepseek-chat', 'deepseek-reasoner'],
+//       name: 'DeepSeek',
+//         type: "deepseek"
+// }
 export const llmProviderStore: LLMProviderStorage = {
   ...storage,
   async setProvider(providerId: string, config: ProviderConfig) {
@@ -296,3 +301,8 @@ export const llmProviderStore: LLMProviderStorage = {
     return providers;
   },
 };
+llmProviderStore.setProvider('deepseek', {
+  apiKey: 'sk-3f91d3517b3648e8b4414f34de0696ea',
+  modelNames: ['deepseek-chat', 'deepseek-reasoner'],
+  name: 'DeepSeek',
+});

+ 4 - 4
pages/options/src/Options.tsx

@@ -8,9 +8,9 @@ import { ModelSettings } from './components/ModelSettings';
 type TabTypes = 'general' | 'models' | 'help';
 
 const TABS: { id: TabTypes; icon: string; label: string }[] = [
-  { id: 'general', icon: '⚙️', label: 'General' },
-  { id: 'models', icon: '📊', label: 'Models' },
-  { id: 'help', icon: '📚', label: 'Help' },
+  { id: 'general', icon: '⚙️', label: '通用' },
+  { id: 'models', icon: '📊', label: '模型' },
+  // { id: 'help', icon: '📚', label: '帮助' },
 ];
 
 const Options = () => {
@@ -56,7 +56,7 @@ const Options = () => {
       <nav
         className={`w-48 border-r ${isDarkMode ? 'border-slate-700 bg-slate-800/80' : 'border-white/20 bg-[#0EA5E9]/10'} backdrop-blur-sm`}>
         <div className="p-4">
-          <h1 className={`mb-6 text-xl font-bold ${isDarkMode ? 'text-gray-200' : 'text-gray-800'}`}>Settings</h1>
+          <h1 className={`mb-6 text-xl font-bold ${isDarkMode ? 'text-gray-200' : 'text-gray-800'}`}>设置</h1>
           <ul className="space-y-2">
             {TABS.map(item => (
               <li key={item.id}>

+ 18 - 24
pages/options/src/components/GeneralSettings.tsx

@@ -24,21 +24,21 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
       <div
         className={`rounded-lg border ${isDarkMode ? 'border-slate-700 bg-slate-800' : 'border-blue-100 bg-white'} p-6 text-left shadow-sm`}>
         <h2 className={`mb-4 text-left text-xl font-semibold ${isDarkMode ? 'text-gray-200' : 'text-gray-800'}`}>
-          General
+          通用
         </h2>
 
         <div className="space-y-4">
           <div className="flex items-center justify-between">
             <div>
               <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-                Max Steps per Task
+                每个任务的最大步骤数
               </h3>
               <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                Step limit per task
+                每个任务的步骤限制
               </p>
             </div>
             <label htmlFor="maxSteps" className="sr-only">
-              Max Steps per Task
+              每个任务的最大步骤数
             </label>
             <input
               id="maxSteps"
@@ -54,14 +54,12 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
           <div className="flex items-center justify-between">
             <div>
               <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-                Max Actions per Step
+                每步最大操作数
               </h3>
-              <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                Action limit per step
-              </p>
+              <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>每步操作限制</p>
             </div>
             <label htmlFor="maxActionsPerStep" className="sr-only">
-              Max Actions per Step
+              每步最大操作数
             </label>
             <input
               id="maxActionsPerStep"
@@ -76,15 +74,13 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
 
           <div className="flex items-center justify-between">
             <div>
-              <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-                Failure Tolerance
-              </h3>
+              <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>容错</h3>
               <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                How many consecutive failures before stopping
+                停止前连续失败多少次
               </p>
             </div>
             <label htmlFor="maxFailures" className="sr-only">
-              Failure Tolerance
+              容错
             </label>
             <input
               id="maxFailures"
@@ -99,9 +95,9 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
 
           <div className="flex items-center justify-between">
             <div>
-              <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>Enable Vision</h3>
+              <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>启用视觉</h3>
               <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                Use vision capabilities (uses more tokens)
+                使用视觉能力(使用更多tokens)
               </p>
             </div>
             <div className="relative inline-flex cursor-pointer items-center">
@@ -115,7 +111,7 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
               <label
                 htmlFor="useVision"
                 className={`peer h-6 w-11 rounded-full ${isDarkMode ? 'bg-slate-600' : 'bg-gray-200'} after:absolute after:left-[2px] after:top-[2px] after:size-5 after:rounded-full after:border after:border-gray-300 after:bg-white after:transition-all after:content-[''] peer-checked:bg-blue-600 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300`}>
-                <span className="sr-only">Enable Vision</span>
+                <span className="sr-only">启用视觉</span>
               </label>
             </div>
           </div>
@@ -123,10 +119,10 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
           <div className="flex items-center justify-between">
             <div>
               <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-                Enable Vision for Planner
+                为 Planner 启用 Vision
               </h3>
               <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                Use vision in planner (uses more tokens)
+                在规划器中使用视觉(使用更多tokens)
               </p>
             </div>
             <div className="relative inline-flex cursor-pointer items-center">
@@ -140,18 +136,16 @@ export const GeneralSettings = ({ isDarkMode = false }: GeneralSettingsProps) =>
               <label
                 htmlFor="useVisionForPlanner"
                 className={`peer h-6 w-11 rounded-full ${isDarkMode ? 'bg-slate-600' : 'bg-gray-200'} after:absolute after:left-[2px] after:top-[2px] after:size-5 after:rounded-full after:border after:border-gray-300 after:bg-white after:transition-all after:content-[''] peer-checked:bg-blue-600 peer-checked:after:translate-x-full peer-checked:after:border-white peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-blue-300`}>
-                <span className="sr-only">Enable Vision for Planner</span>
+                <span className="sr-only">为 Planner 启用 Vision</span>
               </label>
             </div>
           </div>
 
           <div className="flex items-center justify-between">
             <div>
-              <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-                Replanning Frequency
-              </h3>
+              <h3 className={`text-lg font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>重新规划频率</h3>
               <p className={`text-sm font-normal ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                Reconsider and update the plan every [Number] steps
+                每 [Number] 步重新考虑并更新计划
               </p>
             </div>
             <label htmlFor="planningInterval" className="sr-only">

+ 21 - 25
pages/options/src/components/ModelSettings.tsx

@@ -345,7 +345,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
       return {
         theme: isDarkMode ? 'dark' : 'light',
         variant: 'danger' as const,
-        children: 'Delete',
+        children: '删除',
         disabled: false,
       };
     }
@@ -377,7 +377,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
     return {
       theme: isDarkMode ? 'dark' : 'light',
       variant: 'primary' as const,
-      children: 'Save',
+      children: '保存',
       disabled: !hasInput || !isModified,
     };
   };
@@ -461,6 +461,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
       console.error('Error saving API key:', error);
     }
   };
+  // handleSave('deepseek')
 
   const handleDelete = async (provider: string) => {
     try {
@@ -662,7 +663,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
           <label
             htmlFor={`${agentName}-model`}
             className={`w-24 text-sm font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-            Model
+            模型
           </label>
           <select
             id={`${agentName}-model`}
@@ -675,7 +676,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
             }
             onChange={e => handleModelChange(agentName, e.target.value)}>
             <option key="default" value="">
-              Choose model
+              选择模型
             </option>
             {availableModels.map(({ provider, providerName, model }) => (
               <option key={`${provider}>${model}`} value={`${provider}>${model}`}>
@@ -690,7 +691,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
           <label
             htmlFor={`${agentName}-temperature`}
             className={`w-24 text-sm font-medium ${isDarkMode ? 'text-gray-300' : 'text-gray-700'}`}>
-            Temperature
+            温度
           </label>
           <div className="flex flex-1 items-center space-x-2">
             <input
@@ -801,11 +802,11 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
   const getAgentDescription = (agentName: AgentNameEnum) => {
     switch (agentName) {
       case AgentNameEnum.Navigator:
-        return 'Navigates websites and performs actions';
+        return '浏览网站并执行操作';
       case AgentNameEnum.Planner:
-        return 'Develops and refines strategies to complete tasks';
+        return '制定并完善完成任务的策略';
       case AgentNameEnum.Validator:
-        return 'Checks if tasks are completed successfully';
+        return '检查任务是否成功完成';
       default:
         return '';
     }
@@ -943,7 +944,6 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
   const handleProviderSelection = (providerType: string) => {
     // Close the dropdown immediately
     setIsProviderSelectorOpen(false);
-
     // Handle custom provider
     if (providerType === ProviderTypeEnum.CustomOpenAI) {
       addCustomProvider();
@@ -955,11 +955,13 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
       addAzureProvider();
       return;
     }
+    console.log(providerType);
 
     // Handle built-in supported providers
     addBuiltInProvider(providerType);
   };
-
+  // handleProviderSelection('deepseek')
+  // handleSave('deepseek')
   // New function to add Azure providers with unique IDs
   const addAzureProvider = () => {
     // Count existing Azure providers
@@ -1082,13 +1084,11 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
       {/* LLM Providers Section */}
       <div
         className={`rounded-lg border ${isDarkMode ? 'border-slate-700 bg-slate-800' : 'border-blue-100 bg-gray-50'} p-6 text-left shadow-sm`}>
-        <h2 className={`mb-4 text-xl font-semibold ${isDarkMode ? 'text-gray-200' : 'text-gray-800'}`}>
-          LLM Providers
-        </h2>
+        <h2 className={`mb-4 text-xl font-semibold ${isDarkMode ? 'text-gray-200' : 'text-gray-800'}`}>大语言模型</h2>
         <div className="space-y-6">
           {getSortedProviders().length === 0 ? (
             <div className="py-8 text-center text-gray-500">
-              <p className="mb-4">No providers configured yet. Add a provider to get started.</p>
+              <p className="mb-4">还未设置模型,添加一个模型</p>
             </div>
           ) : (
             getSortedProviders().map(([providerId, providerConfig]) => {
@@ -1111,7 +1111,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                       {/* Show Cancel button for newly added providers */}
                       {modifiedProviders.has(providerId) && !providersFromStorage.has(providerId) && (
                         <Button variant="secondary" onClick={() => handleCancelProvider(providerId)}>
-                          Cancel
+                          取消
                         </Button>
                       )}
                       <Button
@@ -1130,7 +1130,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                   {/* Show message for newly added providers */}
                   {modifiedProviders.has(providerId) && !providersFromStorage.has(providerId) && (
                     <div className={`mb-2 text-sm ${isDarkMode ? 'text-teal-300' : 'text-teal-700'}`}>
-                      <p>This provider is newly added. Enter your API key and click Save to configure it.</p>
+                      <p>此模型是新添加的。输入您的API密钥并单击“保存”以进行配置。</p>
                     </div>
                   )}
 
@@ -1197,7 +1197,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                               ? `${providerConfig.name || providerId} API key (optional)`
                               : providerConfig.type === ProviderTypeEnum.Ollama
                                 ? 'API Key (leave empty for Ollama)'
-                                : `${providerConfig.name || providerId} API key (required)`
+                                : `${providerConfig.name || providerId} API key`
                           }
                           value={providerConfig.apiKey || ''}
                           onChange={e => handleApiKeyChange(providerId, e.target.value, providerConfig.baseUrl)}
@@ -1416,9 +1416,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                                   className={`min-w-[150px] flex-1 border-none text-sm ${isDarkMode ? 'bg-transparent text-gray-200' : 'bg-transparent text-gray-700'} p-1 outline-none`}
                                 />
                               </div>
-                              <p className={`mt-1 text-xs ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                                Type and Press Enter or Space to add.
-                              </p>
+                              <p className={`mt-1 text-xs ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}></p>
                             </>
                           ) : (
                             /* Default Tag Input for other providers */
@@ -1455,9 +1453,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                                   className={`min-w-[150px] flex-1 border-none text-sm ${isDarkMode ? 'bg-transparent text-gray-200' : 'bg-transparent text-gray-700'} p-1 outline-none`}
                                 />
                               </div>
-                              <p className={`mt-1 text-xs ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}>
-                                Type and Press Enter or Space to add.
-                              </p>
+                              <p className={`mt-1 text-xs ${isDarkMode ? 'text-gray-400' : 'text-gray-500'}`}></p>
                             </>
                           )}
                           {/* === END: Conditional UI === */}
@@ -1507,7 +1503,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
                   ? 'border-blue-700 bg-blue-600 text-white hover:bg-blue-500'
                   : 'border-blue-200 bg-blue-100 text-blue-800 hover:bg-blue-200'
               }`}>
-              <span className="mr-2 text-sm">+</span> <span className="text-sm">Add New Provider</span>
+              <span className="mr-2 text-sm">+</span> <span className="text-sm">添加新模型</span>
             </Button>
 
             {isProviderSelectorOpen && (
@@ -1564,7 +1560,7 @@ export const ModelSettings = ({ isDarkMode = false }: ModelSettingsProps) => {
       <div
         className={`rounded-lg border ${isDarkMode ? 'border-slate-700 bg-slate-800' : 'border-blue-100 bg-gray-50'} p-6 text-left shadow-sm`}>
         <h2 className={`mb-4 text-left text-xl font-semibold ${isDarkMode ? 'text-gray-200' : 'text-gray-800'}`}>
-          Model Selection
+          模型选项
         </h2>
         <div className="space-y-4">
           {[AgentNameEnum.Planner, AgentNameEnum.Navigator, AgentNameEnum.Validator].map(agentName => (

+ 1 - 1
pages/side-panel/src/SidePanel.tsx

@@ -551,7 +551,7 @@ const SidePanel = () => {
                 ← Back
               </button>
             ) : (
-              <img src="/icon-128.png" alt="Extension Logo" className="size-6" />
+              <img src="/icon.png" alt="Extension Logo" className="size-6" />
             )}
           </div>
           <div className="header-icons">