feat: 集成Hermes智能体系统,增强聊天和差旅报销功能

This commit is contained in:
caoxiaozhu
2026-05-16 06:14:08 +00:00
parent 763afa0ee2
commit 212c935308
46 changed files with 8802 additions and 5372 deletions

View File

@@ -1,6 +1,6 @@
from __future__ import annotations
from datetime import UTC, datetime
from datetime import UTC, datetime, timedelta
from typing import Annotated
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
@@ -26,7 +26,11 @@ from app.schemas.knowledge import (
LlmWikiSummaryUpdateWrite,
)
from app.services.agent_runs import AgentRunService
from app.services.knowledge import KNOWLEDGE_INGEST_STATUS_SYNCING, KnowledgeService
from app.services.knowledge import (
KNOWLEDGE_INGEST_STATUS_FAILED,
KNOWLEDGE_INGEST_STATUS_SYNCING,
KnowledgeService,
)
from app.services.llm_wiki import LlmWikiService
from app.services.llm_wiki_tasks import llm_wiki_task_manager
@@ -169,6 +173,78 @@ def sync_llm_wiki(
for item in knowledge_service.list_folder_documents(folder=payload.folder)
if str(item.get("id") or "").strip() and (not requested_ids or str(item.get("id") or "").strip() in requested_ids)
]
active_run = None
for item in run_service.list_runs(
agent=AgentName.HERMES.value,
status=AgentRunStatus.RUNNING.value,
limit=100,
):
if item.route_json.get("job_type") != "llm_wiki_sync":
continue
if item.route_json.get("folder") != payload.folder:
continue
heartbeat_raw = str(item.route_json.get("heartbeat_at") or "").strip()
heartbeat_at = None
if heartbeat_raw:
try:
heartbeat_at = datetime.fromisoformat(heartbeat_raw)
except ValueError:
heartbeat_at = None
last_seen_at = heartbeat_at or item.started_at
if last_seen_at.tzinfo is None:
last_seen_at = last_seen_at.replace(tzinfo=UTC)
if datetime.now(UTC) - last_seen_at > timedelta(minutes=30):
stale_document_ids = [
str(document_id).strip()
for document_id in list(item.route_json.get("requested_document_ids") or [])
if str(document_id).strip()
]
if stale_document_ids:
knowledge_service.set_document_ingest_statuses(
stale_document_ids,
status_code=KNOWLEDGE_INGEST_STATUS_FAILED,
agent_run_id=item.run_id,
)
run_service.merge_route_json(
item.run_id,
{
"phase": "stale_failed",
"heartbeat_at": datetime.now(UTC).isoformat(),
},
status=AgentRunStatus.FAILED.value,
result_summary="Hermes 归纳任务长时间无心跳,已自动标记为失败。",
error_message="Hermes callback heartbeat timed out.",
finished_at=datetime.now(UTC),
)
continue
if (
not target_document_ids
or not list(item.route_json.get("requested_document_ids") or [])
or bool(
set(target_document_ids)
& {
str(document_id).strip()
for document_id in list(item.route_json.get("requested_document_ids") or [])
if str(document_id).strip()
}
)
):
active_run = item
break
if active_run is not None:
return LlmWikiSyncTaskRead(
ok=True,
agent_run_id=active_run.run_id,
folder=payload.folder,
document_ids=[
str(item).strip()
for item in list(active_run.route_json.get("requested_document_ids") or target_document_ids)
if str(item).strip()
],
queued_at=active_run.started_at,
status=active_run.status,
summary="已有 Hermes 归纳任务正在执行,已复用当前任务而不是重复创建。",
)
task_asset = db.scalar(
select(AgentAsset).where(AgentAsset.code == "task.hermes.llm_wiki_rule_formation")
)
@@ -186,6 +262,8 @@ def sync_llm_wiki(
"folder": payload.folder,
"force": payload.force,
"requested_document_ids": target_document_ids,
"requested_by_username": current_user.username,
"requested_by_name": current_user.name,
"progress": {
"total_documents": len(target_document_ids),
"completed_documents": 0,