ForcePilot/backend/package/yuxi/channel/extensions/feishu/tools/wiki.py
Kris 5e91bb9985 feat(feishu): 新增飞书渠道完整插件实现
新增飞书渠道插件,包含基础配置、事件处理、消息收发、工具调用、权限管理等完整功能模块,支持WebSocket长连接、卡片消息、流式响应、群管理、审批通知等能力
2026-05-21 10:46:42 +08:00

300 lines
9.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from __future__ import annotations
import logging
from yuxi.channel.extensions.feishu.client import get_client
logger = logging.getLogger(__name__)
FEISHU_WIKI_TOOLS = [
{
"name": "feishu_wiki_spaces",
"description": "列出飞书知识库空间",
"parameters": {},
},
{
"name": "feishu_wiki_nodes",
"description": "列出知识库节点",
"parameters": {"space_id": "知识空间 ID", "parent_node_token": "父节点 token可选"},
},
{
"name": "feishu_wiki_get_node",
"description": "获取知识库节点详情",
"parameters": {"node_token": "节点 token"},
},
{
"name": "feishu_wiki_create_node",
"description": "创建知识库节点",
"parameters": {"space_id": "空间 ID", "parent_node_token": "父节点 token", "title": "节点标题", "obj_type": "类型docx/sheet/bitable"},
},
{
"name": "feishu_wiki_update_node",
"description": "更新知识库节点",
"parameters": {"space_id": "空间 ID", "node_token": "节点 token", "title": "新标题"},
},
{
"name": "feishu_wiki_move_node",
"description": "移动知识库节点",
"parameters": {"space_id": "空间 ID", "node_token": "节点 token", "target_parent_token": "目标父节点 token"},
},
{
"name": "feishu_wiki_delete_node",
"description": "删除知识库节点",
"parameters": {"node_token": "节点 token"},
},
]
async def list_wiki_spaces(
app_id: str,
app_secret: str,
domain: str,
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.ListSpaceRequest(page_size=50)
resp = await client.wiki.v2.space.list_async(req)
if resp.success() and resp.data:
items = getattr(resp.data, "items", []) or []
return {
"success": True,
"spaces": [
{
"space_id": getattr(s, "space_id", ""),
"name": getattr(s, "name", ""),
"description": getattr(s, "description", ""),
}
for s in items
],
}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu list_wiki_spaces error")
return {"success": False, "error": "Internal error"}
async def list_wiki_nodes(
app_id: str,
app_secret: str,
domain: str,
space_id: str,
parent_node_token: str = "",
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.ListSpaceNodeRequest(
space_id=space_id,
parent_node_token=parent_node_token if parent_node_token else None,
page_size=50,
)
resp = await client.wiki.v2.space_node.list_async(req)
if resp.success() and resp.data:
items = getattr(resp.data, "items", []) or []
return {
"success": True,
"nodes": [
{
"node_token": getattr(n, "node_token", ""),
"title": getattr(n, "title", ""),
"obj_type": getattr(n, "obj_type", ""),
"obj_token": getattr(n, "obj_token", ""),
"has_child": getattr(n, "has_child", False),
}
for n in items
],
}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu list_wiki_nodes error")
return {"success": False, "error": "Internal error"}
async def get_wiki_node(
app_id: str,
app_secret: str,
domain: str,
node_token: str,
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.GetNodeRequest(token=node_token)
resp = await client.wiki.v2.node.get_async(req)
if resp.success() and resp.data:
node = resp.data.node
return {
"success": True,
"node": {
"node_token": getattr(node, "node_token", ""),
"title": getattr(node, "title", ""),
"obj_type": getattr(node, "obj_type", ""),
"obj_token": getattr(node, "obj_token", ""),
"space_id": getattr(node, "space_id", ""),
},
}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu get_wiki_node error")
return {"success": False, "error": "Internal error"}
async def create_wiki_node(
app_id: str,
app_secret: str,
domain: str,
space_id: str,
parent_node_token: str,
title: str,
obj_type: str = "docx",
http_timeout_ms: int = 30000,
) -> dict:
try:
from yuxi.channel.extensions.feishu.tools.doc import create_doc
doc_result = await create_doc(app_id, app_secret, domain, title, "", http_timeout_ms)
if not doc_result.get("success"):
return doc_result
doc_token = doc_result.get("document_id", "")
if not doc_token:
return {"success": False, "error": "Failed to get document_id from created doc"}
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.CreateSpaceNodeRequest(
space_id=space_id,
request_body=lark_oapi.wiki.v2.CreateSpaceNodeRequestBody(
parent_node_token=parent_node_token,
node_type="origin",
origin_node_token=doc_token,
title=title,
),
)
resp = await client.wiki.v2.space_node.create_async(req)
if resp.success() and resp.data:
node = getattr(resp.data, "node", None)
return {
"success": True,
"node_token": getattr(node, "node_token", "") if node else "",
}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu create_wiki_node error")
return {"success": False, "error": "Internal error"}
async def update_wiki_node(
app_id: str,
app_secret: str,
domain: str,
space_id: str,
node_token: str,
title: str = "",
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.UpdateSpaceNodeRequest(
space_id=space_id,
node_token=node_token,
request_body=lark_oapi.wiki.v2.UpdateSpaceNodeRequestBody(
title=title if title else None,
),
)
resp = await client.wiki.v2.space_node.update_async(req)
if resp.success():
return {"success": True}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu update_wiki_node error")
return {"success": False, "error": "Internal error"}
async def move_wiki_node(
app_id: str,
app_secret: str,
domain: str,
space_id: str,
node_token: str,
target_parent_token: str,
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.MoveSpaceNodeRequest(
space_id=space_id,
node_token=node_token,
request_body=lark_oapi.wiki.v2.MoveSpaceNodeRequestBody(
target_parent_token=target_parent_token,
),
)
resp = await client.wiki.v2.space_node.move_async(req)
if resp.success():
return {"success": True}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu move_wiki_node error")
return {"success": False, "error": "Internal error"}
async def delete_wiki_node(
app_id: str,
app_secret: str,
domain: str,
node_token: str,
http_timeout_ms: int = 30000,
) -> dict:
try:
client = get_client(app_id, app_secret, domain, http_timeout_ms)
import lark_oapi
req = lark_oapi.wiki.v2.DeleteSpaceNodeRequest(token=node_token)
resp = await client.wiki.v2.space_node.delete_async(req)
if resp.success():
return {"success": True}
else:
return {"success": False, "error": getattr(resp, "msg", "")}
except ImportError:
return {"success": False, "error": "lark-oapi SDK not installed"}
except Exception:
logger.exception("Feishu delete_wiki_node error")
return {"success": False, "error": "Internal error"}