mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-15 19:19:35 +08:00
✨ feat(ai-tools): 新增外部 SQL 目录探针
- 新增外部 SQL 目录快照构建与本地工具执行入口 - 补充内置工具目录、系统提示和状态文案 - 覆盖 AI 面板、工具注册与探针链路测试
This commit is contained in:
@@ -45,8 +45,10 @@ describe('AIChatPanel message render isolation', () => {
|
||||
expect(systemContextSource).toContain('inspect_active_tab 读取当前活动页签上下文');
|
||||
expect(systemContextSource).toContain('inspect_workspace_tabs 盘点当前工作区');
|
||||
expect(systemContextSource).toContain('inspect_current_connection');
|
||||
expect(systemContextSource).toContain('inspect_external_sql_directories');
|
||||
expect(source).toContain('tabs: useStore.getState().tabs');
|
||||
expect(source).toContain('activeTabId: useStore.getState().activeTabId');
|
||||
expect(source).toContain('externalSQLDirectories: useStore.getState().externalSQLDirectories');
|
||||
expect(source).toContain('toolContextMap: toolContextMapRef.current');
|
||||
expect(source).toContain('buildToolResultMessage');
|
||||
});
|
||||
|
||||
@@ -461,6 +461,7 @@ export const AIChatPanel: React.FC<AIChatPanelProps> = ({
|
||||
sqlLogs: useStore.getState().sqlLogs,
|
||||
savedQueries: useStore.getState().savedQueries,
|
||||
sqlSnippets: useStore.getState().sqlSnippets,
|
||||
externalSQLDirectories: useStore.getState().externalSQLDirectories,
|
||||
skills,
|
||||
userPromptSettings,
|
||||
dynamicModels,
|
||||
|
||||
@@ -46,6 +46,8 @@ describe('AIBuiltinToolsCatalog', () => {
|
||||
expect(markup).toContain('inspect_connection_capabilities');
|
||||
expect(markup).toContain('盘点本地连接资产');
|
||||
expect(markup).toContain('inspect_saved_connections');
|
||||
expect(markup).toContain('盘点外部 SQL 目录');
|
||||
expect(markup).toContain('inspect_external_sql_directories');
|
||||
expect(markup).toContain('读取当前页签');
|
||||
expect(markup).toContain('inspect_active_tab');
|
||||
expect(markup).toContain('盘点当前工作区');
|
||||
|
||||
@@ -87,6 +87,11 @@ const BUILTIN_TOOL_FLOWS = [
|
||||
steps: 'inspect_saved_connections → inspect_current_connection / get_databases',
|
||||
description: '适合先按关键词或类型筛出本地保存的数据源,再挑目标连接继续看当前状态或库表结构。',
|
||||
},
|
||||
{
|
||||
title: '盘点外部 SQL 目录',
|
||||
steps: 'inspect_external_sql_directories → inspect_workspace_tabs / inspect_active_tab',
|
||||
description: '适合先确认本地配置了哪些外部 SQL 目录、目录绑定到哪个连接/库,以及当前打开的 SQL 文件来自哪里,再继续分析脚本内容。',
|
||||
},
|
||||
{
|
||||
title: '读取当前页签',
|
||||
steps: 'inspect_active_tab → get_columns / get_indexes / execute_sql',
|
||||
|
||||
79
frontend/src/components/ai/aiExternalSqlInsights.test.ts
Normal file
79
frontend/src/components/ai/aiExternalSqlInsights.test.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import type { ExternalSQLDirectory, SavedConnection, TabData } from '../../types';
|
||||
import { buildExternalSQLDirectoriesSnapshot } from './aiExternalSqlInsights';
|
||||
|
||||
const connections: SavedConnection[] = [
|
||||
{
|
||||
id: 'conn-1',
|
||||
name: '本地开发库',
|
||||
config: {
|
||||
type: 'mysql',
|
||||
host: '127.0.0.1',
|
||||
port: 3306,
|
||||
user: 'root',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe('aiExternalSqlInsights', () => {
|
||||
it('filters configured external sql directories and reports matching open file tabs', () => {
|
||||
const externalSQLDirectories: ExternalSQLDirectory[] = [
|
||||
{
|
||||
id: 'dir-1',
|
||||
name: '报表脚本',
|
||||
path: 'D:/sql/reports',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'crm',
|
||||
createdAt: 2,
|
||||
},
|
||||
{
|
||||
id: 'dir-2',
|
||||
name: '运维脚本',
|
||||
path: 'D:/sql/ops',
|
||||
createdAt: 1,
|
||||
},
|
||||
];
|
||||
const tabs: TabData[] = [
|
||||
{
|
||||
id: 'tab-1',
|
||||
title: '日报.sql',
|
||||
type: 'query',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'crm',
|
||||
filePath: 'D:/sql/reports/daily.sql',
|
||||
query: 'select 1',
|
||||
},
|
||||
{
|
||||
id: 'tab-2',
|
||||
title: '用户.sql',
|
||||
type: 'query',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'crm',
|
||||
filePath: 'D:/sql/reports/users/detail.sql',
|
||||
query: 'select 2',
|
||||
},
|
||||
];
|
||||
|
||||
const snapshot = buildExternalSQLDirectoriesSnapshot({
|
||||
externalSQLDirectories,
|
||||
connections,
|
||||
tabs,
|
||||
keyword: '报表',
|
||||
});
|
||||
|
||||
expect(snapshot.totalMatched).toBe(1);
|
||||
expect(snapshot.returnedDirectories).toBe(1);
|
||||
expect(snapshot.totalOpenExternalSqlTabs).toBe(2);
|
||||
expect(snapshot.boundConnectionCount).toBe(1);
|
||||
expect(snapshot.directories[0]).toMatchObject({
|
||||
id: 'dir-1',
|
||||
connectionName: '本地开发库',
|
||||
connectionType: 'mysql',
|
||||
dbName: 'crm',
|
||||
openFileTabCount: 2,
|
||||
hasBoundConnection: true,
|
||||
});
|
||||
expect(snapshot.directories[0].openFileTitles[0].title).toBe('日报.sql');
|
||||
});
|
||||
});
|
||||
117
frontend/src/components/ai/aiExternalSqlInsights.ts
Normal file
117
frontend/src/components/ai/aiExternalSqlInsights.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
import type { ExternalSQLDirectory, SavedConnection, TabData } from '../../types';
|
||||
|
||||
const normalizeLimit = (input: unknown, fallback: number, max: number): number => {
|
||||
const value = Math.floor(Number(input) || fallback);
|
||||
if (value < 1) return 1;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
};
|
||||
|
||||
const normalizeKeyword = (input: unknown): string => String(input || '').trim().toLowerCase();
|
||||
|
||||
const normalizePath = (input: unknown): string =>
|
||||
String(input || '').trim().replace(/\\/g, '/').replace(/\/+$/u, '');
|
||||
|
||||
const matchesKeyword = (keyword: string, fields: Array<string | undefined>): boolean => {
|
||||
if (!keyword) {
|
||||
return true;
|
||||
}
|
||||
return fields.some((field) => String(field || '').toLowerCase().includes(keyword));
|
||||
};
|
||||
|
||||
const belongsToDirectory = (filePath: string, directoryPath: string): boolean => {
|
||||
if (!filePath || !directoryPath) {
|
||||
return false;
|
||||
}
|
||||
const normalizedFilePath = normalizePath(filePath).toLowerCase();
|
||||
const normalizedDirectoryPath = normalizePath(directoryPath).toLowerCase();
|
||||
if (!normalizedFilePath || !normalizedDirectoryPath) {
|
||||
return false;
|
||||
}
|
||||
return normalizedFilePath === normalizedDirectoryPath || normalizedFilePath.startsWith(`${normalizedDirectoryPath}/`);
|
||||
};
|
||||
|
||||
export const buildExternalSQLDirectoriesSnapshot = (params: {
|
||||
externalSQLDirectories?: ExternalSQLDirectory[];
|
||||
connections: SavedConnection[];
|
||||
tabs?: TabData[];
|
||||
keyword?: unknown;
|
||||
connectionId?: unknown;
|
||||
dbName?: unknown;
|
||||
limit?: unknown;
|
||||
}) => {
|
||||
const {
|
||||
externalSQLDirectories = [],
|
||||
connections,
|
||||
tabs = [],
|
||||
keyword,
|
||||
connectionId,
|
||||
dbName,
|
||||
limit,
|
||||
} = params;
|
||||
|
||||
const safeKeyword = normalizeKeyword(keyword);
|
||||
const safeConnectionId = String(connectionId || '').trim();
|
||||
const safeDbName = String(dbName || '').trim();
|
||||
const safeLimit = normalizeLimit(limit, 20, 100);
|
||||
const externalSqlTabs = tabs.filter((tab) => String(tab.filePath || '').trim());
|
||||
|
||||
const filteredDirectories = [...externalSQLDirectories]
|
||||
.sort((left, right) => Number(right.createdAt || 0) - Number(left.createdAt || 0))
|
||||
.filter((directory) => {
|
||||
if (safeConnectionId && String(directory.connectionId || '').trim() !== safeConnectionId) {
|
||||
return false;
|
||||
}
|
||||
if (safeDbName && String(directory.dbName || '').trim() !== safeDbName) {
|
||||
return false;
|
||||
}
|
||||
const connection = connections.find((item) => item.id === directory.connectionId);
|
||||
return matchesKeyword(safeKeyword, [
|
||||
directory.id,
|
||||
directory.name,
|
||||
directory.path,
|
||||
directory.connectionId,
|
||||
directory.dbName,
|
||||
connection?.name,
|
||||
connection?.config?.type,
|
||||
]);
|
||||
});
|
||||
|
||||
const visibleDirectories = filteredDirectories.slice(0, safeLimit).map((directory) => {
|
||||
const connection = connections.find((item) => item.id === directory.connectionId);
|
||||
const matchingTabs = externalSqlTabs.filter((tab) => belongsToDirectory(String(tab.filePath || ''), directory.path));
|
||||
|
||||
return {
|
||||
id: directory.id,
|
||||
name: directory.name,
|
||||
path: directory.path,
|
||||
connectionId: directory.connectionId || '',
|
||||
connectionName: connection?.name || '',
|
||||
connectionType: connection?.config?.type || '',
|
||||
dbName: directory.dbName || '',
|
||||
createdAt: Number(directory.createdAt || 0),
|
||||
hasBoundConnection: Boolean(String(directory.connectionId || '').trim()),
|
||||
openFileTabCount: matchingTabs.length,
|
||||
openFileTitles: matchingTabs.slice(0, 5).map((tab) => ({
|
||||
tabId: tab.id,
|
||||
title: tab.title,
|
||||
filePath: tab.filePath || '',
|
||||
dbName: tab.dbName || '',
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
keyword: safeKeyword,
|
||||
connectionId: safeConnectionId,
|
||||
dbName: safeDbName,
|
||||
limit: safeLimit,
|
||||
totalMatched: filteredDirectories.length,
|
||||
returnedDirectories: visibleDirectories.length,
|
||||
truncated: filteredDirectories.length > visibleDirectories.length,
|
||||
totalConfiguredDirectories: externalSQLDirectories.length,
|
||||
totalOpenExternalSqlTabs: externalSqlTabs.length,
|
||||
boundConnectionCount: filteredDirectories.filter((item) => String(item.connectionId || '').trim()).length,
|
||||
directories: visibleDirectories,
|
||||
};
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { AIMCPToolDescriptor, AIToolCall, SavedConnection } from '../../types';
|
||||
import type { AIMCPToolDescriptor, AIToolCall, ExternalSQLDirectory, SavedConnection } from '../../types';
|
||||
import { buildToolResultMessage, executeLocalAIToolCall } from './aiLocalToolExecutor';
|
||||
|
||||
const buildConnection = (): SavedConnection => ({
|
||||
@@ -605,6 +605,57 @@ describe('aiLocalToolExecutor', () => {
|
||||
expect(result.content).not.toContain('分析仓库');
|
||||
});
|
||||
|
||||
it('returns configured external sql directories so the model can locate local script assets', async () => {
|
||||
const externalSQLDirectories: ExternalSQLDirectory[] = [
|
||||
{
|
||||
id: 'dir-1',
|
||||
name: '报表脚本',
|
||||
path: 'D:/sql/reports',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'crm',
|
||||
createdAt: 2,
|
||||
},
|
||||
{
|
||||
id: 'dir-2',
|
||||
name: '运维脚本',
|
||||
path: 'D:/sql/ops',
|
||||
createdAt: 1,
|
||||
},
|
||||
];
|
||||
const result = await executeLocalAIToolCall({
|
||||
toolCall: buildToolCall('inspect_external_sql_directories', {
|
||||
keyword: '报表',
|
||||
}),
|
||||
connections: [buildConnection()],
|
||||
tabs: [
|
||||
{
|
||||
id: 'tab-1',
|
||||
title: '日报.sql',
|
||||
type: 'query',
|
||||
connectionId: 'conn-1',
|
||||
dbName: 'crm',
|
||||
filePath: 'D:/sql/reports/daily.sql',
|
||||
query: 'select 1',
|
||||
},
|
||||
],
|
||||
mcpTools: [],
|
||||
toolContextMap: new Map(),
|
||||
externalSQLDirectories,
|
||||
runtime: {
|
||||
getDatabases: vi.fn(),
|
||||
getTables: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.content).toContain('"totalMatched":1');
|
||||
expect(result.content).toContain('"name":"报表脚本"');
|
||||
expect(result.content).toContain('"connectionName":"主库"');
|
||||
expect(result.content).toContain('"openFileTabCount":1');
|
||||
expect(result.content).toContain('日报.sql');
|
||||
expect(result.content).not.toContain('运维脚本');
|
||||
});
|
||||
|
||||
it('blocks execute_sql when the AI safety check rejects the statement', async () => {
|
||||
const query = vi.fn();
|
||||
const result = await executeLocalAIToolCall({
|
||||
|
||||
@@ -9,6 +9,7 @@ import type {
|
||||
SavedConnection,
|
||||
SavedQuery,
|
||||
SqlSnippet,
|
||||
ExternalSQLDirectory,
|
||||
TabData,
|
||||
} from '../../types';
|
||||
import { executeDatabaseToolCall } from './aiDatabaseToolExecutor';
|
||||
@@ -36,6 +37,7 @@ export interface ExecuteLocalAIToolCallOptions {
|
||||
sqlLogs?: SqlLog[];
|
||||
savedQueries?: SavedQuery[];
|
||||
sqlSnippets?: SqlSnippet[];
|
||||
externalSQLDirectories?: ExternalSQLDirectory[];
|
||||
skills?: AISkillConfig[];
|
||||
userPromptSettings?: AIUserPromptSettings;
|
||||
dynamicModels?: string[];
|
||||
@@ -66,6 +68,7 @@ export async function executeLocalAIToolCall({
|
||||
sqlLogs = [],
|
||||
savedQueries = [],
|
||||
sqlSnippets = [],
|
||||
externalSQLDirectories = [],
|
||||
skills = [],
|
||||
userPromptSettings,
|
||||
dynamicModels = [],
|
||||
@@ -92,6 +95,7 @@ export async function executeLocalAIToolCall({
|
||||
sqlLogs,
|
||||
savedQueries,
|
||||
sqlSnippets,
|
||||
externalSQLDirectories,
|
||||
skills,
|
||||
userPromptSettings,
|
||||
dynamicModels,
|
||||
|
||||
@@ -8,6 +8,7 @@ import type {
|
||||
AISafetyLevel,
|
||||
AISkillConfig,
|
||||
AIUserPromptSettings,
|
||||
ExternalSQLDirectory,
|
||||
SavedConnection,
|
||||
SavedQuery,
|
||||
SqlSnippet,
|
||||
@@ -30,6 +31,7 @@ import {
|
||||
buildSqlSnippetsSnapshot,
|
||||
} from './aiSavedSqlInsights';
|
||||
import { buildSavedConnectionsSnapshot } from './aiSavedConnectionInsights';
|
||||
import { buildExternalSQLDirectoriesSnapshot } from './aiExternalSqlInsights';
|
||||
import {
|
||||
buildActiveTabSnapshot,
|
||||
buildRecentSqlLogsSnapshot,
|
||||
@@ -64,6 +66,7 @@ interface ExecuteSnapshotInspectionToolCallOptions {
|
||||
sqlLogs?: SqlLog[];
|
||||
savedQueries?: SavedQuery[];
|
||||
sqlSnippets?: SqlSnippet[];
|
||||
externalSQLDirectories?: ExternalSQLDirectory[];
|
||||
skills?: AISkillConfig[];
|
||||
userPromptSettings?: AIUserPromptSettings;
|
||||
dynamicModels?: string[];
|
||||
@@ -95,6 +98,7 @@ export async function executeSnapshotInspectionToolCall(
|
||||
sqlLogs = [],
|
||||
savedQueries = [],
|
||||
sqlSnippets = [],
|
||||
externalSQLDirectories = [],
|
||||
skills = [],
|
||||
userPromptSettings,
|
||||
dynamicModels = [],
|
||||
@@ -220,6 +224,19 @@ export async function executeSnapshotInspectionToolCall(
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
case 'inspect_external_sql_directories':
|
||||
return {
|
||||
content: JSON.stringify(buildExternalSQLDirectoriesSnapshot({
|
||||
externalSQLDirectories,
|
||||
connections,
|
||||
tabs,
|
||||
keyword: args.keyword,
|
||||
connectionId: args.connectionId,
|
||||
dbName: args.dbName,
|
||||
limit: args.limit,
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
case 'inspect_active_tab':
|
||||
return {
|
||||
content: JSON.stringify(buildActiveTabSnapshot({
|
||||
@@ -310,6 +327,7 @@ export async function executeSnapshotInspectionToolCall(
|
||||
inspect_current_connection: '读取当前连接失败',
|
||||
inspect_connection_capabilities: '读取当前连接能力矩阵失败',
|
||||
inspect_saved_connections: '读取本地连接清单失败',
|
||||
inspect_external_sql_directories: '读取外部 SQL 目录失败',
|
||||
inspect_ai_sessions: '读取本地 AI 会话清单失败',
|
||||
inspect_active_tab: '读取当前活动页签失败',
|
||||
inspect_workspace_tabs: '读取当前工作区页签失败',
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('buildAISystemContextMessages', () => {
|
||||
connections: [connections[0]],
|
||||
tabs: [],
|
||||
activeTabId: null,
|
||||
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_connection_capabilities', 'inspect_saved_connections', 'inspect_saved_queries', 'inspect_ai_sessions', '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_connection_capabilities', 'inspect_saved_connections', 'inspect_external_sql_directories', 'inspect_saved_queries', 'inspect_ai_sessions', 'inspect_sql_snippets', 'get_columns'],
|
||||
skills,
|
||||
userPromptSettings,
|
||||
});
|
||||
@@ -85,6 +85,7 @@ describe('buildAISystemContextMessages', () => {
|
||||
expect(joined).toContain('inspect_current_connection');
|
||||
expect(joined).toContain('inspect_connection_capabilities');
|
||||
expect(joined).toContain('inspect_saved_connections');
|
||||
expect(joined).toContain('inspect_external_sql_directories');
|
||||
expect(joined).toContain('inspect_saved_queries');
|
||||
expect(joined).toContain('inspect_ai_sessions');
|
||||
expect(joined).toContain('inspect_sql_snippets');
|
||||
|
||||
@@ -423,6 +423,12 @@ SELECT * FROM users WHERE status = 1;
|
||||
content: '如果用户提到“本地存了哪些连接”“帮我找 mysql / postgres / redis 连接”“哪条连接配了 SSH/代理”,优先调用 inspect_saved_connections 读取真实本地连接清单,再决定继续查看哪条连接。',
|
||||
});
|
||||
}
|
||||
if (availableToolNames.includes('inspect_external_sql_directories')) {
|
||||
systemMessages.push({
|
||||
role: 'system',
|
||||
content: '如果用户提到“外部 SQL 目录”“目录里的脚本”“某个 SQL 文件放在哪个目录”“当前打开的 SQL 文件来自哪里”,优先调用 inspect_external_sql_directories 读取真实外部 SQL 目录资产,再决定继续读取活动页签还是定位具体脚本。',
|
||||
});
|
||||
}
|
||||
if (availableToolNames.includes('inspect_saved_queries')) {
|
||||
systemMessages.push({
|
||||
role: 'system',
|
||||
|
||||
@@ -43,6 +43,7 @@ const TOOL_ACTION_LABELS: Record<string, string> = {
|
||||
inspect_current_connection: '读取当前连接摘要',
|
||||
inspect_connection_capabilities: '读取当前连接能力矩阵',
|
||||
inspect_saved_connections: '盘点本地已保存连接',
|
||||
inspect_external_sql_directories: '盘点外部 SQL 目录',
|
||||
inspect_ai_sessions: '盘点本地 AI 历史会话',
|
||||
inspect_active_tab: '读取当前活动页签',
|
||||
inspect_workspace_tabs: '盘点当前工作区页签',
|
||||
|
||||
@@ -495,6 +495,31 @@ export const BUILTIN_AI_TOOL_INFO: AIBuiltinToolInfo[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_external_sql_directories",
|
||||
icon: "🗂️",
|
||||
desc: "查看本地外部 SQL 目录资产",
|
||||
detail:
|
||||
"可按关键词、连接或数据库过滤,返回本地配置的外部 SQL 目录、目录路径、绑定连接/数据库,以及当前是否已经打开这些目录里的 SQL 文件。适合用户提到“外部 SQL 目录”“某个脚本在哪个目录”“现在打开的 SQL 文件来自哪个外部目录”时,先读真实资产。",
|
||||
params: "keyword?, connectionId?, dbName?, limit?",
|
||||
tool: {
|
||||
type: "function",
|
||||
function: {
|
||||
name: "inspect_external_sql_directories",
|
||||
description:
|
||||
"读取本地配置的外部 SQL 目录清单,可按关键词、连接和数据库过滤,并返回目录路径、绑定连接/数据库,以及当前打开的外部 SQL 文件页签摘要。适用于用户提到外部 SQL 目录、某个 SQL 文件放在哪、当前打开的脚本来自哪个目录时,先读取真实本地资产再回答。",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
keyword: { type: "string", description: "可选,按目录名、路径、连接名或数据库名做关键词筛选" },
|
||||
connectionId: { type: "string", description: "可选,只看绑定到某个连接的外部 SQL 目录" },
|
||||
dbName: { type: "string", description: "可选,只看绑定到某个数据库的外部 SQL 目录" },
|
||||
limit: { type: "number", description: "可选,最多返回多少条目录,默认 20,最大 100" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_active_tab",
|
||||
icon: "📍",
|
||||
|
||||
@@ -66,6 +66,13 @@ describe('aiToolRegistry', () => {
|
||||
expect(info?.tool.function.description).toContain('本地已保存连接清单');
|
||||
});
|
||||
|
||||
it('registers the external-sql-directory inspector as a builtin tool', () => {
|
||||
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_external_sql_directories');
|
||||
expect(info).toBeTruthy();
|
||||
expect(info?.desc).toContain('外部 SQL 目录');
|
||||
expect(info?.tool.function.description).toContain('当前打开的外部 SQL 文件页签');
|
||||
});
|
||||
|
||||
it('registers the saved-query and sql-snippet inspectors as builtin tools', () => {
|
||||
const savedQueryTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_saved_queries');
|
||||
const aiSessionsTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_sessions');
|
||||
@@ -104,6 +111,7 @@ describe('aiToolRegistry', () => {
|
||||
expect(tools.some((item) => item.function.name === 'inspect_current_connection')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_connection_capabilities')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_saved_connections')).toBe(true);
|
||||
expect(tools.some((item) => item.function.name === 'inspect_external_sql_directories')).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