Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions backend/app/api/dingtalk.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,22 @@ async def process_dingtalk_message(
)
platform_user_id = platform_user.id

# Check for channel commands (/new, /reset)
from app.services.channel_commands import is_channel_command, handle_channel_command
if is_channel_command(user_text):
cmd_result = await handle_channel_command(
db=db, command=user_text, agent_id=agent_id,
user_id=platform_user_id, external_conv_id=conv_id,
source_channel="dingtalk",
)
await db.commit()
async with httpx.AsyncClient(timeout=10) as _cl_cmd:
await _cl_cmd.post(session_webhook, json={
"msgtype": "text",
"text": {"content": cmd_result["message"]},
})
return

# Find or create session
sess = await find_or_create_channel_session(
db=db,
Expand Down
17 changes: 17 additions & 0 deletions backend/app/api/feishu.py
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,23 @@ async def process_feishu_event(agent_id: uuid.UUID, body: dict, db: AsyncSession
from app.models.agent import DEFAULT_CONTEXT_WINDOW_SIZE
ctx_size = (agent_obj.context_window_size or DEFAULT_CONTEXT_WINDOW_SIZE) if agent_obj else DEFAULT_CONTEXT_WINDOW_SIZE

# Check for channel commands (/new, /reset)
from app.services.channel_commands import is_channel_command, handle_channel_command
if is_channel_command(user_text):
_cmd_result = await handle_channel_command(
db=db, command=user_text, agent_id=agent_id,
user_id=creator_id, external_conv_id=conv_id,
source_channel="feishu",
)
await db.commit()
import json as _j_cmd
_cmd_reply = _j_cmd.dumps({"text": _cmd_result["message"]})
if chat_type == "group" and chat_id:
await feishu_service.send_message(config.app_id, config.app_secret, chat_id, "text", _cmd_reply, receive_id_type="chat_id")
else:
await feishu_service.send_message(config.app_id, config.app_secret, sender_open_id, "text", _cmd_reply)
return {"code": 0, "msg": "command handled"}

# Pre-resolve session so history lookup uses the UUID (session created later if new)
_pre_sess_r = await db.execute(
select(__import__('app.models.chat_session', fromlist=['ChatSession']).ChatSession).where(
Expand Down
75 changes: 75 additions & 0 deletions backend/app/services/channel_commands.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Channel command handler for external channels (DingTalk, Feishu, etc.)

Supports slash commands like /new to reset session context.
"""

import uuid
from datetime import datetime, timezone
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.chat_session import ChatSession
from app.services.channel_session import find_or_create_channel_session


COMMANDS = {"/new", "/reset"}


def is_channel_command(text: str) -> bool:
"""Check if the message is a recognized channel command."""
stripped = text.strip().lower()
return stripped in COMMANDS


async def handle_channel_command(
db: AsyncSession,
command: str,
agent_id: uuid.UUID,
user_id: uuid.UUID,
external_conv_id: str,
source_channel: str,
) -> dict:
"""Handle a channel command and return response info.

Returns:
{"action": "new_session", "message": "..."}
"""
cmd = command.strip().lower()

if cmd in ("/new", "/reset"):
# Find current session
result = await db.execute(
select(ChatSession).where(
ChatSession.agent_id == agent_id,
ChatSession.external_conv_id == external_conv_id,
)
)
old_session = result.scalar_one_or_none()

if old_session:
# Rename old external_conv_id so find_or_create will make a new one
now = datetime.now(timezone.utc)
old_session.external_conv_id = (
f"{external_conv_id}__archived_{now.strftime('%Y%m%d_%H%M%S')}"
)
await db.flush()

# Create new session
new_session = ChatSession(
agent_id=agent_id,
user_id=user_id,
title="New Session",
source_channel=source_channel,
external_conv_id=external_conv_id,
created_at=datetime.now(timezone.utc),
)
db.add(new_session)
await db.flush()

return {
"action": "new_session",
"session_id": str(new_session.id),
"message": "已开启新对话,之前的上下文已清除。",
}

return {"action": "unknown", "message": f"未知命令: {cmd}"}