feat(ai-tools): 新增安全边界探针并拆分工具注册

This commit is contained in:
Syngnat
2026-06-08 23:50:15 +08:00
parent 1284c8c8ef
commit 20e817b203
12 changed files with 935 additions and 607 deletions

View File

@@ -28,6 +28,8 @@ describe('AIBuiltinToolsCatalog', () => {
expect(markup).toContain('inspect_database_bundle');
expect(markup).toContain('查看 AI 当前能力');
expect(markup).toContain('inspect_ai_runtime');
expect(markup).toContain('核对写入安全边界');
expect(markup).toContain('inspect_ai_safety');
expect(markup).toContain('排查供应商与模型');
expect(markup).toContain('inspect_ai_providers');
expect(markup).toContain('排查聊天发送状态');

View File

@@ -42,6 +42,11 @@ const BUILTIN_TOOL_FLOWS = [
steps: 'inspect_ai_runtime → inspect_ai_context / inspect_current_connection',
description: '适合先确认当前模型、安全级别、上下文级别、Skills 和 MCP 工具,再决定让 AI 走哪条探针链路。',
},
{
title: '核对写入安全边界',
steps: 'inspect_ai_safety → inspect_ai_runtime → inspect_current_connection',
description: '适合先确认当前是不是只读、DDL/DML 到底允不允许、MCP 写操作是否还需要 allowMutating再决定后续该走查询、改数据还是改结构。',
},
{
title: '排查供应商与模型',
steps: 'inspect_ai_providers → inspect_ai_runtime',

View File

@@ -224,6 +224,57 @@ describe('aiLocalToolExecutor', () => {
expect(result.content).toContain('"builtinToolCount":');
});
it('returns the current ai safety snapshot so the model can inspect write boundaries and readonly guards', async () => {
const result = await executeLocalAIToolCall({
toolCall: buildToolCall('inspect_ai_safety', {}),
connections: [{
id: 'jvm-1',
name: 'JVM 诊断环境',
config: {
type: 'jvm',
host: '10.0.0.8',
port: 0,
user: '',
jvm: {
environment: 'uat',
readOnly: true,
diagnostic: {
transport: 'agent-bridge',
allowObserveCommands: true,
allowTraceCommands: true,
allowMutatingCommands: false,
},
},
},
}],
tabs: [{
id: 'diag-tab-1',
title: 'JVM 诊断',
type: 'jvm-diagnostic',
connectionId: 'jvm-1',
readOnly: true,
}],
activeTabId: 'diag-tab-1',
mcpTools: [],
toolContextMap: new Map(),
runtime: {
getDatabases: vi.fn(),
getTables: vi.fn(),
getAIRuntimeState: vi.fn().mockResolvedValue({
safetyLevel: 'readwrite',
}),
},
});
expect(result.success).toBe(true);
expect(result.content).toContain('"safetyLevel":"readwrite"');
expect(result.content).toContain('"allowDML":true');
expect(result.content).toContain('"allowDDL":false');
expect(result.content).toContain('"readOnly":true');
expect(result.content).toContain('"allowMutatingCommands":false');
expect(result.content).toContain('allowMutating=true');
});
it('returns the current ai provider snapshot so the model can inspect provider readiness and model selection', async () => {
const result = await executeLocalAIToolCall({
toolCall: buildToolCall('inspect_ai_providers', {}),

View File

@@ -0,0 +1,65 @@
import { describe, expect, it } from 'vitest';
import { buildAISafetySnapshot } from './aiSafetyInsights';
describe('buildAISafetySnapshot', () => {
it('describes readonly ai safety when no active connection is selected', () => {
const snapshot = buildAISafetySnapshot({
safetyLevel: 'readonly',
connections: [],
});
expect(snapshot.safetyLevel).toBe('readonly');
expect(snapshot.permissionMatrix.allowQuery).toBe(true);
expect(snapshot.permissionMatrix.allowDML).toBe(false);
expect(snapshot.permissionMatrix.allowDDL).toBe(false);
expect(snapshot.hasActiveConnection).toBe(false);
expect(snapshot.effectiveRestrictions).toContain('只读模式仅允许查询语句。');
expect(snapshot.recommendations).toContain('如需执行 INSERT/UPDATE/DELETE请先把 AI 安全级别切到读写模式。');
});
it('includes jvm connection restrictions and MCP write confirmation hints', () => {
const snapshot = buildAISafetySnapshot({
safetyLevel: 'readwrite',
connections: [
{
id: 'jvm-1',
name: 'JVM 诊断环境',
config: {
type: 'jvm',
host: '10.0.0.8',
port: 0,
user: '',
jvm: {
environment: 'uat',
readOnly: true,
diagnostic: {
transport: 'agent-bridge',
allowObserveCommands: true,
allowTraceCommands: true,
allowMutatingCommands: false,
},
},
},
},
],
tabs: [
{
id: 'diag-tab-1',
title: 'JVM 诊断',
type: 'jvm-diagnostic',
connectionId: 'jvm-1',
readOnly: true,
},
],
activeTabId: 'diag-tab-1',
});
expect(snapshot.permissionMatrix.allowDML).toBe(true);
expect(snapshot.permissionMatrix.allowDDL).toBe(false);
expect(snapshot.activeConnection?.readOnly).toBe(true);
expect(snapshot.jvmGuards?.allowMutatingCommands).toBe(false);
expect(snapshot.effectiveRestrictions.join('\n')).toContain('allowMutating=true');
expect(snapshot.effectiveRestrictions.join('\n')).toContain('当前 JVM 诊断明确禁止 mutating 命令');
});
});

View File

@@ -0,0 +1,135 @@
import type { AISafetyLevel, SavedConnection, TabData } from '../../types';
const SAFETY_LEVEL_LABELS: Record<string, string> = {
readonly: '只读',
readwrite: '读写',
full: '完全开放',
};
const SAFETY_RULE_TEXTS: Record<string, string> = {
readonly: '只读模式仅允许查询语句。',
readwrite: '读写模式允许查询和 DMLDDL 仍会被阻止。',
full: '完全开放模式允许查询、DML 和 DDL未识别操作仍会被阻止。',
};
const normalizeSafetyLevel = (value: AISafetyLevel | string | undefined): string => {
const level = String(value || 'readonly').trim().toLowerCase();
if (level === 'readwrite' || level === 'full') {
return level;
}
return 'readonly';
};
const buildPermissionMatrix = (safetyLevel: string) => ({
allowQuery: true,
allowDML: safetyLevel === 'readwrite' || safetyLevel === 'full',
allowDDL: safetyLevel === 'full',
requiresConfirmationForAllowedNonQuery: true,
requiresMCPAllowMutatingForAllowedNonQuery: true,
});
export const buildAISafetySnapshot = (params: {
safetyLevel?: AISafetyLevel | string;
activeContext?: { connectionId: string; dbName?: string } | null;
tabs?: TabData[];
activeTabId?: string | null;
connections: SavedConnection[];
}) => {
const {
safetyLevel,
activeContext = null,
tabs = [],
activeTabId = null,
connections,
} = params;
const normalizedSafetyLevel = normalizeSafetyLevel(safetyLevel);
const activeTab = tabs.find((tab) => tab.id === activeTabId);
const connectionId = String(activeContext?.connectionId || activeTab?.connectionId || '').trim();
const activeDbName = String(activeContext?.dbName || activeTab?.dbName || '').trim();
const connection = connectionId
? connections.find((item) => item.id === connectionId)
: undefined;
const config = connection?.config;
const jvm = config?.jvm;
const diagnostic = jvm?.diagnostic;
const isJVMSession = config?.type === 'jvm';
const activeResultReadOnly = activeTab?.readOnly === true;
const jvmReadOnly = isJVMSession && jvm?.readOnly !== false;
const effectiveRestrictions = [
SAFETY_RULE_TEXTS[normalizedSafetyLevel] || SAFETY_RULE_TEXTS.readonly,
];
if (normalizedSafetyLevel === 'readonly') {
effectiveRestrictions.push('当前安全级别下,任何 DML/DDL 都会被直接阻止。');
} else {
effectiveRestrictions.push('任何允许通过的非查询语句都仍然需要人工确认。');
effectiveRestrictions.push('如果通过 GoNavi MCP 的 execute_sql 执行非查询语句,还必须显式传 allowMutating=true。');
}
if (activeResultReadOnly) {
effectiveRestrictions.push('当前活动页签结果集是只读的,不能把它当成可直接回写的数据网格。');
}
if (jvmReadOnly) {
effectiveRestrictions.push('当前 JVM 连接本身是只读连接,默认只能按观察/排障思路生成诊断计划。');
}
if (isJVMSession && diagnostic?.allowMutatingCommands !== true) {
effectiveRestrictions.push('当前 JVM 诊断明确禁止 mutating 命令,即使 AI 安全级别允许写入,也不能假设这类命令能执行。');
}
const recommendations: string[] = [];
if (normalizedSafetyLevel === 'readonly') {
recommendations.push('如需执行 INSERT/UPDATE/DELETE请先把 AI 安全级别切到读写模式。');
recommendations.push('如需执行 CREATE/ALTER/DROP/TRUNCATE 等结构变更,请切到完全开放模式。');
} else if (normalizedSafetyLevel === 'readwrite') {
recommendations.push('当前已经允许 DML如果目标是改表结构仍需要切到完全开放模式。');
}
if (activeResultReadOnly) {
recommendations.push('如果目标是编辑结果网格,请重新打开可编辑的表或查询结果,不要只看当前只读页签。');
}
if (jvmReadOnly) {
recommendations.push('当前 JVM 连接按只读策略回答;需要变更类诊断前先确认连接策略是否应调整。');
}
if (isJVMSession && diagnostic?.allowMutatingCommands !== true) {
recommendations.push('当前 JVM 诊断禁止 mutating 命令;如需执行高风险命令,应先调整诊断权限。');
}
return {
safetyLevel: normalizedSafetyLevel,
safetyLabel: SAFETY_LEVEL_LABELS[normalizedSafetyLevel] || normalizedSafetyLevel,
sqlRuleText: SAFETY_RULE_TEXTS[normalizedSafetyLevel] || SAFETY_RULE_TEXTS.readonly,
permissionMatrix: buildPermissionMatrix(normalizedSafetyLevel),
hasActiveConnection: Boolean(connection),
activeConnection: connection
? {
connectionId: connection.id,
connectionName: connection.name,
connectionType: config?.type || '',
host: config?.host || '',
activeDbName: activeDbName || config?.database || '',
readOnly: activeResultReadOnly || jvmReadOnly,
}
: null,
activeTab: activeTab
? {
id: activeTab.id,
title: activeTab.title || '',
type: activeTab.type || '',
readOnly: activeResultReadOnly,
}
: null,
jvmGuards: isJVMSession
? {
readOnly: jvmReadOnly,
transport: diagnostic?.transport || 'agent-bridge',
allowObserveCommands: diagnostic?.allowObserveCommands !== false,
allowTraceCommands: diagnostic?.allowTraceCommands === true,
allowMutatingCommands: diagnostic?.allowMutatingCommands === true,
}
: null,
effectiveRestrictions,
recommendations,
message: connection
? `当前 AI 安全级别为 ${SAFETY_LEVEL_LABELS[normalizedSafetyLevel] || normalizedSafetyLevel},活动连接为 ${connection.name}`
: `当前 AI 安全级别为 ${SAFETY_LEVEL_LABELS[normalizedSafetyLevel] || normalizedSafetyLevel},当前没有活动连接`,
};
};

View File

@@ -21,6 +21,7 @@ import { buildAIGuidanceSnapshot } from './aiPromptInsights';
import { buildAIChatReadinessSnapshot } from './aiChatReadiness';
import { buildAIProviderSnapshot } from './aiProviderInsights';
import { buildAIRuntimeSnapshot } from './aiRuntimeInsights';
import { buildAISafetySnapshot } from './aiSafetyInsights';
import {
buildSavedQueriesSnapshot,
buildSqlSnippetsSnapshot,
@@ -111,6 +112,21 @@ export async function executeSnapshotInspectionToolCall(
success: true,
};
}
case 'inspect_ai_safety': {
const runtimeState = typeof runtime?.getAIRuntimeState === 'function'
? await runtime.getAIRuntimeState()
: undefined;
return {
content: JSON.stringify(buildAISafetySnapshot({
safetyLevel: runtimeState?.safetyLevel,
activeContext,
tabs,
activeTabId,
connections,
})),
success: true,
};
}
case 'inspect_ai_providers': {
const runtimeState = typeof runtime?.getAIRuntimeState === 'function'
? await runtime.getAIRuntimeState()
@@ -254,6 +270,7 @@ export async function executeSnapshotInspectionToolCall(
} catch (error: any) {
const label = {
inspect_ai_runtime: '读取当前 AI 运行状态失败',
inspect_ai_safety: '读取当前 AI 安全边界失败',
inspect_ai_providers: '读取当前 AI 供应商配置失败',
inspect_ai_chat_readiness: '读取 AI 聊天发送前置状态失败',
inspect_mcp_setup: '读取 MCP 配置状态失败',

View File

@@ -68,7 +68,7 @@ describe('buildAISystemContextMessages', () => {
connections: [connections[0]],
tabs: [],
activeTabId: null,
availableToolNames: ['inspect_workspace_tabs', 'inspect_ai_runtime', 'inspect_ai_providers', 'inspect_ai_chat_readiness', 'inspect_mcp_setup', 'inspect_ai_guidance', 'inspect_ai_context', 'inspect_current_connection', 'inspect_saved_connections', 'inspect_saved_queries', 'inspect_sql_snippets', 'get_columns'],
availableToolNames: ['inspect_workspace_tabs', 'inspect_ai_runtime', 'inspect_ai_safety', 'inspect_ai_providers', 'inspect_ai_chat_readiness', 'inspect_mcp_setup', 'inspect_ai_guidance', 'inspect_ai_context', 'inspect_current_connection', 'inspect_saved_connections', 'inspect_saved_queries', 'inspect_sql_snippets', 'get_columns'],
skills,
userPromptSettings,
});
@@ -76,6 +76,7 @@ describe('buildAISystemContextMessages', () => {
const joined = messages.map((message) => message.content).join('\n');
expect(joined).toContain('inspect_workspace_tabs 盘点当前工作区');
expect(joined).toContain('inspect_ai_runtime 读取当前 AI 运行状态');
expect(joined).toContain('inspect_ai_safety 读取真实安全边界');
expect(joined).toContain('inspect_ai_providers 读取真实供应商配置');
expect(joined).toContain('inspect_ai_chat_readiness 读取真实发送前置状态');
expect(joined).toContain('inspect_mcp_setup 读取真实 MCP 配置');

View File

@@ -108,6 +108,19 @@ const appendAIRuntimeInspectionGuidance = (
});
};
const appendAISafetyInspectionGuidance = (
messages: AISystemContextMessage[],
availableToolNames: string[],
) => {
if (!availableToolNames.includes('inspect_ai_safety')) {
return;
}
messages.push({
role: 'system',
content: '如果用户提到“为什么现在不能写”“当前是不是只读”“DDL 能不能执行”“allowMutating 要不要传”,优先调用 inspect_ai_safety 读取真实安全边界,不要只凭界面现象或记忆猜测。',
});
};
const appendAIProviderInspectionGuidance = (
messages: AISystemContextMessage[],
availableToolNames: string[],
@@ -271,6 +284,7 @@ export function buildAISystemContextMessages({
7. 如果命令权限不允许某类操作,就不要输出该类命令;无法满足时直接说明限制。`,
});
appendAIRuntimeInspectionGuidance(systemMessages, availableToolNames);
appendAISafetyInspectionGuidance(systemMessages, availableToolNames);
appendCustomPromptGroup(systemMessages, ['jvmDiagnostic'], userPromptSettings);
appendSkillPromptGroup(systemMessages, ['jvmDiagnostic'], skills, availableToolNames);
return systemMessages;
@@ -305,6 +319,7 @@ ${resourcePath ? `当前资源路径:${resourcePath}` : '当前未选中具体
6. 不要输出脚本、命令或“已经执行成功”之类的表述。`,
});
appendAIRuntimeInspectionGuidance(systemMessages, availableToolNames);
appendAISafetyInspectionGuidance(systemMessages, availableToolNames);
appendCustomPromptGroup(systemMessages, ['jvm'], userPromptSettings);
appendSkillPromptGroup(systemMessages, ['jvm'], skills, availableToolNames);
return systemMessages;
@@ -377,6 +392,7 @@ SELECT * FROM users WHERE status = 1;
});
}
appendAIRuntimeInspectionGuidance(systemMessages, availableToolNames);
appendAISafetyInspectionGuidance(systemMessages, availableToolNames);
appendAIChatReadinessInspectionGuidance(systemMessages, availableToolNames);
appendAIProviderInspectionGuidance(systemMessages, availableToolNames);
appendMCPSetupInspectionGuidance(systemMessages, availableToolNames);

View File

@@ -24,6 +24,7 @@ interface AIToolCallingBlockProps {
const TOOL_ACTION_LABELS: Record<string, string> = {
inspect_ai_runtime: '读取当前 AI 运行状态',
inspect_ai_safety: '读取当前 AI 安全边界',
inspect_ai_providers: '读取当前 AI 供应商与模型配置',
inspect_ai_chat_readiness: '读取当前 AI 聊天发送前置状态',
inspect_mcp_setup: '读取当前 MCP 配置状态',

View File

@@ -0,0 +1,623 @@
export interface AIChatToolDefinition {
type: "function";
function: {
name: string;
description: string;
parameters: Record<string, any>;
};
}
export interface AIBuiltinToolInfo {
name: string;
icon: string;
desc: string;
detail: string;
params: string;
tool: AIChatToolDefinition;
}
export const BUILTIN_AI_TOOL_INFO: AIBuiltinToolInfo[] = [
{
name: "get_connections",
icon: "🔗",
desc: "获取所有可用的数据库连接",
detail:
"返回连接 ID、名称、类型 (MySQL/PostgreSQL 等) 和 Host 地址。AI 根据返回信息决定优先探索哪个连接。",
params: "无参数",
tool: {
type: "function",
function: {
name: "get_connections",
description:
"当需要查询、操作数据库但用户没有选择任何连接上下文时获取当前软件中可用的所有数据库连接信息。返回的数据包含连接ID(id)和名称(name)。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "get_databases",
icon: "🗄️",
desc: "获取指定连接下的所有数据库",
detail: "传入 connectionId返回该连接下的数据库/Schema 名称列表。",
params: "connectionId: 连接 ID",
tool: {
type: "function",
function: {
name: "get_databases",
description: "获取指定连接connectionId下的所有数据库(Database/Schema)名。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID (从 get_connections 获取)" },
},
required: ["connectionId"],
},
},
},
},
{
name: "get_tables",
icon: "📋",
desc: "获取指定数据库下的所有表名",
detail:
"传入 connectionId 和 dbName返回表名列表。AI 用它来定位用户提到的目标表。",
params: "connectionId, dbName",
tool: {
type: "function",
function: {
name: "get_tables",
description:
"当已经确定了目标连接和数据库名后,如果用户询问或隐式提到了表但你不知道确切表名,调用此工具获取该数据库下的所有表名列表(只含表名,帮助你推断目标表)。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
},
required: ["connectionId", "dbName"],
},
},
},
},
{
name: "get_all_columns",
icon: "🧱",
desc: "获取指定数据库下所有表的字段摘要",
detail:
"传入 connectionId 和 dbName返回跨表字段列表表名、字段名、类型、注释。适合用户只知道业务字段、不知道具体在哪张表时快速定位目标表。",
params: "connectionId, dbName",
tool: {
type: "function",
function: {
name: "get_all_columns",
description:
"获取指定数据库下全部表的字段摘要,返回表名、字段名、类型和注释。适用于按字段反查表、跨表梳理相同字段、做数据地图探索。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
},
required: ["connectionId", "dbName"],
},
},
},
},
{
name: "get_columns",
icon: "🔍",
desc: "获取指定表的字段结构",
detail:
"传入 connectionId、dbName 和 tableName返回每个字段的名称、类型、是否可空、默认值和注释。AI 在生成 SQL 前必须调用此工具确认真实字段名。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_columns",
description:
"获取指定表的字段列表(字段名、类型、是否可空、默认值、注释等)。在生成 SQL 之前必须先调用此工具确认真实字段名,禁止猜测字段名。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_indexes",
icon: "🧭",
desc: "获取指定表的索引定义",
detail:
"传入 connectionId、dbName 和 tableName返回索引名、索引列、唯一性和索引类型。AI 在做慢 SQL 分析、索引优化和执行计划推断时应优先调用。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_indexes",
description:
"获取指定表的索引定义,包括索引名、字段顺序、唯一性和索引类型。适用于慢 SQL 分析、索引优化建议和确认现有索引覆盖情况。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_foreign_keys",
icon: "🧬",
desc: "获取指定表的外键关系",
detail:
"传入 connectionId、dbName 和 tableName返回当前表到其他表的外键映射。AI 在推断表关系、生成联表 SQL 和评审数据一致性时可直接使用。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_foreign_keys",
description:
"获取指定表的外键关系包括本表字段、引用表、引用字段和约束名。适用于联表路径分析、ER 关系梳理和约束检查。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_triggers",
icon: "⏱️",
desc: "获取指定表的触发器定义",
detail:
"传入 connectionId、dbName 和 tableName返回触发器名、触发时机、事件类型和语句体。AI 在分析隐式写入、副作用和审计逻辑时可直接查看。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_triggers",
description:
"获取指定表的触发器定义,包括触发时机、事件和触发语句。适用于排查隐式数据变更、审计逻辑和表级副作用。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_table_ddl",
icon: "📝",
desc: "获取表的建表语句 (DDL)",
detail:
"传入 connectionId、dbName 和 tableName返回完整的 CREATE TABLE 语句,包含字段定义、索引、约束等信息。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_table_ddl",
description: "获取指定表的完整建表语句CREATE TABLE DDL包含字段、索引、约束等完整结构信息。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "preview_table_rows",
icon: "👀",
desc: "抽样预览指定表的前几行数据",
detail:
"传入 connectionId、dbName、tableName 和可选 limit返回该表的前几行真实样例数据。适合先看数据形态、空值分布和枚举值再决定怎么写 SQL。",
params: "connectionId, dbName, tableName, limit?",
tool: {
type: "function",
function: {
name: "preview_table_rows",
description:
"预览指定表的前几行样例数据。适用于快速理解字段取值形态、空值情况、时间格式和状态枚举,减少模型盲写 SQL。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
limit: { type: "number", description: "可选,预览行数,默认 20最大 100" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "inspect_table_bundle",
icon: "🧰",
desc: "一次抓取指定表的结构快照",
detail:
"传入 connectionId、dbName 和 tableName返回字段、索引、外键、触发器和 DDL还可以附带前几行样例数据。适合在写 SQL、评审表设计或排查副作用前先做完整摸底。",
params: "connectionId, dbName, tableName, includeSampleRows?, sampleLimit?",
tool: {
type: "function",
function: {
name: "inspect_table_bundle",
description:
"一次性获取指定表的结构快照返回字段、索引、外键、触发器、DDL以及可选样例数据。适用于做完整表设计摸底、快速理解表关系和降低模型多次往返调用。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
includeSampleRows: { type: "boolean", description: "可选,是否附带前几行样例数据" },
sampleLimit: { type: "number", description: "可选,样例行数,默认 10最大 100" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "inspect_database_bundle",
icon: "🗂️",
desc: "一次抓取指定数据库的结构总览",
detail:
"传入 connectionId 和 dbName返回库内表清单、表数量、总字段数以及按表聚合的字段摘要预览。适合刚接手陌生库时先做全局摸底再决定深入哪张表。",
params: "connectionId, dbName, includeColumns?, tableLimit?, perTableColumnLimit?",
tool: {
type: "function",
function: {
name: "inspect_database_bundle",
description:
"一次性获取指定数据库的结构总览,返回表名列表、总字段数,以及按表聚合的字段摘要预览。适用于陌生数据库摸底、做数据地图和快速选择下一步要深入分析的表。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
includeColumns: { type: "boolean", description: "可选,是否附带按表聚合的字段摘要,默认 true" },
tableLimit: { type: "number", description: "可选,最多返回多少张表,默认 80最大 200" },
perTableColumnLimit: { type: "number", description: "可选,每张表最多返回多少个字段摘要,默认 8最大 30" },
},
required: ["connectionId", "dbName"],
},
},
},
},
{
name: "inspect_ai_runtime",
icon: "🎛️",
desc: "查看当前 AI 自身运行状态",
detail:
"返回当前启用的模型供应商、模型名、安全级别、上下文级别、启用的 Skills以及当前已暴露的内置工具和 MCP 工具。适合用户问“你现在能调用什么”“当前用的哪个模型”“为什么不能执行写操作”时,先读真实运行状态再回答。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_runtime",
description:
"读取当前 AI 运行时快照,包括当前供应商、模型、安全级别、上下文级别、启用的 Skills、当前可用的内置工具与 MCP 工具。适用于用户询问当前 AI 能力边界、当前使用哪个模型、为什么不能执行某些操作时,先读取真实运行状态,避免模型猜测。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_safety",
icon: "🛡️",
desc: "查看当前 AI 写入安全边界",
detail:
"返回当前 AI 安全级别对应的 SQL 允许范围、非只读语句是否仍需确认 / allowMutating以及当前活动连接、页签或 JVM 诊断权限是否还叠加了只读限制。适合用户问“为什么现在不能写”“DDL 能不能执行”“allowMutating 要不要传”时先读真实边界。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_safety",
description:
"读取当前 AI 安全边界快照,包括当前安全级别允许的 SQL 范围、非查询语句的确认要求、MCP execute_sql 对 allowMutating 的要求,以及当前活动连接、结果页签或 JVM 诊断权限是否额外处于只读限制。适用于用户提到为什么现在不能写、当前是不是只读、DDL 能不能执行、allowMutating 是否必须传时,先读取真实边界再回答。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_providers",
icon: "🪪",
desc: "查看当前 AI 供应商与模型配置",
detail:
"返回当前配置了哪些 AI 供应商、哪个正在生效、各自的 baseUrl、已选模型、声明模型列表、密钥是否存在、自定义请求头 key以及缺少密钥/模型/地址等待检查项。适合用户问“为什么没有模型”“API Key 有没有配”“当前到底配了哪些供应商”时先读真实配置。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_providers",
description:
"读取当前 AI 供应商配置快照,包括供应商列表、活动供应商、接口地址、已选模型、声明模型列表、是否存在密钥、自定义请求头 key以及缺少密钥/模型/地址等待检查项。适用于用户提到当前供应商、模型列表为空、API Key 是否配置、为什么 AI 不能正常发起请求时,先读取真实配置再解释。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_chat_readiness",
icon: "🚦",
desc: "查看当前 AI 聊天是否具备发送条件",
detail:
"返回当前聊天输入区是否已经具备发送条件,包括有没有活动供应商、当前供应商是否缺密钥或接口地址、是否已选模型、当前连接/表结构上下文是否已挂载,以及下一步建议动作。适合用户问“为什么现在不能发送”“输入框到底缺什么配置”“当前 AI 聊天准备好了没有”时先读真实状态。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_chat_readiness",
description:
"读取当前 AI 聊天输入区的发送前置状态,包括活动供应商、密钥和接口地址是否完整、是否已选模型、当前连接上下文和已挂载表结构数量,以及建议的下一步动作。适用于用户提到为什么现在不能发送、为什么输入区还没准备好、当前到底缺什么配置时,先读取真实状态再回答。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_mcp_setup",
icon: "🪛",
desc: "查看当前 MCP 配置与外部接入状态",
detail:
"返回当前本地配置了哪些 MCP 服务、哪些已启用、每个服务声明了什么启动命令,以及 Claude Code / Codex 这类外部客户端的写入状态与命令检测结果。适合用户问“我现在配了哪些 MCP”“为什么外部客户端还用不了”“MCP 到底写没写进去”时先读真实状态。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_mcp_setup",
description:
"读取当前本地 MCP 配置快照,包括 MCP 服务列表、启用状态、启动命令、环境变量 key、已发现工具以及外部客户端的 GoNavi MCP 写入状态与本机 CLI 检测结果。适用于用户提到 MCP 服务配置、Claude/Codex 是否已接入、为什么外部客户端用不了、当前到底启用了哪些 MCP 时,先读取真实配置再回答。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_guidance",
icon: "🧠",
desc: "查看当前 AI 提示词与 Skills 配置",
detail:
"返回当前用户自定义的全局/数据库/JVM 提示词,以及当前启用的 Skills、作用域、依赖工具和 skill prompt 内容。适合用户问“你现在到底带了哪些提示词”“为什么你会这样回答”“当前有哪些 Skills 在生效”时先读真实配置。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_guidance",
description:
"读取当前 AI 的提示与技能配置快照,包括用户自定义提示词、当前启用的 Skills、作用域、依赖工具和各自的 system prompt。适用于用户提到当前提示词、当前 Skill、为什么 AI 当前会这样回答、当前有哪些规则在生效时,先读取真实配置再解释。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_context",
icon: "🧷",
desc: "查看当前 AI 已关联的表结构上下文",
detail:
"返回当前对话已经挂载到 AI 上下文里的表清单、所属连接与数据库,以及每张表的 DDL 预览。适合用户说“看看我现在带了哪些表结构”“当前 AI 上下文是什么”时,先读取真实挂载状态再继续分析。",
params: "includeDDL?(默认 false), ddlLimit?(默认 4000)",
tool: {
type: "function",
function: {
name: "inspect_ai_context",
description:
"读取当前对话已经关联到 AI 上下文里的表结构快照,包括连接、数据库、表名,以及可选的 DDL 内容。适用于用户提到当前 AI 上下文、当前关联表、当前挂载的表结构时,先读取真实状态,避免模型凭记忆复述。",
parameters: {
type: "object",
properties: {
includeDDL: { type: "boolean", description: "可选,是否附带每张表的 DDL 内容,默认 false" },
ddlLimit: { type: "number", description: "可选DDL 截断长度,默认 4000最大 12000" },
},
},
},
},
},
{
name: "inspect_current_connection",
icon: "🛰️",
desc: "查看当前活动连接/数据源摘要",
detail:
"返回当前活动连接的类型、地址、端口、当前数据库、是否启用 SSH/代理/HTTP 隧道,以及当前活动页签绑定的表信息。适合用户问“我现在连的是哪个库”“这个连接走没走 SSH”“当前数据源是什么类型”时先读取真实连接状态。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_current_connection",
description:
"读取当前活动连接或当前页签对应数据源的真实摘要包括连接类型、地址、端口、当前数据库、SSH/代理/HTTP 隧道状态,以及当前页签绑定的表上下文。适用于用户提到当前连接、当前数据源、当前库地址、是否走 SSH、当前连的是哪种数据库时先读取真实界面上下文避免模型猜测。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_saved_connections",
icon: "🧭",
desc: "查看本地已保存连接清单",
detail:
"可按关键词或数据库类型过滤返回本地保存的数据源列表、连接类型分布以及每条连接的地址、当前库、SSH/代理/HTTP 隧道状态。适合用户问“我本地存了哪些连接”“帮我找 mysql / postgres 连接”“哪条连接配置了 SSH”时先读真实本地连接资产。",
params: "keyword?, type?, limit?",
tool: {
type: "function",
function: {
name: "inspect_saved_connections",
description:
"读取本地已保存连接清单可按关键词和数据库类型过滤并返回每条连接的类型、地址、当前库、SSH/代理/HTTP 隧道等摘要。适用于用户提到本地保存了哪些连接、要找哪条 mysql/postgres 连接、哪条连接启用了 SSH 或代理时,先读取真实本地连接资产再回答。",
parameters: {
type: "object",
properties: {
keyword: { type: "string", description: "可选按连接名、ID、类型、主机、数据库名或 SSH/代理地址做关键词筛选" },
type: { type: "string", description: "可选,只看某种数据库类型,例如 mysql、postgres、redis、mongodb" },
limit: { type: "number", description: "可选,最多返回多少条连接,默认 20最大 100" },
},
},
},
},
},
{
name: "inspect_active_tab",
icon: "📍",
desc: "查看当前活动页签上下文",
detail:
"返回当前活动页签的类型、连接、数据库、表名,以及当前 SQL / 命令页签里的草稿内容(超长会截断)。适合用户说“看我当前这条 SQL”“优化这个编辑器里的语句”时先让 AI 直接读取当前工作区上下文。",
params: "includeContent?(默认 true)",
tool: {
type: "function",
function: {
name: "inspect_active_tab",
description:
"获取当前活动页签的上下文快照,包括页签类型、连接、数据库、表名,以及当前 SQL / 命令页签里的草稿内容。适用于用户提到当前页签、当前 SQL、当前编辑器、这条语句时先读取真实界面上下文避免让模型猜测。",
parameters: {
type: "object",
properties: {
includeContent: { type: "boolean", description: "可选,是否附带页签中的 SQL / 命令草稿内容,默认 true" },
},
},
},
},
},
{
name: "inspect_workspace_tabs",
icon: "🗃️",
desc: "查看当前工作区打开的页签总览",
detail:
"返回当前工作区里打开的页签列表、哪个是活动页签,以及每个页签对应的连接、数据库、表名等上下文。适合用户说“我现在开了哪些 SQL”“看看我工作区里有哪些页签”“帮我对比这几个查询页签”时先读取真实工作区布局再继续分析。",
params: "limit?(默认 12), includeContent?(默认 false)",
tool: {
type: "function",
function: {
name: "inspect_workspace_tabs",
description:
"获取当前工作区已打开页签的总览,包括活动页签、页签类型、连接、数据库、表名,以及可选的 SQL / 命令草稿内容。适用于用户提到当前工作区、打开了哪些页签、哪几个查询页签、想对比多个编辑器内容时,先读取真实界面状态,避免模型猜测。",
parameters: {
type: "object",
properties: {
limit: { type: "number", description: "可选,最多返回多少个页签,默认 12最大 30" },
includeContent: { type: "boolean", description: "可选,是否附带页签中的 SQL / 命令草稿内容,默认 false" },
},
},
},
},
},
{
name: "inspect_recent_sql_logs",
icon: "🧾",
desc: "查看最近 SQL 执行日志",
detail:
"传入可选 limit 和 status返回最近 SQL 执行记录,包括数据库、耗时、成功/失败、报错、受影响行数和 SQL 文本。适合追查刚执行失败的语句、定位慢查询,并让 AI 基于真实执行历史给出解释或优化建议。",
params: "limit?, status?(all|success|error)",
tool: {
type: "function",
function: {
name: "inspect_recent_sql_logs",
description:
"获取最近 SQL 执行日志摘要,可按成功/失败过滤。适用于回看刚执行过的 SQL、排查失败原因、定位慢查询以及让 AI 基于真实执行历史给出解释和优化建议。",
parameters: {
type: "object",
properties: {
limit: { type: "number", description: "可选,返回多少条日志,默认 20最大 100" },
status: {
type: "string",
description: "可选,按执行状态过滤,支持 all、success、error默认 all",
enum: ["all", "success", "error"],
},
},
},
},
},
},
{
name: "inspect_saved_queries",
icon: "💾",
desc: "查看本地已保存的 SQL 查询",
detail:
"可按关键词、连接或数据库过滤,返回保存查询的名称、所属连接、数据库和 SQL 预览。适合用户提到“我之前保存过的查询”“帮我找那条历史 SQL”时先从真实本地收藏里检索。",
params: "keyword?, connectionId?, dbName?, limit?, includeSql?(默认 true)",
tool: {
type: "function",
function: {
name: "inspect_saved_queries",
description:
"读取本地已保存的 SQL 查询列表,可按关键词、连接和数据库过滤,并返回每条查询的名称、所属连接、数据库与 SQL 预览。适用于用户想找历史查询、复用旧 SQL、核对保存脚本时先读取真实本地记录。",
parameters: {
type: "object",
properties: {
keyword: { type: "string", description: "可选按查询名称、SQL 文本、连接名或数据库名做关键词筛选" },
connectionId: { type: "string", description: "可选,只看某个连接下保存的查询" },
dbName: { type: "string", description: "可选,只看某个数据库下保存的查询" },
limit: { type: "number", description: "可选,最多返回多少条,默认 12最大 50" },
includeSql: { type: "boolean", description: "可选,是否附带 SQL 预览,默认 true" },
},
},
},
},
},
{
name: "inspect_sql_snippets",
icon: "🧩",
desc: "查看 SQL 片段模板",
detail:
"返回本地 SQL 片段的 prefix、名称、说明和模板预览可按关键词过滤。适合用户想找现成模板、补全片段、团队约定 SQL 模板时先读取真实片段库。",
params: "keyword?, limit?, includeBody?(默认 true)",
tool: {
type: "function",
function: {
name: "inspect_sql_snippets",
description:
"读取本地 SQL 片段模板列表,可按关键词过滤,并返回 prefix、名称、说明和模板预览。适用于用户想找 snippet、复用模板、核对 SQL 片段配置时,先读取真实本地片段库。",
parameters: {
type: "object",
properties: {
keyword: { type: "string", description: "可选,按 prefix、名称、描述或模板内容做关键词筛选" },
limit: { type: "number", description: "可选,最多返回多少条,默认 20最大 80" },
includeBody: { type: "boolean", description: "可选,是否附带模板内容预览,默认 true" },
},
},
},
},
},
{
name: "execute_sql",
icon: "▶️",
desc: "执行 SQL 查询并返回结果",
detail:
"传入 connectionId、dbName 和 sql在目标数据库上执行 SQL 并返回结果(最多 50 行)。受安全级别控制,只读模式下仅允许 SELECT/SHOW/DESCRIBE。",
params: "connectionId, dbName, sql",
tool: {
type: "function",
function: {
name: "execute_sql",
description:
"在指定连接和数据库上执行 SQL 查询并返回结果。受安全级别控制,只读模式下只能执行 SELECT/SHOW/DESCRIBE 等查询操作。结果最多返回 50 行。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
sql: { type: "string", description: "要执行的 SQL 语句" },
},
required: ["connectionId", "dbName", "sql"],
},
},
},
},
];

View File

@@ -10,6 +10,13 @@ describe('aiToolRegistry', () => {
expect(info?.tool.function.description).toContain('当前供应商');
});
it('registers the ai-safety inspector as a builtin tool', () => {
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_safety');
expect(info).toBeTruthy();
expect(info?.desc).toContain('写入安全边界');
expect(info?.tool.function.description).toContain('allowMutating');
});
it('registers the mcp-setup inspector as a builtin tool', () => {
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_mcp_setup');
expect(info).toBeTruthy();
@@ -79,6 +86,7 @@ describe('aiToolRegistry', () => {
}]);
expect(tools.some((item) => item.function.name === 'inspect_ai_runtime')).toBe(true);
expect(tools.some((item) => item.function.name === 'inspect_ai_safety')).toBe(true);
expect(tools.some((item) => item.function.name === 'inspect_ai_providers')).toBe(true);
expect(tools.some((item) => item.function.name === 'inspect_ai_chat_readiness')).toBe(true);
expect(tools.some((item) => item.function.name === 'inspect_mcp_setup')).toBe(true);

View File

@@ -1,611 +1,15 @@
import type { AIMCPToolDescriptor } from "../types";
import {
BUILTIN_AI_TOOL_INFO,
type AIChatToolDefinition,
type AIBuiltinToolInfo,
} from "./aiBuiltinToolInfo";
export interface AIChatToolDefinition {
type: "function";
function: {
name: string;
description: string;
parameters: Record<string, any>;
};
}
export interface AIBuiltinToolInfo {
name: string;
icon: string;
desc: string;
detail: string;
params: string;
tool: AIChatToolDefinition;
}
export const BUILTIN_AI_TOOL_INFO: AIBuiltinToolInfo[] = [
{
name: "get_connections",
icon: "🔗",
desc: "获取所有可用的数据库连接",
detail:
"返回连接 ID、名称、类型 (MySQL/PostgreSQL 等) 和 Host 地址。AI 根据返回信息决定优先探索哪个连接。",
params: "无参数",
tool: {
type: "function",
function: {
name: "get_connections",
description:
"当需要查询、操作数据库但用户没有选择任何连接上下文时获取当前软件中可用的所有数据库连接信息。返回的数据包含连接ID(id)和名称(name)。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "get_databases",
icon: "🗄️",
desc: "获取指定连接下的所有数据库",
detail: "传入 connectionId返回该连接下的数据库/Schema 名称列表。",
params: "connectionId: 连接 ID",
tool: {
type: "function",
function: {
name: "get_databases",
description: "获取指定连接connectionId下的所有数据库(Database/Schema)名。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID (从 get_connections 获取)" },
},
required: ["connectionId"],
},
},
},
},
{
name: "get_tables",
icon: "📋",
desc: "获取指定数据库下的所有表名",
detail:
"传入 connectionId 和 dbName返回表名列表。AI 用它来定位用户提到的目标表。",
params: "connectionId, dbName",
tool: {
type: "function",
function: {
name: "get_tables",
description:
"当已经确定了目标连接和数据库名后,如果用户询问或隐式提到了表但你不知道确切表名,调用此工具获取该数据库下的所有表名列表(只含表名,帮助你推断目标表)。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
},
required: ["connectionId", "dbName"],
},
},
},
},
{
name: "get_all_columns",
icon: "🧱",
desc: "获取指定数据库下所有表的字段摘要",
detail:
"传入 connectionId 和 dbName返回跨表字段列表表名、字段名、类型、注释。适合用户只知道业务字段、不知道具体在哪张表时快速定位目标表。",
params: "connectionId, dbName",
tool: {
type: "function",
function: {
name: "get_all_columns",
description:
"获取指定数据库下全部表的字段摘要,返回表名、字段名、类型和注释。适用于按字段反查表、跨表梳理相同字段、做数据地图探索。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
},
required: ["connectionId", "dbName"],
},
},
},
},
{
name: "get_columns",
icon: "🔍",
desc: "获取指定表的字段结构",
detail:
"传入 connectionId、dbName 和 tableName返回每个字段的名称、类型、是否可空、默认值和注释。AI 在生成 SQL 前必须调用此工具确认真实字段名。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_columns",
description:
"获取指定表的字段列表(字段名、类型、是否可空、默认值、注释等)。在生成 SQL 之前必须先调用此工具确认真实字段名,禁止猜测字段名。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_indexes",
icon: "🧭",
desc: "获取指定表的索引定义",
detail:
"传入 connectionId、dbName 和 tableName返回索引名、索引列、唯一性和索引类型。AI 在做慢 SQL 分析、索引优化和执行计划推断时应优先调用。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_indexes",
description:
"获取指定表的索引定义,包括索引名、字段顺序、唯一性和索引类型。适用于慢 SQL 分析、索引优化建议和确认现有索引覆盖情况。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_foreign_keys",
icon: "🧬",
desc: "获取指定表的外键关系",
detail:
"传入 connectionId、dbName 和 tableName返回当前表到其他表的外键映射。AI 在推断表关系、生成联表 SQL 和评审数据一致性时可直接使用。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_foreign_keys",
description:
"获取指定表的外键关系包括本表字段、引用表、引用字段和约束名。适用于联表路径分析、ER 关系梳理和约束检查。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_triggers",
icon: "⏱️",
desc: "获取指定表的触发器定义",
detail:
"传入 connectionId、dbName 和 tableName返回触发器名、触发时机、事件类型和语句体。AI 在分析隐式写入、副作用和审计逻辑时可直接查看。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_triggers",
description:
"获取指定表的触发器定义,包括触发时机、事件和触发语句。适用于排查隐式数据变更、审计逻辑和表级副作用。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "get_table_ddl",
icon: "📝",
desc: "获取表的建表语句 (DDL)",
detail:
"传入 connectionId、dbName 和 tableName返回完整的 CREATE TABLE 语句,包含字段定义、索引、约束等信息。",
params: "connectionId, dbName, tableName",
tool: {
type: "function",
function: {
name: "get_table_ddl",
description: "获取指定表的完整建表语句CREATE TABLE DDL包含字段、索引、约束等完整结构信息。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "preview_table_rows",
icon: "👀",
desc: "抽样预览指定表的前几行数据",
detail:
"传入 connectionId、dbName、tableName 和可选 limit返回该表的前几行真实样例数据。适合先看数据形态、空值分布和枚举值再决定怎么写 SQL。",
params: "connectionId, dbName, tableName, limit?",
tool: {
type: "function",
function: {
name: "preview_table_rows",
description:
"预览指定表的前几行样例数据。适用于快速理解字段取值形态、空值情况、时间格式和状态枚举,减少模型盲写 SQL。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
limit: { type: "number", description: "可选,预览行数,默认 20最大 100" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "inspect_table_bundle",
icon: "🧰",
desc: "一次抓取指定表的结构快照",
detail:
"传入 connectionId、dbName 和 tableName返回字段、索引、外键、触发器和 DDL还可以附带前几行样例数据。适合在写 SQL、评审表设计或排查副作用前先做完整摸底。",
params: "connectionId, dbName, tableName, includeSampleRows?, sampleLimit?",
tool: {
type: "function",
function: {
name: "inspect_table_bundle",
description:
"一次性获取指定表的结构快照返回字段、索引、外键、触发器、DDL以及可选样例数据。适用于做完整表设计摸底、快速理解表关系和降低模型多次往返调用。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
tableName: { type: "string", description: "表名" },
includeSampleRows: { type: "boolean", description: "可选,是否附带前几行样例数据" },
sampleLimit: { type: "number", description: "可选,样例行数,默认 10最大 100" },
},
required: ["connectionId", "dbName", "tableName"],
},
},
},
},
{
name: "inspect_database_bundle",
icon: "🗂️",
desc: "一次抓取指定数据库的结构总览",
detail:
"传入 connectionId 和 dbName返回库内表清单、表数量、总字段数以及按表聚合的字段摘要预览。适合刚接手陌生库时先做全局摸底再决定深入哪张表。",
params: "connectionId, dbName, includeColumns?, tableLimit?, perTableColumnLimit?",
tool: {
type: "function",
function: {
name: "inspect_database_bundle",
description:
"一次性获取指定数据库的结构总览,返回表名列表、总字段数,以及按表聚合的字段摘要预览。适用于陌生数据库摸底、做数据地图和快速选择下一步要深入分析的表。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
includeColumns: { type: "boolean", description: "可选,是否附带按表聚合的字段摘要,默认 true" },
tableLimit: { type: "number", description: "可选,最多返回多少张表,默认 80最大 200" },
perTableColumnLimit: { type: "number", description: "可选,每张表最多返回多少个字段摘要,默认 8最大 30" },
},
required: ["connectionId", "dbName"],
},
},
},
},
{
name: "inspect_ai_runtime",
icon: "🎛️",
desc: "查看当前 AI 自身运行状态",
detail:
"返回当前启用的模型供应商、模型名、安全级别、上下文级别、启用的 Skills以及当前已暴露的内置工具和 MCP 工具。适合用户问“你现在能调用什么”“当前用的哪个模型”“为什么不能执行写操作”时,先读真实运行状态再回答。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_runtime",
description:
"读取当前 AI 运行时快照,包括当前供应商、模型、安全级别、上下文级别、启用的 Skills、当前可用的内置工具与 MCP 工具。适用于用户询问当前 AI 能力边界、当前使用哪个模型、为什么不能执行某些操作时,先读取真实运行状态,避免模型猜测。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_providers",
icon: "🪪",
desc: "查看当前 AI 供应商与模型配置",
detail:
"返回当前配置了哪些 AI 供应商、哪个正在生效、各自的 baseUrl、已选模型、声明模型列表、密钥是否存在、自定义请求头 key以及缺少密钥/模型/地址等待检查项。适合用户问“为什么没有模型”“API Key 有没有配”“当前到底配了哪些供应商”时先读真实配置。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_providers",
description:
"读取当前 AI 供应商配置快照,包括供应商列表、活动供应商、接口地址、已选模型、声明模型列表、是否存在密钥、自定义请求头 key以及缺少密钥/模型/地址等待检查项。适用于用户提到当前供应商、模型列表为空、API Key 是否配置、为什么 AI 不能正常发起请求时,先读取真实配置再解释。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_chat_readiness",
icon: "🚦",
desc: "查看当前 AI 聊天是否具备发送条件",
detail:
"返回当前聊天输入区是否已经具备发送条件,包括有没有活动供应商、当前供应商是否缺密钥或接口地址、是否已选模型、当前连接/表结构上下文是否已挂载,以及下一步建议动作。适合用户问“为什么现在不能发送”“输入框到底缺什么配置”“当前 AI 聊天准备好了没有”时先读真实状态。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_chat_readiness",
description:
"读取当前 AI 聊天输入区的发送前置状态,包括活动供应商、密钥和接口地址是否完整、是否已选模型、当前连接上下文和已挂载表结构数量,以及建议的下一步动作。适用于用户提到为什么现在不能发送、为什么输入区还没准备好、当前到底缺什么配置时,先读取真实状态再回答。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_mcp_setup",
icon: "🪛",
desc: "查看当前 MCP 配置与外部接入状态",
detail:
"返回当前本地配置了哪些 MCP 服务、哪些已启用、每个服务声明了什么启动命令,以及 Claude Code / Codex 这类外部客户端的写入状态与命令检测结果。适合用户问“我现在配了哪些 MCP”“为什么外部客户端还用不了”“MCP 到底写没写进去”时先读真实状态。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_mcp_setup",
description:
"读取当前本地 MCP 配置快照,包括 MCP 服务列表、启用状态、启动命令、环境变量 key、已发现工具以及外部客户端的 GoNavi MCP 写入状态与本机 CLI 检测结果。适用于用户提到 MCP 服务配置、Claude/Codex 是否已接入、为什么外部客户端用不了、当前到底启用了哪些 MCP 时,先读取真实配置再回答。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_guidance",
icon: "🧠",
desc: "查看当前 AI 提示词与 Skills 配置",
detail:
"返回当前用户自定义的全局/数据库/JVM 提示词,以及当前启用的 Skills、作用域、依赖工具和 skill prompt 内容。适合用户问“你现在到底带了哪些提示词”“为什么你会这样回答”“当前有哪些 Skills 在生效”时先读真实配置。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_ai_guidance",
description:
"读取当前 AI 的提示与技能配置快照,包括用户自定义提示词、当前启用的 Skills、作用域、依赖工具和各自的 system prompt。适用于用户提到当前提示词、当前 Skill、为什么 AI 当前会这样回答、当前有哪些规则在生效时,先读取真实配置再解释。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_ai_context",
icon: "🧷",
desc: "查看当前 AI 已关联的表结构上下文",
detail:
"返回当前对话已经挂载到 AI 上下文里的表清单、所属连接与数据库,以及每张表的 DDL 预览。适合用户说“看看我现在带了哪些表结构”“当前 AI 上下文是什么”时,先读取真实挂载状态再继续分析。",
params: "includeDDL?(默认 false), ddlLimit?(默认 4000)",
tool: {
type: "function",
function: {
name: "inspect_ai_context",
description:
"读取当前对话已经关联到 AI 上下文里的表结构快照,包括连接、数据库、表名,以及可选的 DDL 内容。适用于用户提到当前 AI 上下文、当前关联表、当前挂载的表结构时,先读取真实状态,避免模型凭记忆复述。",
parameters: {
type: "object",
properties: {
includeDDL: { type: "boolean", description: "可选,是否附带每张表的 DDL 内容,默认 false" },
ddlLimit: { type: "number", description: "可选DDL 截断长度,默认 4000最大 12000" },
},
},
},
},
},
{
name: "inspect_current_connection",
icon: "🛰️",
desc: "查看当前活动连接/数据源摘要",
detail:
"返回当前活动连接的类型、地址、端口、当前数据库、是否启用 SSH/代理/HTTP 隧道,以及当前活动页签绑定的表信息。适合用户问“我现在连的是哪个库”“这个连接走没走 SSH”“当前数据源是什么类型”时先读取真实连接状态。",
params: "无参数",
tool: {
type: "function",
function: {
name: "inspect_current_connection",
description:
"读取当前活动连接或当前页签对应数据源的真实摘要包括连接类型、地址、端口、当前数据库、SSH/代理/HTTP 隧道状态,以及当前页签绑定的表上下文。适用于用户提到当前连接、当前数据源、当前库地址、是否走 SSH、当前连的是哪种数据库时先读取真实界面上下文避免模型猜测。",
parameters: { type: "object", properties: {} },
},
},
},
{
name: "inspect_saved_connections",
icon: "🧭",
desc: "查看本地已保存连接清单",
detail:
"可按关键词或数据库类型过滤返回本地保存的数据源列表、连接类型分布以及每条连接的地址、当前库、SSH/代理/HTTP 隧道状态。适合用户问“我本地存了哪些连接”“帮我找 mysql / postgres 连接”“哪条连接配置了 SSH”时先读真实本地连接资产。",
params: "keyword?, type?, limit?",
tool: {
type: "function",
function: {
name: "inspect_saved_connections",
description:
"读取本地已保存连接清单可按关键词和数据库类型过滤并返回每条连接的类型、地址、当前库、SSH/代理/HTTP 隧道等摘要。适用于用户提到本地保存了哪些连接、要找哪条 mysql/postgres 连接、哪条连接启用了 SSH 或代理时,先读取真实本地连接资产再回答。",
parameters: {
type: "object",
properties: {
keyword: { type: "string", description: "可选按连接名、ID、类型、主机、数据库名或 SSH/代理地址做关键词筛选" },
type: { type: "string", description: "可选,只看某种数据库类型,例如 mysql、postgres、redis、mongodb" },
limit: { type: "number", description: "可选,最多返回多少条连接,默认 20最大 100" },
},
},
},
},
},
{
name: "inspect_active_tab",
icon: "📍",
desc: "查看当前活动页签上下文",
detail:
"返回当前活动页签的类型、连接、数据库、表名,以及当前 SQL / 命令页签里的草稿内容(超长会截断)。适合用户说“看我当前这条 SQL”“优化这个编辑器里的语句”时先让 AI 直接读取当前工作区上下文。",
params: "includeContent?(默认 true)",
tool: {
type: "function",
function: {
name: "inspect_active_tab",
description:
"获取当前活动页签的上下文快照,包括页签类型、连接、数据库、表名,以及当前 SQL / 命令页签里的草稿内容。适用于用户提到当前页签、当前 SQL、当前编辑器、这条语句时先读取真实界面上下文避免让模型猜测。",
parameters: {
type: "object",
properties: {
includeContent: { type: "boolean", description: "可选,是否附带页签中的 SQL / 命令草稿内容,默认 true" },
},
},
},
},
},
{
name: "inspect_workspace_tabs",
icon: "🗃️",
desc: "查看当前工作区打开的页签总览",
detail:
"返回当前工作区里打开的页签列表、哪个是活动页签,以及每个页签对应的连接、数据库、表名等上下文。适合用户说“我现在开了哪些 SQL”“看看我工作区里有哪些页签”“帮我对比这几个查询页签”时先读取真实工作区布局再继续分析。",
params: "limit?(默认 12), includeContent?(默认 false)",
tool: {
type: "function",
function: {
name: "inspect_workspace_tabs",
description:
"获取当前工作区已打开页签的总览,包括活动页签、页签类型、连接、数据库、表名,以及可选的 SQL / 命令草稿内容。适用于用户提到当前工作区、打开了哪些页签、哪几个查询页签、想对比多个编辑器内容时,先读取真实界面状态,避免模型猜测。",
parameters: {
type: "object",
properties: {
limit: { type: "number", description: "可选,最多返回多少个页签,默认 12最大 30" },
includeContent: { type: "boolean", description: "可选,是否附带页签中的 SQL / 命令草稿内容,默认 false" },
},
},
},
},
},
{
name: "inspect_recent_sql_logs",
icon: "🧾",
desc: "查看最近 SQL 执行日志",
detail:
"传入可选 limit 和 status返回最近 SQL 执行记录,包括数据库、耗时、成功/失败、报错、受影响行数和 SQL 文本。适合追查刚执行失败的语句、定位慢查询,并让 AI 基于真实执行历史给出解释或优化建议。",
params: "limit?, status?(all|success|error)",
tool: {
type: "function",
function: {
name: "inspect_recent_sql_logs",
description:
"获取最近 SQL 执行日志摘要,可按成功/失败过滤。适用于回看刚执行过的 SQL、排查失败原因、定位慢查询以及让 AI 基于真实执行历史给出解释和优化建议。",
parameters: {
type: "object",
properties: {
limit: { type: "number", description: "可选,返回多少条日志,默认 20最大 100" },
status: {
type: "string",
description: "可选,按执行状态过滤,支持 all、success、error默认 all",
enum: ["all", "success", "error"],
},
},
},
},
},
},
{
name: "inspect_saved_queries",
icon: "💾",
desc: "查看本地已保存的 SQL 查询",
detail:
"可按关键词、连接或数据库过滤,返回保存查询的名称、所属连接、数据库和 SQL 预览。适合用户提到“我之前保存过的查询”“帮我找那条历史 SQL”时先从真实本地收藏里检索。",
params: "keyword?, connectionId?, dbName?, limit?, includeSql?(默认 true)",
tool: {
type: "function",
function: {
name: "inspect_saved_queries",
description:
"读取本地已保存的 SQL 查询列表,可按关键词、连接和数据库过滤,并返回每条查询的名称、所属连接、数据库与 SQL 预览。适用于用户想找历史查询、复用旧 SQL、核对保存脚本时先读取真实本地记录。",
parameters: {
type: "object",
properties: {
keyword: { type: "string", description: "可选按查询名称、SQL 文本、连接名或数据库名做关键词筛选" },
connectionId: { type: "string", description: "可选,只看某个连接下保存的查询" },
dbName: { type: "string", description: "可选,只看某个数据库下保存的查询" },
limit: { type: "number", description: "可选,最多返回多少条,默认 12最大 50" },
includeSql: { type: "boolean", description: "可选,是否附带 SQL 预览,默认 true" },
},
},
},
},
},
{
name: "inspect_sql_snippets",
icon: "🧩",
desc: "查看 SQL 片段模板",
detail:
"返回本地 SQL 片段的 prefix、名称、说明和模板预览可按关键词过滤。适合用户想找现成模板、补全片段、团队约定 SQL 模板时先读取真实片段库。",
params: "keyword?, limit?, includeBody?(默认 true)",
tool: {
type: "function",
function: {
name: "inspect_sql_snippets",
description:
"读取本地 SQL 片段模板列表,可按关键词过滤,并返回 prefix、名称、说明和模板预览。适用于用户想找 snippet、复用模板、核对 SQL 片段配置时,先读取真实本地片段库。",
parameters: {
type: "object",
properties: {
keyword: { type: "string", description: "可选,按 prefix、名称、描述或模板内容做关键词筛选" },
limit: { type: "number", description: "可选,最多返回多少条,默认 20最大 80" },
includeBody: { type: "boolean", description: "可选,是否附带模板内容预览,默认 true" },
},
},
},
},
},
{
name: "execute_sql",
icon: "▶️",
desc: "执行 SQL 查询并返回结果",
detail:
"传入 connectionId、dbName 和 sql在目标数据库上执行 SQL 并返回结果(最多 50 行)。受安全级别控制,只读模式下仅允许 SELECT/SHOW/DESCRIBE。",
params: "connectionId, dbName, sql",
tool: {
type: "function",
function: {
name: "execute_sql",
description:
"在指定连接和数据库上执行 SQL 查询并返回结果。受安全级别控制,只读模式下只能执行 SELECT/SHOW/DESCRIBE 等查询操作。结果最多返回 50 行。",
parameters: {
type: "object",
properties: {
connectionId: { type: "string", description: "连接ID" },
dbName: { type: "string", description: "数据库名" },
sql: { type: "string", description: "要执行的 SQL 语句" },
},
required: ["connectionId", "dbName", "sql"],
},
},
},
},
];
export {
BUILTIN_AI_TOOL_INFO,
type AIChatToolDefinition,
type AIBuiltinToolInfo,
} from "./aiBuiltinToolInfo";
export const BUILTIN_AI_TOOLS: AIChatToolDefinition[] = BUILTIN_AI_TOOL_INFO.map((item) => item.tool);