Merge branch 'ji' into master (操作日志 Y-Log 上报)
# Conflicts: # CLAUDE.md
This commit is contained in:
commit
053d3e300e
35 files changed
+1182
-125
No files matched your search
@@ -26,3 +26,10 @@ async def get_task_deeplink_config() -> dict:
|
||||
"""返回 ``config.yaml`` 的 ``task_deeplink`` 段(含 test/delete_test/各 URL/mock)。"""
|
||||
config = get_app_config()
|
||||
return config.task_deeplink.model_dump()
|
||||
|
||||
|
||||
@router.get("/y-log")
|
||||
async def get_y_log_config() -> dict:
|
||||
"""返回 ``config.yaml`` 的 ``y_log`` 段(enabled / write_url),无密钥,公开只读。"""
|
||||
config = get_app_config()
|
||||
return config.y_log.model_dump()
|
||||
@@ -314,7 +314,7 @@ def build_run_config(
|
||||
the LangGraph Platform-compatible HTTP API and the IM channel path behave
|
||||
identically.
|
||||
"""
|
||||
config: dict[str, Any] = {"recursion_limit": 100}
|
||||
config: dict[str, Any] = {"recursion_limit": 250}
|
||||
if request_config:
|
||||
# LangGraph >= 0.6.0 introduced ``context`` as the preferred way to
|
||||
# pass thread-level data and rejects requests that include both
|
||||
|
||||
@@ -431,11 +431,14 @@ task_deeplink:
|
||||
delete_test: true # 删除接口走 mock.delete 假数据(该接口尚未开发完)
|
||||
action_test: true # 行动→任务解析走 mock.action_detail 假数据(xdfx 行动id→任务id)
|
||||
purpose_detail_url: "https://ch1.b.uat.4.cn/consumer/taskAnalyseSearch/getTaskPurposeDetail"
|
||||
delete_url: "https://ch1.b.uat.4.cn/consumer/taskAnalyseSearch/delete"
|
||||
# rwfx 与 xdfx 共用同一删除接口:rwfx 追加 ?taskId=(不传 actionId);xdfx 追加 ?actionId=(不传 taskId,直接不出现)。
|
||||
delete_url: "https://ch1.b.uat.4.cn/bwjt/dropSixOrSevenData"
|
||||
treemap_edit_url: "https://ch1.b.uat.4.cn/web/#/task/item-aicoh/step-mode-treemap-full-edit"
|
||||
treemap_next_url: "https://ch1.b.uat.4.cn/web/#/task/item-aicoh/step-mode-treemap-full-next"
|
||||
# xdfx 深链传入的是「行动id」,先调该接口(追加 /{actionId})拿 data.taskId 解析出真正「任务id」。
|
||||
action_detail_url: "https://ch1.b.uat.4.cn/consumer/plan/action"
|
||||
# xdfx 删除前「行动历史是否存在」预检接口(追加 ?actionId=);地址待提供,留空则前端视作无历史、不阻断删除。
|
||||
action_history_url: ""
|
||||
# rwfx 目的树面板「3q详情」链接的目标页(地址待定,留空则前端提示未配置);跳转追加 ?id=任务id。
|
||||
detail_3q_url: ""
|
||||
mock:
|
||||
|
||||
+10
-10
@@ -28,12 +28,12 @@ from langgraph.runtime import Runtime
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Defaults — can be overridden via constructor
|
||||
_DEFAULT_WARN_THRESHOLD = 3 # inject warning after 3 identical calls
|
||||
_DEFAULT_HARD_LIMIT = 5 # force-stop after 5 identical calls
|
||||
_DEFAULT_WINDOW_SIZE = 20 # track last N tool calls
|
||||
_DEFAULT_WARN_THRESHOLD = 8 # inject warning after 8 identical calls
|
||||
_DEFAULT_HARD_LIMIT = 20 # force-stop after 20 identical calls
|
||||
_DEFAULT_WINDOW_SIZE = 60 # track last N tool calls (must be >= hard_limit)
|
||||
_DEFAULT_MAX_TRACKED_THREADS = 100 # LRU eviction limit
|
||||
_DEFAULT_TOOL_FREQ_WARN = 30 # warn after 30 calls to the same tool type
|
||||
_DEFAULT_TOOL_FREQ_HARD_LIMIT = 50 # force-stop after 50 calls to the same tool type
|
||||
_DEFAULT_TOOL_FREQ_WARN = 80 # warn after 80 calls to the same tool type
|
||||
_DEFAULT_TOOL_FREQ_HARD_LIMIT = 120 # force-stop after 120 calls to the same tool type
|
||||
|
||||
|
||||
def _normalize_tool_call_args(raw_args: object) -> tuple[dict, str | None]:
|
||||
@@ -142,19 +142,19 @@ class LoopDetectionMiddleware(AgentMiddleware[AgentState]):
|
||||
|
||||
Args:
|
||||
warn_threshold: Number of identical tool call sets before injecting
|
||||
a warning message. Default: 3.
|
||||
a warning message. Default: 8.
|
||||
hard_limit: Number of identical tool call sets before stripping
|
||||
tool_calls entirely. Default: 5.
|
||||
tool_calls entirely. Default: 20.
|
||||
window_size: Size of the sliding window for tracking calls.
|
||||
Default: 20.
|
||||
Default: 60.
|
||||
max_tracked_threads: Maximum number of threads to track before
|
||||
evicting the least recently used. Default: 100.
|
||||
tool_freq_warn: Number of calls to the same tool *type* (regardless
|
||||
of arguments) before injecting a frequency warning. Catches
|
||||
cross-file read loops that hash-based detection misses.
|
||||
Default: 30.
|
||||
Default: 80.
|
||||
tool_freq_hard_limit: Number of calls to the same tool type before
|
||||
forcing a stop. Default: 50.
|
||||
forcing a stop. Default: 120.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
||||
@@ -39,6 +39,7 @@ from deerflow.config.token_usage_config import TokenUsageConfig
|
||||
from deerflow.config.tool_config import ToolConfig, ToolGroupConfig
|
||||
from deerflow.config.tool_search_config import ToolSearchConfig, load_tool_search_config_from_dict
|
||||
from deerflow.config.vision_config import VisionConfig
|
||||
from deerflow.config.y_log_config import YLogConfig
|
||||
|
||||
load_dotenv()
|
||||
|
||||
@@ -141,6 +142,7 @@ class AppConfig(BaseModel):
|
||||
knowledge: KnowledgeConfig = Field(default_factory=KnowledgeConfig, description="Product knowledge base (obsidian-wiki compatible vault) configuration")
|
||||
knowledge_ingest: KnowledgeIngestConfig = Field(default_factory=KnowledgeIngestConfig, description="External knowledge-ingest endpoint configuration")
|
||||
task_deeplink: TaskDeeplinkConfig = Field(default_factory=TaskDeeplinkConfig, description="任务深链(rwfx)目的树闸门与跳转地址配置(前端经 /api/public/config/task-deeplink 读取)")
|
||||
y_log: YLogConfig = Field(default_factory=YLogConfig, description="操作日志上报配置(前端经 /api/public/config/y-log 读取)")
|
||||
|
||||
@classmethod
|
||||
def resolve_config_path(cls, config_path: str | None = None) -> Path:
|
||||
|
||||
+10
-1
@@ -8,8 +8,13 @@
|
||||
- ``test`` → 目的树查询(``purpose_detail_url``)走 ``mock.purpose_detail`` 假数据;
|
||||
同时 rwfx 进入「3q 是否完成」预检(``selectSqReport``,外部接口不可用)走 ``mock.sq_report`` 假数据。
|
||||
- ``delete_test`` → 删除接口(``delete_url``)走 ``mock.delete`` 假数据(该接口尚未开发完时打开)。
|
||||
rwfx 与 xdfx 共用同一个删除接口 ``dropSixOrSevenData``:rwfx 传 ``?taskId=``、xdfx 传 ``?actionId=``
|
||||
(另一参数直接不传,不出现在 URL 里)。
|
||||
- ``action_test`` → 行动详情接口(``action_detail_url``)走 ``mock.action_detail`` 假数据。
|
||||
xdfx 深链传入的是「行动id」,需先调该接口拿 ``data.taskId`` 解析出真正的「任务id」。
|
||||
|
||||
``action_history_url`` 为 xdfx 删除前「行动历史是否存在」预检接口,地址待提供:留空则前端视作
|
||||
「无历史/不查询」,不阻断删除(后续配上真实地址即生效)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -44,13 +49,17 @@ class TaskDeeplinkConfig(BaseModel):
|
||||
default="",
|
||||
description="行动详情接口基址(xdfx 行动→任务),调用时追加 /{actionId} 路径段;返回 data.taskId 为真正任务id",
|
||||
)
|
||||
action_history_url: str = Field(
|
||||
default="",
|
||||
description="xdfx「行动历史是否存在」查询完整 URL(删除前预检),调用时追加 ?actionId=;地址待提供,留空则前端视作「无历史/不查询」(不阻断删除)",
|
||||
)
|
||||
detail_3q_url: str = Field(
|
||||
default="",
|
||||
description="「3q详情」详情页 URL(rwfx 目的树面板的链接),跳转时追加 ?id=(任务id)",
|
||||
)
|
||||
delete_url: str = Field(
|
||||
default="",
|
||||
description="删除完整 URL,调用时追加 ?taskId=",
|
||||
description="删除完整 URL(rwfx 与 xdfx 共用同一个删除接口 dropSixOrSevenData):rwfx 调用追加 ?taskId=(不传 actionId),xdfx 调用追加 ?actionId=(不传 taskId)——另一参数直接不出现在 URL 里,不是空值",
|
||||
)
|
||||
treemap_edit_url: str = Field(
|
||||
default="",
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
"""操作日志(Y-Log)上报配置。
|
||||
|
||||
前端经公开只读接口 ``GET /api/public/config/y-log`` 读取本段(地址 + 开关),
|
||||
据此决定是否把用户的关键操作上报到外部日志接口。段内只有地址与开关,无密钥,
|
||||
公开只读。仿 :mod:`deerflow.config.log_system_config` 的写法。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class YLogConfig(BaseModel):
|
||||
"""操作日志(Y-Log)上报配置:前端经 /api/public/config/y-log 读取。"""
|
||||
|
||||
enabled: bool = Field(default=False, description="是否启用操作日志上报")
|
||||
write_url: str = Field(
|
||||
default="",
|
||||
description="日志上报外部接口完整地址(POST),如 https://ch1.b.uat.4.cn/api/y-log/write",
|
||||
)
|
||||
@@ -308,6 +308,14 @@ log_system:
|
||||
url: "https://your-log-system.example.com"
|
||||
label: "日志系统"
|
||||
|
||||
# ───────────────────────────────────────────────────────────────────────────
|
||||
# 操作日志(Y-Log)上报:前端直连外部接口记录用户的关键操作(审计/统计)。
|
||||
# 仅在「token 登录」(存在 token1)时上报;前端经公开只读接口
|
||||
# GET /api/public/config/y-log 读取本段,改这里即时生效(Gateway mtime 热重载)。
|
||||
y_log:
|
||||
enabled: true
|
||||
write_url: https://ch1.b.uat.4.cn/api/y-log/write
|
||||
|
||||
summarization:
|
||||
# 开关已移到聊天框下方(参考文献下面)的「上下文压缩」按钮,默认关闭。
|
||||
# 这里 enabled 仅作为非 Web 路径(渠道/定时任务)的后备开关;下面的 trigger/keep
|
||||
@@ -341,11 +349,14 @@ task_deeplink:
|
||||
delete_test: true # 删除接口走 mock.delete 假数据(该接口尚未开发完)
|
||||
action_test: true # 行动→任务解析走 mock.action_detail 假数据(xdfx 行动id→任务id)
|
||||
purpose_detail_url: "https://ch1.b.uat.4.cn/consumer/taskAnalyseSearch/getTaskPurposeDetail"
|
||||
delete_url: "https://ch1.b.uat.4.cn/consumer/taskAnalyseSearch/delete"
|
||||
# rwfx 与 xdfx 共用同一删除接口:rwfx 追加 ?taskId=(不传 actionId);xdfx 追加 ?actionId=(不传 taskId,直接不出现)。
|
||||
delete_url: "https://ch1.b.uat.4.cn/bwjt/dropSixOrSevenData"
|
||||
treemap_edit_url: "https://ch1.b.uat.4.cn/web/#/task/item-aicoh/step-mode-treemap-full-edit"
|
||||
treemap_next_url: "https://ch1.b.uat.4.cn/web/#/task/item-aicoh/step-mode-treemap-full-next"
|
||||
# xdfx 深链传入的是「行动id」,先调该接口(追加 /{actionId})拿 data.taskId 解析出真正「任务id」。
|
||||
action_detail_url: "https://ch1.b.uat.4.cn/consumer/plan/action"
|
||||
# xdfx 删除前「行动历史是否存在」预检接口(追加 ?actionId=);地址待提供,留空则前端视作无历史、不阻断删除。
|
||||
action_history_url: ""
|
||||
# rwfx 目的树面板「3q详情」链接的目标页(地址待定,留空则前端提示未配置);跳转追加 ?id=任务id。
|
||||
detail_3q_url: ""
|
||||
mock:
|
||||
|
||||
Reference in new issue
Block a user