mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-17 03:59:41 +08:00
✨ feat(ai): 新增代码热点诊断探针
- 注册 inspect_codebase_hotspots 内置工具并接入本地执行器 - 在工具目录、系统提示和斜杠菜单中暴露大文件治理入口 - 增加工具注册、执行器、目录和斜杠菜单测试
This commit is contained in:
@@ -104,6 +104,9 @@ describe('AIBuiltinToolsCatalog', () => {
|
||||
expect(markup).toContain('诊断 AI 上下文体量');
|
||||
expect(markup).toContain('inspect_ai_context_budget');
|
||||
expect(markup).toContain('messageLimit');
|
||||
expect(markup).toContain('治理前端大文件');
|
||||
expect(markup).toContain('inspect_codebase_hotspots');
|
||||
expect(markup).toContain('大文件和拆分热点');
|
||||
expect(markup).toContain('复用历史 SQL');
|
||||
expect(markup).toContain('inspect_saved_queries');
|
||||
expect(markup).toContain('回看 AI 历史对话');
|
||||
|
||||
180
frontend/src/components/ai/aiCodebaseHotspotInsights.ts
Normal file
180
frontend/src/components/ai/aiCodebaseHotspotInsights.ts
Normal file
@@ -0,0 +1,180 @@
|
||||
export interface CodebaseHotspotEntry {
|
||||
path: string;
|
||||
lines: number;
|
||||
area: string;
|
||||
riskLevel: 'medium' | 'high' | 'critical';
|
||||
why: string;
|
||||
suggestedSlices: string[];
|
||||
testTargets: string[];
|
||||
}
|
||||
|
||||
export interface CodebaseHotspotSnapshotOptions {
|
||||
keyword?: string;
|
||||
minLines?: number;
|
||||
limit?: number;
|
||||
includeRecommendations?: boolean;
|
||||
}
|
||||
|
||||
const CODEBASE_HOTSPOT_SNAPSHOT: CodebaseHotspotEntry[] = [
|
||||
{
|
||||
path: 'frontend/src/components/Sidebar.tsx',
|
||||
lines: 8910,
|
||||
area: 'workspace-navigation',
|
||||
riskLevel: 'critical',
|
||||
why: '左侧树、命令面板、上下文菜单和连接动作集中在单文件,修改入口多且回归面大。',
|
||||
suggestedSlices: ['V2 命令面板', '外部 SQL 目录弹窗', '连接树动作', '批量操作弹窗'],
|
||||
testTargets: ['Sidebar.locate-toolbar.test.tsx', 'sidebarV2Utils.test.ts'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/DataGrid.tsx',
|
||||
lines: 8080,
|
||||
area: 'result-grid',
|
||||
riskLevel: 'critical',
|
||||
why: '结果展示、编辑、DDL、导出和列操作耦合,容易让单点修复影响查询结果区。',
|
||||
suggestedSlices: ['结果导出工具栏', '列头菜单', 'DDL 视图', '单元格编辑事务提示'],
|
||||
testTargets: ['DataGrid.layout.test.tsx', 'DataGrid.ddl.test.tsx'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/ConnectionModal.tsx',
|
||||
lines: 7462,
|
||||
area: 'connection-form',
|
||||
riskLevel: 'critical',
|
||||
why: '多数据源连接表单仍集中在一个组件,新增数据源或密钥规则时容易互相影响。',
|
||||
suggestedSlices: ['SSH/代理配置区', 'TLS 配置区', 'MongoDB 配置区', 'JVM 配置区'],
|
||||
testTargets: ['ConnectionModal.edit-password.test.tsx', 'connectionModalPresentation.test.ts'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/QueryEditor.tsx',
|
||||
lines: 5367,
|
||||
area: 'sql-editor',
|
||||
riskLevel: 'critical',
|
||||
why: 'SQL 编辑、执行、事务、结果区布局和快捷键状态集中,事务和结果区回归风险高。',
|
||||
suggestedSlices: ['结果区工具栏', '事务状态条', '执行日志提示', '编辑器快捷键绑定'],
|
||||
testTargets: ['QueryEditor.result-panel.test.tsx', 'useSqlEditorTransactionController.test.ts'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/TableDesigner.tsx',
|
||||
lines: 3549,
|
||||
area: 'table-designer',
|
||||
riskLevel: 'high',
|
||||
why: '字段编辑、索引、外键、分区和 DDL 生成集中,数据库方言差异容易扩散。',
|
||||
suggestedSlices: ['字段编辑表格', '索引配置面板', '外键配置面板', '方言 DDL 预览'],
|
||||
testTargets: ['TableDesigner.*.test.tsx', 'tableDesignerSchemaSql.test.ts'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/RedisViewer.tsx',
|
||||
lines: 2120,
|
||||
area: 'redis-browser',
|
||||
riskLevel: 'high',
|
||||
why: 'Key 浏览、不同数据结构编辑、TTL、编码显示和新增弹窗集中,Redis Cluster/Sentinel 后续验证面较宽。',
|
||||
suggestedSlices: ['Key 搜索栏', 'String/List/Set/ZSet/Hash/Stream 编辑器', '新增 Key 弹窗'],
|
||||
testTargets: ['redisViewerTree.test.ts', 'RedisViewer.*.test.tsx'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/DriverManagerModal.tsx',
|
||||
lines: 1729,
|
||||
area: 'driver-manager',
|
||||
riskLevel: 'high',
|
||||
why: '驱动安装、状态展示、下载和可选代理逻辑较多,适合继续拆出状态卡片和操作区。',
|
||||
suggestedSlices: ['驱动状态列表', '安装操作区', '下载日志区'],
|
||||
testTargets: ['DriverManagerModal.*.test.tsx'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/DataSyncModal.tsx',
|
||||
lines: 1526,
|
||||
area: 'data-sync',
|
||||
riskLevel: 'high',
|
||||
why: '数据同步连接、表映射、预检查和执行结果集中,数据库方言问题容易隐藏。',
|
||||
suggestedSlices: ['连接选择区', '表映射区', '同步预检查结果', '执行日志区'],
|
||||
testTargets: ['DataSyncModal.*.test.tsx'],
|
||||
},
|
||||
{
|
||||
path: 'frontend/src/components/JVMDiagnosticConsole.tsx',
|
||||
lines: 1146,
|
||||
area: 'jvm-diagnostics',
|
||||
riskLevel: 'medium',
|
||||
why: '诊断命令、输出块、权限提示和会话状态可继续拆分,降低 JVM 诊断回归面。',
|
||||
suggestedSlices: ['命令输入区', '诊断输出区', '权限提示区'],
|
||||
testTargets: ['JVMDiagnosticConsole.*.test.tsx'],
|
||||
},
|
||||
];
|
||||
|
||||
const normalizeKeyword = (value: unknown): string => String(value || '').trim().toLowerCase();
|
||||
|
||||
const clampNumber = (value: unknown, fallback: number, min: number, max: number): number => {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed)) {
|
||||
return fallback;
|
||||
}
|
||||
return Math.max(min, Math.min(max, Math.floor(parsed)));
|
||||
};
|
||||
|
||||
const matchesKeyword = (entry: CodebaseHotspotEntry, keyword: string): boolean => {
|
||||
if (!keyword) {
|
||||
return true;
|
||||
}
|
||||
return [
|
||||
entry.path,
|
||||
entry.area,
|
||||
entry.riskLevel,
|
||||
entry.why,
|
||||
...entry.suggestedSlices,
|
||||
...entry.testTargets,
|
||||
].some((item) => item.toLowerCase().includes(keyword));
|
||||
};
|
||||
|
||||
export const buildCodebaseHotspotSnapshot = ({
|
||||
keyword,
|
||||
minLines,
|
||||
limit,
|
||||
includeRecommendations = true,
|
||||
}: CodebaseHotspotSnapshotOptions = {}) => {
|
||||
const normalizedKeyword = normalizeKeyword(keyword);
|
||||
const normalizedMinLines = clampNumber(minLines, 1000, 1, 20000);
|
||||
const normalizedLimit = clampNumber(limit, 8, 1, 30);
|
||||
const matched = CODEBASE_HOTSPOT_SNAPSHOT
|
||||
.filter((entry) => entry.lines >= normalizedMinLines)
|
||||
.filter((entry) => matchesKeyword(entry, normalizedKeyword))
|
||||
.slice(0, normalizedLimit);
|
||||
const criticalCount = matched.filter((entry) => entry.riskLevel === 'critical').length;
|
||||
const highCount = matched.filter((entry) => entry.riskLevel === 'high').length;
|
||||
|
||||
return {
|
||||
kind: 'codebase_hotspots',
|
||||
source: 'static_maintainability_snapshot',
|
||||
evidence: {
|
||||
measuredAt: '2026-06-12',
|
||||
note: '基于当前仓库前端文件行数热点快照;提交前仍应用 git diff 和定向测试核对具体改动。',
|
||||
},
|
||||
filters: {
|
||||
keyword: normalizedKeyword || undefined,
|
||||
minLines: normalizedMinLines,
|
||||
limit: normalizedLimit,
|
||||
includeRecommendations,
|
||||
},
|
||||
summary: {
|
||||
totalKnownHotspots: CODEBASE_HOTSPOT_SNAPSHOT.length,
|
||||
totalMatched: matched.length,
|
||||
maxLines: matched[0]?.lines || 0,
|
||||
criticalCount,
|
||||
highCount,
|
||||
},
|
||||
hotspots: matched.map((entry, index) => ({
|
||||
rank: index + 1,
|
||||
path: entry.path,
|
||||
lines: entry.lines,
|
||||
area: entry.area,
|
||||
riskLevel: entry.riskLevel,
|
||||
why: entry.why,
|
||||
suggestedSlices: includeRecommendations ? entry.suggestedSlices : [],
|
||||
testTargets: includeRecommendations ? entry.testTargets : [],
|
||||
})),
|
||||
nextActions: includeRecommendations
|
||||
? [
|
||||
'优先选择已有测试覆盖的 slice 做小步拆分,避免直接重写整个大组件。',
|
||||
'拆分后至少运行对应组件测试、相关 utils 测试和 npm --prefix frontend run build。',
|
||||
'涉及可见 UI 的拆分需要用浏览器打开真实页面做一次冒烟验证。',
|
||||
]
|
||||
: [],
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,52 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { AIToolCall, SavedConnection } from '../../types';
|
||||
import { executeLocalAIToolCall } from './aiLocalToolExecutor';
|
||||
|
||||
const buildToolCall = (name: string, args: Record<string, unknown>): AIToolCall => ({
|
||||
id: `call-${name}`,
|
||||
type: 'function',
|
||||
function: {
|
||||
name,
|
||||
arguments: JSON.stringify(args),
|
||||
},
|
||||
});
|
||||
|
||||
const buildConnection = (): SavedConnection => ({
|
||||
id: 'conn-1',
|
||||
name: '本地开发库',
|
||||
config: {
|
||||
type: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
port: 3306,
|
||||
user: 'root',
|
||||
},
|
||||
});
|
||||
|
||||
describe('aiLocalToolExecutor inspect_codebase_hotspots', () => {
|
||||
it('returns frontend large-file hotspots and refactor test targets without source content', async () => {
|
||||
const result = await executeLocalAIToolCall({
|
||||
toolCall: buildToolCall('inspect_codebase_hotspots', {
|
||||
keyword: 'QueryEditor',
|
||||
minLines: 1000,
|
||||
limit: 5,
|
||||
}),
|
||||
connections: [buildConnection()],
|
||||
mcpTools: [],
|
||||
toolContextMap: new Map(),
|
||||
runtime: {
|
||||
getDatabases: vi.fn(),
|
||||
getTables: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.toolName).toBe('inspect_codebase_hotspots');
|
||||
expect(result.content).toContain('"kind":"codebase_hotspots"');
|
||||
expect(result.content).toContain('frontend/src/components/QueryEditor.tsx');
|
||||
expect(result.content).toContain('"riskLevel":"critical"');
|
||||
expect(result.content).toContain('事务状态条');
|
||||
expect(result.content).toContain('QueryEditor.result-panel.test.tsx');
|
||||
expect(result.content).not.toContain('import React');
|
||||
});
|
||||
});
|
||||
@@ -14,6 +14,7 @@ describe('aiSlashCommands', () => {
|
||||
expect(commands.some((command) => command.cmd === '/health')).toBe(true);
|
||||
expect(commands.some((command) => command.cmd === '/tools')).toBe(true);
|
||||
expect(commands.some((command) => command.cmd === '/budget')).toBe(true);
|
||||
expect(commands.some((command) => command.cmd === '/hotspots')).toBe(true);
|
||||
expect(commands.some((command) => command.cmd === '/mcp')).toBe(true);
|
||||
expect(commands.some((command) => command.cmd === '/mcpfail')).toBe(true);
|
||||
expect(commands.some((command) => command.cmd === '/mcpadd')).toBe(true);
|
||||
@@ -45,6 +46,12 @@ describe('aiSlashCommands', () => {
|
||||
expect(filterAISlashCommands('/bud').map((command) => command.cmd)).toContain('/budget');
|
||||
});
|
||||
|
||||
it('supports filtering code hotspot diagnostics by keyword and command prefix', () => {
|
||||
expect(filterAISlashCommands('大文件').map((command) => command.cmd)).toContain('/hotspots');
|
||||
expect(filterAISlashCommands('拆分').map((command) => command.cmd)).toContain('/hotspots');
|
||||
expect(filterAISlashCommands('/hot').map((command) => command.cmd)).toContain('/hotspots');
|
||||
});
|
||||
|
||||
it('supports filtering shortcut diagnostics by chinese keyword and command prefix', () => {
|
||||
expect(filterAISlashCommands('快捷键').map((command) => command.cmd)).toContain('/shortcuts');
|
||||
expect(filterAISlashCommands('/sho').map((command) => command.cmd)).toContain('/shortcuts');
|
||||
|
||||
@@ -50,6 +50,7 @@ export const DEFAULT_AI_SLASH_COMMANDS: AISlashCommandDefinition[] = [
|
||||
{ cmd: '/health', label: '🩺 AI 配置体检', desc: '调用体检探针总览当前 AI 配置', prompt: '请先调用 inspect_ai_setup_health,对当前 GoNavi AI 配置做一次完整体检,然后总结 blockers、warnings 和 nextActions。', category: 'diagnose', featured: true, keywords: ['health', '体检', 'ai配置', '探针'] },
|
||||
{ cmd: '/tools', label: '🧰 工具目录', desc: '按关键词选择该用哪个内置探针', prompt: '请先调用 inspect_ai_tool_catalog,按我的问题关键词筛选推荐流程、内置工具参数提示和当前 MCP 工具摘要,再告诉我下一步应该调用哪个工具。关键词:', category: 'diagnose', keywords: ['工具目录', '内置工具', 'toolcatalog', '参数提示', 'arguments', '探针路线'] },
|
||||
{ cmd: '/budget', label: '🧠 上下文体量', desc: '诊断消息、DDL、MCP schema 和 Skills 体量', prompt: '请先调用 inspect_ai_context_budget,检查当前会话消息、工具结果、DDL、MCP schema、提示词和 Skills 的体量风险,并给出应该收窄哪些上下文。', category: 'diagnose', keywords: ['上下文', 'context', '体量', '预算', '变慢', '乱答', 'schema太大', '工具结果'] },
|
||||
{ cmd: '/hotspots', label: '🧱 代码热点', desc: '查看大文件拆分候选和测试范围', prompt: '请先调用 inspect_codebase_hotspots,读取当前 GoNavi 前端大文件热点、建议拆分切片和测试目标,再告诉我下一步最适合拆哪个文件、拆到什么边界,以及需要跑哪些验证。关键词:', category: 'diagnose', keywords: ['大文件', '臃肿', '拆分', '重构', 'hotspots', '代码热点', '几千行'] },
|
||||
{ cmd: '/mcp', label: '🪛 排查 MCP 接入', desc: '检查 MCP 服务和外部客户端状态', prompt: '请先调用 inspect_mcp_setup,帮我盘点当前 MCP 服务、工具发现结果,以及 Claude Code / Codex 本机客户端和 OpenClaw / Hermans 远程 Agent 的接入状态。', category: 'diagnose', featured: true, keywords: ['mcp', 'codex', 'claude', 'openclaw', 'hermans', '外部客户端'] },
|
||||
{ cmd: '/mcpfail', label: '🧯 MCP 运行失败', desc: '读取 MCP 启动、发现和调用失败日志', prompt: '请先调用 inspect_mcp_runtime_failures,读取最近 MCP 启动、工具发现、工具调用、stdio、Docker 或 HTTP MCP 失败日志,结合当前 MCP 服务配置判断原因和 nextActions。关键词或服务名:', category: 'diagnose', keywords: ['mcpfail', 'mcp失败', '运行期失败', '工具发现0个', 'stdio', 'docker mcp', 'http mcp', '启动失败', '调用失败'] },
|
||||
{ cmd: '/mcpadd', label: '🧭 新增 MCP 指引', desc: '查看 command、args、env 和模板怎么填', prompt: '请先调用 inspect_mcp_authoring_guide;如果我贴了完整启动命令或草稿,再调用 inspect_mcp_draft 试算字段和校验问题;最后结合 inspect_mcp_setup,告诉我新增 GoNavi MCP 服务时 command、args、env、timeout 应该怎么填,以及最接近的模板应该选哪个。', category: 'diagnose', featured: true, keywords: ['mcp新增', 'command', 'args', 'env', '模板'] },
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
buildAIMessageFlowSnapshot,
|
||||
} from './aiChatSessionInsights';
|
||||
import { buildAIContextBudgetSnapshot } from './aiContextBudgetInsights';
|
||||
import { buildCodebaseHotspotSnapshot } from './aiCodebaseHotspotInsights';
|
||||
import {
|
||||
buildSavedQueriesSnapshot,
|
||||
buildSqlSnippetsSnapshot,
|
||||
@@ -114,6 +115,16 @@ export async function executeDiagnosticsSnapshotToolCall({
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
case 'inspect_codebase_hotspots':
|
||||
return {
|
||||
content: JSON.stringify(buildCodebaseHotspotSnapshot({
|
||||
keyword: args.keyword,
|
||||
minLines: args.minLines,
|
||||
limit: args.limit,
|
||||
includeRecommendations: args.includeRecommendations !== false,
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
case 'inspect_recent_sql_logs':
|
||||
return {
|
||||
content: JSON.stringify(buildRecentSqlLogsSnapshot({
|
||||
|
||||
@@ -180,6 +180,7 @@ export async function executeSnapshotInspectionToolCall(
|
||||
inspect_ai_last_render_error: '读取最近一次 AI 渲染异常失败',
|
||||
inspect_ai_message_flow: '读取 AI 消息流诊断失败',
|
||||
inspect_ai_context_budget: '读取 AI 上下文体量诊断失败',
|
||||
inspect_codebase_hotspots: '读取代码热点诊断失败',
|
||||
inspect_saved_queries: '读取已保存查询失败',
|
||||
inspect_sql_snippets: '读取 SQL 片段失败',
|
||||
inspect_shortcuts: '读取快捷键配置失败',
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('buildAISystemContextMessages', () => {
|
||||
connections: [connections[0]],
|
||||
tabs: [],
|
||||
activeTabId: null,
|
||||
availableToolNames: ['inspect_workspace_tabs', 'inspect_app_health', 'inspect_ai_support_bundle', 'inspect_ai_setup_health', 'inspect_ai_runtime', 'inspect_ai_safety', 'inspect_ai_providers', 'inspect_ai_chat_readiness', 'inspect_ai_upstream_logs', 'inspect_ai_tool_catalog', 'inspect_mcp_setup', 'inspect_mcp_runtime_failures', 'inspect_mcp_authoring_guide', 'inspect_mcp_draft', 'inspect_mcp_tool_schema', 'inspect_ai_guidance', 'inspect_ai_context', 'inspect_current_connection', 'inspect_connection_capabilities', 'inspect_saved_connections', 'inspect_external_sql_directories', 'inspect_external_sql_file', 'inspect_recent_sql_activity', 'inspect_sql_editor_transaction', 'inspect_sql_risk', 'inspect_recent_connection_failures', 'inspect_app_logs', 'inspect_ai_last_render_error', 'inspect_ai_message_flow', 'inspect_ai_context_budget', 'inspect_saved_queries', 'inspect_ai_sessions', 'inspect_sql_snippets', 'inspect_shortcuts', 'get_columns'],
|
||||
availableToolNames: ['inspect_workspace_tabs', 'inspect_app_health', 'inspect_ai_support_bundle', 'inspect_ai_setup_health', 'inspect_ai_runtime', 'inspect_ai_safety', 'inspect_ai_providers', 'inspect_ai_chat_readiness', 'inspect_ai_upstream_logs', 'inspect_ai_tool_catalog', 'inspect_mcp_setup', 'inspect_mcp_runtime_failures', 'inspect_mcp_authoring_guide', 'inspect_mcp_draft', 'inspect_mcp_tool_schema', 'inspect_ai_guidance', 'inspect_ai_context', 'inspect_current_connection', 'inspect_connection_capabilities', 'inspect_saved_connections', 'inspect_external_sql_directories', 'inspect_external_sql_file', 'inspect_recent_sql_activity', 'inspect_sql_editor_transaction', 'inspect_sql_risk', 'inspect_recent_connection_failures', 'inspect_app_logs', 'inspect_ai_last_render_error', 'inspect_ai_message_flow', 'inspect_ai_context_budget', 'inspect_codebase_hotspots', 'inspect_saved_queries', 'inspect_ai_sessions', 'inspect_sql_snippets', 'inspect_shortcuts', 'get_columns'],
|
||||
skills,
|
||||
userPromptSettings,
|
||||
});
|
||||
@@ -104,6 +104,7 @@ describe('buildAISystemContextMessages', () => {
|
||||
expect(joined).toContain('inspect_ai_last_render_error 读取最近一次被隔离的前端渲染异常记录');
|
||||
expect(joined).toContain('inspect_ai_message_flow 读取当前会话的真实消息结构');
|
||||
expect(joined).toContain('inspect_ai_context_budget 读取消息、DDL、MCP schema、提示词和 Skills 的体量风险');
|
||||
expect(joined).toContain('inspect_codebase_hotspots 读取大文件热点');
|
||||
expect(joined).toContain('inspect_saved_queries');
|
||||
expect(joined).toContain('inspect_ai_sessions');
|
||||
expect(joined).toContain('inspect_sql_snippets');
|
||||
|
||||
@@ -170,6 +170,12 @@ export const appendDatabaseInspectionGuidanceMessages = (
|
||||
'inspect_ai_context_budget',
|
||||
'如果用户提到“AI 变慢”“上下文太大”“表结构挂太多”“工具结果太长”“模型开始乱答”或复杂任务前需要判断是否该拆小上下文,优先调用 inspect_ai_context_budget 读取消息、DDL、MCP schema、提示词和 Skills 的体量风险,再决定收窄上下文或拆任务。',
|
||||
);
|
||||
appendGuidanceIfToolAvailable(
|
||||
messages,
|
||||
availableToolNames,
|
||||
'inspect_codebase_hotspots',
|
||||
'如果用户提到“几千行文件太臃肿”“继续拆分大组件”“下一步该拆哪个文件”“AI/MCP/UI 改动风险大不大”,优先调用 inspect_codebase_hotspots 读取大文件热点、建议拆分切片和测试目标,再制定改动范围。',
|
||||
);
|
||||
appendGuidanceIfToolAvailable(
|
||||
messages,
|
||||
availableToolNames,
|
||||
|
||||
@@ -62,6 +62,7 @@ const TOOL_ACTION_LABELS: Record<string, string> = {
|
||||
inspect_ai_last_render_error: '读取最近一次 AI 渲染异常',
|
||||
inspect_ai_message_flow: '诊断当前 AI 消息流',
|
||||
inspect_ai_context_budget: '诊断 AI 上下文体量风险',
|
||||
inspect_codebase_hotspots: '读取代码大文件热点',
|
||||
inspect_saved_queries: '检索本地已保存查询',
|
||||
inspect_sql_snippets: '读取 SQL 片段模板',
|
||||
inspect_shortcuts: '读取当前快捷键配置',
|
||||
|
||||
@@ -163,6 +163,31 @@ export const BUILTIN_AI_INSPECTION_DIAGNOSTICS_TOOL_INFO: AIBuiltinToolInfo[] =
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_codebase_hotspots",
|
||||
icon: "🧱",
|
||||
desc: "查看前端大文件和拆分热点",
|
||||
detail:
|
||||
"返回当前 GoNavi 前端代码中的大文件热点、行数、风险等级、建议拆分切片和应该运行的回归测试。适合用户要求继续治理几千行大文件、评估下一步该拆哪个组件,或 AI 在修改前需要先判断改动风险时调用。",
|
||||
params: "keyword?, minLines?(默认 1000), limit?(默认 8), includeRecommendations?(默认 true)",
|
||||
tool: {
|
||||
type: "function",
|
||||
function: {
|
||||
name: "inspect_codebase_hotspots",
|
||||
description:
|
||||
"读取 GoNavi 前端大文件和拆分热点快照,返回文件路径、行数、风险等级、建议拆分切片和测试目标。适用于用户提到几千行文件太臃肿、需要继续拆分组件、评估下一个重构切入点或在改 UI/AI/MCP 前需要先判断代码热点风险时优先调用。",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
keyword: { type: "string", description: "可选,按路径、模块、风险、拆分切片或测试目标过滤,例如 Sidebar、DataGrid、Redis、事务、连接" },
|
||||
minLines: { type: "number", description: "可选,只返回不少于多少行的热点文件,默认 1000,最大 20000" },
|
||||
limit: { type: "number", description: "可选,最多返回多少个热点,默认 8,最大 30" },
|
||||
includeRecommendations: { type: "boolean", description: "可选,是否返回 suggestedSlices、testTargets 和 nextActions,默认 true" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_sql_snippets",
|
||||
icon: "🧩",
|
||||
|
||||
@@ -89,5 +89,9 @@ describe('describeBuiltinToolParameters', () => {
|
||||
const mcpFlows = filterBuiltinToolFlows(BUILTIN_TOOL_FLOWS, '运行期失败日志')
|
||||
.map((flow) => flow.title);
|
||||
expect(mcpFlows).toContain('排查 MCP 接入状态');
|
||||
|
||||
const codebaseFlows = filterBuiltinToolFlows(BUILTIN_TOOL_FLOWS, '拆分热点')
|
||||
.map((flow) => flow.title);
|
||||
expect(codebaseFlows).toContain('治理前端大文件');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -207,6 +207,11 @@ export const BUILTIN_TOOL_FLOWS: AIBuiltinToolFlow[] = [
|
||||
steps: 'inspect_ai_context_budget -> inspect_ai_context / inspect_ai_message_flow / inspect_ai_tool_catalog',
|
||||
description: '适合用户反馈 AI 变慢、乱答、上下文太大、工具结果过长或表结构挂太多时,先看消息、DDL、MCP schema、提示词和 Skills 的体量来源,再决定收窄上下文或拆任务。',
|
||||
},
|
||||
{
|
||||
title: '治理前端大文件',
|
||||
steps: 'inspect_codebase_hotspots -> inspect_ai_tool_catalog',
|
||||
description: '适合用户要求继续拆分几千行组件、评估下一步重构切入点,或 AI 修改 UI/AI/MCP 前先判断大文件拆分热点、风险和验证范围。',
|
||||
},
|
||||
{
|
||||
title: '复用历史 SQL',
|
||||
steps: 'inspect_saved_queries -> get_columns / execute_sql',
|
||||
|
||||
@@ -204,6 +204,14 @@ describe('aiToolRegistry', () => {
|
||||
expect(info?.tool.function.parameters?.properties?.messageLimit?.description).toContain('最大 120');
|
||||
});
|
||||
|
||||
it('registers the codebase-hotspots inspector as a builtin tool', () => {
|
||||
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_codebase_hotspots');
|
||||
expect(info).toBeTruthy();
|
||||
expect(info?.desc).toContain('前端大文件');
|
||||
expect(info?.tool.function.description).toContain('拆分热点快照');
|
||||
expect(info?.tool.function.parameters?.properties?.minLines?.description).toContain('默认 1000');
|
||||
});
|
||||
|
||||
it('registers the recent-sql-activity, saved-query, and sql-snippet inspectors as builtin tools', () => {
|
||||
const recentActivityTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_recent_sql_activity');
|
||||
const sqlEditorTransactionTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_sql_editor_transaction');
|
||||
@@ -282,6 +290,7 @@ describe('aiToolRegistry', () => {
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_last_render_error')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_message_flow')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_context_budget')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_codebase_hotspots')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_saved_queries')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_ai_sessions')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_sql_snippets')).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user