ForcePilot/backend/package/yuxi/channels/adapters/googlechat/target.py
Kris ca07c593a8 feat(googlechat): 实现 Google Chat 适配器完整功能集
新增 Google Chat 对接的全套工具模块,包括:
- 会话线程管理、消息解析与格式化
- Pub/Sub 消息解码、提及和命令识别
- 权限审批、目录管理和审计日志
- 消息缓存、媒体上传下载和 SSFR 防护
- 策略配置、卡片构建和流式回复支持
2026-05-12 00:44:18 +08:00

93 lines
2.6 KiB
Python

from __future__ import annotations
import re
from typing import Any
_CHANNEL_PREFIXES = ("googlechat:", "gchat:", "google-chat:")
def normalize_googlechat_target(target: str) -> dict[str, Any]:
if not target:
return {"raw": target, "type": "unknown"}
target = _strip_channel_prefix(target)
if "@" in target and not target.startswith(("spaces/", "users/")):
target = _convert_email_to_user(target)
if target.startswith("spaces/"):
parts = target.removeprefix("spaces/").split("/")
space_id = parts[0]
thread_key = parts[2] if len(parts) > 2 and parts[1] == "threads" else None
return {
"raw": target,
"type": "thread" if thread_key else "space",
"space_id": space_id,
"space_name": f"spaces/{space_id}",
"thread_key": thread_key,
"full_target": target,
}
if target.startswith("users/"):
user_id = target.removeprefix("users/")
cleaned = user_id.removeprefix("user:")
return {
"raw": target,
"type": "user",
"user_id": cleaned,
"user_name": f"users/{cleaned}",
"full_target": target,
}
if target.startswith("user:"):
user_id = target.removeprefix("user:")
return {
"raw": target,
"type": "user",
"user_id": user_id,
"user_name": f"users/{user_id}",
"full_target": f"users/{user_id}",
}
return {"raw": target, "type": "unknown"}
def is_googlechat_user_target(target: str) -> bool:
target = _strip_channel_prefix(target)
return target.startswith("users/") or target.startswith("user:")
def is_googlechat_space_target(target: str) -> bool:
target = _strip_channel_prefix(target)
return target.startswith("spaces/")
def resolve_targets(inputs: list[str], kind: str | None = None) -> list[dict[str, Any]]:
results: list[dict[str, Any]] = []
for target in inputs:
normalized = normalize_googlechat_target(target)
target_type = normalized.get("type", "unknown")
if kind and target_type != kind:
continue
results.append(normalized)
return results
def _strip_channel_prefix(target: str) -> str:
for prefix in _CHANNEL_PREFIXES:
if target.lower().startswith(prefix):
return target[len(prefix) :]
return target
def _convert_email_to_user(email: str) -> str:
email_match = re.match(r"^[\w.+-]+@[\w-]+\.[\w.-]+$", email)
if email_match:
return f"users/{email}"
return f"users/{email}"