feat: Reconstructed the overall skill set and add web-skills implementation#323
feat: Reconstructed the overall skill set and add web-skills implementation#323
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughStandardizes skills around SKILL.md (YAML front matter + Markdown body), replaces JS/TS skill modules with raw Markdown aggregation (import.meta.glob), adds next-sdk skill utilities and MCP server wiring, and refactors composables/components to consume skillMdModules and new MCP server APIs. Changes
Sequence Diagram(s)sequenceDiagram
participant Build as Vite Build
participant SkillMd as Skill MD modules
participant App as App / TinyRemoter
participant Composable as useSkillWithTools
participant SDK as next-sdk (createSkillTools)
participant MCP as MCP Server (createMcpServer)
Build->>SkillMd: import.meta.glob(...) eager -> skillMdModules
SkillMd->>App: pass skillMdModules prop
App->>MCP: onMounted -> createMcpServer()
App->>Composable: init useSkillWithTools({ skillsRef: skillMdModules, systemPrompt, agent })
Composable->>SDK: getSkillOverviews / formatSkillsForSystemPrompt / createSkillTools
SDK-->>Composable: skillPromptPart, skillTools (includes get_skill_content)
TinyRobot->>MCP: tool call -> get_skill_content(path|name)
MCP->>SkillMd: fetch requested MD content
SkillMd-->>MCP: return MD content
MCP-->>TinyRobot: tool result (content/path)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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: 6
🤖 Fix all issues with AI agents
In `@packages/doc-ai/src/skills/calculator/SKILL.md`:
- Around line 12-14: Fix the duplicated/unclear parameter descriptions for `a`,
`b`, and `operation` in SKILL.md: replace "商品数量 当前商品数量" with a single clear
description like "商品数量(当前商品数量)" or simply "商品数量", replace "商品库存 商品库存" with
"商品库存", and simplify `operation` to "运算类型(加、减、乘、除)" so each parameter line is
concise and non-redundant.
In `@packages/doc-ai/src/skills/product-guide/SKILL.md`:
- Line 12: Update the relative reference in SKILL.md so get_skill_content can
find the file: change the path string './reference/product-shangjia.md' in
packages/doc-ai/src/skills/product-guide/SKILL.md to the full skills-root
relative path './product-guide/reference/product-shangjia.md' so that the
modules lookup used by get_skill_content(modules, path) matches the key stored
in the import.meta.glob('?raw') map.
In `@packages/next-remoter/src/composable/useSkill.ts`:
- Around line 44-45: The code reads customAgentProvider.llmConfig?.extraTools
but then assigns to customAgentProvider.llmConfig.extraTools unguarded, causing
a TypeError if llmConfig is nullish; update the logic around symbols
customAgentProvider, llmConfig, extraTools and skillTools.value so llmConfig is
guaranteed to exist before assignment (e.g., if llmConfig is null/undefined,
initialize it to an object) and then merge extraTools safely (use the existing
extra from llmConfig or {} and set llmConfig.extraTools = { ...extra,
...skillTools.value }).
- Around line 39-45: The code reads computed reactive values
(skillPromptPart.value and skillTools.value) once and assigns them into
customAgentProvider, so later updates to skillsRef won't propagate; change this
by wrapping the assignments in a reactive watcher (e.g., watchEffect or watch)
that updates customAgentProvider.systemPrompt (combining systemPrompt and
skillPromptPart.value) and customAgentProvider.llmConfig.extraTools (merging
existing extra with skillTools.value) whenever skillPromptPart or skillTools
change, keeping references to customAgentProvider, systemPrompt,
skillPromptPart, skillTools, and llmConfig in the watcher closure.
In `@packages/next-sdk/skills/index.ts`:
- Around line 109-141: The module docs mention a list_skills tool but
createSkillTools only returns get_skill_content; either re-add list_skills or
remove/update the stale comments. If you want the tool, implement a new tool
inside createSkillTools named list_skills that returns the array of skill
overviews (name/description) derived from modules (e.g., by reusing the logic in
formatSkillsForSystemPrompt or by scanning modules keys and reading SKILL.md via
getSkillMdContent/getMainSkillPathByName), and include it in the returned
SkillToolsSet as list_skills; otherwise update the docstring and any references
to remove mention of list_skills so comments match the implementation.
In `@packages/next-wxt/skills/drawer-expert/SKILL.md`:
- Line 88: Fix the typo in the SKILL.md text: replace the incorrect fragment
"必须)" with "(必须)" so the opening parenthesis is restored; locate the sentence
containing "调用updateElement,更新形状元素,添加boundElements属性,其值为一个数组,包含指向文本元素的引用" and
update that occurrence accordingly.
🧹 Nitpick comments (9)
packages/next-remoter/src/composable/CustomAgentModelProvider.ts (1)
99-109: Fragile/promptpath manipulation.
baseURL.includes('/prompt')andbaseURL.replace('/prompt', '')match any occurrence of/promptin the URL, not just the suffix. If a future baseURL contains/promptelsewhere in the path, this logic would break. Consider usingendsWith/suffix-based checks instead.Suggested improvement
- if (!baseURL.includes('/prompt')) { - baseURL = baseURL + '/prompt' + if (!baseURL.endsWith('/prompt')) { + baseURL = baseURL + '/prompt' } } else { // 如果关闭了生成式UI,移除 '/prompt' 后缀 - baseURL = baseURL.replace('/prompt', '') + if (baseURL.endsWith('/prompt')) { + baseURL = baseURL.slice(0, -'/prompt'.length) + }packages/next-wxt/skills/drawer-expert/SKILL.md (1)
139-178: JSON examples contain invalid JavaScript-style comments.The binding example (lines 168–170) uses
//comments inside JSON blocks. While this is a Markdown prompt for an LLM and may work in practice, invalid JSON in examples could confuse the model or lead to malformed output. Consider removing the comments or placing them outside the JSON block.packages/next-wxt/entrypoints/sidepanel/App.vue (1)
233-238: Dead code: button withv-if="false"will never render.This button and its associated styles (
.record-button,.record-button__icon,.record-button:hover) are unreachable. Consider removing both the template block and the unused CSS, or leaving a comment explaining why it's kept (e.g., feature flag placeholder).packages/next-remoter/src/components/TinyRobotChat.vue (1)
338-345:processSkillMentionsnaming is now misleading — no@-mentionprocessing remains.The function name
processSkillMentionsimplies@-mentionhandling, but the refactor removed that behavior. Consider renaming to something likeprocessSkillsorprepareSkillContextto better reflect its current role.packages/next-sdk/skills/index.ts (3)
29-43: Regex-based YAML front matter parser won't handle quoted values.
parseSkillFrontMatterextracts values via/^name:\s*(.+)$/m, which captures the entire remainder of the line including quotes. Forname: "my skill", it returns"my skill"(with quotes). If skill documents might use quoted YAML values, consider stripping surrounding quotes. For now this is fine if you control all SKILL.md authoring.Optional: strip surrounding quotes
const name = nameMatch?.[1]?.trim() const description = descMatch?.[1]?.trim() + const unquote = (s?: string) => s?.replace(/^(['"])(.*)\1$/, '$2') - return name && description ? { name, description } : null + return name && description ? { name: unquote(name)!, description: unquote(description)! } : null
96-101: Prefer strict equality overstartsWithfor path matching.
getMainSkillPathByNameusesstartsWithto match./name/SKILL.md, but since all main skill paths follow the exact./X/SKILL.mdpattern,===is the correct semantic and avoids any edge-case ambiguity.Proposed fix
export function getMainSkillPathByName(modules: Record<string, string>, name: string): string | undefined { - return getMainSkillPaths(modules).find((p) => p.startsWith(`./${name}/SKILL.md`)) + return getMainSkillPaths(modules).find((p) => p === `./${name}/SKILL.md`) }
115-137: BothskillNameandpathare optional — no input validation for the case when neither is provided.When the LLM calls
get_skill_contentwith{}(both fields omitted), the tool silently returns an error object. Consider adding a Zodrefineto require at least one field, which gives better error messages at the schema validation layer.Proposed fix
inputSchema: z.object({ skillName: z.string().optional().describe('技能名称,与目录名一致,如 calculator'), path: z.string().optional().describe('文档相对路径,如 ./calculator/SKILL.md 或 ./product-guide/reference/xxx.md') - }), + }).refine( + (data) => data.skillName || data.path, + { message: '至少需要提供 skillName 或 path 其中一个参数' } + ),packages/next-remoter/src/composable/useSkill.ts (2)
4-13:agentandcustomAgentProviderare typed asany;agentis unused.
- Both
agent(Line 10) andcustomAgentProvider(Line 12) useany, which defeats TypeScript's type safety. Consider defining or importing proper interface types for these.agentis declared in the options interface but never destructured or referenced inuseSkillWithTools(Line 20 only pullsskillsRef,systemPrompt,customAgentProvider). If it's no longer needed, remove it to avoid a misleading API surface.Proposed fix (remove unused property, add TODO for proper typing)
export interface UseSkillWithToolsOptions { /** 用户层传入的 skill .md 模块(key 路径,value 内容),由 next-sdk 处理;大模型通过 list_skills / get_skill_content 自动识别并加载技能 */ skillsRef?: Ref<Record<string, string> | undefined> /** 基础系统提示词 */ systemPrompt: string - /** CustomAgentModelProvider 的 agent 实例 */ - agent: any - /** CustomAgentModelProvider 实例,用于写 systemPrompt、合并 extraTools */ - customAgentProvider: any + /** CustomAgentModelProvider 实例,用于写 systemPrompt、合并 extraTools */ + // TODO: replace `any` with the actual CustomAgentModelProvider type + customAgentProvider: any }As per coding guidelines, "All code must be TypeScript with strict typing".
47-50: Consider a more descriptive element type forskillItemsif this stub will be extended.
never[]is technically precise for a permanently empty array, but it prevents consumers from typing any future use ofskillItems. If this is a temporary placeholder that may later carry items, consider using a named type (e.g.,SkillMeta[]or a dedicatedSkillItem[]) to keep the return contract forward-compatible.
…cpServers 与 mcpServers 的区别
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In `@packages/doc-ai/src/App.vue`:
- Line 8: The tiny-remoter component is using one-way binding (:show="show") so
it cannot emit update:show to update parent state; change the binding on the
TinyRemoter/TinyRobotChat usage from :show="show" to v-model:show="show" so the
component's defineModel('show') / emit('update:show') will update the parent's
show reactive variable; keep the other props (skillMdModules, menuItems,
mcpServers) as-is and remove the old :show binding to avoid duplicate bindings.
In `@packages/next-remoter/src/components/TinyRobotChat.vue`:
- Around line 274-281: The prop declaration for skills in TinyRobotChat.vue was
changed to Record<string,string>, which is a breaking change for callers that
pass an array of MentionItem[]; update the component to accept both shapes and
normalize them internally: restore the prop validator/type to allow Array or
Object (keep the prop name skills), provide a default of undefined, and add a
small normalization step (e.g., normalizeSkills or inline logic where skills are
used) that detects an Array<MentionItem> vs Record<string,string> and converts
arrays into the expected Record shape before downstream use; this preserves
backwards compatibility while keeping the new Record format supported.
🧹 Nitpick comments (5)
packages/doc-ai/src/mcp-servers/product-guide/tools.ts (1)
3-18: Stub handler returns placeholder text — is this intentional?The tool handler just echoes back
产品指南${productId}without any real product-guide logic. If this is a temporary scaffold, consider adding a// TODOcomment so it doesn't get forgotten.packages/doc-ai/src/mcp-servers/index.ts (1)
1-2: Minor: consolidate imports from the same module.Both imports come from
@opentiny/next-sdk.Proposed fix
-import { WebMcpServer } from '@opentiny/next-sdk' -import { createMessageChannelPairTransport } from '@opentiny/next-sdk' +import { WebMcpServer, createMessageChannelPairTransport } from '@opentiny/next-sdk'docs/guide/tiny-robot-remoter.md (1)
314-326:mcpServersexample:typestring value should match documented options.The example uses
type: 'streamableHttp'(line 318) andtype: 'local'(line 322), which matches the documented types on lines 330-332. Looks good.One minor note: the
clientTransportvariable in the example (line 323) is used without showing its import/creation. Consider adding a brief comment or import hint so readers know where it comes from.packages/next-remoter/src/components/TinyRobotChat.vue (1)
540-544: Sequentialawaitinfor...ofloop serializes MCP server loading.If multiple MCP servers are configured, they'll be loaded one at a time. This is acceptable for a small number of servers, but consider
Promise.allif parallel initialization is safe.Parallel loading alternative
if (props.mcpServers) { - for (const [name, config] of Object.entries(props.mcpServers)) { - await loadMcpServerToPlugin(name, config) - } + await Promise.all( + Object.entries(props.mcpServers).map(([name, config]) => loadMcpServerToPlugin(name, config)) + ) }packages/doc-ai/src/App.vue (1)
22-27: Addas constor type annotation to ensuretype: 'local'is narrowed.Without a type annotation, TypeScript infers
typeasstringrather than the literal'local', which may not satisfy a discriminated union inMcpServerConfig.Proposed fix
+import type { McpServerConfig } from '@opentiny/next-sdk' + // 业界格式:key 为 MCP 服务器名称,value 为 McpServerConfig -const mcpServers = { +const mcpServers: Record<string, McpServerConfig> = { 'local-mcp-server': { type: 'local', transport: clientTransport } }
| /** | ||
| * 用户层传入的 skill .md 模块(Vite import.meta.glob 等得到的 Record<path, content>), | ||
| * 由 remoter 调用 next-sdk 的 skill 能力处理:生成 systemPrompt 技能说明、内置 list_skills / get_skill_content 工具,大模型可自动识别并加载技能 | ||
| */ | ||
| skills: { | ||
| type: Object as () => MentionItem[], | ||
| default: () => [] | ||
| type: Object as () => Record<string, string>, | ||
| default: undefined | ||
| }, |
There was a problem hiding this comment.
Breaking change: skills prop type changed from array to Record<string, string>.
This is a breaking API change — existing consumers passing an array of MentionItem[] will silently receive incorrect behavior (no type error at runtime in JS templates). Ensure this is communicated in release notes or a migration guide.
🤖 Prompt for AI Agents
In `@packages/next-remoter/src/components/TinyRobotChat.vue` around lines 274 -
281, The prop declaration for skills in TinyRobotChat.vue was changed to
Record<string,string>, which is a breaking change for callers that pass an array
of MentionItem[]; update the component to accept both shapes and normalize them
internally: restore the prop validator/type to allow Array or Object (keep the
prop name skills), provide a default of undefined, and add a small normalization
step (e.g., normalizeSkills or inline logic where skills are used) that detects
an Array<MentionItem> vs Record<string,string> and converts arrays into the
expected Record shape before downstream use; this preserves backwards
compatibility while keeping the new Record format supported.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@packages/next-remoter/src/composable/useSkill.ts`:
- Around line 4-13: Remove the unused agent field from the
UseSkillWithToolsOptions interface since useSkillWithTools only destructures
skillsRef, systemPrompt, and customAgentProvider; update the interface
declaration by deleting the "agent: any" property (symbol:
UseSkillWithToolsOptions) and then run a quick search for any external
references to UseSkillWithToolsOptions to update call sites or tests if they
relied on agent to avoid type errors; ensure TypeScript compiles after the
change.
In `@packages/next-wxt/skills/drawer-expert/SKILL.md`:
- Line 229: 在第 3 条标题 "箭头/连线必须绑定元素" 中将口语词 "俩俩" 替换为正式用语;建议直接改为 "两两双向链接" 或更简洁地改为
"双向链接"(保留示例 "eleA arrow eleB" 以示意关系),确保句子流畅且与文档风格一致。
- Line 38: The sentence in SKILL.md that explains using
ExcalidrawElementSkeleton currently has an incorrect Chinese punctuation mark
before "等"; remove the enumerative comma/pause "、" before "等" so the phrase
reads "...随机种子等属性" (no preceding "、"), updating the sentence that mentions
ExcalidrawElementSkeleton and ExcalidrawElement accordingly to ensure correct
Chinese grammar and punctuation.
🧹 Nitpick comments (2)
packages/next-sdk/skills/index.ts (1)
96-101:getMainSkillPathByNameuses.startsWithwhere strict equality would be more precise.Since
MAIN_SKILL_PATH_REGguarantees paths match exactly./name/SKILL.md,startsWithis functionally equivalent to===here but could match unintended prefixes in theory (e.g., if module keys changed format). Consider using===for clarity.export function getMainSkillPathByName(modules: Record<string, string>, name: string): string | undefined { - return getMainSkillPaths(modules).find((p) => p.startsWith(`./${name}/SKILL.md`)) + return getMainSkillPaths(modules).find((p) => p === `./${name}/SKILL.md`) }packages/next-remoter/src/composable/useSkill.ts (1)
22-37: Skill tool objects are recreated on everyskillsRefchange — acceptable but worth noting.
createSkillTools(line 36) builds a newtool()instance on each reactive update. For typical usage this is fine, but ifskillsRefchanges frequently, this creates unnecessary allocations. If this becomes a concern, memoizing by module identity could help.
| export interface UseSkillWithToolsOptions { | ||
| /** 用户层传入的 skill .md 模块(key 路径,value 内容),由 next-sdk 处理;大模型通过 get_skill_content 自动识别并加载技能 */ | ||
| skillsRef?: Ref<Record<string, string> | undefined> | ||
| /** 基础系统提示词 */ | ||
| systemPrompt: string | ||
| /** CustomAgentModelProvider 的 agent 实例 */ | ||
| agent: any | ||
| /** CustomAgentModelProvider 实例,用于写 systemPrompt、合并 extraTools */ | ||
| customAgentProvider: any | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's examine the file structure and get the full context
cat -n packages/next-remoter/src/composable/useSkill.ts | head -50Repository: opentiny/next-sdk
Length of output: 2204
🏁 Script executed:
# Search for how agent is used in this file
rg -n 'agent' packages/next-remoter/src/composable/useSkill.ts -B2 -A2Repository: opentiny/next-sdk
Length of output: 268
🏁 Script executed:
# Check how useSkillWithTools is called and if agent is passed
rg -nC5 'useSkillWithTools' --type=ts --type=vueRepository: opentiny/next-sdk
Length of output: 88
🏁 Script executed:
# Search for files that import or use useSkillWithTools
rg -l 'useSkillWithTools' --type tsRepository: opentiny/next-sdk
Length of output: 109
🏁 Script executed:
# Check if UseSkillWithToolsOptions is imported elsewhere
rg -l 'UseSkillWithToolsOptions' --type tsRepository: opentiny/next-sdk
Length of output: 109
🏁 Script executed:
# Search for useSkillWithTools calls to see what parameters are passed
rg -B2 -A2 'useSkillWithTools\(' --type tsRepository: opentiny/next-sdk
Length of output: 524
Remove unused agent field from UseSkillWithToolsOptions interface.
The agent property is declared in the interface but never destructured or referenced in the useSkillWithTools function (line 20 only destructures skillsRef, systemPrompt, and customAgentProvider). Removing it eliminates unnecessary interface bloat.
Proposed fix
export interface UseSkillWithToolsOptions {
skillsRef?: Ref<Record<string, string> | undefined>
systemPrompt: string
- agent: any
customAgentProvider: any
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export interface UseSkillWithToolsOptions { | |
| /** 用户层传入的 skill .md 模块(key 路径,value 内容),由 next-sdk 处理;大模型通过 get_skill_content 自动识别并加载技能 */ | |
| skillsRef?: Ref<Record<string, string> | undefined> | |
| /** 基础系统提示词 */ | |
| systemPrompt: string | |
| /** CustomAgentModelProvider 的 agent 实例 */ | |
| agent: any | |
| /** CustomAgentModelProvider 实例,用于写 systemPrompt、合并 extraTools */ | |
| customAgentProvider: any | |
| } | |
| export interface UseSkillWithToolsOptions { | |
| /** 用户层传入的 skill .md 模块(key 路径,value 内容),由 next-sdk 处理;大模型通过 get_skill_content 自动识别并加载技能 */ | |
| skillsRef?: Ref<Record<string, string> | undefined> | |
| /** 基础系统提示词 */ | |
| systemPrompt: string | |
| /** CustomAgentModelProvider 实例,用于写 systemPrompt、合并 extraTools */ | |
| customAgentProvider: any | |
| } |
🤖 Prompt for AI Agents
In `@packages/next-remoter/src/composable/useSkill.ts` around lines 4 - 13, Remove
the unused agent field from the UseSkillWithToolsOptions interface since
useSkillWithTools only destructures skillsRef, systemPrompt, and
customAgentProvider; update the interface declaration by deleting the "agent:
any" property (symbol: UseSkillWithToolsOptions) and then run a quick search for
any external references to UseSkillWithToolsOptions to update call sites or
tests if they relied on agent to avoid type errors; ensure TypeScript compiles
after the change.
There was a problem hiding this comment.
Fix punctuation: remove comma before "等".
In Chinese grammar, "等" should not be preceded by "、" when used at the end of a list.
📝 Proposed fix
-**重要理念**: 你将通过创建**元素骨架 (`ExcalidrawElementSkeleton`)** 对象来添加元素,而非手动构建完整的 `ExcalidrawElement`。`ExcalidrawElementSkeleton` 是一个简化的、专为编程创建而设计的对象。Excalidraw前端会自动补全版本号、随机种子、等属性。
+**重要理念**: 你将通过创建**元素骨架 (`ExcalidrawElementSkeleton`)** 对象来添加元素,而非手动构建完整的 `ExcalidrawElement`。`ExcalidrawElementSkeleton` 是一个简化的、专为编程创建而设计的对象。Excalidraw前端会自动补全版本号、随机种子等属性。📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| **重要理念**: 你将通过创建**元素骨架 (`ExcalidrawElementSkeleton`)** 对象来添加元素,而非手动构建完整的 `ExcalidrawElement`。`ExcalidrawElementSkeleton` 是一个简化的、专为编程创建而设计的对象。Excalidraw前端会自动补全版本号、随机种子、等属性。 | |
| **重要理念**: 你将通过创建**元素骨架 (`ExcalidrawElementSkeleton`)** 对象来添加元素,而非手动构建完整的 `ExcalidrawElement`。`ExcalidrawElementSkeleton` 是一个简化的、专为编程创建而设计的对象。Excalidraw前端会自动补全版本号、随机种子等属性。 |
🧰 Tools
🪛 LanguageTool
[uncategorized] ~38-~38: 您的意思是“"不"全”?
Context: ...ton` 是一个简化的、专为编程创建而设计的对象。Excalidraw前端会自动补全版本号、随机种子、等属性。 ### A. 通用核心属性 (所有元素骨架都包含...
(BU)
🤖 Prompt for AI Agents
In `@packages/next-wxt/skills/drawer-expert/SKILL.md` at line 38, The sentence in
SKILL.md that explains using ExcalidrawElementSkeleton currently has an
incorrect Chinese punctuation mark before "等"; remove the enumerative
comma/pause "、" before "等" so the phrase reads "...随机种子等属性" (no preceding "、"),
updating the sentence that mentions ExcalidrawElementSkeleton and
ExcalidrawElement accordingly to ensure correct Chinese grammar and punctuation.
There was a problem hiding this comment.
Improve wording: replace "俩俩" with standard Chinese.
"俩俩" is colloquial. Use "两两" (pairwise) for formal documentation, or simplify to just "双向链接" since "必须" already conveys the requirement.
📝 Proposed fixes
Option 1 (recommended - simpler):
-3. **箭头/连线必须绑定元素** 箭头或连线必须双向链接到对应的元素上,比如eleA arrow eleB,必须俩俩双向链接
+3. **箭头/连线必须绑定元素** 箭头或连线必须双向链接到对应的元素上,比如eleA arrow eleB,必须双向链接Option 2 (more formal):
-3. **箭头/连线必须绑定元素** 箭头或连线必须双向链接到对应的元素上,比如eleA arrow eleB,必须俩俩双向链接
+3. **箭头/连线必须绑定元素** 箭头或连线必须双向链接到对应的元素上,比如eleA arrow eleB,必须两两双向链接📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| 3. **箭头/连线必须绑定元素** 箭头或连线必须双向链接到对应的元素上,比如eleA arrow eleB,必须俩俩双向链接 | |
| 3. **箭头/连线必须绑定元素** 箭头或连线必须双向链接到对应的元素上,比如eleA arrow eleB,必须双向链接 |
🤖 Prompt for AI Agents
In `@packages/next-wxt/skills/drawer-expert/SKILL.md` at line 229, 在第 3 条标题
"箭头/连线必须绑定元素" 中将口语词 "俩俩" 替换为正式用语;建议直接改为 "两两双向链接" 或更简洁地改为 "双向链接"(保留示例 "eleA arrow
eleB" 以示意关系),确保句子流畅且与文档风格一致。
feat: 重构整体的skills技能方案,删除@专家的功能,改为web-skills渐进式披露方式
Pull Request (OpenTiny NEXT-SDKs)
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
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
Bug Fixes & Improvements
Documentation