feat: 工具/技能调用统计 + 用户活动审计 + 标签多选筛选
- 任务1: 用户管理/定时任务管理移入左下角菜单, 从侧边栏删除原入口
- 任务2: 管理员查看用户问答(读 LangGraph checkpoint)与记忆, 新增 admin_users 路由与审计页
- 任务3: 标签筛选改为顶部多选标签栏(OR), agents/skills/scheduled_tasks 三端
- 任务4: 新增 tool_call_metrics 表 + ToolMetricsMiddleware + tool-metrics 路由,
工具/技能调用统计并入大模型统计页, 含错误分类
- 技能识别: lead agent 经 read_file 加载 /mnt/skills/<cat>/<name>/SKILL.md 调用技能,
中间件扫描工具参数里的 skills/{public,custom}/{name}/ 路径还原 skill_name
- 单元测试 tests/test_tool_metrics_middleware.py (18 项全过)
- 附: SQLite->MySQL 切换后清理脚本
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
e3cde9be25
commit
4940e0d8ed
46 files changed
+3299
-315
No files matched your search
@@ -0,0 +1,72 @@
|
||||
import { apiFetch } from "@/core/api";
|
||||
import { getBackendBaseURL } from "@/core/config";
|
||||
|
||||
/** A conversation thread owned by some user (admin view). */
|
||||
export interface AdminThread {
|
||||
thread_id: string;
|
||||
display_name: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* One conversation message, as serialized from the LangGraph checkpoint —
|
||||
* a LangChain message dump: ``type`` is "human" | "ai" | "tool" | "system",
|
||||
* ``content`` is a string or a content-block list.
|
||||
*/
|
||||
export interface AdminMessage {
|
||||
type?: string;
|
||||
content?: unknown;
|
||||
id?: string | null;
|
||||
name?: string | null;
|
||||
}
|
||||
|
||||
/** One memory bucket: the global file or a per-agent file. */
|
||||
export interface AdminMemoryBucket {
|
||||
name: string;
|
||||
data: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export interface AdminMemoryResponse {
|
||||
user_id: string;
|
||||
buckets: AdminMemoryBucket[];
|
||||
}
|
||||
|
||||
const base = () => `${getBackendBaseURL()}/api/admin/users`;
|
||||
|
||||
async function parse<T>(res: Response, what: string): Promise<T> {
|
||||
if (!res.ok) {
|
||||
const err = (await res.json().catch(() => ({}))) as { detail?: string };
|
||||
throw new Error(err.detail ?? `${what} (HTTP ${res.status})`);
|
||||
}
|
||||
return res.json() as Promise<T>;
|
||||
}
|
||||
|
||||
export async function listUserThreads(userId: string): Promise<AdminThread[]> {
|
||||
return parse(
|
||||
await apiFetch(`${base()}/${encodeURIComponent(userId)}/threads?limit=200`),
|
||||
"Failed to load threads",
|
||||
);
|
||||
}
|
||||
|
||||
export async function listUserThreadMessages(
|
||||
userId: string,
|
||||
threadId: string,
|
||||
): Promise<AdminMessage[]> {
|
||||
return parse(
|
||||
await apiFetch(
|
||||
`${base()}/${encodeURIComponent(userId)}/threads/${encodeURIComponent(threadId)}/messages`,
|
||||
),
|
||||
"Failed to load messages",
|
||||
);
|
||||
}
|
||||
|
||||
export async function getUserMemory(
|
||||
userId: string,
|
||||
): Promise<AdminMemoryResponse> {
|
||||
return parse(
|
||||
await apiFetch(`${base()}/${encodeURIComponent(userId)}/memory`),
|
||||
"Failed to load memory",
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user