Feat:Add and complete small models and robot meta-services#1639
Feat:Add and complete small models and robot meta-services#1639hexqi merged 5 commits intoopentiny:developfrom
Conversation
WalkthroughCentralizes robot plugin state and APIs behind a new useRobot hook and RobotService, refactors components to consume useRobot and reactive robotSettingState (adding completeModel), removes maxTokens from model definitions and UI, updates docs to reference Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant App
participant Plugin as Robot Plugin
participant Registry as Meta Registry
participant RobotService as RobotService (meta)
User->>App: Open application
App->>Plugin: Load robot plugin
Plugin->>Registry: register metas (RobotService)
Registry-->>Plugin: registration confirmed
Note right of RobotService #DDEBF7: RobotService.composable -> useRobot
sequenceDiagram
autonumber
participant Component as Vue Component
participant Hooks as exported useRobot
participant Registry as Hook Resolver
participant Service as RobotService.apis
participant Impl as useRobot implementation
Component->>Hooks: call useRobot()
Hooks->>Registry: getHook(HOOK_NAME.useRobot)
Registry->>Service: resolve composable
Service->>Impl: invoke composable
Impl-->>Component: return { robotSettingState, AIModelOptions, AI_MODES, helpers }
Component->>Component: bind UI, persist completeModel, send requests using robotSettingState
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
Tip 👮 Agentic pre-merge checks are now available in preview!Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.
Please see the documentation for more information. Example: reviews:
pre_merge_checks:
custom_checks:
- name: "Undocumented Breaking Changes"
mode: "warning"
instructions: |
Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).Please share your feedback with us on this Discord post. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
packages/plugins/robot/src/js/useRobot.ts (2)
13-13: Consider updating the meta comment to reflect the actual service path.The comment references
engine.plugins.robot.useRobot, but according to the RobotService definition, the actual ID isengine.service.robot.-/* metaService: engine.plugins.robot.useRobot */ +/* metaService: engine.service.robot */
119-132: Improve error handling transparency.The error message "获取block列表失败" (Failed to fetch block list) doesn't provide enough context. Consider including the actual error details for better debugging.
} catch (err) { // 捕获错误 - throw new Error('获取block列表失败', { cause: err }) + throw new Error(`获取block列表失败: ${err.message}`, { cause: err }) }packages/register/src/hooks.ts (1)
68-69: Consider removing or translating the Chinese comment.The comment "// 自定义" (meaning "// custom") doesn't provide additional context beyond what's already clear from the code. Either remove it or translate it to English for consistency.
[HOOK_NAME.useCustom]: {}, - [HOOK_NAME.useRobot]: {} // 自定义 + [HOOK_NAME.useRobot]: {}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
docs/extension-capabilities-tutorial/ai-plugin-configuration.md(1 hunks)packages/plugins/robot/index.ts(1 hunks)packages/plugins/robot/src/Main.vue(11 hunks)packages/plugins/robot/src/RobotSettingPopover.vue(3 hunks)packages/plugins/robot/src/RobotTypeSelect.vue(2 hunks)packages/plugins/robot/src/js/index.ts(1 hunks)packages/plugins/robot/src/js/useRobot.ts(4 hunks)packages/register/src/hooks.ts(4 hunks)packages/register/src/types.ts(2 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-01-14T08:42:18.574Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1038
File: packages/plugins/block/index.js:24-24
Timestamp: 2025-01-14T08:42:18.574Z
Learning: In the tiny-engine project, breaking changes are documented in the changelog rather than in JSDoc comments or separate migration guides.
Applied to files:
docs/extension-capabilities-tutorial/ai-plugin-configuration.md
📚 Learning: 2025-01-14T06:55:59.692Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:95-98
Timestamp: 2025-01-14T06:55:59.692Z
Learning: The tiny-select component from opentiny/vue library ensures selected options are valid internally, requiring no additional validation in the change handler.
Applied to files:
packages/plugins/robot/src/RobotSettingPopover.vue
📚 Learning: 2025-01-14T06:49:00.797Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:63-73
Timestamp: 2025-01-14T06:49:00.797Z
Learning: In the tiny-engine project, the SvgIcon component is globally registered and available throughout Vue components without requiring explicit imports.
Applied to files:
packages/plugins/robot/src/Main.vue
🧬 Code graph analysis (5)
packages/register/src/types.ts (1)
packages/plugins/robot/src/js/index.ts (1)
RobotService(4-11)
packages/plugins/robot/index.ts (1)
packages/plugins/robot/src/js/index.ts (1)
RobotService(4-11)
packages/plugins/robot/src/js/index.ts (1)
packages/register/src/hooks.ts (2)
useRobot(97-97)HOOK_NAME(22-44)
packages/register/src/hooks.ts (1)
packages/register/src/types.ts (1)
UseRobotApi(27-27)
packages/plugins/robot/src/js/useRobot.ts (1)
packages/register/src/common.ts (1)
getOptions(32-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: push-check
🔇 Additional comments (19)
docs/extension-capabilities-tutorial/ai-plugin-configuration.md (1)
19-19: Documentation reference correctly updated to TypeScript file.The path update from
robotSetting.jstouseRobot.tsaligns with the new hook-based architecture.packages/plugins/robot/src/js/useRobot.ts (1)
177-198: Well-structured module export pattern.The default export factory pattern provides a clean API surface and good encapsulation of the internal state.
packages/register/src/types.ts (2)
14-14: Type import path should use package name.The import uses a relative path to access the robot plugin. Consider using the package name for consistency with other imports.
-import type { RobotService } from '@opentiny/tiny-engine-plugin-robot' +import type { RobotService } from '@opentiny/tiny-engine-plugin-robot'Note: The import is already using the package name. This is correct.
27-27: Type alias follows consistent pattern.The new
UseRobotApitype follows the established naming convention and correctly references the service's API surface.packages/plugins/robot/index.ts (1)
17-23: Plugin metadata properly exposed.The addition of
metas: [RobotService]correctly registers the robot service with the plugin system, following the established pattern.packages/register/src/hooks.ts (3)
18-19: LGTM!The addition of
UseRobotApito the imports anduseRobotto the exports aligns well with the PR's goal of centralizing robot plugin state and APIs. The implementation follows the established pattern for hook registration.
42-43: LGTM!The robot hook is correctly added to
HOOK_NAMEconstant following the existing naming convention.
97-97: LGTM!The
useRobothook is correctly exposed following the established pattern with proper typing.packages/plugins/robot/src/RobotTypeSelect.vue (3)
48-48: LGTM!Good architectural improvement - switching from local imports to the centralized
useRobotregistry hook aligns with the PR's goal of centralizing robot state management.
64-64: LGTM!The constants are properly destructured from
useRobot()and correctly returned for template usage, maintaining the component's functionality while adopting the centralized state management pattern.Also applies to: 83-85
59-59: Default prop changed to literal 'talk' — no break detected.Repo search shows RobotTypeSelect is only used in packages/plugins/robot/src/Main.vue where :aiType is passed (aiType is initialized to TALK_TYPE from useRobot, and useRobot defines TALK_TYPE = 'talk'), so current usage is unaffected.
packages/plugins/robot/src/RobotSettingPopover.vue (3)
86-86: LGTM!Good migration to the centralized registry-based approach via
useRobot, replacing the local module import.
107-107: LGTM!The destructuring of
EXISTING_MODELS,CUSTOMIZE, andgetAIModelOptionsfromuseRobot()properly replaces the previous local imports, maintaining functionality while using the centralized API.
196-207: Good cleanup of the component's public API.The removal of
changeModelandmaxTokensTipfrom the return object, along with the removal of maxTokens-related form fields, simplifies the component interface. This aligns with the centralized state management approach where model changes are likely handled at a higher level.packages/plugins/robot/src/Main.vue (5)
127-134: LGTM!The import changes properly consolidate robot-related functionality under the centralized
useRobothook from the meta-register, aligning with the PR's architectural goals.
191-201: Excellent centralization of robot state management.The destructuring of all robot-related constants and
robotSettingStatefromuseRobot()successfully centralizes the state management. This is a significant architectural improvement that reduces coupling and makes the state more maintainable.
28-28: Consistent use of centralized robotSettingState.All references to the selected model have been correctly updated to use
robotSettingState.selectedModelinstead of the local state. This ensures the state remains synchronized across all components using the robot functionality.Also applies to: 77-78, 237-237
575-578: LGTM - Model management properly centralized.The
initCurrentModelandchangeModelfunctions now correctly operate onrobotSettingState.selectedModel, ensuring model changes are reflected globally across all components using the robot service.Also applies to: 625-654
814-814: LGTM!The component properly exposes
robotSettingStateinstead of the localselectedModel, maintaining consistency with the centralized state management approach.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
docs/advanced-features/new-ai-plugin-usage.md (2)
26-26: Typo: “MC工具按钮” → “MCP工具按钮”.Apply:
- - **MC工具按钮**:管理和配置MCP工具的入口 + - **MCP工具按钮**:管理和配置MCP工具的入口
111-111: Correct acronym expansion: MCP = Model Context Protocol (not Model Connector Protocol).Apply:
- MCP(Model Connector Protocol)是新版AI插件的核心功能之一。 + MCP(Model Context Protocol)是新版AI插件的核心功能之一。packages/plugins/robot/src/RobotSettingPopover.vue (1)
204-210: Consider null-safe access for options lookup.When
AIModelOptions.find()returnsundefined(e.g., whenbaseUrldoesn't match any option), accessingoptions?.modelandoptions?.completeModelcorrectly returnsundefined, but this leavesstate.modelOptionsandstate.completeModelOptionsasundefinedinstead of empty arrays.Consider providing default empty arrays for consistency:
const options = AIModelOptions.find((option) => option.value === state.existFormData.baseUrl) - state.modelOptions = options?.model - state.completeModelOptions = options?.completeModel || [] + state.modelOptions = options?.model || [] + state.completeModelOptions = options?.completeModel || []packages/plugins/robot/src/js/useRobot.ts (1)
80-80: Add validation for completeModel array access.When
getAIModelOptions()[0].completeModelis undefined or empty, accessing[0]?.valuecorrectly returnsundefined, but consider whether an empty string is the intended fallback for all cases.Consider extracting the initialization logic for better maintainability:
+const getDefaultModelConfig = () => { + const options = getAIModelOptions() + const firstOption = options[0] + return { + label: firstOption.label, + activeName: EXISTING_MODELS, + baseUrl: firstOption.value, + model: firstOption.model[0].value, + completeModel: firstOption.completeModel?.[0]?.value || '', + apiKey: '' + } +} + const robotSettingState = reactive({ - selectedModel: { - label: getAIModelOptions()[0].label, - activeName: EXISTING_MODELS, - baseUrl: getAIModelOptions()[0].value, - model: getAIModelOptions()[0].model[0].value, - completeModel: getAIModelOptions()[0].completeModel[0]?.value || '', - apiKey: '' - } + selectedModel: getDefaultModelConfig() })
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
docs/advanced-features/new-ai-plugin-usage.md(1 hunks)packages/plugins/robot/src/Main.vue(10 hunks)packages/plugins/robot/src/RobotSettingPopover.vue(8 hunks)packages/plugins/robot/src/js/useRobot.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-01-14T06:49:00.797Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:63-73
Timestamp: 2025-01-14T06:49:00.797Z
Learning: In the tiny-engine project, the SvgIcon component is globally registered and available throughout Vue components without requiring explicit imports.
Applied to files:
packages/plugins/robot/src/Main.vue
📚 Learning: 2025-01-14T06:55:59.692Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:95-98
Timestamp: 2025-01-14T06:55:59.692Z
Learning: The tiny-select component from opentiny/vue library ensures selected options are valid internally, requiring no additional validation in the change handler.
Applied to files:
packages/plugins/robot/src/RobotSettingPopover.vue
🧬 Code graph analysis (1)
packages/plugins/robot/src/js/useRobot.ts (1)
packages/register/src/common.ts (1)
getOptions(32-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: push-check
🔇 Additional comments (4)
docs/advanced-features/new-ai-plugin-usage.md (2)
68-70: Add migration note for deprecated maxTokens & verify repo-wide cleanupmaxTokens removal is correct — add the migration hint below the model-list snippet and confirm no lingering references.
Location: docs/advanced-features/new-ai-plugin-usage.md — insert after the model list (≈ lines 68–70).
Add:
> 迁移提示:自 v2.8 起,模型项不再支持/需要 maxTokens 字段;插件会基于模型/服务端能力自动处理上下文与长度控制。旧配置中的该字段将被忽略。Verify with:
rg -nP -S '\bmaxTokens\b' -uu rg -nP -S '\bmax_tokens\b' -uu rg -nP -S -i 'maxtokens' -uu rg -nP -S 'customCompatibleAIModels' docsIf matches are found, update/remove those occurrences and re-run the searches.
19-20: Verify referenced images exist and paths are correct.
Automated sandbox checks failed; manually confirm the images referenced in docs/advanced-features/new-ai-plugin-usage.md (lines 19-20, 28-29, 36-37, 43-49, 124-139, 199-203) exist under docs/advanced-features/imgs/ (./imgs) or update the paths. Quick local check: ls -la docs/advanced-features/imgs/packages/plugins/robot/src/Main.vue (1)
368-372: Security: Remove client-side VITE_API_TOKEN fallback to prevent secret exposure.The code falls back to
import.meta.env.VITE_API_TOKENwhenrobotSettingState.selectedModel.apiKeyis unavailable. VITE_* environment variables are embedded in frontend bundles and must not contain secrets. This exposes sensitive API keys to anyone who can access your application's JavaScript.Remove the client-side fallback and require explicit API key configuration:
- Authorization: `Bearer ${robotSettingState.selectedModel.apiKey || import.meta.env.VITE_API_TOKEN}` + Authorization: `Bearer ${robotSettingState.selectedModel.apiKey}`Add validation to reject requests when no API key is provided:
const sendStreamRequest = async () => { const requestData = getSendSeesionProcess() + if (!robotSettingState.selectedModel.apiKey) { + messages.value[messages.value.length - 1].content = '请先配置 API Key' + inProcesing.value = false + return + } if (useMcpServer().isToolsEnabled && aiType.value === TALK_TYPE) {Also applies to line 469.
packages/plugins/robot/src/RobotSettingPopover.vue (1)
150-158: Incorrect — both model defaults already use fallbacks
Both assignments use optional chaining with an empty-string fallback:state.existFormData.model = state.modelOptions[0]?.value || ''andstate.existFormData.completeModel = state.completeModelOptions[0]?.value || ''(packages/plugins/robot/src/RobotSettingPopover.vue lines 153–157).Likely an incorrect or invalid review comment.
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/plugins/robot/src/Main.vue (2)
701-733: Null‑safety and types for file selection; fix potential crash on files === nullfiles can be null; accessing files.length will throw. Retry passes a File, not a FileList. Normalize types and guards.
- const handleSingleFilesSelected = (files: FileList | null, retry = false) => { + const handleSingleFilesSelected = (files: FileList | File | null, retry = false) => { if (retry) { singleAttachmentItems.value[0].status = 'uploading' singleAttachmentItems.value[0].isUploading = true singleAttachmentItems.value[0].messageType = 'uploading' } else { - if (!files.length) return + if (!files || (files as FileList).length === 0) return @@ - if (files && files.length > 1) { + if ((files as FileList).length > 1) { @@ - if (files && files.length > 0) { - // 将选中的文件转换为 Attachment 格式并添加到附件列表 - const newAttachments = Array.from(files).map((file) => ({ + if ((files as FileList).length > 0) { + const list = Array.from(files as FileList) + const newAttachments = list.map((file) => ({ size: file.size, rawFile: file })) singleAttachmentItems.value.push(...newAttachments) } } @@ - const fileData = retry ? files : files[0] + const fileData = retry ? (files as File) : (files as FileList)[0]
229-243: Security: stop persisting API keys in localStorage — remove apiKey from persisted session and source it from in-memory stateConfirmed: Main.vue writes robotSettingState.selectedModel (including apiKey) to localStorage 'aiChat' and RobotSettingPopover stores model info; requests also read apiKey from stored foundationModel — this exposes secrets to XSS and must be fixed.
Actions (minimal):
- Do not persist apiKey into localStorage when writing 'aiChat'. (packages/plugins/robot/src/Main.vue — setContextSession(), ~lines 229-236)
- Use in-memory apiKey for requests instead of requestData.foundationModel?.apiKey (packages/plugins/robot/src/Main.vue — params ~393-399; Authorization headers ~368-372 and ~466-469).
- When hydrating from storage, merge non-sensitive fields and preserve any in-memory apiKey (initCurrentModel, ~572-576).
- Prevent RobotSettingPopover from persisting apiKey into 'AICompleteModel' (packages/plugins/robot/src/RobotSettingPopover.vue ~174-199).
- After changes, verify changeApiKey()/endContent() flows still function (they currently clear and recreate session).
Suggested patch (apply where shown):
@@ - foundationModel: { - ...robotSettingState.selectedModel - }, + // Avoid persisting secrets in localStorage + foundationModel: (({ apiKey, ...rest }) => rest)(robotSettingState.selectedModel || {}), @@ - apiKey: requestData.foundationModel?.apiKey, + // Source from memory, not storage + apiKey: robotSettingState.selectedModel?.apiKey, @@ - robotSettingState.selectedModel = { - ...JSON.parse(aiSession)?.foundationModel - } + // Preserve any existing in-memory apiKey while hydrating non-sensitive fields + robotSettingState.selectedModel = { + ...robotSettingState.selectedModel, + ...JSON.parse(aiSession)?.foundationModel + }
🧹 Nitpick comments (2)
packages/plugins/robot/src/Main.vue (2)
624-627: Also compare completeModel when deciding to clear sessionIf completeModel affects behavior, include it in the change detection to avoid stale sessions.
- if ( - robotSettingState.selectedModel.baseUrl !== model.baseUrl || - robotSettingState.selectedModel.model !== model.model - ) { + if ( + robotSettingState.selectedModel.baseUrl !== model.baseUrl || + robotSettingState.selectedModel.model !== model.model || + robotSettingState.selectedModel.completeModel !== model.completeModel + ) {Also applies to: 637-637
735-740: Avoid manually setting multipart Content-Type for FormDataLet the browser set the boundary; forcing Content-Type can break uploads in some environments.
- .post('/material-center/api/resource/upload', formData, { - headers: { - 'Content-Type': 'multipart/form-data' - } - }) + .post('/material-center/api/resource/upload', formData)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/plugins/robot/src/Main.vue(10 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-01-14T06:49:00.797Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:63-73
Timestamp: 2025-01-14T06:49:00.797Z
Learning: In the tiny-engine project, the SvgIcon component is globally registered and available throughout Vue components without requiring explicit imports.
Applied to files:
packages/plugins/robot/src/Main.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: push-check
🔇 Additional comments (6)
packages/plugins/robot/src/Main.vue (6)
75-78: Upload gating by model and mode — LGTMOnly allowing a single image when the selected model is visual and in BUILD mode is correct and consistent with downstream handling.
126-133: Adopting meta-register hooks — LGTMImporting useRobot/useHistory/useCanvas/useModal/getMetaApi centralizes deps and improves cohesion.
190-201: Centralized robot state via useRobot — LGTMDestructuring robotSettingState and constants from useRobot aligns this component with the new state model.
624-627: Fix comparison bug — LGTMComparing baseUrl and model strings against the incoming model is correct and resolves the always-true condition.
647-652: Credential-only updates handled in-place — LGTMUpdating apiKey without resetting when baseUrl/model are unchanged is correct.
368-373: Security — remove client-side fallback to VITE_API_TOKEN; fail-fast when missing apiKeyVITE_* variables are baked into the bundle and must not hold secrets. Using them as a fallback risks unauthorized API usage. Require an explicit apiKey and abort when absent.
Apply:
@@ - await sendMcpRequest(messages.value, { - model: robotSettingState.selectedModel.model, - headers: { - Authorization: `Bearer ${robotSettingState.selectedModel.apiKey || import.meta.env.VITE_API_TOKEN}` - }, - baseUrl: robotSettingState.selectedModel.baseUrl - }) + await sendMcpRequest(messages.value, { + model: robotSettingState.selectedModel.model, + headers: { + Authorization: `Bearer ${robotSettingState.selectedModel.apiKey}` + }, + baseUrl: robotSettingState.selectedModel.baseUrl + }) @@ - { - Authorization: `Bearer ${robotSettingState.selectedModel.apiKey || import.meta.env.VITE_API_TOKEN}` - } + { + Authorization: `Bearer ${robotSettingState.selectedModel.apiKey}` + }Add a guard at the start of sendStreamRequest:
const sendStreamRequest = async () => { + if (!robotSettingState.selectedModel?.apiKey) { + requestLoading.value = false + inProcesing.value = false + Notify({ type: 'error', message: '未配置 API Key', position: 'top-right', duration: 5000 }) + return + } const requestData = getSendSeesionProcess()#!/bin/bash # Ensure no remaining fallbacks to VITE_API_TOKEN rg -n -C2 'VITE_API_TOKEN' --type js --type ts --type vueAlso applies to: 468-469
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/plugins/robot/src/Main.vue (1)
223-236: Do not persist API keys in localStorage.
setContextSessionstoresselectedModelincludingapiKeyintolocalStorage. This is a client-side secret leak.Apply:
- localStorage.setItem( - 'aiChat', - sessionProcess - ? JSON.stringify(sessionProcess) - : JSON.stringify({ - foundationModel: { - ...robotSettingState.selectedModel - }, - messages: [], - displayMessages: [], // 专门用来进行展示的消息,非原始消息,仅作为展示但是不作为请求的发送 - aiType: aiType.value - }) - ) + const { apiKey, ...safeModel } = robotSettingState.selectedModel + localStorage.setItem( + 'aiChat', + sessionProcess + ? JSON.stringify(sessionProcess) + : JSON.stringify({ + foundationModel: safeModel, + messages: [], + displayMessages: [], + aiType: aiType.value + }) + )packages/plugins/robot/src/RobotSettingPopover.vue (1)
159-166: Fix potential crash when baseUrl has no matching option.Indexing
state.modelOptions[0]without ensuring the array exists will throw.Apply:
- const options = AIModelOptions.find((option) => option.value === state.existFormData.baseUrl) - state.modelOptions = options?.model - state.existFormData.label = options?.label - state.existFormData.model = state.modelOptions[0]?.value || '' - state.existFormData.completeModel = state.modelOptions[0]?.value || '' + const options = AIModelOptions.find((o) => o.value === state.existFormData.baseUrl) + state.modelOptions = options?.model ?? [] + state.existFormData.label = options?.label ?? '' + state.existFormData.model = state.modelOptions?.[0]?.value ?? '' + state.existFormData.completeModel = state.modelOptions?.[0]?.value ?? ''
🧹 Nitpick comments (6)
packages/plugins/robot/src/js/useRobot.ts (3)
65-68: Cache or memoize getAIModelOptions result for stability.Multiple calls can return different references if options are mutated externally; also avoids repeated lookups.
Consider memoizing once per session or returning a frozen copy to discourage mutation.
117-130: Don’t throw in initBlockList; propagate errors via return and let caller decide.Throwing here bubbles into onMounted in Main.vue and can prevent cleanup/further init.
Either handle here or ensure the caller wraps with try/finally. See Main.vue comment proposing a caller-side fix.
18-22: Prefer ability-driven checks over VISUAL_MODEL list.You already annotate visual-capable models via
ability: ['visual']. KeepingVISUAL_MODELrisks drift.Remove
VISUAL_MODELfrom the public surface and rely onabilitywhen determining visual features.packages/plugins/robot/src/Main.vue (2)
598-601: Ensure loader closes and chat initializes even if initBlockList fails.Wrap with try/catch/finally.
Apply:
- await initBlockList() - loadingInstance.close() - initChat() + try { + await initBlockList() + } catch (err) { + // eslint-disable-next-line no-console + console.error('初始化区块失败', err) + } finally { + loadingInstance.close() + } + initChat()
511-516: Avoid hard-coded user name in messages.Using
'John'is misleading; prefer current user or omit.Apply:
- return { - role: 'user', - content, - name: 'John' - } + return { role: 'user', content }packages/plugins/robot/src/RobotSettingPopover.vue (1)
42-43: Mask API keys in inputs.Use password input to avoid shoulder-surfing.
Apply:
- <tiny-input class="filedName" v-model="state.existFormData.apiKey" placeholder="请输入"></tiny-input> + <tiny-input class="filedName" type="password" v-model="state.existFormData.apiKey" placeholder="请输入"></tiny-input>- <tiny-input class="filedName" v-model="state.customizeFormData.apiKey" placeholder="请输入"></tiny-input> + <tiny-input class="filedName" type="password" v-model="state.customizeFormData.apiKey" placeholder="请输入"></tiny-input>Also applies to: 79-80
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
packages/plugins/robot/src/Main.vue(22 hunks)packages/plugins/robot/src/RobotSettingPopover.vue(10 hunks)packages/plugins/robot/src/RobotTypeSelect.vue(5 hunks)packages/plugins/robot/src/js/useRobot.ts(4 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-01-14T06:49:00.797Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:63-73
Timestamp: 2025-01-14T06:49:00.797Z
Learning: In the tiny-engine project, the SvgIcon component is globally registered and available throughout Vue components without requiring explicit imports.
Applied to files:
packages/plugins/robot/src/Main.vue
📚 Learning: 2025-01-14T06:55:59.692Z
Learnt from: gene9831
PR: opentiny/tiny-engine#1011
File: packages/configurator/src/router-select-configurator/RouterSelectConfigurator.vue:95-98
Timestamp: 2025-01-14T06:55:59.692Z
Learning: The tiny-select component from opentiny/vue library ensures selected options are valid internally, requiring no additional validation in the change handler.
Applied to files:
packages/plugins/robot/src/RobotSettingPopover.vue
🧬 Code graph analysis (1)
packages/plugins/robot/src/js/useRobot.ts (1)
packages/register/src/common.ts (1)
getOptions(32-34)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: push-check
🔇 Additional comments (5)
packages/plugins/robot/src/RobotTypeSelect.vue (1)
48-67: LGTM — moved to AI_MODES from hook and simplified defaults.Bindings and emits look correct.
packages/plugins/robot/src/Main.vue (3)
617-646: Good fix on model-switch comparison.Comparing
selectedModel.modeltomodel.modelprevents unintended session clearing.
357-367: Remove client-side fallback to VITE_API_TOKEN; require explicit apiKey or use a secure server token.Reintroduces a previously flagged security risk by falling back to
import.meta.env.VITE_API_TOKEN.Apply:
- await sendMcpRequest(messages.value, { - model: robotSettingState.selectedModel.model, - headers: { - Authorization: `Bearer ${robotSettingState.selectedModel.apiKey || import.meta.env.VITE_API_TOKEN}` - }, - baseUrl: robotSettingState.selectedModel.baseUrl - }) + const token = robotSettingState.selectedModel.apiKey?.trim() + if (!token) { + Notify({ type: 'error', message: '缺少 API Key,请在设置中配置后重试。', position: 'top-right', duration: 5000 }) + return + } + await sendMcpRequest(messages.value, { + model: robotSettingState.selectedModel.model, + headers: { Authorization: `Bearer ${token}` }, + baseUrl: robotSettingState.selectedModel.baseUrl + })
462-463: Same: remove fallback to VITE_API_TOKEN in chatStream headers.Apply:
- { - Authorization: `Bearer ${robotSettingState.selectedModel.apiKey || import.meta.env.VITE_API_TOKEN}` - } + { + Authorization: `Bearer ${robotSettingState.selectedModel.apiKey}` + }And guard before invoking
chatStream:+ if (!robotSettingState.selectedModel.apiKey?.trim()) { + Notify({ type: 'error', message: '缺少 API Key,请在设置中配置后重试。', position: 'top-right', duration: 5000 }) + inProcesing.value = false + return + }packages/plugins/robot/src/RobotSettingPopover.vue (1)
185-191: Confirm necessity of completeModel; remove if unused.
Automated search failed (ripgrep skipped files), so verification is inconclusive. Check whether Main.vue or any other code reads the 'AICompleteModel' localStorage key; if not, remove the persisted completeModel to avoid redundant state.
Location: packages/plugins/robot/src/RobotSettingPopover.vue (lines 185–191).
English | 简体中文
PR
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
Background and solution
What is the current behavior?
Issue Number: N/A
What is the new behavior?
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
New Features
Refactor
Documentation