feat(engine): 添加MCP连接管理和工具集成功能

- 集成MCP连接管理器,支持MCP服务器连接
- 添加多种内置工具:ClarifyTool、CronTool、DelegateTool、ExecuteCodeTool、
  PatchFileTool、ProcessTool、SendMessageTool、SpawnTool、TerminalTool、
  TodoTool、WebFetchTool、WebSearchTool、WriteFileTool等
- 实现工具注册和装配功能
- 添加技能选择上下文参数
- 支持思考模式控制参数thinking_enabled

feat(coordinator): 重构任务执行计划器参数命名

- 将learning_candidate_enabled重命名为allow_candidate_generation
- 更新TeamGraphScheduler中的参数传递
- 修改LocalAgentRunner中的相关参数处理
- 更新README文档中的相应描述

refactor(context): 标准化工具调用参数格式

- 添加_json导入用于参数序列化
- 实现_provider_tool_calls方法标准化OpenAI兼容的工具调用载荷
- 修复工具调用中参数非字符串类型的序列化问题

refactor(session): 优化消息历史记录过滤逻辑

- 修改get_messages_as_conversation为基于运行状态过滤消息
- 排除未完成、失败或错误结束的运行记录
- 改进对话历史的可见性控制机制

fix(store): 修复FTS索引重建逻辑

- 添加异常处理防止FTS索引创建失败
- 实现_rebuild_fts_index方法重新构建全文搜索索引
- 优化索引触发器和表的维护流程
This commit is contained in:
2026-05-14 09:43:48 +08:00
parent 8a12c30141
commit 30ab74ffb2
149 changed files with 12293 additions and 2812 deletions

View File

