Resolve merge conflicts

This commit is contained in:
吉鑫升 committed 2026-06-05 10:28:45 +08:00
1 parent e96cc97462
commit 22be6325a8
3 files changed
+52 -34

No files matched your search

@@ -7,7 +7,7 @@ import {
Settings2Icon, Settings2Icon,
Trash2Icon, Trash2Icon,
} from "lucide-react"; } from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner"; import { toast } from "sonner";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@@ -28,8 +28,7 @@ import {
} from "@/components/ui/select"; } from "@/components/ui/select";
import { Switch } from "@/components/ui/switch"; import { Switch } from "@/components/ui/switch";
import { Textarea } from "@/components/ui/textarea"; import { Textarea } from "@/components/ui/textarea";
import { useAgents } from "@/core/agents/hooks"; import { useAgentSelector } from "@/core/agents/hooks";
import { getStoredAuth } from "@/core/auth";
import { import {
useCreateCustomPrompt, useCreateCustomPrompt,
useCustomPrompts, useCustomPrompts,
@@ -165,10 +164,9 @@ function ManagePromptsDialog({
const createPrompt = useCreateCustomPrompt(); const createPrompt = useCreateCustomPrompt();
const updatePrompt = useUpdateCustomPrompt(); const updatePrompt = useUpdateCustomPrompt();
const deletePrompt = useDeleteCustomPrompt(); const deletePrompt = useDeleteCustomPrompt();
const { agents } = useAgents(); const { agents } = useAgentSelector();
const preferences = useUserPreferences(); const preferences = useUserPreferences();
const updatePreferences = useUpdateUserPreferences(); const updatePreferences = useUpdateUserPreferences();
const currentUserId = getStoredAuth()?.user_id ?? null;
const [editingId, setEditingId] = useState<string | null>(null); const [editingId, setEditingId] = useState<string | null>(null);
const [title, setTitle] = useState(""); const [title, setTitle] = useState("");
const [content, setContent] = useState(""); const [content, setContent] = useState("");
@@ -176,16 +174,7 @@ function ManagePromptsDialog({
const saving = createPrompt.isPending || updatePrompt.isPending; const saving = createPrompt.isPending || updatePrompt.isPending;
const selectableAgents = useMemo(() => { const selectableAgents = agents;
const owned = currentUserId
? agents.filter((agent) => agent.user_id === currentUserId)
: [];
if (agentId && !owned.some((agent) => agent.id === agentId)) {
const bound = agents.find((agent) => agent.id === agentId);
if (bound) return [bound, ...owned];
}
return owned;
}, [agents, agentId, currentUserId]);
const agentNameById = (id?: string | null) => const agentNameById = (id?: string | null) =>
id ? agents.find((agent) => agent.id === id)?.name ?? null : null; id ? agents.find((agent) => agent.id === id)?.name ?? null : null;
@@ -235,7 +224,11 @@ function ManagePromptsDialog({
setEditingId(id); setEditingId(id);
setTitle(target.title); setTitle(target.title);
setContent(target.content); setContent(target.content);
setAgentId(target.agent_id || undefined); setAgentId(
target.agent_id && selectableAgents.some((agent) => agent.id === target.agent_id)
? target.agent_id
: undefined,
);
}; };
const handleToggleHideAdmin = async (next: boolean) => { const handleToggleHideAdmin = async (next: boolean) => {
@@ -25,7 +25,7 @@ from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, Query, Request from fastapi import APIRouter, Depends, HTTPException, Query, Request
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from sqlalchemy import and_, case, desc, func, or_, select from sqlalchemy import and_, case, desc, func, not_, or_, select
from langchain_core.messages import HumanMessage, SystemMessage from langchain_core.messages import HumanMessage, SystemMessage
from app.gateway.deps import ( from app.gateway.deps import (
@@ -355,6 +355,22 @@ def _run_time_filter(since: datetime, until: datetime):
return and_(RunRow.created_at >= since, RunRow.created_at <= until) return and_(RunRow.created_at >= since, RunRow.created_at <= until)
def _non_scheduled_run_filter():
"""Exclude scheduler-generated runs that predate scheduled_task_runs links."""
return or_(
RunRow.first_human_message.is_(None),
not_(RunRow.first_human_message.like("【定时任务触发】%")),
)
def _non_scheduled_tool_filter():
return or_(
ToolCallMetricRow.run_id.is_(None),
RunRow.run_id.is_(None),
_non_scheduled_run_filter(),
)
def _tool_time_filter(since: datetime, until: datetime): def _tool_time_filter(since: datetime, until: datetime):
return and_(ToolCallMetricRow.created_at >= since, ToolCallMetricRow.created_at <= until) return and_(ToolCallMetricRow.created_at >= since, ToolCallMetricRow.created_at <= until)
@@ -404,6 +420,7 @@ def _apply_run_scope(
stmt = stmt.where(RunRow.status != "error") stmt = stmt.where(RunRow.status != "error")
if not include_scheduled: if not include_scheduled:
stmt = stmt.where(or_(run_id_column.is_(None), run_id_column.not_in(_scheduled_run_ids_stmt()))) stmt = stmt.where(or_(run_id_column.is_(None), run_id_column.not_in(_scheduled_run_ids_stmt())))
stmt = stmt.where(_non_scheduled_run_filter())
return stmt return stmt
@@ -417,6 +434,7 @@ def _apply_tool_scope(
stmt = _apply_user_scope(stmt, ToolCallMetricRow.user_id, exclude_user_ids=exclude_user_ids, include_admins=include_admins) stmt = _apply_user_scope(stmt, ToolCallMetricRow.user_id, exclude_user_ids=exclude_user_ids, include_admins=include_admins)
if not include_scheduled: if not include_scheduled:
stmt = stmt.where(or_(ToolCallMetricRow.run_id.is_(None), ToolCallMetricRow.run_id.not_in(_scheduled_run_ids_stmt()))) stmt = stmt.where(or_(ToolCallMetricRow.run_id.is_(None), ToolCallMetricRow.run_id.not_in(_scheduled_run_ids_stmt())))
stmt = stmt.outerjoin(RunRow, RunRow.run_id == ToolCallMetricRow.run_id).where(_non_scheduled_tool_filter())
return stmt return stmt
@@ -910,6 +928,7 @@ async def _query_overview(
if not include_scheduled: if not include_scheduled:
run_where.append(or_(RunRow.run_id.is_(None), RunRow.run_id.not_in(_scheduled_run_ids_stmt()))) run_where.append(or_(RunRow.run_id.is_(None), RunRow.run_id.not_in(_scheduled_run_ids_stmt())))
tool_where.append(or_(ToolCallMetricRow.run_id.is_(None), ToolCallMetricRow.run_id.not_in(_scheduled_run_ids_stmt()))) tool_where.append(or_(ToolCallMetricRow.run_id.is_(None), ToolCallMetricRow.run_id.not_in(_scheduled_run_ids_stmt())))
tool_where.append(_non_scheduled_tool_filter())
total_users_stmt = select(func.count(UserRow.id)) total_users_stmt = select(func.count(UserRow.id))
total_users_stmt = _apply_user_scope(total_users_stmt, UserRow.id, exclude_user_ids=exclude_user_ids, include_admins=include_admins) total_users_stmt = _apply_user_scope(total_users_stmt, UserRow.id, exclude_user_ids=exclude_user_ids, include_admins=include_admins)
@@ -928,7 +947,9 @@ async def _query_overview(
select( select(
func.count(ToolCallMetricRow.id), func.count(ToolCallMetricRow.id),
func.sum(case((func.nullif(ToolCallMetricRow.skill_name, "").is_not(None), 1), else_=0)), func.sum(case((func.nullif(ToolCallMetricRow.skill_name, "").is_not(None), 1), else_=0)),
).where(*tool_where) )
.outerjoin(RunRow, RunRow.run_id == ToolCallMetricRow.run_id)
.where(*tool_where)
)).one() )).one()
return AdminLeaderboardOverview( return AdminLeaderboardOverview(
+20 -16
View File
@@ -147,18 +147,7 @@ title:
# - keep:压缩后保留多少最近的上下文(同样支持 tokens / messages / fraction)。 # - keep:压缩后保留多少最近的上下文(同样支持 tokens / messages / fraction)。
# - trim_tokens_to_summarize:喂给摘要模型的消息最多裁到多少 token。 # - trim_tokens_to_summarize:喂给摘要模型的消息最多裁到多少 token。
# - model_name:生成摘要用的模型(留空则用主对话模型)。 # - model_name:生成摘要用的模型(留空则用主对话模型)。
summarization:
enabled: true
# model_name: deepseek-chat
trigger:
- type: tokens
value: 60000
- type: messages
value: 80
keep:
type: messages
value: 20
trim_tokens_to_summarize: 4000
skills: skills:
path: /app/skills path: /app/skills
security_scan: security_scan:
@@ -187,10 +176,7 @@ auth_login:
ca_cert_path: "" # 可选:PEM 格式 CA 包路径,设置后优先生效并启用校验 ca_cert_path: "" # 可选:PEM 格式 CA 包路径,设置后优先生效并启用校验
# 日志系统入口(仅管理员可见):右下角「设置」菜单中会多出一个「日志系统」入口, # 日志系统入口(仅管理员可见):右下角「设置」菜单中会多出一个「日志系统」入口,
# 点击后在新标签页打开下面的 url。enabled 关掉则不显示该入口。 # 点击后在新标签页打开下面的 url。enabled 关掉则不显示该入口。
log_system:
enabled: true
url: "https://your-log-system.example.com"
label: "日志系统"
database: database:
backend: mysql backend: mysql
mysql_url: $MYSQL_DATABASE_URL mysql_url: $MYSQL_DATABASE_URL
@@ -270,3 +256,21 @@ memory:
block_invisible_unicode: true block_invisible_unicode: true
# streaming_scrubber:预留字段,代码尚未实现 —— 待版本支持后取消注释。 # streaming_scrubber:预留字段,代码尚未实现 —— 待版本支持后取消注释。
# streaming_scrubber: true # SSE 流前清洗 <memory-context> # streaming_scrubber: true # SSE 流前清洗 <memory-context>
log_system:
enabled: true
url: "https://your-log-system.example.com"
label: "日志系统"
summarization:
enabled: true
# model_name: deepseek-chat
trigger:
- type: tokens
value: 60000
- type: messages
value: 80
keep:
type: messages
value: 20
trim_tokens_to_summarize: 4000