mirror of
https://github.com/Syngnat/GoNavi.git
synced 2026-06-15 10:59:41 +08:00
✨ feat(ai): 新增 AI 消息流诊断探针
- 新增 inspect_ai_message_flow 内置工具 - 识别连续 assistant 气泡、空消息和未闭环工具调用 - 同步工具目录、系统引导、执行状态文案和回归测试
This commit is contained in:
@@ -75,6 +75,8 @@ describe('AIBuiltinToolsCatalog', () => {
|
||||
expect(markup).toContain('inspect_recent_connection_failures');
|
||||
expect(markup).toContain('排查 AI 气泡渲染异常');
|
||||
expect(markup).toContain('inspect_ai_last_render_error');
|
||||
expect(markup).toContain('诊断 AI 消息流');
|
||||
expect(markup).toContain('inspect_ai_message_flow');
|
||||
expect(markup).toContain('复用历史 SQL');
|
||||
expect(markup).toContain('inspect_saved_queries');
|
||||
expect(markup).toContain('回看 AI 历史对话');
|
||||
|
||||
@@ -42,8 +42,8 @@ const BUILTIN_TOOL_FLOWS = [
|
||||
},
|
||||
{
|
||||
title: 'AI 应用健康总览',
|
||||
steps: 'inspect_app_health → inspect_ai_setup_health / inspect_app_logs / inspect_recent_connection_failures / inspect_ai_last_render_error',
|
||||
description: '适合用户反馈 AI 不稳定、连接和 MCP 问题交织、回复气泡显示异常,或需要先看整体健康状态时,一次汇总配置、日志、连接失败、渲染异常和工作区现场。',
|
||||
steps: 'inspect_app_health → inspect_ai_setup_health / inspect_app_logs / inspect_recent_connection_failures / inspect_ai_last_render_error / inspect_ai_message_flow',
|
||||
description: '适合用户反馈 AI 不稳定、连接和 MCP 问题交织、回复气泡显示异常,或需要先看整体健康状态时,一次汇总配置、日志、连接失败、渲染异常、消息流和工作区现场。',
|
||||
},
|
||||
{
|
||||
title: '一键体检 AI 配置',
|
||||
@@ -160,6 +160,11 @@ const BUILTIN_TOOL_FLOWS = [
|
||||
steps: 'inspect_ai_last_render_error → inspect_active_tab / inspect_ai_runtime',
|
||||
description: '适合用户反馈 AI 某条消息空白、气泡局部报错但整个面板没挂时,先拿到最近一次被隔离的渲染异常快照,再回到具体会话和运行时上下文继续缩小范围。',
|
||||
},
|
||||
{
|
||||
title: '诊断 AI 消息流',
|
||||
steps: 'inspect_ai_message_flow → inspect_ai_last_render_error / inspect_app_logs',
|
||||
description: '适合用户反馈回复被拆成多个气泡、工具调用后没继续回答、消息流状态不对时,先读取当前会话的真实消息结构和异常信号。',
|
||||
},
|
||||
{
|
||||
title: '复用历史 SQL',
|
||||
steps: 'inspect_saved_queries → get_columns / execute_sql',
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { buildAIChatSessionsSnapshot } from './aiChatSessionInsights';
|
||||
import {
|
||||
buildAIChatSessionsSnapshot,
|
||||
buildAIMessageFlowSnapshot,
|
||||
} from './aiChatSessionInsights';
|
||||
|
||||
describe('aiChatSessionInsights', () => {
|
||||
it('filters and summarizes ai sessions with previews from local history', () => {
|
||||
@@ -34,4 +37,42 @@ describe('aiChatSessionInsights', () => {
|
||||
latestMessagePreview: '先检查支付回调日志',
|
||||
});
|
||||
});
|
||||
|
||||
it('diagnoses active ai message flow anomalies', () => {
|
||||
const snapshot = buildAIMessageFlowSnapshot({
|
||||
aiChatSessions: [
|
||||
{ id: 'session-1', title: '气泡异常排查', updatedAt: 300 },
|
||||
],
|
||||
aiChatHistory: {
|
||||
'session-1': [
|
||||
{ id: 'msg-1', role: 'user', content: '为什么回复变成多个气泡', timestamp: 101 },
|
||||
{
|
||||
id: 'msg-2',
|
||||
role: 'assistant',
|
||||
content: '我先检查消息流',
|
||||
timestamp: 102,
|
||||
tool_calls: [{ id: 'tool-1', type: 'function', function: { name: 'inspect_ai_runtime', arguments: '{}' } }],
|
||||
},
|
||||
{ id: 'msg-3', role: 'assistant', content: '这里被拆成了第二个气泡', timestamp: 103 },
|
||||
{ id: 'msg-4', role: 'assistant', content: '', timestamp: 104 },
|
||||
],
|
||||
},
|
||||
activeSessionId: 'session-1',
|
||||
limit: 10,
|
||||
});
|
||||
|
||||
expect(snapshot.found).toBe(true);
|
||||
expect(snapshot.title).toBe('气泡异常排查');
|
||||
expect(snapshot.totalMessages).toBe(4);
|
||||
expect(snapshot.unresolvedToolCallCount).toBe(1);
|
||||
expect(snapshot.consecutiveAssistantPairCount).toBe(2);
|
||||
expect(snapshot.emptyAssistantMessageCount).toBe(1);
|
||||
expect(snapshot.warnings).toContain('有 1 个工具调用没有匹配到 tool 结果消息');
|
||||
expect(snapshot.nextActions).toContain('检查流式追加逻辑是否复用了同一个 assistantMsgId,而不是为同一轮回复新建 assistant 消息');
|
||||
expect(snapshot.messages[1]).toMatchObject({
|
||||
id: 'msg-2',
|
||||
toolCallNames: ['inspect_ai_runtime'],
|
||||
toolCallIds: ['tool-1'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@ interface AIChatSessionMeta {
|
||||
}
|
||||
|
||||
const AI_CHAT_SESSION_PREVIEW_LIMIT = 240;
|
||||
const AI_MESSAGE_FLOW_PREVIEW_LIMIT = 180;
|
||||
|
||||
const normalizeLimit = (input: unknown, fallback: number, max: number): number => {
|
||||
const value = Math.floor(Number(input) || fallback);
|
||||
@@ -134,3 +135,138 @@ export const buildAIChatSessionsSnapshot = (params: {
|
||||
sessions: visibleSessions,
|
||||
};
|
||||
};
|
||||
|
||||
const buildMessagePreview = (message: AIChatMessage, previewLimit: number): string => {
|
||||
const raw = String(message.content || message.reasoning_content || '').trim();
|
||||
return raw.slice(0, previewLimit);
|
||||
};
|
||||
|
||||
const getToolCallNames = (message: AIChatMessage): string[] => (
|
||||
(message.tool_calls || [])
|
||||
.map((toolCall) => String(toolCall?.function?.name || '').trim())
|
||||
.filter(Boolean)
|
||||
);
|
||||
|
||||
export const buildAIMessageFlowSnapshot = (params: {
|
||||
aiChatSessions?: AIChatSessionMeta[];
|
||||
aiChatHistory?: Record<string, AIChatMessage[]>;
|
||||
activeSessionId?: string | null;
|
||||
sessionId?: unknown;
|
||||
limit?: unknown;
|
||||
includeContent?: unknown;
|
||||
previewLimit?: unknown;
|
||||
}) => {
|
||||
const {
|
||||
aiChatSessions = [],
|
||||
aiChatHistory = {},
|
||||
activeSessionId = null,
|
||||
sessionId,
|
||||
limit,
|
||||
includeContent = true,
|
||||
previewLimit,
|
||||
} = params;
|
||||
|
||||
const requestedSessionId = String(sessionId || activeSessionId || '').trim();
|
||||
const safeLimit = normalizeLimit(limit, 24, 80);
|
||||
const safePreviewLimit = normalizeLimit(previewLimit, AI_MESSAGE_FLOW_PREVIEW_LIMIT, 1000);
|
||||
const shouldIncludeContent = includeContent !== false;
|
||||
const sessionMetaMap = new Map(aiChatSessions.map((session) => [session.id, session]));
|
||||
const messages = requestedSessionId
|
||||
? [...(aiChatHistory[requestedSessionId] || [])].sort((left, right) => left.timestamp - right.timestamp)
|
||||
: [];
|
||||
const toolResultsByCallId = new Map(
|
||||
messages
|
||||
.filter((message) => message.role === 'tool' && message.tool_call_id)
|
||||
.map((message) => [String(message.tool_call_id), message]),
|
||||
);
|
||||
|
||||
const assistantMessages = messages.filter((message) => message.role === 'assistant');
|
||||
const toolCallMessages = assistantMessages.filter((message) => (message.tool_calls || []).length > 0);
|
||||
const unresolvedToolCalls = toolCallMessages.flatMap((message) =>
|
||||
(message.tool_calls || [])
|
||||
.filter((toolCall) => !toolResultsByCallId.has(toolCall.id))
|
||||
.map((toolCall) => ({
|
||||
assistantMessageId: message.id,
|
||||
toolCallId: toolCall.id,
|
||||
toolName: toolCall.function?.name || '',
|
||||
})),
|
||||
);
|
||||
const emptyAssistantMessages = assistantMessages.filter((message) =>
|
||||
!String(message.content || '').trim()
|
||||
&& !String(message.reasoning_content || '').trim()
|
||||
&& !(message.tool_calls || []).length
|
||||
&& !message.loading,
|
||||
);
|
||||
|
||||
const consecutiveAssistantPairs: Array<{ previousMessageId: string; nextMessageId: string }> = [];
|
||||
for (let index = 1; index < messages.length; index += 1) {
|
||||
if (messages[index - 1]?.role === 'assistant' && messages[index]?.role === 'assistant') {
|
||||
consecutiveAssistantPairs.push({
|
||||
previousMessageId: messages[index - 1].id,
|
||||
nextMessageId: messages[index].id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const warnings = [
|
||||
unresolvedToolCalls.length > 0 ? `有 ${unresolvedToolCalls.length} 个工具调用没有匹配到 tool 结果消息` : '',
|
||||
consecutiveAssistantPairs.length > 0 ? `发现 ${consecutiveAssistantPairs.length} 组连续 assistant 消息,可能存在回复被拆成多个气泡` : '',
|
||||
emptyAssistantMessages.length > 0 ? `发现 ${emptyAssistantMessages.length} 条空 assistant 消息` : '',
|
||||
messages.some((message) => message.loading) ? '会话中仍有 loading 消息,可能还在流式生成或上次中断未清理' : '',
|
||||
].filter(Boolean);
|
||||
|
||||
const nextActions = [
|
||||
unresolvedToolCalls.length > 0 ? '优先核对 useAIChatLocalTools 是否为每个 tool_call_id 写入 tool 消息' : '',
|
||||
consecutiveAssistantPairs.length > 0 ? '检查流式追加逻辑是否复用了同一个 assistantMsgId,而不是为同一轮回复新建 assistant 消息' : '',
|
||||
emptyAssistantMessages.length > 0 ? '检查异常或取消路径是否留下了空 assistant 占位消息' : '',
|
||||
warnings.length === 0 ? '消息流未发现明显结构异常,可继续结合 inspect_ai_last_render_error 或 inspect_app_logs 排查渲染/运行时问题' : '',
|
||||
].filter(Boolean);
|
||||
|
||||
const recentMessages = messages.slice(-safeLimit).map((message) => {
|
||||
const preview = shouldIncludeContent ? buildMessagePreview(message, safePreviewLimit) : '';
|
||||
const toolCallNames = getToolCallNames(message);
|
||||
return {
|
||||
id: message.id,
|
||||
role: message.role,
|
||||
phase: message.phase || '',
|
||||
timestamp: message.timestamp,
|
||||
loading: Boolean(message.loading),
|
||||
contentLength: String(message.content || '').length,
|
||||
reasoningLength: String(message.reasoning_content || '').length,
|
||||
preview,
|
||||
previewTruncated: shouldIncludeContent
|
||||
&& String(message.content || message.reasoning_content || '').trim().length > preview.length,
|
||||
toolCallCount: (message.tool_calls || []).length,
|
||||
toolCallNames,
|
||||
toolCallIds: (message.tool_calls || []).map((toolCall) => toolCall.id),
|
||||
toolCallId: message.tool_call_id || '',
|
||||
toolName: message.tool_name || '',
|
||||
success: message.success,
|
||||
};
|
||||
});
|
||||
|
||||
const meta = requestedSessionId ? sessionMetaMap.get(requestedSessionId) : undefined;
|
||||
return {
|
||||
activeSessionId: activeSessionId || '',
|
||||
requestedSessionId,
|
||||
found: Boolean(requestedSessionId && (messages.length > 0 || meta)),
|
||||
title: String(meta?.title || '').trim(),
|
||||
updatedAt: Number(meta?.updatedAt || messages[messages.length - 1]?.timestamp || 0),
|
||||
totalMessages: messages.length,
|
||||
returnedMessages: recentMessages.length,
|
||||
truncated: messages.length > recentMessages.length,
|
||||
userMessageCount: messages.filter((message) => message.role === 'user').length,
|
||||
assistantMessageCount: assistantMessages.length,
|
||||
toolMessageCount: messages.filter((message) => message.role === 'tool').length,
|
||||
systemMessageCount: messages.filter((message) => message.role === 'system').length,
|
||||
assistantToolCallMessageCount: toolCallMessages.length,
|
||||
unresolvedToolCallCount: unresolvedToolCalls.length,
|
||||
emptyAssistantMessageCount: emptyAssistantMessages.length,
|
||||
consecutiveAssistantPairCount: consecutiveAssistantPairs.length,
|
||||
unresolvedToolCalls,
|
||||
consecutiveAssistantPairs,
|
||||
warnings,
|
||||
nextActions,
|
||||
messages: recentMessages,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -101,6 +101,44 @@ describe('aiLocalToolExecutor local asset inspection tools', () => {
|
||||
expect(result.content).not.toContain('列出最近注册用户');
|
||||
});
|
||||
|
||||
it('returns ai message flow diagnostics for the active session', async () => {
|
||||
const result = await executeLocalAIToolCall({
|
||||
toolCall: buildToolCall('inspect_ai_message_flow', {
|
||||
limit: 8,
|
||||
}),
|
||||
connections: [buildConnection()],
|
||||
mcpTools: [],
|
||||
toolContextMap: new Map(),
|
||||
aiChatSessions: [
|
||||
{ id: 'session-1', title: '消息流异常', updatedAt: 200 },
|
||||
],
|
||||
aiChatHistory: {
|
||||
'session-1': [
|
||||
{ id: 'msg-1', role: 'user', content: 'AI 回复拆成多个气泡', timestamp: 101 },
|
||||
{
|
||||
id: 'msg-2',
|
||||
role: 'assistant',
|
||||
content: '先调用探针',
|
||||
timestamp: 102,
|
||||
tool_calls: [{ id: 'tool-1', type: 'function', function: { name: 'inspect_ai_runtime', arguments: '{}' } }],
|
||||
},
|
||||
{ id: 'msg-3', role: 'assistant', content: '继续回答', timestamp: 103 },
|
||||
],
|
||||
},
|
||||
activeSessionId: 'session-1',
|
||||
runtime: {
|
||||
getDatabases: vi.fn(),
|
||||
getTables: vi.fn(),
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.content).toContain('"requestedSessionId":"session-1"');
|
||||
expect(result.content).toContain('"unresolvedToolCallCount":1');
|
||||
expect(result.content).toContain('"consecutiveAssistantPairCount":1');
|
||||
expect(result.content).toContain('回复拆成多个气泡');
|
||||
});
|
||||
|
||||
it('returns sql snippets so the model can inspect local query templates', async () => {
|
||||
const result = await executeLocalAIToolCall({
|
||||
toolCall: buildToolCall('inspect_sql_snippets', {
|
||||
|
||||
@@ -12,7 +12,10 @@ import type {
|
||||
} from '../../types';
|
||||
import type { SqlLog } from '../../store';
|
||||
import { buildAIContextSnapshot } from './aiContextInsights';
|
||||
import { buildAIChatSessionsSnapshot } from './aiChatSessionInsights';
|
||||
import {
|
||||
buildAIChatSessionsSnapshot,
|
||||
buildAIMessageFlowSnapshot,
|
||||
} from './aiChatSessionInsights';
|
||||
import { buildConnectionCapabilitiesSnapshot } from './aiConnectionCapabilitiesInsights';
|
||||
import { buildCurrentConnectionSnapshot } from './aiConnectionInsights';
|
||||
import {
|
||||
@@ -262,6 +265,19 @@ export async function executeSnapshotInspectionToolCall(
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
case 'inspect_ai_message_flow':
|
||||
return {
|
||||
content: JSON.stringify(buildAIMessageFlowSnapshot({
|
||||
aiChatSessions,
|
||||
aiChatHistory,
|
||||
activeSessionId,
|
||||
sessionId: args.sessionId,
|
||||
limit: args.limit,
|
||||
includeContent: args.includeContent !== false,
|
||||
previewLimit: args.previewLimit,
|
||||
})),
|
||||
success: true,
|
||||
};
|
||||
case 'inspect_recent_sql_logs':
|
||||
return {
|
||||
content: JSON.stringify(buildRecentSqlLogsSnapshot({
|
||||
@@ -390,6 +406,7 @@ export async function executeSnapshotInspectionToolCall(
|
||||
inspect_app_logs: '读取 GoNavi 应用日志失败',
|
||||
inspect_recent_connection_failures: '汇总最近连接失败记录失败',
|
||||
inspect_ai_last_render_error: '读取最近一次 AI 渲染异常失败',
|
||||
inspect_ai_message_flow: '读取 AI 消息流诊断失败',
|
||||
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_setup_health', 'inspect_ai_runtime', 'inspect_ai_safety', 'inspect_ai_providers', 'inspect_ai_chat_readiness', 'inspect_mcp_setup', 'inspect_mcp_authoring_guide', '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_risk', 'inspect_recent_connection_failures', 'inspect_app_logs', 'inspect_ai_last_render_error', 'inspect_saved_queries', 'inspect_ai_sessions', 'inspect_sql_snippets', 'inspect_shortcuts', 'get_columns'],
|
||||
availableToolNames: ['inspect_workspace_tabs', 'inspect_app_health', 'inspect_ai_setup_health', 'inspect_ai_runtime', 'inspect_ai_safety', 'inspect_ai_providers', 'inspect_ai_chat_readiness', 'inspect_mcp_setup', 'inspect_mcp_authoring_guide', '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_risk', 'inspect_recent_connection_failures', 'inspect_app_logs', 'inspect_ai_last_render_error', 'inspect_ai_message_flow', 'inspect_saved_queries', 'inspect_ai_sessions', 'inspect_sql_snippets', 'inspect_shortcuts', 'get_columns'],
|
||||
skills,
|
||||
userPromptSettings,
|
||||
});
|
||||
@@ -95,6 +95,7 @@ describe('buildAISystemContextMessages', () => {
|
||||
expect(joined).toContain('inspect_recent_connection_failures 读取真实连接失败总结');
|
||||
expect(joined).toContain('inspect_app_logs 读取真实应用日志尾部');
|
||||
expect(joined).toContain('inspect_ai_last_render_error 读取最近一次被隔离的前端渲染异常记录');
|
||||
expect(joined).toContain('inspect_ai_message_flow 读取当前会话的真实消息结构');
|
||||
expect(joined).toContain('inspect_saved_queries');
|
||||
expect(joined).toContain('inspect_ai_sessions');
|
||||
expect(joined).toContain('inspect_sql_snippets');
|
||||
|
||||
@@ -122,6 +122,12 @@ export const appendDatabaseInspectionGuidanceMessages = (
|
||||
'inspect_ai_last_render_error',
|
||||
'如果用户提到“AI 某条消息空白了”“某个气泡渲染失败”“消息块局部报错但面板没全挂”,优先调用 inspect_ai_last_render_error 读取最近一次被隔离的前端渲染异常记录,不要只凭截图现象猜测。',
|
||||
);
|
||||
appendGuidanceIfToolAvailable(
|
||||
messages,
|
||||
availableToolNames,
|
||||
'inspect_ai_message_flow',
|
||||
'如果用户提到“AI 回复被拆成多个气泡”“工具调用后没继续回答”“消息流状态不对”“同一轮回答没有追加到同一个气泡”,优先调用 inspect_ai_message_flow 读取当前会话的真实消息结构、连续 assistant 消息和未闭环工具调用,不要只凭界面现象猜测。',
|
||||
);
|
||||
appendGuidanceIfToolAvailable(
|
||||
messages,
|
||||
availableToolNames,
|
||||
|
||||
@@ -54,6 +54,7 @@ const TOOL_ACTION_LABELS: Record<string, string> = {
|
||||
inspect_app_logs: '回看 GoNavi 应用日志',
|
||||
inspect_recent_connection_failures: '总结最近连接失败记录',
|
||||
inspect_ai_last_render_error: '读取最近一次 AI 渲染异常',
|
||||
inspect_ai_message_flow: '诊断当前 AI 消息流',
|
||||
inspect_saved_queries: '检索本地已保存查询',
|
||||
inspect_sql_snippets: '读取 SQL 片段模板',
|
||||
inspect_shortcuts: '读取当前快捷键配置',
|
||||
|
||||
@@ -539,6 +539,31 @@ export const BUILTIN_AI_INSPECTION_TOOL_INFO: AIBuiltinToolInfo[] = [
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_ai_message_flow",
|
||||
icon: "🧬",
|
||||
desc: "诊断当前 AI 会话消息流",
|
||||
detail:
|
||||
"读取当前或指定 AI 会话的最近消息流,统计用户/助手/tool 消息、工具调用是否都有结果、是否出现连续 assistant 气泡、空 assistant 占位或未清理 loading。适合用户反馈“AI 回复被拆成多个气泡”“工具调用后没继续回答”“消息流看着不对”时先看真实消息结构。",
|
||||
params: "sessionId?(默认当前会话), limit?(默认 24), includeContent?(默认 true), previewLimit?(默认 180)",
|
||||
tool: {
|
||||
type: "function",
|
||||
function: {
|
||||
name: "inspect_ai_message_flow",
|
||||
description:
|
||||
"读取当前或指定 AI 会话的最近消息流诊断,包括消息角色序列、assistant/tool 消息数量、工具调用与 tool 结果匹配情况、连续 assistant 消息、空 assistant 消息和 loading 残留。适用于用户提到 AI 回复被拆成多个气泡、流式追加异常、工具调用没有闭环、某轮回答没有继续生成时,先读取真实消息结构再定位。",
|
||||
parameters: {
|
||||
type: "object",
|
||||
properties: {
|
||||
sessionId: { type: "string", description: "可选,指定要诊断的 AI 会话 ID;不传时读取当前活动会话" },
|
||||
limit: { type: "number", description: "可选,最多返回最近多少条消息,默认 24,最大 80" },
|
||||
includeContent: { type: "boolean", description: "可选,是否附带消息内容预览,默认 true" },
|
||||
previewLimit: { type: "number", description: "可选,每条消息预览字符数,默认 180,最大 1000" },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "inspect_sql_snippets",
|
||||
icon: "🧩",
|
||||
|
||||
@@ -122,12 +122,20 @@ describe('aiToolRegistry', () => {
|
||||
expect(info?.tool.function.description).toContain('消息渲染异常');
|
||||
});
|
||||
|
||||
it('registers the ai-message-flow inspector as a builtin tool', () => {
|
||||
const info = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_message_flow');
|
||||
expect(info).toBeTruthy();
|
||||
expect(info?.desc).toContain('消息流');
|
||||
expect(info?.tool.function.description).toContain('连续 assistant 消息');
|
||||
});
|
||||
|
||||
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 sqlRiskTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_sql_risk');
|
||||
const appLogTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_app_logs');
|
||||
const connectionFailureTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_recent_connection_failures');
|
||||
const renderErrorTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_last_render_error');
|
||||
const messageFlowTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_ai_message_flow');
|
||||
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');
|
||||
const snippetTool = BUILTIN_AI_TOOL_INFO.find((item) => item.name === 'inspect_sql_snippets');
|
||||
@@ -142,6 +150,8 @@ describe('aiToolRegistry', () => {
|
||||
expect(connectionFailureTool?.tool.function.description).toContain('连接冷却');
|
||||
expect(renderErrorTool?.desc).toContain('渲染异常记录');
|
||||
expect(renderErrorTool?.tool.function.description).toContain('气泡局部报错');
|
||||
expect(messageFlowTool?.desc).toContain('消息流');
|
||||
expect(messageFlowTool?.tool.function.description).toContain('工具调用没有闭环');
|
||||
expect(savedQueryTool?.desc).toContain('已保存的 SQL 查询');
|
||||
expect(savedQueryTool?.tool.function.description).toContain('历史查询');
|
||||
expect(aiSessionsTool?.desc).toContain('AI 历史会话');
|
||||
@@ -184,6 +194,7 @@ describe('aiToolRegistry', () => {
|
||||
expect(tools.some((item) => item.function.name === 'inspect_app_logs')).toBe(true);
|
||||
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_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