AgentEvalTool/frontend/web/src/api.ts
sinohqb 00ad929d68
All checks were successful
CI / test (push) Successful in 3m58s
feat(intelligent-eval): v4.2 UI — stat bar + single-line table + unified detail drawer
评估列表页(v4.2):
- 顶部状态统计条(stat-chip 点击筛选,后端列表接口新增 stats 状态分布 +
  status 筛选参数)
- 单行表格(名称/评测对象 ellipsis 省略)+ 会话进度迷你进度条 +
  最后一列醒目查看按钮 + 整行可点击
- 详情/报告合一单层抽屉(1000px,Tabs:概览/决策过程/配置历史/报告),
  审批/取消在抽屉头部;移除独立详情页 /intelligent-evals/detail 与
  intelligentEvalNav store

任务队列页:
- 与列表页统一 stat-chip 统计条 + 单行表格(评估状态小标、失败原因 tooltip)

清理:删除 IntelligentEvalDetail.tsx / intelligentEvalNav.ts;App.tsx 移除
detail 路由。任务队列保持独立菜单页。tsc 0 错误 vitest 19 passed 895 passed
2026-08-17 20:03:55 +08:00

942 lines
27 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import axios from 'axios'
import { message } from 'antd'
const AUTH_TOKEN_KEY = 'agenteval_auth_token'
export const authToken = {
get: () => sessionStorage.getItem(AUTH_TOKEN_KEY),
set: (token: string) => sessionStorage.setItem(AUTH_TOKEN_KEY, token),
clear: () => sessionStorage.removeItem(AUTH_TOKEN_KEY),
}
/** Registered by App to switch back to the login screen on 401. */
let onUnauthorized: (() => void) | null = null
export const setOnUnauthorized = (handler: (() => void) | null) => { onUnauthorized = handler }
const api = axios.create({
baseURL: '/api',
timeout: 30000,
})
api.interceptors.request.use((config) => {
const token = authToken.get()
if (token) config.headers['X-Auth-Token'] = token
return config
})
api.interceptors.response.use(
(response) => response,
(error) => {
const isLoginCall = error.config?.url?.includes('/auth/login')
if (error.response?.status === 401 && !isLoginCall && onUnauthorized) {
authToken.clear()
onUnauthorized()
return Promise.reject(error)
}
const msg = error.response?.data?.detail || error.message || '请求失败'
message.error(msg)
return Promise.reject(error)
},
)
export default api
export interface AuthStatus {
auth_required: boolean
authenticated: boolean
}
export const authApi = {
status: () => api.get<AuthStatus>('/auth/status'),
login: (password: string) => api.post<{ token: string }>('/auth/login', { password }),
}
export interface Target {
id: string
name: string
description: string
platform: string
channel_type: string
channel_config: Record<string, unknown>
status: string
created_at: string
updated_at: string
}
export interface Scenario {
id: string
name: string
description: string
tags: string[]
cases: any[]
model_bindings: Record<string, string>
version: number
created_at: string
updated_at: string
}
export type ModelCapability = 'chat' | 'embedding' | 'moderation'
export type ModelProtocol = 'openai_compatible' | 'anthropic' | 'google_gemini' | 'dashscope'
export type ModelModality = 'text' | 'image' | 'audio' | 'video'
export interface ModelConfig {
id: string
name: string
provider: ModelProtocol
capability: ModelCapability
endpoint_url: string
model_name: string | null
vendor_name: string
input_modalities: ModelModality[]
output_modalities: ModelModality[]
context_window: number | null
max_output_tokens: number | null
supports_streaming: boolean
supports_tool_calling: boolean
supports_structured_output: boolean
supports_reasoning: boolean
region: string
documentation_url: string | null
has_api_key: boolean
enabled: boolean
is_default: boolean
is_analysis_default: boolean
description: string
created_at: string | null
updated_at: string | null
}
export interface ModelConfigPayload {
name: string
provider: ModelProtocol
capability: ModelCapability
endpoint_url: string
model_name?: string | null
vendor_name: string
input_modalities: ModelModality[]
output_modalities: ModelModality[]
context_window?: number | null
max_output_tokens?: number | null
supports_streaming: boolean
supports_tool_calling: boolean
supports_structured_output: boolean
supports_reasoning: boolean
region: string
documentation_url?: string | null
api_key?: string | null
clear_api_key?: boolean
enabled: boolean
is_default: boolean
is_analysis_default?: boolean
description: string
}
export interface ModelConfigReference {
scenario_id: string
scenario_name: string
purpose: string
}
export type RunTrigger = 'manual' | 'ai_assistant' | 'cli' | 'campaign'
export interface RunError {
code: string
message: string
}
export interface RunSummary {
total_cases: number
passed_cases: number
failed_cases: number
total_rules: number
passed_rules: number
pass_rate: number | null
avg_latency_ms: number | null
case_outcomes: Record<string, { passed: boolean; connectivity: boolean }>
case_errors: Array<Record<string, string>>
error: RunError | null
}
export interface Run {
id: string
target_id: string
scenario_id: string
scenario_version?: number
campaign_id?: string | null
status: string
triggered_by?: RunTrigger
scenario_name?: string | null
target_name?: string | null
started_at: string
completed_at: string | null
summary: RunSummary | null
}
export interface ScenarioStat {
scenario_id: string
scenario_name: string
run_count: number
avg_pass_rate: number | null
last_run_at: string | null
}
export interface DashboardStats {
targets_count: number
scenarios_count: number
runs_count: number
model_configs_count: number
today_runs: number
running_count: number
overall_pass_rate: number | null
trigger_breakdown: Partial<Record<RunTrigger, number>>
scenario_stats: ScenarioStat[]
recent_runs: Run[]
}
export interface TrendPoint {
date: string
pass_rate: number
run_count: number
}
export const targetsApi = {
list: () => api.get<Target[]>('/targets'),
get: (id: string) => api.get<Target>(`/targets/${id}`),
create: (data: Partial<Target>) => api.post<Target>('/targets', data),
update: (id: string, data: Partial<Target>) => api.put<Target>(`/targets/${id}`, data),
delete: (id: string) => api.delete(`/targets/${id}`),
test: (id: string) => api.post<{ ok: boolean; message: string }>(`/targets/${id}/test`),
runs: (id: string) => api.get<Run[]>(`/targets/${id}/runs`),
}
export const scenariosApi = {
list: () => api.get<Scenario[]>('/scenarios'),
get: (id: string) => api.get<Scenario>(`/scenarios/${id}`),
create: (data: Partial<Scenario>) => api.post<Scenario>('/scenarios', data),
update: (id: string, data: Partial<Scenario>) => api.put<Scenario>(`/scenarios/${id}`, data),
delete: (id: string) => api.delete(`/scenarios/${id}`),
validate: (data: any) => api.post<{ valid: boolean; errors: string[] }>('/scenarios/validate', data),
listTemplates: () => api.get<any[]>('/scenarios/templates'),
getTemplate: (id: string) => api.get<any>(`/scenarios/templates/${id}`),
}
export const modelConfigsApi = {
list: (params?: { capability?: ModelCapability; enabled?: boolean }) =>
api.get<ModelConfig[]>('/model-configs', { params }),
get: (id: string) => api.get<ModelConfig>(`/model-configs/${id}`),
create: (data: ModelConfigPayload) => api.post<ModelConfig>('/model-configs', data),
update: (id: string, data: ModelConfigPayload) => api.put<ModelConfig>(`/model-configs/${id}`, data),
delete: (id: string) => api.delete(`/model-configs/${id}`),
test: (id: string) => api.post<{ ok: boolean; message: string; tested_at: string }>(`/model-configs/${id}/test`),
references: (id: string) => api.get<ModelConfigReference[]>(`/model-configs/${id}/references`),
}
export const runsApi = {
list: () => api.get<Run[]>('/runs'),
start: (target_id: string, scenario_id: string) =>
api.post<Run>('/runs', { target_id, scenario_id }),
get: (id: string) => api.get<Run>(`/runs/${id}`),
logs: (id: string) => api.get<RunLogsResponse>(`/runs/${id}/logs`),
cancel: (id: string) => api.post(`/runs/${id}/cancel`),
}
export interface RunLogsTurn {
id: string
case_id: string
round_index: number
latency_ms: number | null
sent_text: string
reply_text: string
sent_at: string | null
received_at: string | null
}
export interface RunLogsResult {
case_id: string
rule_type: string
passed: boolean
score: number | null
reason: string | null
}
export interface CaseSnapshotExpectations {
intent?: string | null
keywords_include: string[]
keywords_exclude: string[]
response_time_max_ms?: number | null
coherence_min_score?: number | null
}
export interface CaseSnapshot {
id: string
type: string
messages: string[]
prompt?: string | null
turns?: number | null
expectations: CaseSnapshotExpectations
eval_rules: { type: string; params: Record<string, unknown> }[]
}
export interface RunLogsResponse {
turns: RunLogsTurn[]
results: RunLogsResult[]
case_verdicts: Record<string, { passed: boolean; connectivity: boolean }>
scenario_snapshot: Record<string, CaseSnapshot>
}
export const reportsApi = {
get: (runId: string) => api.get(`/reports/${runId}`),
download: async (runId: string, format: 'html' | 'json' | 'markdown') => {
const ext = format === 'markdown' ? 'md' : format
const res = await api.get(`/reports/${runId}/${format}`, { responseType: 'blob' })
const url = URL.createObjectURL(res.data as Blob)
const a = document.createElement('a')
a.href = url
a.download = `report-${runId.slice(0, 8)}.${ext}`
a.click()
URL.revokeObjectURL(url)
},
compare: (run1: string, run2: string) =>
api.get(`/reports/compare`, { params: { run1, run2 } }),
}
export const statsApi = {
dashboard: () => api.get<DashboardStats>('/stats/dashboard'),
trend: (days?: number) => api.get<TrendPoint[]>('/stats/trend', { params: { days } }),
}
// ── Campaigns评估活动 ──────────────────────────────────────────
export interface CampaignPlanEntry {
scenario_id: string
offset_seconds: number
count: number
}
export interface ExplorationSeeds {
personas: string[]
goals: string[]
}
export interface ExplorationBudgetConfig {
max_sessions?: number | null
max_turns?: number | null
min_interval_seconds?: number | null
}
export interface ExplorationIssueCount {
issue: string
count: number
}
export interface ExplorationJudgeReview {
reviewed_sessions: number
findings: { dimension: string; rating: string; comment: string }[]
summaries: string[]
}
export interface ExplorationSummary {
session_count: number
sessions_with_experience: number
goal_achieved_count: number
goal_achievement_rate: number | null
issues: ExplorationIssueCount[]
misled: ExplorationIssueCount[]
judge_review: ExplorationJudgeReview | null
}
export interface ExplorationExperience {
goal_achieved: boolean
blockers: string[]
misled: string[]
emotion: string
notes: string
}
export interface ExplorationSession {
id: string
campaign_id: string
target_id: string
persona: Record<string, unknown>
goal: string
seed_ref: Record<string, unknown> | null
status: string
triggered_by: string
experience: ExplorationExperience | null
judge_review: Record<string, unknown> | null
turn_count: number
error: string | null
created_at: string | null
closed_at: string | null
}
export interface ExplorationMessage {
id: string
session_id: string
round_index: number
role: string
content: string
latency_ms: number | null
created_at: string | null
}
export const explorationApi = {
listSessions: (campaignId: string) =>
api.get<{ sessions: ExplorationSession[] }>(`/exploration/campaigns/${campaignId}/sessions`),
listMessages: (sessionId: string) =>
api.get<{ messages: ExplorationMessage[] }>(`/exploration/sessions/${sessionId}/messages`),
}
export interface CampaignProgress {
current_offset_seconds: number
spawned_runs: number
completed_runs: number
}
export interface CampaignListProgress {
completed_runs: number
planned_total: number
overall_pass_rate: number | null
}
export interface Campaign {
id: string
name: string
target_id: string
window_seconds: number
time_scale: number
plan: CampaignPlanEntry[]
status: string
started_at: string | null
completed_at: string | null
summary: Record<string, unknown> | null
analysis_model_config_id: string | null
exploration_seeds: ExplorationSeeds | null
exploration_budget: ExplorationBudgetConfig | null
progress?: CampaignProgress
}
export interface CampaignListItem extends Omit<Campaign, 'progress'> {
progress: CampaignListProgress
}
export interface CampaignTrendBucket {
bucket_index: number
start_seconds: number
end_seconds: number
run_count: number
pass_rate: number | null
availability: number | null
avg_latency_ms: number | null
}
export interface CampaignCapability {
scenario_id: string
scenario_name: string
run_count: number
pass_rate: number | null
availability: number | null
avg_latency_ms: number | null
}
export interface CampaignReport {
campaign_id: string
name: string
target_id: string
status: string
window_seconds: number
time_scale: number
started_at: string | null
completed_at: string | null
summary: {
total_runs: number
completed_runs: number
overall_pass_rate: number | null
overall_availability: number | null
avg_latency_ms: number | null
}
time_trend: CampaignTrendBucket[]
capability_summary: CampaignCapability[]
exploration?: ExplorationSummary | null
}
export interface CampaignTimelineEntry {
run_id: string
scenario_id: string
scenario_name: string
offset_seconds: number
status: string
pass_rate: number | null
avg_latency_ms: number | null
started_at: string | null
}
export type CampaignAnalysisStatus = 'none' | 'queued' | 'generating' | 'completed' | 'failed'
export interface CampaignAnalysisProblem {
severity: string
title: string
description: string
scenario_ids: string[]
evidence_run_ids: string[]
}
export interface CampaignAnalysisResult {
overall: string
problems: CampaignAnalysisProblem[]
scenario_narratives: { scenario_id: string; narrative: string }[]
suggestions: { priority: number; text: string }[]
}
export interface CampaignAnalysis {
status: CampaignAnalysisStatus
result?: CampaignAnalysisResult | null
error?: string | null
model_config_id?: string | null
triggered_by?: string
updated_at?: string | null
}
export interface CreateCampaignPayload {
name: string
target_id: string
window_seconds: number
time_scale: number
plan: CampaignPlanEntry[]
analysis_model_config_id?: string | null
exploration_seeds?: ExplorationSeeds | null
exploration_budget?: ExplorationBudgetConfig | null
}
// ── Period comparison (v0.8) ────────────────────────────────────
export type ComparisonTrend = 'improving' | 'stable' | 'regressing'
export interface MetricDeltaPair {
baseline: number | null
current: number | null
delta: number | null
}
export interface MetricDiffScenario {
scenario_id: string
scenario_name: string
pass_rate: MetricDeltaPair
availability: MetricDeltaPair
avg_latency_ms: MetricDeltaPair
}
export interface MetricDiff {
overall: {
pass_rate: MetricDeltaPair
availability: MetricDeltaPair
avg_latency_ms: MetricDeltaPair
}
scenarios: MetricDiffScenario[]
}
export interface ComparisonBaselineInfo {
id: string
name: string
completed_at: string | null
}
export interface ComparisonProblemEvolution {
status: string
title: string
detail: string
scenario_ids: string[]
}
export interface ComparisonSuggestionTracking {
text: string
status: string
note: string
}
export interface ComparisonResult {
trend: ComparisonTrend
summary: string
problem_evolution: ComparisonProblemEvolution[]
suggestion_tracking: ComparisonSuggestionTracking[]
}
export interface CampaignComparison {
status: CampaignAnalysisStatus
auto_baseline: ComparisonBaselineInfo | null
metric_diff: MetricDiff | null
comparison: {
baseline_campaign_id: string
baseline: ComparisonBaselineInfo | null
result: ComparisonResult | null
error: string | null
model_config_id: string | null
triggered_by: string
updated_at: string | null
} | null
}
export const campaignsApi = {
list: () => api.get<CampaignListItem[]>('/campaigns'),
get: (id: string) => api.get<Campaign>(`/campaigns/${id}`),
create: (data: CreateCampaignPayload) => api.post<Campaign>('/campaigns', data),
cancel: (id: string) => api.post<Campaign>(`/campaigns/${id}/cancel`),
report: (id: string) => api.get<CampaignReport>(`/campaigns/${id}/report`),
timeline: (id: string) =>
api.get<{ entries: CampaignTimelineEntry[] }>(`/campaigns/${id}/timeline`),
getAnalysis: (id: string) => api.get<CampaignAnalysis>(`/campaigns/${id}/analysis`),
generateAnalysis: (id: string) => api.post<{ status: string }>(`/campaigns/${id}/analysis`),
getComparison: (id: string) => api.get<CampaignComparison>(`/campaigns/${id}/comparison`),
generateComparison: (id: string, baselineCampaignId?: string) =>
api.post<{ status: string }>(
`/campaigns/${id}/comparison`,
baselineCampaignId ? { baseline_campaign_id: baselineCampaignId } : {},
),
downloadReport: async (id: string) => {
const res = await api.get(`/campaigns/${id}/report/markdown`, { responseType: 'blob' })
const url = URL.createObjectURL(res.data as Blob)
const a = document.createElement('a')
a.href = url
a.download = `campaign-report-${id.slice(0, 8)}.md`
a.click()
URL.revokeObjectURL(url)
},
}
// ── Intelligent Evaluation智能评估 v1.0 ────────────────────────
export type IntelligentEvalStatus =
| 'draft' | 'planning' | 'pending_approval'
| 'executing' | 'completed' | 'cancelled' | 'failed'
export type IntelligentEvalSessionStatus = 'running' | 'completed' | 'failed' | 'expired'
export interface IntelligentEvalMessage {
id: string
session_id: string
role: string
content: string
latency_ms: number | null
created_at: string | null
}
export interface IntelligentEvalSession {
id: string
eval_id: string
target_id: string
persona: Record<string, unknown>
goal: string
dimension: string | null
status: IntelligentEvalSessionStatus
verdict: Record<string, unknown> | null
turn_count: number
created_at: string | null
closed_at: string | null
}
export interface IntelligentEvalVirtualUser {
persona: Record<string, unknown>
goal: string
}
export interface IntelligentEvalTimeSlot {
time_slot: string
sessions: number
scenario: string
}
export interface IntelligentEvalPlan {
dimensions: string[]
virtual_users: IntelligentEvalVirtualUser[]
time_distribution: IntelligentEvalTimeSlot[]
estimated_sessions: number
budget: { max_turns_per_session: number; total_max_turns: number }
completion_criteria: string
}
export interface ReportEvidence {
session_id?: string
turn_index?: number | null
user_said?: string
assistant_replied?: string
}
export interface ReportFinding {
issue: string
severity: string
dimension: string
evidence: ReportEvidence[]
suggestion?: string | null
related_sop?: string | null
}
export interface ReportHighlight {
description: string
dimension?: string | null
}
export interface IntelligentEvalReport {
summary: string
scores: Record<string, number> | null
findings: ReportFinding[]
highlights: ReportHighlight[]
priority_recommendations: string[]
}
export interface IntelligentEval {
id: string
name: string
target_id: string
status: IntelligentEvalStatus
goal: string
seeds: Record<string, unknown>
intent: string
role_description: string
plan: IntelligentEvalPlan | null
plan_feedback: string | null
time_window_hours: number
report: IntelligentEvalReport | null
created_at: string | null
updated_at: string | null
started_at: string | null
completed_at: string | null
session_count: number
completed_sessions: number
sessions?: IntelligentEvalSession[]
}
export interface CreateIntelligentEvalPayload {
name: string
target_id: string
goal: string
seeds: Record<string, unknown>
intent: string
role_description: string
time_window_hours: number
}
export interface ConfigSnapshot {
id: string
eval_id: string
snapshot_type: 'created' | 'plan_submitted' | 'config_updated'
goal: string
seeds: Record<string, unknown>
intent: string
role_description: string
time_window_hours: number
plan: IntelligentEvalPlan | null
created_at: string | null
created_by: string
}
export interface ConfigSnapshotComparison {
snapshot_1: {
id: string
snapshot_type: string
created_at: string | null
}
snapshot_2: {
id: string
snapshot_type: string
created_at: string | null
}
differences: Record<string, { old: unknown; new: unknown }>
}
export interface DecisionLog {
id: string
eval_id: string
decision_type: 'execute_session' | 'wait' | 'start_analysis'
reason: string
context: Record<string, unknown>
cron_id: string
created_at: string | null
}
export type TaskQueueStatus = 'pending' | 'assigned' | 'completed' | 'failed'
export interface TaskQueueStats {
pending: number
assigned: number
completed: number
failed: number
unresolved: number
}
export interface TaskQueueItem {
id: string
eval_id: string
eval_name: string | null
eval_status: string | null
status: TaskQueueStatus
priority: number
reason: string
assigned_cron_id: string | null
assigned_at: string | null
completed_at: string | null
created_at: string | null
updated_at: string | null
error: string | null
}
export interface TaskQueueList {
tasks: TaskQueueItem[]
stats: TaskQueueStats
}
export const intelligentEvalsApi = {
list: (params?: { page?: number; page_size?: number; status?: string }) =>
api.get<{
intelligent_evals: IntelligentEval[]
total?: number
stats?: Record<string, number>
page?: number
page_size?: number
}>(
'/intelligent-evals',
{ params },
),
listTasks: (params?: { status?: TaskQueueStatus; limit?: number }) =>
api.get<TaskQueueList>('/intelligent-evals/tasks', { params }),
get: (id: string) => api.get<IntelligentEval>(`/intelligent-evals/${id}`),
create: (data: CreateIntelligentEvalPayload) => api.post<IntelligentEval>('/intelligent-evals', data),
submitPlan: (id: string, plan: Record<string, unknown>) =>
api.put<IntelligentEval>(`/intelligent-evals/${id}/plan`, { plan }),
approve: (id: string) => api.post<IntelligentEval>(`/intelligent-evals/${id}/approve`),
reject: (id: string, feedback: string) =>
api.post<IntelligentEval>(`/intelligent-evals/${id}/reject`, { feedback }),
cancel: (id: string) => api.post<IntelligentEval>(`/intelligent-evals/${id}/cancel`),
listSessions: (id: string) =>
api.get<{ sessions: IntelligentEvalSession[] }>(`/intelligent-evals/${id}/sessions`),
listMessages: (id: string, sessionId: string) =>
api.get<{ messages: IntelligentEvalMessage[] }>(`/intelligent-evals/${id}/sessions/${sessionId}/messages`),
getReport: (id: string) => api.get<IntelligentEvalReport>(`/intelligent-evals/${id}/report`),
downloadReportMarkdown: async (id: string) => {
const res = await api.get(`/intelligent-evals/${id}/report/markdown`, { responseType: 'blob' })
const url = URL.createObjectURL(res.data as Blob)
const a = document.createElement('a')
a.href = url
a.download = `intelligent-eval-report-${id.slice(0, 8)}.md`
a.click()
URL.revokeObjectURL(url)
},
// Config Snapshots
listConfigSnapshots: (id: string) =>
api.get<{ snapshots: ConfigSnapshot[] }>(`/intelligent-evals/${id}/config-snapshots`),
getConfigSnapshot: (id: string, snapshotId: string) =>
api.get<ConfigSnapshot>(`/intelligent-evals/${id}/config-snapshots/${snapshotId}`),
compareConfigSnapshots: (id: string, snapshotId1: string, snapshotId2: string) =>
api.post<ConfigSnapshotComparison>(`/intelligent-evals/${id}/config-snapshots/compare`, {
snapshot_id_1: snapshotId1,
snapshot_id_2: snapshotId2,
}),
// Decision Logs
listDecisionLogs: (id: string) =>
api.get<{ logs: DecisionLog[] }>(`/intelligent-evals/${id}/decision-logs`),
}
// ── OpenClaw Cron Pool ──────────────────────────────────────────────
export interface CronPoolStatus {
total: number
idle: number
busy: number
stuck: number
min_size: number
max_size: number
}
export interface CronPoolMetrics {
pool_utilization: number
task_backlog: number
stuck_rate: number
avg_processing_time_seconds: number | null
eval_completion_rate: number
timestamp: string
}
export interface CronPoolAlert {
id: string
alert_type: string
severity: string
message: string
metric_value: number
threshold: number
created_at: string
resolved_at: string | null
webhook_sent: boolean
}
export const openclawCronPoolApi = {
getStatus: () => api.get<{ pool: CronPoolStatus }>('/openclaw/cron-pool'),
scale: (targetSize: number) =>
api.post<{ success: boolean; scaled_up?: number; scaled_down?: number; current_size: number }>(
'/openclaw/cron-pool/scale',
{ target_size: targetSize },
),
sync: () => api.post<{ success: boolean; synced: number }>('/openclaw/cron-pool/sync'),
autoScale: () =>
api.post<{ success: boolean; scaled_up: number; scaled_down: number }>('/openclaw/cron-pool/auto-scale'),
getMetrics: () => api.get<{ metrics: CronPoolMetrics }>('/openclaw/cron-pool/metrics'),
checkAlerts: () =>
api.post<{ success: boolean; alerts_triggered: number; alerts: CronPoolAlert[] }>('/openclaw/cron-pool/check-alerts'),
getAlerts: (limit = 100, unresolvedOnly = false) =>
api.get<{ alerts: CronPoolAlert[] }>('/openclaw/cron-pool/alerts', {
params: { limit, unresolved_only: unresolvedOnly },
}),
resolveAlert: (alertId: string) =>
api.post<{ success: boolean }>(`/openclaw/cron-pool/alerts/${alertId}/resolve`),
}
// ── File Management ──────────────────────────────────────────────
export interface FileCategory {
id: string
name: string
parent_id: string | null
children: FileCategory[]
}
export interface FileRecord {
id: string
original_name: string
file_size: number
mime_type: string
file_ext: string
category_id: string | null
storage_directory: string
created_at: string | null
}
export interface FileUploadConfig {
allowed_extensions: string[]
max_upload_size_mb: number
}
export const filesApi = {
// Categories
getConfig: () => api.get<FileUploadConfig>('/files/config'),
listCategories: () => api.get<FileCategory[]>('/files/categories'),
createCategory: (data: { name: string; parent_id?: string | null }) =>
api.post<FileCategory>('/files/categories', data),
updateCategory: (id: string, data: { name: string }) =>
api.put(`/files/categories/${id}`, data),
deleteCategory: (id: string) => api.delete(`/files/categories/${id}`),
// Files
list: (categoryId?: string | null) =>
api.get<FileRecord[]>('/files', { params: categoryId ? { category_id: categoryId } : {} }),
upload: (file: File, categoryId?: string | null) => {
const form = new FormData()
form.append('file', file)
if (categoryId) {
form.append('category_id', categoryId)
}
return api.post<FileRecord>('/files/upload', form, {
timeout: 120000,
})
},
download: (id: string) => api.get<Blob>(`/files/${id}/download`, { responseType: 'blob' }),
delete: (id: string) => api.delete(`/files/${id}`),
}