**AgentKit Wrapper for User-Defined Agent**
This file wraps your Agent definition (agent.py) to make it deployable with AgentKit.
Your Agent is imported from: agent
Agent variable: root_agent
from concurrent.futures import Future
from dotenv import load_dotenv
from agent import root_agent
from veadk import Runner
from agentkit.apps import AgentkitSimpleApp
import lark_oapi as lark
from lark_oapi.api.im.v1.model.p2_im_message_receive_v1 import P2ImMessageReceiveV1
from lark_oapi.api.im.v1 import ReplyMessageRequest
from lark_oapi.api.im.v1 import ReplyMessageRequestBody
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
app = AgentkitSimpleApp()
runner = Runner(agent=root_agent)
agent_ready = threading.Event()
async def run(payload: dict, headers: dict) -> str:
Main entrypoint for the Agent.
This wrapper handles the standard AgentKit request/response protocol
and delegates to your Agent for processing.
prompt = payload["prompt"]
user_id = headers["user_id"]
session_id = headers["session_id"]
f"Running agent with prompt: {prompt}, user_id: {user_id}, session_id: {session_id}"
if agent_loop and agent_loop.is_running():
logger.info("Dispatching run request to agent_loop")
future = asyncio.run_coroutine_threadsafe(
runner.run(messages=prompt, user_id=user_id, session_id=session_id),
response = await asyncio.wrap_future(future)
logger.info("Running request on main loop")
response = await runner.run(
logger.info(f"Run response: {response}")
"""Health check endpoint."""
async def run_agent_async(prompt: str, user_id: str, session_id: str) -> str:
"""Async wrapper for running the agent."""
logger.info(f"Running agent async: user_id={user_id}, session_id={session_id}")
return await runner.run(messages=prompt, user_id=user_id, session_id=session_id)
启动一个独立的线程来运行 asyncio 事件循环。
1. 飞书 WebSocket 客户端 (ws_client.start()) 会阻塞主线程。
2. 如果我们在 WebSocket 回调中直接调用 asyncio.run(),会因为当前已在事件循环中(或环境限制)而报错。
3. 因此,我们需要一个专门的线程 (Agent Thread) 来处理 Agent 的异步任务 (runner.run)。
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
logger.info("Agent event loop started.")
启动飞书机器人(WebSocket 长连接模式)。
该模式不需要公网 IP,适合本地开发和内网部署。
app_id = os.getenv("FEISHU_APP_ID")
app_secret = os.getenv("FEISHU_APP_SECRET")
encrypt_key = os.getenv("FEISHU_ENCRYPT_KEY", "")
verification_token = os.getenv("FEISHU_VERIFICATION_TOKEN", "")
if not app_id or not app_secret:
logger.warning("FEISHU_APP_ID or FEISHU_APP_SECRET not found. Skipping Feishu Bot startup.")
agent_thread = threading.Thread(target=start_agent_loop, daemon=True)
client = lark.Client.builder() \
.app_secret(app_secret) \
.log_level(lark.LogLevel.DEBUG) \
async def process_message_and_reply(text: str, user_id: str, chat_id: str, message_id: str):
logger.info(f"[Feishu] Processing agent task for message_id: {message_id}")
response_text = await runner.run(messages=text, user_id=user_id, session_id=chat_id)
logger.info(f"[Feishu] Agent response: {response_text}")
client.im.v1.message.reply(
ReplyMessageRequest.builder()
.request_body(ReplyMessageRequestBody.builder()
.content(json.dumps({"text": response_text}))
logger.error(f"[Feishu] Async processing failed: {e}", exc_info=True)
def do_p2_im_message_receive_v1(data: P2ImMessageReceiveV1) -> None:
content_json = json.loads(data.event.message.content)
text = content_json.get("text", "")
chat_id = data.event.message.chat_id
user_id = data.event.sender.sender_id.open_id
message_id = data.event.message.message_id
logger.info(f"[Feishu] Received message: {text} from {user_id}")
logger.error("[Feishu] Agent loop not initialized!")
asyncio.run_coroutine_threadsafe(
process_message_and_reply(text, user_id, chat_id, message_id),
logger.info(f"[Feishu] Task scheduled for message_id: {message_id}")
logger.error(f"[Feishu] Error handling message: {e}", exc_info=True)
event_handler = lark.EventDispatcherHandler.builder(encrypt_key, verification_token) \
.register_p2_im_message_receive_v1(do_p2_im_message_receive_v1) \
ws_client = lark.ws.Client(
event_handler=event_handler,
log_level=lark.LogLevel.DEBUG
ws_thread = threading.Thread(target=ws_client.start, daemon=True)
logger.info("Feishu WebSocket Client started in background thread.")
if __name__ == "__main__":
if os.getenv("FEISHU_APP_ID") and os.getenv("ENABLE_FEISHU_BOT", "true").lower() == "true":
app.run(host="0.0.0.0", port=8000)