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:
@ -39,6 +39,65 @@ class EmbeddingConfig:
|
||||
request_timeout_seconds: float | None = None
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class MCPServerConfig:
|
||||
"""One configured MCP server.
|
||||
|
||||
Transport is inferred from fields:
|
||||
- command => local stdio MCP server
|
||||
- url => remote streamable HTTP MCP server
|
||||
"""
|
||||
|
||||
command: str = ""
|
||||
args: list[str] = field(default_factory=list)
|
||||
env: dict[str, str] = field(default_factory=dict)
|
||||
url: str = ""
|
||||
headers: dict[str, str] = field(default_factory=dict)
|
||||
auth_mode: str = "none"
|
||||
auth_audience: str = ""
|
||||
auth_scopes: list[str] = field(default_factory=list)
|
||||
tool_timeout: int = 30
|
||||
sensitive: bool = False
|
||||
kind: str = "online"
|
||||
category: str = "online"
|
||||
managed: bool = False
|
||||
display_name: str = ""
|
||||
source: str = "config"
|
||||
|
||||
@property
|
||||
def transport(self) -> str:
|
||||
return "stdio" if _clean(self.command) else "http"
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class ToolsConfig:
|
||||
"""Runtime tool configuration."""
|
||||
|
||||
restrict_to_workspace: bool = True
|
||||
mcp_servers: dict[str, MCPServerConfig] = field(default_factory=dict)
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class AuthzConfig:
|
||||
"""External AuthZ service configuration."""
|
||||
|
||||
enabled: bool = False
|
||||
base_url: str = ""
|
||||
request_timeout_seconds: int = 10
|
||||
outlook_mcp_url: str = ""
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class BackendIdentityConfig:
|
||||
"""This backend's AuthZ client identity."""
|
||||
|
||||
backend_id: str = ""
|
||||
client_id: str = ""
|
||||
client_secret: str = ""
|
||||
name: str = ""
|
||||
public_base_url: str = ""
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
class BeaverConfig:
|
||||
"""Config loaded once per backend sandbox instance."""
|
||||
@ -46,6 +105,9 @@ class BeaverConfig:
|
||||
agents_defaults: AgentDefaultsConfig = field(default_factory=AgentDefaultsConfig)
|
||||
providers: dict[str, ProviderConfig] = field(default_factory=dict)
|
||||
embedding: EmbeddingConfig = field(default_factory=EmbeddingConfig)
|
||||
tools: ToolsConfig = field(default_factory=ToolsConfig)
|
||||
authz: AuthzConfig = field(default_factory=AuthzConfig)
|
||||
backend_identity: BackendIdentityConfig = field(default_factory=BackendIdentityConfig)
|
||||
config_path: Path | None = None
|
||||
|
||||
@property
|
||||
@ -69,7 +131,13 @@ class BeaverConfig:
|
||||
"""
|
||||
|
||||
resolved_model = _clean(model) or self.default_model
|
||||
resolved_provider = _clean(provider_name) or self._infer_provider(resolved_model)
|
||||
requested_provider = _clean(provider_name)
|
||||
enabled_providers = self._enabled_provider_names()
|
||||
resolved_provider = (
|
||||
requested_provider
|
||||
if requested_provider and requested_provider in enabled_providers
|
||||
else self._infer_provider(resolved_model)
|
||||
)
|
||||
provider_cfg = self.providers.get(resolved_provider or "") if resolved_provider else None
|
||||
payload: dict[str, Any] = {
|
||||
"model": resolved_model,
|
||||
@ -115,22 +183,36 @@ class BeaverConfig:
|
||||
|
||||
def _infer_provider(self, model: str | None) -> str | None:
|
||||
configured_provider = _clean(self.agents_defaults.provider)
|
||||
if configured_provider:
|
||||
if configured_provider and configured_provider != "custom":
|
||||
return configured_provider
|
||||
|
||||
if model and "/" in model:
|
||||
prefix = model.split("/", 1)[0]
|
||||
if prefix in self.providers:
|
||||
if prefix in self._enabled_provider_names():
|
||||
return prefix
|
||||
|
||||
if len(self.providers) == 1:
|
||||
return next(iter(self.providers))
|
||||
enabled_providers = self._enabled_provider_names()
|
||||
if len(enabled_providers) == 1:
|
||||
return enabled_providers[0]
|
||||
return None
|
||||
|
||||
def _enabled_provider_names(self) -> list[str]:
|
||||
return [
|
||||
name
|
||||
for name, provider in self.providers.items()
|
||||
if name != "custom"
|
||||
and any(
|
||||
[
|
||||
_clean(provider.api_key),
|
||||
_clean(provider.api_base),
|
||||
provider.extra_headers,
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
|
||||
def _clean(value: str | None) -> str | None:
|
||||
if value is None:
|
||||
return None
|
||||
value = str(value).strip()
|
||||
return value or None
|
||||
|
||||
|
||||
Reference in New Issue
Block a user