Skip to content

Conversation

@SonyLeo
Copy link
Contributor

@SonyLeo SonyLeo commented Jan 16, 2026

English | 简体中文

PR:优化 JS 面板编辑器 AI 代码补全架构

本 PR 对 AI 代码补全功能进行了全面重构,移除了旧的补全系统,
采用 monacopilot 作为新的补全引擎,并优化了模型配置和选择体验。

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)
  • Built its own designer, fully self-validated

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

Background and solution

🌐 体验入口 --> TinyEngine

🎯 主要变更

1. 移除旧的 AI 补全实现

删除的代码:

  • packages/common/js/completion.js 中的旧 AI 补全相关函数(~150 行)
    • generateBaseReference() - 生成 AI prompt 的上下文
    • fetchAiInlineCompletion() - 调用 AI API
    • initInlineCompletion() - 注册旧的 inline completion provider
  • packages/common/js/completion-files/context.md - 旧的 AI prompt 模板
  • packages/common/js/completion-files/ 目录

保留的功能:

  • 基础的 Lowcode API 补全(this.state/props/utils 等)
  • 代码片段提示
  • 用户变量提示

2. 新的 AI 补全架构(基于 monacopilot)

核心实现:

  • 📁 packages/plugins/script/src/ai-completion/ - 新的 AI 补全模块
    • adapters/ - 适配器层,支持 Qwen 和 DeepSeek 模型
    • builders/ - Prompt 构建器,支持 FIM(Fill-In-the-Middle)
    • triggers/ - 智能触发器,优化补全时机
    • utils/ - 工具函数(模型检测、Token 计算等)
    • constants.js - 配置常量