@ -6,11 +6,16 @@ import type {
AuthzRegisterBackendResponse,
AuthzStatus,
AuthUser,
ActiveTask,
ChatLogsResponse,
BackendTask,
ChatMessage,
CronJob,
FileAttachment,
Marketplace,
MarketplacePlugin,
NotificationDetail,
NotificationRun,
PluginInfo,
ProviderConfigPayload,
Session,
@ -19,6 +24,10 @@ import type {
SkillDraft,
SkillDraftEvalReport,
SkillDraftSafetyReport,
SkillHubInstallResponse,
SkillHubSearchItem,
SkillHubSearchResponse,
SkillHubVersionResponse,
SkillLearningCandidate,
SkillReviewRecord,
SlashCommand,
@ -252,7 +261,12 @@ export async function getMe(): Promise<AuthUser> {
export async function sendMessage(
message: string,
sessionId: string = 'web:default',
attachments?: FileAttachment[]
attachments?: FileAttachment[],
options?: {
replyToScheduledRunId?: string;
scheduledReplyIntent?: 'revise_once' | 'update_future' | 'continue_task';
thinkingEnabled?: boolean;
}
): Promise<{
response?: string;
status?: string;
@ -266,6 +280,13 @@ export async function sendMessage(
if (attachments && attachments.length > 0) {
body.attachments = attachments;
}
if (options?.replyToScheduledRunId) {
body.reply_to_scheduled_run_id = options.replyToScheduledRunId;
body.scheduled_reply_intent = options.scheduledReplyIntent || 'revise_once';
}
if (typeof options?.thinkingEnabled === 'boolean') {
body.thinking_enabled = options.thinkingEnabled;
}
const result = await fetchJSON<{
response?: string;
status?: string;
@ -583,8 +604,14 @@ export async function getSessionProcess(key: string): Promise<SessionProcessProj
return fetchJSON(`/api/sessions/${encodeURIComponent(key)}/process`);
}
export async function deleteSession(key: string): Promise<void> {
await fetchJSON(`/api/sessions/${encodeURIComponent(key)}`, { method: 'DELETE' });
export async function getChatLogs(limit = 50): Promise<ChatLogsResponse> {
return fetchJSON(`/api/debug/chat-logs?limit=${encodeURIComponent(String(limit))}`, {
timeoutMs: 30000,
});
}
export async function archiveSession(key: string): Promise<void> {
await fetchJSON(`/api/sessions/${encodeURIComponent(key)}/archive`, { method: 'POST' });
}
// ---------------------------------------------------------------------------
@ -629,7 +656,10 @@ export async function addCronJob(params: {
every_seconds?: number;
cron_expr?: string;
at_iso?: string;
tz?: string;
session_key?: string;
mode?: 'notification' | 'task';
requires_followup?: boolean;
}): Promise<CronJob> {
return fetchJSON('/api/cron/jobs', {
method: 'POST',
@ -652,6 +682,40 @@ export async function runCronJob(jobId: string): Promise<void> {
await fetchJSON(`/api/cron/jobs/${jobId}/run`, { method: 'POST' });
}
export async function listNotifications(): Promise<NotificationRun[]> {
return fetchJSON('/api/notifications');
}
export async function getNotification(scheduledRunId: string): Promise<NotificationDetail> {
return fetchJSON(`/api/notifications/${encodeURIComponent(scheduledRunId)}`);
}
export async function engageNotification(
scheduledRunId: string,
intent: 'revise_once' | 'update_future' | 'continue_task'
): Promise<{ ok: boolean; task_id: string; intent: string }> {
return fetchJSON(`/api/notifications/${encodeURIComponent(scheduledRunId)}/engage`, {
method: 'POST',
body: JSON.stringify({ intent }),
});
}
export async function listBackendTasks(): Promise<BackendTask[]> {
return fetchJSON('/api/tasks');
}
export async function getBackendTask(taskId: string): Promise<BackendTask> {
return fetchJSON(`/api/tasks/${encodeURIComponent(taskId)}`);
}
export async function deleteBackendTask(taskId: string): Promise<void> {
await fetchJSON(`/api/tasks/${encodeURIComponent(taskId)}`, { method: 'DELETE' });
}
export async function getActiveTask(sessionId: string): Promise<ActiveTask | null> {
return fetchJSON(`/api/sessions/${encodeURIComponent(sessionId)}/active-task`);
}
export async function ping(): Promise<{ message: string }> {
return fetchJSON('/api/ping');
}
@ -877,6 +941,12 @@ export async function cancelDelegation(runId: string): Promise<{ ok: boolean; ru
});
}
export async function retryDelegation(runId: string): Promise<{ ok: boolean; run_id: string }> {
return fetchJSON(`/api/delegations/${encodeURIComponent(runId)}/retry`, {
method: 'POST',
});
}
export async function listMcpServers(): Promise<UiMcpServerDescriptor[]> {
return fetchJSON('/api/mcp/servers');
}
@ -1190,6 +1260,62 @@ export async function uploadSkill(file: File): Promise<Skill> {
return res.json();
}
export async function migrateSkills(): Promise<{ included: Array<Record<string, unknown>>; skipped: Array<Record<string, unknown>> }> {
return fetchJSON('/api/skills/migrate', { method: 'POST', timeoutMs: 45000 });
}
// ---------------------------------------------------------------------------
// SkillHub marketplace
// ---------------------------------------------------------------------------
export async function searchSkillHubSkills(params: {
q?: string;
sort?: 'relevance' | 'downloads' | 'newest';
page?: number;
size?: number;
namespace?: string;
} = {}): Promise<SkillHubSearchResponse> {
const search = new URLSearchParams();
if (params.q) search.set('q', params.q);
if (params.sort) search.set('sort', params.sort);
if (typeof params.page === 'number') search.set('page', String(params.page));
if (typeof params.size === 'number') search.set('size', String(params.size));
if (params.namespace) search.set('namespace', params.namespace);
const suffix = search.toString();
return fetchJSON(`/api/marketplaces/skills/search${suffix ? `?${suffix}` : ''}`);
}
export async function getSkillHubDetail(namespace: string, slug: string): Promise<SkillHubSearchItem> {
return fetchJSON(
`/api/marketplaces/skills/${encodeURIComponent(namespace.replace(/^@/, ''))}/${encodeURIComponent(slug)}`
);
}
export async function getSkillHubVersion(
namespace: string,
slug: string,
version: string
): Promise<SkillHubVersionResponse> {
return fetchJSON(
`/api/marketplaces/skills/${encodeURIComponent(namespace.replace(/^@/, ''))}/${encodeURIComponent(slug)}/versions/${encodeURIComponent(version)}`
);
}
export async function installSkillHubSkill(
namespace: string,
slug: string,
version?: string
): Promise<SkillHubInstallResponse> {
return fetchJSON(
`/api/marketplaces/skills/${encodeURIComponent(namespace.replace(/^@/, ''))}/${encodeURIComponent(slug)}/install`,
{
method: 'POST',
body: JSON.stringify({ version }),
timeoutMs: 45000,
}
);
}
// ---------------------------------------------------------------------------
// Marketplace (proxied)
// ---------------------------------------------------------------------------