feat: 添加MinIO文件系统支持并优化外部连接器功能
- 添加MinIO用户文件系统配置选项(BEAVER_MINIO_ROOT_USER等) - 更新外部连接器配置结构,包括BASE_URL和认证令牌设置 - 改进connector provider支持更多类型(official, feishu_bot等) - 实现Mistral模型推理模式支持reasoning_effort参数 - 增强外部连接器策略配置和运行时配置管理 - 添加connector bridge事件验证和安全保护机制 - 优化任务路由逻辑,区分simple_chat和new_task场景 - 更新初始技能工具提示配置,分离authoring admin功能
This commit is contained in:
@ -8,6 +8,18 @@ from .models import ChannelRuntimeSpec, ValidationResult
|
||||
from .sidecar_client import ConnectorSidecarClient
|
||||
from .store import ChannelConnectionStore, CredentialStore
|
||||
|
||||
POLICY_CONFIG_KEYS = {
|
||||
"allowFrom",
|
||||
"groupAllowFrom",
|
||||
"requireMentionInGroups",
|
||||
"respondToMentionAll",
|
||||
"dmMode",
|
||||
"maxMessageChars",
|
||||
"textBatchDelayMs",
|
||||
"textBatchMaxMessages",
|
||||
"textBatchMaxChars",
|
||||
}
|
||||
|
||||
|
||||
class ExternalConnectorBase:
|
||||
kind = ""
|
||||
@ -33,6 +45,8 @@ class ExternalConnectorBase:
|
||||
owner_user_id: str | None,
|
||||
options: dict[str, Any],
|
||||
) -> dict[str, Any]:
|
||||
runtime_config = {"sidecarBaseUrl": self.sidecar_base_url}
|
||||
runtime_config.update(_policy_runtime_config(options))
|
||||
connection = self.connection_store.create(
|
||||
kind=self.kind,
|
||||
mode="sidecar",
|
||||
@ -40,7 +54,7 @@ class ExternalConnectorBase:
|
||||
account_id="",
|
||||
owner_user_id=owner_user_id,
|
||||
auth_type="connector_session",
|
||||
runtime_config={"sidecarBaseUrl": self.sidecar_base_url},
|
||||
runtime_config=runtime_config,
|
||||
capabilities=list(self.capabilities),
|
||||
)
|
||||
connection = self.connection_store.update_status(connection.connection_id, status="pairing", last_error=None)
|
||||
@ -54,7 +68,8 @@ class ExternalConnectorBase:
|
||||
}
|
||||
view = dict(await self.sidecar_client.start_session(payload))
|
||||
connection.pairing_session_id = str(view.get("sessionId") or "")
|
||||
self.connection_store.update(connection)
|
||||
connection = self.connection_store.update(connection)
|
||||
connection = self._apply_session_view(connection, view)
|
||||
view["connectionId"] = connection.connection_id
|
||||
view["channelId"] = connection.channel_id
|
||||
return view
|
||||
@ -62,6 +77,12 @@ class ExternalConnectorBase:
|
||||
async def poll_session(self, session_id: str) -> dict[str, Any]:
|
||||
view = dict(await self.sidecar_client.get_session(session_id))
|
||||
connection = self._connection_for_session(session_id)
|
||||
connection = self._apply_session_view(connection, view)
|
||||
view["connectionId"] = connection.connection_id
|
||||
view["channelId"] = connection.channel_id
|
||||
return view
|
||||
|
||||
def _apply_session_view(self, connection: Any, view: dict[str, Any]) -> Any:
|
||||
status = str(view.get("status") or "")
|
||||
if status == "connected":
|
||||
connection.account_id = str(view.get("accountId") or connection.account_id)
|
||||
@ -78,9 +99,7 @@ class ExternalConnectorBase:
|
||||
status="error",
|
||||
last_error=str(view.get("error") or status),
|
||||
)
|
||||
view["connectionId"] = connection.connection_id
|
||||
view["channelId"] = connection.channel_id
|
||||
return view
|
||||
return self.connection_store.get(connection.connection_id)
|
||||
|
||||
async def validate(self, connection_id: str) -> ValidationResult:
|
||||
connection = self.connection_store.get(connection_id)
|
||||
@ -106,6 +125,7 @@ class ExternalConnectorBase:
|
||||
config={
|
||||
"platformKind": self.kind,
|
||||
"connectionId": connection.connection_id,
|
||||
**dict(connection.runtime_config),
|
||||
"sidecarBaseUrl": connection.runtime_config.get("sidecarBaseUrl") or self.sidecar_base_url,
|
||||
},
|
||||
secrets_ref=None,
|
||||
@ -129,3 +149,52 @@ class WeixinConnector(ExternalConnectorBase):
|
||||
class FeishuConnector(ExternalConnectorBase):
|
||||
kind = "feishu"
|
||||
capabilities = ["receive_text", "send_text", "receive_media", "groups"]
|
||||
|
||||
|
||||
def _policy_runtime_config(options: dict[str, Any]) -> dict[str, Any]:
|
||||
result: dict[str, Any] = {}
|
||||
for key in POLICY_CONFIG_KEYS:
|
||||
if key not in options:
|
||||
continue
|
||||
value = options[key]
|
||||
if key in {"allowFrom", "groupAllowFrom"}:
|
||||
items = _string_list(value)
|
||||
if items:
|
||||
result[key] = items
|
||||
continue
|
||||
if key in {"maxMessageChars", "textBatchDelayMs", "textBatchMaxMessages", "textBatchMaxChars"}:
|
||||
number = _positive_int(value)
|
||||
if number is not None:
|
||||
result[key] = number
|
||||
continue
|
||||
if key in {"requireMentionInGroups", "respondToMentionAll"}:
|
||||
result[key] = _bool(value)
|
||||
continue
|
||||
text = str(value or "").strip()
|
||||
if text:
|
||||
result[key] = text
|
||||
return result
|
||||
|
||||
|
||||
def _string_list(value: Any) -> list[str]:
|
||||
if isinstance(value, str):
|
||||
raw_items = value.replace("\n", ",").split(",")
|
||||
elif isinstance(value, list):
|
||||
raw_items = value
|
||||
else:
|
||||
raw_items = []
|
||||
return [str(item).strip() for item in raw_items if str(item).strip()]
|
||||
|
||||
|
||||
def _positive_int(value: Any) -> int | None:
|
||||
try:
|
||||
number = int(value)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return number if number > 0 else None
|
||||
|
||||
|
||||
def _bool(value: Any) -> bool:
|
||||
if isinstance(value, bool):
|
||||
return value
|
||||
return str(value).strip().lower() in {"1", "true", "yes", "on"}
|
||||
|
||||
Reference in New Issue
Block a user