mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-07-02 19:21:32 +08:00
✨ feat(ai): 增强 MCP 远程接入与上下文诊断
This commit is contained in:
@@ -701,6 +701,30 @@ export const BUILTIN_AI_INSPECTION_TOOL_INFO: AIBuiltinToolInfo[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_ai_context_budget",
|
||||
icon: "📦",
|
||||
desc: "诊断 AI 上下文体量与稳定性风险",
|
||||
detail:
|
||||
"统计当前或指定 AI 会话的最近消息、工具结果、已挂载表结构、MCP 工具 schema、用户提示词和 Skills 体量,返回 low/medium/high/critical 风险、主要膨胀来源和收窄建议。适合用户反馈 AI 变慢、乱答、上下文太大、工具结果过长或表结构挂太多时先做预算体检。",
|
||||
params: "sessionId?(默认当前会话), messageLimit?(默认 40), includeDetails?(默认 true)",
|
||||
tool: {
|
||||
type: "function",
|
||||
function: {
|
||||
name: "inspect_ai_context_budget",
|
||||
description:
|
||||
"读取当前 AI 上下文体量与稳定性风险快照,包括最近消息窗口、tool 结果长度、已挂载表结构 DDL、MCP 工具 schema、用户提示词和启用 Skills 的估算体量,并返回风险级别、告警和收窄建议。适用于用户提到 AI 回复变慢、上下文过大、表结构带太多、工具结果过长、模型开始乱答或复杂任务前需要判断是否应拆小上下文时优先调用。",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sessionId: { type: "string", description: "可选,指定要诊断的 AI 会话 ID;不传时读取当前活动会话" },
|
||||
messageLimit: { type: "number", description: "可选,最多统计最近多少条消息,默认 40,最大 120" },
|
||||
includeDetails: { type: "boolean", description: "可选,是否返回最大消息、最大 DDL 表和最大 MCP schema 明细,默认 true" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_sql_snippets",
|
||||
icon: "🧩",
|
||||
|
||||
@@ -184,6 +184,11 @@ export const BUILTIN_TOOL_FLOWS: AIBuiltinToolFlow[] = [
|
||||
steps: 'inspect_ai_message_flow -> inspect_ai_last_render_error / inspect_app_logs',
|
||||
description: '适合用户反馈回复被拆成多个气泡、工具调用后没继续回答、消息流状态不对时,先读取当前会话的真实消息结构和异常信号。',
|
||||
},
|
||||
{
|
||||
title: '诊断 AI 上下文体量',
|
||||
steps: 'inspect_ai_context_budget -> inspect_ai_context / inspect_ai_message_flow / inspect_ai_tool_catalog',
|
||||
description: '适合用户反馈 AI 变慢、乱答、上下文太大、工具结果过长或表结构挂太多时,先看消息、DDL、MCP schema、提示词和 Skills 的体量来源,再决定收窄上下文或拆任务。',
|
||||
},
|
||||
{
|
||||
title: '复用历史 SQL',
|
||||
steps: 'inspect_saved_queries -> get_columns / execute_sql',
|
||||
|
||||
@@ -162,6 +162,14 @@ describe('aiToolRegistry', () => {
|
||||
expect(info?.tool.function.description).toContain('连续 assistant 消息');
|
||||
});
|
||||
|
||||
it('registers the ai-context-budget inspector as a builtin tool', () => {
|
||||
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_context_budget');
|
||||
expect(info).toBeTruthy();
|
||||
expect(info?.desc).toContain('上下文体量');
|
||||
expect(info?.tool.function.description).toContain('MCP 工具 schema');
|
||||
expect(info?.tool.function.parameters?.properties?.messageLimit?.description).toContain('最大 120');
|
||||
});
|
||||
|
||||
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');
|
||||
@@ -236,6 +244,7 @@ describe('aiToolRegistry', () => {
|
||||
expect(tools.some((item) => item.function.name === 'inspect_recent_connection_failures')).toBe(true);
|
||||
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_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);
|
||||
|
||||
@@ -137,11 +137,13 @@ describe('mcpClientInstallStatus helpers', () => {
|
||||
expect(guide).toContain('allowMutating=true');
|
||||
expect(guide).toContain('"type": "streamable-http"');
|
||||
expect(guide).toContain('"Authorization": "Bearer <随机token>"');
|
||||
expect(guide).toContain('GoNavi.exe mcp-server remote-config --client openclaw --url https://<你的域名或隧道地址>/mcp --token <随机token>');
|
||||
expect(guide).toContain('GoNavi.exe mcp-server http --addr 127.0.0.1:8765 --path /mcp --token <随机token>');
|
||||
});
|
||||
|
||||
it('builds remote quick-start snippets for cloud agents without database secrets', () => {
|
||||
const quickStart = buildRemoteMCPClientQuickStart({
|
||||
client: 'hermans',
|
||||
displayName: 'OpenClaw',
|
||||
});
|
||||
|
||||
@@ -150,6 +152,7 @@ describe('mcpClientInstallStatus helpers', () => {
|
||||
expect(quickStart.configJson).toContain('"url": "https://<你的域名或隧道地址>/mcp"');
|
||||
expect(quickStart.configJson).toContain('"Authorization": "Bearer <随机token>"');
|
||||
expect(quickStart.configJson).not.toContain('password');
|
||||
expect(quickStart.configCommand).toBe('GoNavi.exe mcp-server remote-config --client hermans --url https://<你的域名或隧道地址>/mcp --token <随机token>');
|
||||
expect(quickStart.launchCommand).toBe('GoNavi.exe mcp-server http --addr 127.0.0.1:8765 --path /mcp --token <随机token>');
|
||||
expect(quickStart.standaloneCommand).toBe('gonavi-mcp-server http --addr 127.0.0.1:8765 --path /mcp --token <随机token>');
|
||||
expect(quickStart.verificationSteps.join('\n')).toContain('get_connections');
|
||||
|
||||
@@ -11,6 +11,7 @@ const DEFAULT_REMOTE_MCP_PATH = '/mcp';
|
||||
export interface RemoteMCPClientQuickStart {
|
||||
displayName: string;
|
||||
configJson: string;
|
||||
configCommand: string;
|
||||
launchCommand: string;
|
||||
standaloneCommand: string;
|
||||
verificationSteps: string[];
|
||||
@@ -170,7 +171,7 @@ export const formatMCPLaunchCommand = (
|
||||
};
|
||||
|
||||
export const buildRemoteMCPClientGuide = (
|
||||
status?: Pick<AIMCPClientInstallStatus, 'displayName' | 'message'> | null,
|
||||
status?: Partial<Pick<AIMCPClientInstallStatus, 'client' | 'displayName' | 'message'>> | null,
|
||||
): string => {
|
||||
const quickStart = buildRemoteMCPClientQuickStart(status);
|
||||
return [
|
||||
@@ -194,6 +195,9 @@ export const buildRemoteMCPClientGuide = (
|
||||
'可复制配置片段(适用于支持 mcpServers JSON 的 Agent):',
|
||||
...quickStart.configJson.split('\n'),
|
||||
'',
|
||||
'无 GUI / CLI 生成配置命令:',
|
||||
quickStart.configCommand,
|
||||
'',
|
||||
'CLI / 服务启动命令:',
|
||||
quickStart.launchCommand,
|
||||
`或设置环境变量:GONAVI_MCP_HTTP_TOKEN=<随机token> 后运行 ${quickStart.standaloneCommand.replace(' --token <随机token>', '')}`,
|
||||
@@ -203,11 +207,13 @@ export const buildRemoteMCPClientGuide = (
|
||||
};
|
||||
|
||||
export const buildRemoteMCPClientQuickStart = (
|
||||
status?: Pick<AIMCPClientInstallStatus, 'displayName'> | null,
|
||||
status?: Partial<Pick<AIMCPClientInstallStatus, 'client' | 'displayName'>> | null,
|
||||
): RemoteMCPClientQuickStart => {
|
||||
const displayName = String(status?.displayName || '远程 Agent').trim();
|
||||
const client = isMCPClientKey(String(status?.client || '')) ? String(status?.client || '').trim() : 'openclaw';
|
||||
const launchCommand = `GoNavi.exe mcp-server http --addr ${DEFAULT_REMOTE_MCP_LOCAL_ADDR} --path ${DEFAULT_REMOTE_MCP_PATH} --token <随机token>`;
|
||||
const standaloneCommand = `gonavi-mcp-server http --addr ${DEFAULT_REMOTE_MCP_LOCAL_ADDR} --path ${DEFAULT_REMOTE_MCP_PATH} --token <随机token>`;
|
||||
const configCommand = `GoNavi.exe mcp-server remote-config --client ${client} --url ${DEFAULT_REMOTE_MCP_PUBLIC_URL} --token <随机token>`;
|
||||
const configJson = JSON.stringify({
|
||||
mcpServers: {
|
||||
gonavi: {
|
||||
@@ -223,6 +229,7 @@ export const buildRemoteMCPClientQuickStart = (
|
||||
return {
|
||||
displayName,
|
||||
configJson,
|
||||
configCommand,
|
||||
launchCommand,
|
||||
standaloneCommand,
|
||||
verificationSteps: [
|
||||
|
||||
Reference in New Issue
Block a user