import api from './client' import { downloadBlob } from '../utils/download' 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 goal: string seed_ref: Record | null status: string triggered_by: string experience: ExplorationExperience | null judge_review: Record | 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 | null analysis_model_config_id: string | null exploration_seeds: ExplorationSeeds | null exploration_budget: ExplorationBudgetConfig | null progress?: CampaignProgress } export interface CampaignListItem extends Omit { 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 } 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('/campaigns'), get: (id: string) => api.get(`/campaigns/${id}`), create: (data: CreateCampaignPayload) => api.post('/campaigns', data), cancel: (id: string) => api.post(`/campaigns/${id}/cancel`), report: (id: string) => api.get(`/campaigns/${id}/report`), timeline: (id: string) => api.get<{ entries: CampaignTimelineEntry[] }>(`/campaigns/${id}/timeline`), getAnalysis: (id: string) => api.get(`/campaigns/${id}/analysis`), generateAnalysis: (id: string) => api.post<{ status: string }>(`/campaigns/${id}/analysis`), getComparison: (id: string) => api.get(`/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' }) downloadBlob(res.data as Blob, `campaign-report-${id.slice(0, 8)}.md`) }, }