技术特性:

  • ✅ 使用 monacopilot 库提供的 registerCompletion API
  • ✅ 内置防抖机制(trigger: 'onIdle'
  • ✅ 支持 Qwen 和 DeepSeek 两种模型类型
  • ✅ 完善的 FIM(Fill-In-the-Middle)支持
  • ✅ 智能的代码上下文分析和补全触发

补全触发条件:

  • 输入代码自动触发

  • 命令面板手动触发

manually-trigger-completions

3. 配置化支持

  • 默认onIdle 防抖 400ms
  • 默认onTyping 防抖 120ms

meta.js 配置:

options: {
  aiCompletionEnabled: true, // 启用/禁用 AI 补全
  // aiCompletionTrigger: 'onIdle' // 可选:触发模式 'onIdle'(默认) | 'onTyping' | 'onDemand'
}

Main.vue 实现:

  • 从配置中读取 aiCompletionEnabledaiCompletionTrigger
  • 只有启用时才注册 monacopilot AI 补全
  • 组件卸载时正确清理资源

4. 模型配置优化

新增 codeCompletion 能力标识:

// packages/plugins/robot/src/types/setting.types.ts
export interface ModelConfig {
  capabilities?: {
    toolCalling?: boolean
    vision?: boolean
    reasoning?: boolean | Capability
    compact?: boolean
    codeCompletion?: boolean // ✅ 新增:标识代码补全优化模型
    jsonOutput?: boolean | Capability
  }
}

更新的模型配置:

  • ✅ Qwen Coder 系列模型标记为 codeCompletion: true
  • ✅ DeepSeek Coder 模型标记为 codeCompletion: true

标记为代码补全优化的模型:

  • qwen3-coder-plus
  • qwen-coder-turbo-latest
  • qwen2.5-coder-32b-instruct
  • deepseek-coder
4.1 模型列表调整(支持 FIM)

调整原因:

新的 AI 代码补全基于 FIM(Fill-In-the-Middle)技术,需要模型原生支持 FIM 能力才能提供高质量的代码补全。因此需要:

  • 移除不支持 FIM 的小参数通用模型
  • 新增/升级支持 FIM 的专业编码模型
  • 确保所有代码补全模型都具备 FIM 能力

阿里云百炼模型变更:

删除的模型(3个 - 不支持 FIM):

  • Qwen Coder编程模型(Flash) (qwen3-coder-flash) - 旧版本,不支持 FIM
  • Qwen3(14b) (qwen3-14b) - 小参数通用模型,不支持 FIM
  • Qwen3(8b) (qwen3-8b) - 小参数通用模型,不支持 FIM

新增的模型(2个 - 支持 FIM):

  • Qwen2.5 Coder编程模型-最快响应 (qwen-coder-turbo-latest)
    • 支持 FIM,轻量级,快速响应
    • 替代 qwen3-coder-flash
  • Qwen2.5 Coder编程模型(32B) (qwen2.5-coder-32b-instruct)
    • 支持 FIM,中等参数,平衡性能和质量
    • 替代 qwen3-14bqwen3-8b

保留并增强的模型:

  • Qwen Coder编程模型(PLUS) (qwen3-coder-plus) - 添加 codeCompletion: true

DeepSeek 模型变更:

新增的模型(1个 - 支持 FIM):

  • Deepseek Coder编程模型 (deepseek-coder)
    • 支持 FIM,专门的代码补全模型
    • 提供 DeepSeek 的代码补全能力
    • 配置:toolCalling: true, compact: true, codeCompletion: true

保留的模型:

  • DeepSeek (deepseek-chat) - 对话模型,用于默认助手

代码补全模型(支持 FIM):

  • Qwen Coder编程模型(PLUS)
  • Qwen2.5 Coder编程模型-最快响应
  • Qwen2.5 Coder编程模型(32B)
  • Deepseek Coder编程模型

5. UI/UX 优化

default-model-list quickly-model-list

RobotSetting.vue 改进:

  1. 模型选择分离

    • 默认助手模型:排除代码补全专用模型
    • 快速模型:包含所有轻量和代码补全模型
  2. 视觉标签

    • 🔵「代码」标签 - 标识代码补全优化模型
    • 🔵 「轻量」标签 - 标识轻量级模型
    • 🔵 「工具」标签 - 标识支持工具调用
    • 🔵 「视觉」标签 - 标识支持视觉理解
  3. 智能排序

    • 按服务提供商自动分组(阿里云百炼、DeepSeek 等)
    • 同一服务商的模型聚在一起,避免混乱
  4. 优化提示文案

    用于代码补全、话题命名等快速响应场景。
    推荐选择带「代码」标签的模型以获得更好的代码补全效果。
    

6. 类型安全改进

类型推导:

// 从 monacopilot 的类型定义中推导
type RequestHandler = NonNullable<RegisterCompletionOptions['requestHandler']>
type TriggerMode = NonNullable<RegisterCompletionOptions['trigger']>

优势:

  • 自动同步 monacopilot 的类型更新
  • 避免手动维护联合类型
  • 类型安全且易于维护

7. 依赖变更

新增依赖:

  • monacopilot@^1.2.12 - AI 代码补全引擎库
    • 提供 Monaco Editor 的 AI 补全能力
    • 内置防抖、缓存等优化机制
    • 支持自定义 requestHandler

导入路径调整:

  • @opentiny/tiny-engine-common@opentiny/tiny-engine-common/component
    • 更精确的导入路径,减少打包体积

安装方式:

pnpm install

注意事项:

  • 首次拉取代码后需要执行 pnpm install 安装新依赖
  • monacopilot 依赖 monaco-editor,确保版本兼容

📁 ai-completion 目录结构

packages/plugins/script/src/ai-completion/
├── index.js                    # 统一导出入口
├── constants.js                # 配置常量
├── adapters/                   # 适配器层
│   ├── index.js               # 主适配器(createCompletionHandler)
│   ├── qwenAdapter.js         # Qwen 模型适配器
│   └── deepseekAdapter.js     # DeepSeek 模型适配器
├── builders/                   # Prompt 构建器
│   ├── index.js               # 构建器导出
│   ├── promptBuilder.js       # 智能 Prompt 构建器
│   ├── fimPromptBuilder.js    # FIM Prompt 构建器
│   └── lowcodeContextBuilder.js # 低代码上下文构建器
├── prompts/                    # Prompt 模板
│   └── templates.js           # 模板定义
├── triggers/                   # 触发器
│   └── completionTrigger.js   # 补全触发逻辑
└── utils/                      # 工具函数
    ├── modelUtils.js          # 模型工具(检测、Token 计算等)
    └── completionUtils.js     # 补全工具(清理、元数据构建等)

🔄 基本调用流程

1. 初始化阶段(Main.vue)
// 1. 导入模块
import { createCompletionHandler } from './ai-completion/adapters/index'
import { shouldTriggerCompletion } from './ai-completion/triggers/completionTrigger'

// 2. 创建补全处理器
const handler = createCompletionHandler()

// 3. 注册到 monacopilot
completion = registerCompletion(monaco, editor, {
  trigger: 'onIdle',
  triggerIf: ({ text, position }) => shouldTriggerCompletion({ text, position }),
  requestHandler: handler
})
2. 补全触发流程
用户输入代码
    ↓
monacopilot 检测到输入暂停(onIdle)
    ↓
调用 triggerIf(shouldTriggerCompletion)
    ↓ [通过]
调用 requestHandler(createCompletionHandler 返回的函数)
    ↓
┌─────────────────────────────────────────┐
│ createCompletionHandler 内部流程         │
├─────────────────────────────────────────┤
│ 1. 获取 AI 配置                          │
│    └─ getMetaApi(Robot).getSelectedQuickModelInfo() │
│                                          │
│ 2. 提取代码上下文                        │
│    └─ textBeforeCursor, textAfterCursor │
│                                          │
│ 3. 构建 Prompt                           │
│    ├─ buildLowcodeMetadata()            │
│    └─ createSmartPrompt()               │
│                                          │
│ 4. 检测模型类型                          │
│    └─ detectModelType(completeModel)    │
│                                          │
│ 5. 调用对应的适配器                      │
│    ├─ Qwen: buildQwenMessages()         │
│    │         + callQwenAPI()            │
│    └─ DeepSeek: buildDeepSeekMessages() │
│                 + callDeepSeekAPI()     │
│                                          │
│ 6. 清理补全结果                          │
│    └─ cleanCompletion()                 │
└─────────────────────────────────────────┘
    ↓
返回补全结果给 monacopilot
    ↓
monacopilot 在编辑器中显示补全
3. 详细调用链
// 触发检查
shouldTriggerCompletion(context)
  └─ 检查光标位置、代码上下文
  └─ 返回 true/false

// 补全处理
createCompletionHandler()()
  ├─ getMetaApi(META_SERVICE.Robot).getSelectedQuickModelInfo()
     └─ 获取:completeModel, apiKey, baseUrl
  
  ├─ buildLowcodeMetadata()
     ├─ useResource().appSchemaState
     └─ useCanvas().getPageSchema()
  
  ├─ createSmartPrompt()
     ├─ 分析代码上下文
     └─ 构建 prompt
  
  ├─ detectModelType(completeModel)
     └─ 返回 'qwen' | 'deepseek' | 'unknown'
  
  ├─ [Qwen 分支]
     ├─ buildQwenMessages(fileContent, fimBuilder)
     ├─ calculateTokens(cursorContext)
     ├─ getStopSequences(cursorContext, 'qwen')
     └─ callQwenAPI(messages, config, apiKey, baseUrl)
  
  ├─ [DeepSeek 分支]
     ├─ buildDeepSeekMessages(context, instruction, fileContent)
     ├─ getStopSequences(null, 'deepseek')
     └─ callDeepSeekAPI(messages, config, apiKey, baseUrl, httpClient)
  
  └─ cleanCompletion(completionText, modelType, cursorContext)
      ├─ 移除 markdown 代码块
      ├─ 移除 FIM 标记
      ├─ 智能截断
      └─ 返回清理后的文本

📊 影响范围

新增文件
  • packages/plugins/script/src/ai-completion/ 目录及所有子文件
    • index.js - 统一导出
    • constants.js - 配置常量
    • adapters/index.js - 主适配器
    • adapters/qwenAdapter.js - Qwen 适配器
    • adapters/deepseekAdapter.js - DeepSeek 适配器
    • builders/index.js - 构建器导出
    • builders/promptBuilder.js - Prompt 构建器
    • builders/fimPromptBuilder.js - FIM 构建器
    • builders/lowcodeContextBuilder.js - 低代码上下文构建器
    • prompts/templates.js - Prompt 模板
    • triggers/completionTrigger.js - 触发器
    • utils/modelUtils.js - 模型工具
    • utils/completionUtils.js - 补全工具
修改文件
  • packages/common/js/completion.js - 移除旧 AI 补全代码
  • packages/plugins/script/src/Main.vue - 集成新的 AI 补全
  • packages/plugins/script/meta.js - 添加配置选项
  • packages/plugins/robot/src/constants/model-config.ts - 优化模型配置
  • packages/plugins/robot/src/types/setting.types.ts - 添加 codeCompletion 类型
  • packages/plugins/robot/src/composables/core/useConfig.ts - 添加模型筛选函数
  • packages/plugins/robot/src/components/header-extension/robot-setting/RobotSetting.vue - UI 优化
删除文件
  • packages/common/js/completion-files/context.md
  • packages/common/js/completion-files/ 目录

🎨 用户体验改进

代码补全
  • ✅ 更智能的补全触发时机
  • ✅ 更准确的代码补全结果
  • ✅ 支持多种模型(Qwen、DeepSeek)
  • ✅ 可配置的触发模式
模型选择
  • ✅ 清晰的模型分类和标签
  • ✅ 按服务商自动分组
  • ✅ 代码补全模型与通用模型分离
  • ✅ 直观的视觉提示

📝 配置示例

启用 AI 补全(默认)
// packages/plugins/script/meta.js
options: {
  aiCompletionEnabled: true
}
禁用 AI 补全
options: {
  aiCompletionEnabled: false
}
自定义触发模式
options: {
  aiCompletionEnabled: true,
  aiCompletionTrigger: 'onTyping' // 实时触发
}

options: {
  aiCompletionEnabled: true,
  aiCompletionTrigger: 'onDemand' // 仅手动触发
}

📚 相关文档

扩展阅读

qwen-support-coder-FIM

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

Release Notes

  • New Features

    • AI-assisted code completion now available in the script editor with support for Qwen and DeepSeek models.
    • Enhanced model selection with filtering by capabilities (code completion vs. general-purpose models).
    • Improved model UI with capability indicators and faster-response model recommendations.
  • Chores

    • Updated model roster with new code-specific models and removed legacy entries.
    • Added new external library dependency for completion support.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

Walkthrough

This pull request transitions away from an older AI completion approach by removing related code and documentation, then introduces a new monacopilot-based code completion system. It updates model configurations to mark code-completion-capable models and adjusts the robot plugin UI accordingly.

Changes

Cohort / File(s) Summary
Removal of legacy AI completion
packages/common/js/completion-files/context.md, packages/common/js/completion.js
Deleted context guidance documentation and removed AI-powered inline completion logic (generateBaseReference, fetchAiInlineCompletion, initInlineCompletion), imports, and throttling.
Robot plugin model capability updates
packages/plugins/robot/src/types/setting.types.ts, packages/plugins/robot/src/constants/model-config.ts, packages/plugins/robot/src/composables/core/useConfig.ts
Added codeCompletion boolean capability flag to ModelConfig interface. Updated model entries (Qwen Plus, Qwen Coder variants, new Qwen2.5 Coder 32B, new DeepSeek Coder) with codeCompletion: true. Added helper methods getCodeCompletionModels() and getNonCodeCompletionModels() to filter models. Expanded getCompactModels() to include code-completion models.
Robot plugin UI adjustments
packages/plugins/robot/src/components/header-extension/robot-setting/RobotSetting.vue
Replaced getAllAvailableModels with getNonCodeCompletionModels to source model options. Enhanced quick-model option rendering with capability tags (代码, 轻量) and serviceName sorting. Updated tooltip text for faster response scenarios.
Script plugin monacopilot integration
packages/plugins/script/meta.js, packages/plugins/script/package.json, packages/plugins/script/src/Main.vue
Renamed flag enableAICompletion to aiCompletionEnabled in plugin options. Added monacopilot ^1.2.12 dependency. Refactored editor mount flow to initialize monacopilot-based completion provider with language, filename, context limits, and trigger logic. Added cleanup deregistration on unmount. Introduced CompletionRegistration lifecycle and error handling.
AI completion builder framework
packages/plugins/script/src/ai-completion/builders/*.js
Added FIMPromptBuilder class for Fill-In-the-Middle prompt optimization with cursor context analysis, prefix/suffix truncation, and metadata cleaning. Added promptBuilder module to detect cursor context, extract code constructs, and assemble language/lowcode-aware instructions. Added lowcodeContextBuilder to normalize low-code metadata (data sources, utils, global/local state, methods, schema) into structured context. Exported re-exports via index.
AI completion adapter implementations
packages/plugins/script/src/ai-completion/adapters/*.js
Added qwenAdapter with buildQwenMessages and callQwenAPI for Qwen Completions API integration. Added deepseekAdapter with buildDeepSeekMessages and callDeepSeekAPI for DeepSeek API integration. Created adapter factory createCompletionHandler that detects model type, builds context/instruction/fileContent, routes to appropriate API, and handles responses with cleanup.
AI completion utilities and configuration
packages/plugins/script/src/ai-completion/utils/*.js, packages/plugins/script/src/ai-completion/constants.js, packages/plugins/script/src/ai-completion/prompts/templates.js, packages/plugins/script/src/ai-completion/triggers/completionTrigger.js, packages/plugins/script/src/ai-completion/index.js
Added constants for Qwen/DeepSeek configurations, API endpoints, error messages, FIM markers, stop sequences, and code patterns. Added prompt templates (SYSTEM_BASE_PROMPT, code/comment/lowcode instructions, user prompt builder). Added trigger logic (shouldTriggerCompletion) to exclude triggers after statement/block ends. Added utilities (buildLowcodeMetadata, cleanCompletion, detectModelType, calculateTokens, getStopSequences). Created central re-export index.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Whiskers twitching with delight,
New completion flows shine bright,
Monacopilot takes the stage,
FIM prompts fill the page,
Models sorted, duties clear—
Code assist has arrived here!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the primary change: refactoring AI code completion with monacopilot and FIM support, which aligns with the main objectives of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the enhancement New feature or request label Jan 16, 2026
@SonyLeo SonyLeo changed the title feat: Refactor AI code completion with monacopilot and FIM support feat: refactor AI code completion with monacopilot and FIM support Jan 16, 2026
@SonyLeo SonyLeo marked this pull request as ready for review January 16, 2026 08:25
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In `@packages/plugins/script/package.json`:
- Around line 30-31: The package.json currently depends on "monacopilot":
"^1.2.12", which is not published to npm; change the dependency to the latest
published version "monacopilot": "^1.2.7" (or pin to 1.2.7) so installs succeed;
locate the dependency entry for "monacopilot" in
packages/plugins/script/package.json and update the version string accordingly,
then run install/lockfile update.

In `@packages/plugins/script/src/ai-completion/adapters/deepseekAdapter.js`:
- Around line 37-57: The JSDoc for callDeepSeekAPI wrongly promises
Promise<string> while the implementation uses optional chaining
(response?.choices?.[0]?.message?.content) and can return undefined; either
update the JSDoc to Promise<string|undefined> to match the actual return or
change callDeepSeekAPI to validate the response and either throw an error or
return a defined fallback (e.g., empty string) before returning, making sure to
reference the callDeepSeekAPI function and the
response?.choices?.[0]?.message?.content access when you locate and fix the
code.

In `@packages/plugins/script/src/ai-completion/builders/promptBuilder.js`:
- Around line 15-35: In isInComment, remove the outer trimmed.includes('//')
guard that causes false positives for URLs and instead directly compute the
current line (using lastIndexOf('\n') and substring as already present) and
check currentLine.trim().startsWith('//') to determine line comments; keep the
existing block-comment detection (lastBlockStart/lastBlockEnd) unchanged so only
true line-starting '//' are treated as comments.

In `@packages/plugins/script/src/ai-completion/utils/completionUtils.js`:
- Around line 67-86: The truncation logic can produce an empty result when
cutoffIndex becomes 0 (e.g., first line starts with a CUTOFF_KEYWORD); update
the block in completionUtils.js that computes cutoffIndex (references: lines,
maxLines, truncation.CUTOFF_KEYWORDS, truncation.BLOCK_ENDINGS, cutoffIndex,
cleaned) to ensure at least one non-empty line is kept: if cutoffIndex is 0,
advance it to 1 (or scan forward to the next non-empty/safe line) before slicing
so lines.slice(0, cutoffIndex) never returns an empty array and cleaned always
contains content.

In `@packages/plugins/script/src/Main.vue`:
- Around line 148-155: The global registration uses
monaco.editor.addEditorAction which registers the action for all editors and
lacks cleanup; replace that call with the instance method editor.addAction to
scope the action to this editor (the local editor variable used around line 130)
and ensure it is tied to this editor's lifecycle alongside
completion.deregister(); update the registration to use editor.addAction and
rely on the editor instance unmount/cleanup (or explicitly dispose the returned
action if needed) so triggering only calls completion.trigger() for this editor.
🧹 Nitpick comments (13)
packages/plugins/script/src/ai-completion/triggers/completionTrigger.js (2)

11-17: Edge case: Parenthesis counting may misfire in complex code.

The parenthesis counting approach doesn't account for parentheses inside string literals or comments. For example, console.log("("); would be incorrectly detected as having unclosed parentheses.

This is an acceptable tradeoff for most real-world code, but consider documenting this limitation or using a more robust approach if edge cases become problematic.


32-36: Redundant condition in isAfterBlockEnd.

After trimmedEnd = beforeCursor.trimEnd(), the expression beforeCursor.substring(trimmedEnd.length) yields only trailing whitespace. Checking afterBrace.trim().length === 0 will always be true.

The check can be simplified:

♻️ Suggested simplification
 function isAfterBlockEnd(beforeCursor) {
   const trimmedEnd = beforeCursor.trimEnd()
 
   // 检查是否以右花括号结尾
   if (trimmedEnd.endsWith('}')) {
-    // 检查后面是否只有空格(没有其他字符)
-    const afterBrace = beforeCursor.substring(trimmedEnd.length)
-    return afterBrace.trim().length === 0
+    return true
   }
 
   return false
 }
packages/plugins/script/src/ai-completion/builders/lowcodeContextBuilder.js (2)

32-37: Arrow function regex may miss destructured parameters.

The regex (?:\(([^)]*)\)|(\w+))\s*=> won't correctly capture nested parentheses in destructured parameters like ({a, b}) => or ([x, y]) =>, as [^)]* stops at the first ).

For the current use case (extracting approximate signatures for context), this is likely acceptable, but consider documenting the limitation.


213-252: Consider deduplication when merging contexts.

mergeLowcodeContexts concatenates arrays without deduplication. If the same data source or utility appears in multiple contexts, it will be duplicated in the merged result, potentially inflating the AI prompt context.

If this becomes an issue, consider deduplicating by name or id:

♻️ Optional deduplication approach
+const dedupeByKey = (arr, key) => {
+  const seen = new Set()
+  return arr.filter((item) => {
+    const k = item[key]
+    if (seen.has(k)) return false
+    seen.add(k)
+    return true
+  })
+}
+
 export function mergeLowcodeContexts(...contexts) {
   // ...existing merge logic...
+  
+  // Deduplicate arrays
+  merged.dataSource = dedupeByKey(merged.dataSource, 'name')
+  merged.utils = dedupeByKey(merged.utils, 'name')
+  merged.globalState = dedupeByKey(merged.globalState, 'id')
+  
   return merged
 }
packages/plugins/script/src/Main.vue (1)

129-130: Variable shadowing may cause confusion.

monaco and editor shadow outer variables: monaco shadows the component ref (line 68), and editor shadows the function parameter (line 111). This can lead to maintenance confusion.

♻️ Suggested rename for clarity
         try {
-          const monaco = monacoRef.value.getMonaco()
-          const editor = monacoRef.value.getEditor()
+          const monacoInstance = monacoRef.value.getMonaco()
+          const editorInstance = monacoRef.value.getEditor()
 
-          completion = registerCompletion(monaco, editor, {
+          completion = registerCompletion(monacoInstance, editorInstance, {
             language: 'javascript',
             // ...
           })
 
-          monaco.editor.addEditorAction({
+          monacoInstance.editor.addEditorAction({
packages/plugins/script/src/ai-completion/adapters/qwenAdapter.js (1)

46-61: Consider adding request timeout and handling malformed API responses.

Two potential reliability concerns:

  1. The fetch call has no timeout, which could cause indefinite hangs if the API is unresponsive.
  2. Line 61 returns response?.choices?.[0]?.text which may silently return undefined on malformed responses without signaling an error to callers.
♻️ Suggested improvement
+const TIMEOUT_MS = 30000
+
 export async function callQwenAPI(messages, config, apiKey, baseUrl) {
   const completionsUrl = `${baseUrl}${QWEN_CONFIG.COMPLETION_PATH}`
+  const controller = new AbortController()
+  const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS)

   // ... request body construction ...

-  const fetchResponse = await fetch(completionsUrl, {
+  const fetchResponse = await fetch(completionsUrl, {
     method: HTTP_CONFIG.METHOD,
     headers: {
       'Content-Type': HTTP_CONFIG.CONTENT_TYPE,
       Authorization: `Bearer ${apiKey}`
     },
-    body: JSON.stringify(requestBody)
+    body: JSON.stringify(requestBody),
+    signal: controller.signal
   })
+  clearTimeout(timeoutId)

   // ... error handling ...

   const response = await fetchResponse.json()
-  return response?.choices?.[0]?.text
+  const completionText = response?.choices?.[0]?.text
+  if (completionText === undefined) {
+    throw new Error(`${ERROR_MESSAGES.QWEN_API_ERROR} Malformed response: missing completion text`)
+  }
+  return completionText
 }
packages/plugins/robot/src/constants/model-config.ts (1)

126-135: Minor: Inconsistent capitalization in label.

The label 'Deepseek Coder编程模型' uses lowercase 's' while other DeepSeek references use 'DeepSeek' (e.g., line 66, 108, 113).

✏️ Suggested fix
       {
-        label: 'Deepseek Coder编程模型',
+        label: 'DeepSeek Coder编程模型',
         name: 'deepseek-coder',
packages/plugins/script/src/ai-completion/adapters/index.js (2)

78-79: URL replacement may silently fail if baseUrl doesn't contain /v1.

The replace(DEEPSEEK_CONFIG.PATH_REPLACE, DEEPSEEK_CONFIG.COMPLETION_PATH) will return the original URL unchanged if /v1 is not present. Consider adding validation or a warning log if the replacement doesn't occur, to help with debugging configuration issues.

💡 Optional: Add validation for URL replacement
       // 构建 DeepSeek FIM 端点:将 /v1 替换为 /beta
-      const completionBaseUrl = baseUrl.replace(DEEPSEEK_CONFIG.PATH_REPLACE, DEEPSEEK_CONFIG.COMPLETION_PATH)
+      const completionBaseUrl = baseUrl.replace(DEEPSEEK_CONFIG.PATH_REPLACE, DEEPSEEK_CONFIG.COMPLETION_PATH)
+      if (completionBaseUrl === baseUrl && !baseUrl.includes(DEEPSEEK_CONFIG.COMPLETION_PATH)) {
+        // eslint-disable-next-line no-console
+        console.warn('⚠️ DeepSeek baseUrl does not contain expected path for replacement:', baseUrl)
+      }

84-94: Empty string completion returns success instead of error.

If completionText is a non-empty string that becomes empty after trim() and cleanCompletion(), the function returns { completion: '', error: null }. Consider checking for empty string after cleaning:

💡 Optional: Handle empty completion after cleaning
       if (completionText) {
         completionText = completionText.trim()
-
         completionText = cleanCompletion(completionText, modelType, cursorContext)
 
+        if (!completionText) {
+          return {
+            completion: null,
+            error: ERROR_MESSAGES.NO_COMPLETION
+          }
+        }
+
         return {
           completion: completionText,
           error: null
         }
       }
packages/plugins/robot/src/components/header-extension/robot-setting/RobotSetting.vue (1)

291-294: Type loosening: service parameter changed to any.

The parameter type was changed to any to accommodate broader input types. While this works, consider using a more specific type or union type if the actual input types are known, to maintain better type safety.

💡 Optional: Use more specific type
-const editService = (service: any) => {
+const editService = (service: ModelService | Partial<ModelService>) => {
   state.editingService = JSON.parse(JSON.stringify(service)) as ModelService
   state.showServiceDialog = true
 }
packages/plugins/script/src/ai-completion/builders/fimPromptBuilder.js (1)

86-100: Logic overlap: { is classified as statement, not object-property.

The condition order means a prefix ending with { will match line 92 (/[{;]\s*$/) and be classified as statement, even though line 97 (/{\s*$/) also intends to detect object literals. If you want { to indicate object context, consider reordering the conditions or refining the patterns.

Additionally, in the regex at line 87, the [ character should be escaped as \[ for clarity, though it works at the end of a character class.

💡 Optional: Reorder conditions or refine patterns
     // 检测是否在表达式中
-    if (/[=+\-*/%<>!&|,([]$/.test(prefixTrimmed)) {
+    if (/[=+\-*/%<>!&|,(\[]$/.test(prefixTrimmed)) {
       context.needsExpression = true
       context.type = 'expression'
     }
-    // 检测是否在语句开始
-    else if (/[{;]\s*$/.test(prefixTrimmed) || prefixTrimmed.length === 0) {
-      context.needsStatement = true
-      context.type = 'statement'
-    }
     // 检测是否在对象字面量中
     else if (/{\s*$/.test(prefixTrimmed) || /,\s*$/.test(prefixTrimmed)) {
       context.inObject = true
       context.type = 'object-property'
     }
+    // 检测是否在语句开始
+    else if (/;\s*$/.test(prefixTrimmed) || prefixTrimmed.length === 0) {
+      context.needsStatement = true
+      context.type = 'statement'
+    }
packages/plugins/script/src/ai-completion/prompts/templates.js (1)

130-172: Large JSON payloads could inflate prompt size.

The JSON.stringify(currentSchema, null, 2) at line 161 could produce very large strings for complex component schemas, potentially exceeding token limits or diluting the prompt quality. Consider implementing size limits or summarization for very large schemas.

💡 Optional: Add size limit for schema serialization
     // 添加当前组件 schema
     if (currentSchema) {
-      instruction += `\n\nCURRENT COMPONENT SCHEMA:\n${JSON.stringify(currentSchema, null, 2)}`
+      const schemaJson = JSON.stringify(currentSchema, null, 2)
+      const MAX_SCHEMA_LENGTH = 2000
+      if (schemaJson.length > MAX_SCHEMA_LENGTH) {
+        instruction += `\n\nCURRENT COMPONENT SCHEMA (truncated):\n${schemaJson.substring(0, MAX_SCHEMA_LENGTH)}...`
+      } else {
+        instruction += `\n\nCURRENT COMPONENT SCHEMA:\n${schemaJson}`
+      }
packages/plugins/script/src/ai-completion/constants.js (1)

170-171: Complex regex for meta info pattern.

The META_INFO_PATTERN regex is quite long and could be difficult to maintain. Consider adding inline comments or breaking it into named sub-patterns for clarity.

💡 Optional: Document regex pattern
// Alternative: document the pattern components
META_INFO_PATTERN:
  // Matches optional file/language/context header comments at start of content
  // Format: // File: ...\n // Language: ...\n // Current ...\n etc.
  /^(\/\/ File:.*\n)?(\/\/ Language:.*\n)?(\/\/ Current .*\n)*(\/\/ IMPORTANT:.*\n)*(\/\/ Technologies:.*\n)?(\/\/ NOTE:.*\n)*\n*/
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69efc94 and cae9974.

📒 Files selected for processing (22)
  • packages/common/js/completion-files/context.md
  • packages/common/js/completion.js
  • packages/plugins/robot/src/components/header-extension/robot-setting/RobotSetting.vue
  • packages/plugins/robot/src/composables/core/useConfig.ts
  • packages/plugins/robot/src/constants/model-config.ts
  • packages/plugins/robot/src/types/setting.types.ts
  • packages/plugins/script/meta.js
  • packages/plugins/script/package.json
  • packages/plugins/script/src/Main.vue
  • packages/plugins/script/src/ai-completion/adapters/deepseekAdapter.js
  • packages/plugins/script/src/ai-completion/adapters/index.js
  • packages/plugins/script/src/ai-completion/adapters/qwenAdapter.js
  • packages/plugins/script/src/ai-completion/builders/fimPromptBuilder.js
  • packages/plugins/script/src/ai-completion/builders/index.js
  • packages/plugins/script/src/ai-completion/builders/lowcodeContextBuilder.js
  • packages/plugins/script/src/ai-completion/builders/promptBuilder.js
  • packages/plugins/script/src/ai-completion/constants.js
  • packages/plugins/script/src/ai-completion/index.js
  • packages/plugins/script/src/ai-completion/prompts/templates.js
  • packages/plugins/script/src/ai-completion/triggers/completionTrigger.js
  • packages/plugins/script/src/ai-completion/utils/completionUtils.js
  • packages/plugins/script/src/ai-completion/utils/modelUtils.js
💤 Files with no reviewable changes (1)
  • packages/common/js/completion-files/context.md
🧰 Additional context used
🧠 Learnings (8)
📓 Common learnings
Learnt from: rhlin
Repo: opentiny/tiny-engine PR: 1011
File: packages/canvas/render/src/RenderMain.ts:82-88
Timestamp: 2025-01-14T08:50:50.226Z
Learning: For PR `#1011`, the focus is on resolving conflicts and migrating code, with architectural improvements deferred for future PRs.
📚 Learning: 2024-10-10T02:47:46.239Z
Learnt from: yy-wow
Repo: opentiny/tiny-engine PR: 850
File: packages/toolbars/preview/src/Main.vue:16-16
Timestamp: 2024-10-10T02:47:46.239Z
Learning: In `packages/toolbars/preview/src/Main.vue`, within the `preview` function, the `getMergeMeta` method is used at lines 64 and 65 to retrieve `engine.config` configurations.

Applied to files:

  • packages/common/js/completion.js
  • packages/plugins/script/src/Main.vue
📚 Learning: 2025-01-14T06:49:00.797Z
Learnt from: gene9831
Repo: opentiny/tiny-engine PR: 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/common/js/completion.js
📚 Learning: 2024-09-30T07:51:10.036Z
Learnt from: chilingling
Repo: opentiny/tiny-engine PR: 837
File: packages/vue-generator/src/plugins/genDependenciesPlugin.js:66-66
Timestamp: 2024-09-30T07:51:10.036Z
Learning: In the `tiny-engine` project, `opentiny/tiny-engine-dsl-vue` refers to the current package itself, and importing types from it may cause circular dependencies.

Applied to files:

  • packages/plugins/script/package.json
📚 Learning: 2025-07-03T09:22:59.512Z
Learnt from: hexqi
Repo: opentiny/tiny-engine PR: 1501
File: mockServer/src/tool/Common.js:79-82
Timestamp: 2025-07-03T09:22:59.512Z
Learning: In the tiny-engine project, the mockServer code uses ES6 import syntax but is compiled to CommonJS output. This means CommonJS globals like `__dirname` are available at runtime, while ES6 module-specific features like `import.meta` would cause runtime errors.

Applied to files:

  • packages/plugins/script/package.json
📚 Learning: 2025-01-14T04:25:46.281Z
Learnt from: rhlin
Repo: opentiny/tiny-engine PR: 1011
File: packages/canvas/render/src/material-function/material-getter.ts:66-80
Timestamp: 2025-01-14T04:25:46.281Z
Learning: In the tiny-engine project, styles from block components are processed through Vite's CSS compilation pipeline, and additional style sanitization libraries should be avoided to maintain consistency with this approach.

Applied to files:

  • packages/plugins/script/package.json
📚 Learning: 2025-01-15T02:19:06.755Z
Learnt from: yy-wow
Repo: opentiny/tiny-engine PR: 940
File: packages/canvas/DesignCanvas/src/DesignCanvas.vue:0-0
Timestamp: 2025-01-15T02:19:06.755Z
Learning: In Vue components using message subscriptions from opentiny/tiny-engine-meta-register, always clean up subscriptions in the onUnmounted hook using useMessage().unsubscribe() to prevent memory leaks.

Applied to files:

  • packages/plugins/script/src/Main.vue
📚 Learning: 2025-01-14T06:55:59.692Z
Learnt from: gene9831
Repo: opentiny/tiny-engine PR: 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/components/header-extension/robot-setting/RobotSetting.vue
🧬 Code graph analysis (3)
packages/plugins/script/src/ai-completion/utils/completionUtils.js (2)
packages/register/src/hooks.ts (1)
  • useCanvas (80-80)
packages/plugins/script/src/ai-completion/constants.js (4)
  • MODEL_COMMON_CONFIG (90-118)
  • MODEL_COMMON_CONFIG (90-118)
  • FIM_CONFIG (152-172)
  • FIM_CONFIG (152-172)
packages/plugins/script/src/ai-completion/utils/modelUtils.js (1)
packages/plugins/script/src/ai-completion/constants.js (8)
  • MODEL_CONFIG (37-50)
  • MODEL_CONFIG (37-50)
  • MODEL_COMMON_CONFIG (90-118)
  • MODEL_COMMON_CONFIG (90-118)
  • STOP_SEQUENCES (123-147)
  • STOP_SEQUENCES (123-147)
  • FIM_CONFIG (152-172)
  • FIM_CONFIG (152-172)
packages/plugins/script/src/ai-completion/adapters/deepseekAdapter.js (2)
packages/plugins/script/src/ai-completion/prompts/templates.js (4)
  • instruction (128-128)
  • SYSTEM_BASE_PROMPT (4-18)
  • SYSTEM_BASE_PROMPT (4-18)
  • createUserPrompt (183-190)
packages/plugins/script/src/ai-completion/constants.js (4)
  • API_ENDPOINTS (55-57)
  • API_ENDPOINTS (55-57)
  • HTTP_CONFIG (62-66)
  • HTTP_CONFIG (62-66)
🔇 Additional comments (40)
packages/common/js/completion.js (2)

12-12: LGTM! Clean simplification of imports.

The removal of AI-related imports (vue ref, meta API, context.md) aligns with the refactoring strategy to move AI completion logic to a dedicated module.


174-204: LGTM! Simplified completion initialization.

The initCompletion function now focuses solely on static completions (Lowcode API hints, snippets, user variables), cleanly delegating AI completion to the new monacopilot-based architecture in the script plugin.

packages/plugins/script/src/ai-completion/triggers/completionTrigger.js (1)

50-73: LGTM! Well-structured trigger logic.

The shouldTriggerCompletion function provides sensible defaults: avoiding completion after completed statements or blocks while allowing it in most other contexts. The guard for minimum text length prevents spurious triggers.

packages/plugins/script/src/ai-completion/builders/lowcodeContextBuilder.js (1)

259-270: LGTM! Clean builder composition.

The buildLowcodeContext function provides a well-structured API with sensible defaults. The separation of formatting concerns into individual functions promotes maintainability.

packages/plugins/script/src/Main.vue (2)

163-173: LGTM! Proper cleanup of AI completion and resources.

The cleanup logic correctly deregisters the AI completion, disposes of completion providers, and terminates the ESLint worker. The use of optional chaining ensures safe disposal even if resources weren't initialized.

Based on learnings, this follows the best practice of always cleaning up subscriptions in the unmount hook.


111-161: Solid integration of monacopilot with appropriate error handling.

The AI completion setup is well-structured:

  • Preserves existing Lowcode API hints and ESLint integration
  • Feature-flags AI completion via aiCompletionEnabled
  • Uses try-catch to prevent registration failures from breaking the editor
  • Configures reasonable defaults (maxContextLines: 50, enableCaching: true)
packages/plugins/script/meta.js (1)

9-10: LGTM! Clear configuration options for AI completion.

The renamed aiCompletionEnabled flag and documented aiCompletionTrigger option provide a clean configuration interface. The commented trigger modes—onIdle (default, low resource usage), onTyping (real-time completions), and onDemand (manual trigger)—show all available monacopilot options clearly.

packages/plugins/robot/src/types/setting.types.ts (1)

33-33: LGTM!

The new codeCompletion capability flag follows the existing pattern and is properly typed as optional boolean, consistent with the other capability fields.

packages/plugins/script/src/ai-completion/builders/index.js (1)

1-3: LGTM!

Clean barrel file providing a unified export surface for the builder modules.

packages/plugins/script/src/ai-completion/index.js (1)

1-6: LGTM!

Clean entry point providing unified exports for the AI completion module. The selected exports appropriately expose the main public API surface.

packages/plugins/script/src/ai-completion/adapters/deepseekAdapter.js (1)

11-28: LGTM!

The message construction is clean and properly composes system and user prompts using the shared templates. The cursorContext: null correctly indicates this adapter uses chat-based completion rather than FIM.

packages/plugins/robot/src/composables/core/useConfig.ts (3)

321-324: Verify: Including codeCompletion models in "compact" list.

The getCompactModels function now returns models with compact OR codeCompletion capability. Ensure this is the intended behavior—code completion models (like qwen3-coder-plus) may not necessarily be "compact/lightweight" models. If the intent is to have a combined list for quick model selection, the function name and comment accurately reflect this, but it's worth confirming the semantic alignment.


326-334: LGTM!

The new filter functions are clean, follow existing patterns, and properly use optional chaining for capability access.


469-470: LGTM!

The new helper functions are properly exposed in the composable's public API.

packages/plugins/script/src/ai-completion/adapters/qwenAdapter.js (1)

9-21: LGTM!

Clean delegation to the FIM builder with appropriate structure for the messages payload.

packages/plugins/script/src/ai-completion/utils/completionUtils.js (1)

8-21: LGTM!

Clean extraction of low-code metadata with appropriate defaults for missing values.

packages/plugins/script/src/ai-completion/builders/promptBuilder.js (2)

42-80: LGTM!

Clean backwards iteration to find the nearest code context definitions with early exit optimization.


158-204: LGTM!

Well-structured prompt orchestration with clear conditional logic for different completion contexts (comments, low-code, general code).

packages/plugins/robot/src/constants/model-config.ts (1)

55-64: LGTM!

The codeCompletion: true capability is appropriately added to FIM-capable coding models, aligning with the PR's goal to mark models suitable for code completion.

Also applies to: 84-103

packages/plugins/script/src/ai-completion/utils/modelUtils.js (3)

8-22: LGTM!

Clean model type detection using keyword matching with proper null handling.


29-47: LGTM!

Token calculation follows a clear priority order based on cursor context, with sensible defaults.


55-78: LGTM!

Stop sequence composition correctly builds upon the base sequences with model-specific (FIM markers for Qwen) and context-specific additions. The spread operator ensures the base array isn't mutated.

packages/plugins/script/src/ai-completion/adapters/index.js (4)

14-16: FIMPromptBuilder initialized with QWEN_CONFIG but used for all model types.

The fimBuilder is instantiated with QWEN_CONFIG at line 15, but it's also used in the Qwen flow at line 57 (buildQwenMessages(fileContent, fimBuilder)). For DeepSeek, fimBuilder is not used directly (line 69 uses buildDeepSeekMessages), so this appears intentional. However, if DeepSeek ever needs FIM building with different config, this would need adjustment.


20-27: LGTM!

The configuration retrieval with proper null-safety and early return on missing config is well implemented.


29-35: LGTM!

Good use of optional chaining and default values for extracting completion metadata.


100-107: LGTM!

Error handling is robust with proper logging and fallback error message.

packages/plugins/robot/src/components/header-extension/robot-setting/RobotSetting.vue (3)

45-45: LGTM!

The updated tooltip clearly explains the quick model's purpose and recommends models with the "代码" tag for code completion.


59-71: LGTM!

The custom option template with capability tags provides excellent visual feedback for users selecting quick models. The tag colors are consistent and meaningful.


213-232: LGTM!

The computed properties correctly filter models based on capabilities and sort by service name for better organization. The Chinese locale sorting is appropriate for the target audience.

packages/plugins/script/src/ai-completion/builders/fimPromptBuilder.js (4)

7-10: LGTM!

Simple constructor that stores the configuration for later use.


17-53: LGTM!

The buildOptimizedFIMPrompt method follows a clear workflow: clean → locate cursor → split → analyze → optimize → build. The fallback for missing cursor marker is appropriate.


117-127: LGTM!

The prefix optimization correctly preserves the most recent context by keeping the last N lines closest to the cursor.


134-171: LGTM!

The smart suffix truncation at natural code boundaries (function/class definitions, closing braces) is a good approach for providing relevant context without excessive noise. The heuristics are reasonable for JavaScript/TypeScript code.

packages/plugins/script/src/ai-completion/prompts/templates.js (3)

4-18: LGTM!

The system prompt provides clear, comprehensive rules for the AI assistant. The emphasis on scope constraints and avoiding code from other functions is well-designed for focused completions.


25-39: LGTM!

The instruction template effectively guides the model to follow language best practices while respecting scope boundaries.


183-189: LGTM!

The user prompt template clearly structures the instruction and file content, with explicit guidance to return only the completion text.

packages/plugins/script/src/ai-completion/constants.js (4)

4-32: LGTM!

The model-specific configurations for Qwen and DeepSeek are well-organized with appropriate temperature, top_p, and FIM settings. Having separate configs allows for model-specific tuning.


37-50: LGTM!

The model configuration with type identifiers and keywords provides a clean abstraction for model detection and routing.


123-147: LGTM!

The stop sequences are comprehensive for JavaScript/TypeScript code completion, covering function boundaries, imports, comments, and code blocks. This should help produce focused completions.


184-193: LGTM!

The code patterns provide good coverage for common JavaScript/TypeScript declarations. These patterns serve well for context detection purposes.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant