feat: 重构数据存储路径并优化任务通知机制
将审计日志、会话数据和定时任务文件移动到统一的data目录下 为后台任务添加完成回调功能,优化CC任务完成后的通知流程 更新README和ROADMAP文档,标记已完成的功能项
This commit is contained in:
+1
-1
@@ -10,7 +10,7 @@ from typing import Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
AUDIT_DIR = Path(__file__).parent.parent / "audit"
|
||||
AUDIT_DIR = Path(__file__).parent.parent / "data" / "audit"
|
||||
|
||||
|
||||
def _ensure_audit_dir() -> None:
|
||||
|
||||
+23
-3
@@ -17,7 +17,7 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
DEFAULT_IDLE_TIMEOUT = 30 * 60
|
||||
DEFAULT_CC_TIMEOUT = 300.0
|
||||
PERSISTENCE_FILE = Path(__file__).parent.parent / "sessions.json"
|
||||
PERSISTENCE_FILE = Path(__file__).parent.parent / "data" / "sessions.json"
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -105,7 +105,7 @@ class SessionManager:
|
||||
|
||||
if cc_timeout > 60:
|
||||
from agent.task_runner import task_runner
|
||||
from orchestrator.tools import get_current_chat
|
||||
from orchestrator.tools import get_current_chat, set_current_chat, set_current_user
|
||||
|
||||
chat_id = get_current_chat()
|
||||
|
||||
@@ -126,10 +126,29 @@ class SessionManager:
|
||||
)
|
||||
return output
|
||||
|
||||
async def on_task_complete(task) -> None:
|
||||
if not chat_id or not user_id or not task.result:
|
||||
return
|
||||
set_current_user(user_id)
|
||||
set_current_chat(chat_id)
|
||||
from orchestrator.agent import agent
|
||||
follow_up = (
|
||||
f"CC task completed. Output:\n{task.result}\n\n"
|
||||
f"Original request was: {message}\n\n"
|
||||
"If the user asked you to send a file, use send_file now. "
|
||||
"Otherwise just acknowledge completion."
|
||||
)
|
||||
reply = await agent.run(user_id, follow_up)
|
||||
if reply:
|
||||
from bot.feishu import send_text
|
||||
await send_text(chat_id, "chat_id", reply)
|
||||
|
||||
task_id = await task_runner.submit(
|
||||
run_task,
|
||||
run_task(),
|
||||
description=f"CC session {conv_id}: {message[:50]}",
|
||||
notify_chat_id=chat_id,
|
||||
user_id=user_id,
|
||||
on_complete=on_task_complete,
|
||||
)
|
||||
return f"⏳ Task #{task_id} started (timeout: {int(cc_timeout)}s). I'll notify you when it's done."
|
||||
|
||||
@@ -183,6 +202,7 @@ class SessionManager:
|
||||
def _save(self) -> None:
|
||||
try:
|
||||
data = {cid: s.to_dict() for cid, s in self._sessions.items()}
|
||||
PERSISTENCE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(PERSISTENCE_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
logger.debug("Saved %d sessions to %s", len(data), PERSISTENCE_FILE)
|
||||
|
||||
+2
-1
@@ -14,7 +14,7 @@ from typing import Any, Callable, Dict, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
PERSISTENCE_FILE = Path(__file__).parent.parent / "scheduled_jobs.json"
|
||||
PERSISTENCE_FILE = Path(__file__).parent.parent / "data" / "scheduled_jobs.json"
|
||||
|
||||
|
||||
class JobStatus(str, Enum):
|
||||
@@ -98,6 +98,7 @@ class Scheduler:
|
||||
"""Save jobs to persistence file."""
|
||||
try:
|
||||
data = {jid: job.to_dict() for jid, job in self._jobs.items()}
|
||||
PERSISTENCE_FILE.parent.mkdir(parents=True, exist_ok=True)
|
||||
with open(PERSISTENCE_FILE, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, indent=2, ensure_ascii=False)
|
||||
except Exception:
|
||||
|
||||
@@ -57,6 +57,7 @@ class TaskRunner:
|
||||
description: str,
|
||||
notify_chat_id: Optional[str] = None,
|
||||
user_id: Optional[str] = None,
|
||||
on_complete: Optional[Callable[[BackgroundTask], Awaitable[None]]] = None,
|
||||
) -> str:
|
||||
"""Submit a coroutine as a background task."""
|
||||
task_id = str(uuid.uuid4())[:8]
|
||||
@@ -72,11 +73,11 @@ class TaskRunner:
|
||||
async with self._lock:
|
||||
self._tasks[task_id] = task
|
||||
|
||||
asyncio.create_task(self._run_task(task_id, coro))
|
||||
asyncio.create_task(self._run_task(task_id, coro, on_complete))
|
||||
logger.info("Submitted background task %s: %s", task_id, description)
|
||||
return task_id
|
||||
|
||||
async def _run_task(self, task_id: str, coro: Awaitable[Any]) -> None:
|
||||
async def _run_task(self, task_id: str, coro: Awaitable[Any], on_complete: Optional[Callable[[BackgroundTask], Awaitable[None]]] = None) -> None:
|
||||
"""Execute a task and send notification on completion."""
|
||||
async with self._lock:
|
||||
task = self._tasks.get(task_id)
|
||||
@@ -107,6 +108,12 @@ class TaskRunner:
|
||||
else:
|
||||
await self._send_notification(task)
|
||||
|
||||
if on_complete and task.status == TaskStatus.COMPLETED:
|
||||
try:
|
||||
await on_complete(task)
|
||||
except Exception:
|
||||
logger.exception("on_complete callback failed for task %s", task_id)
|
||||
|
||||
async def _send_notification(self, task: BackgroundTask) -> None:
|
||||
"""Send Feishu notification about task completion."""
|
||||
from bot.feishu import send_text
|
||||
|
||||
Reference in New Issue
Block a user