Fundamental_Analysis/services/common-contracts/src/messages.rs
Lv, Qi 7933c706d1 refactor: strict typing for workflow events using WorkflowEventType enum
- refactor(frontend): replace string literals with WorkflowEventType enum for event handling
- feat(backend): export WorkflowEventType in common-contracts and openapi
- fix(tests): update end-to-end tests to match new ContextSelectorConfig and LlmConfig types
- chore: regenerate openapi.json and frontend client schemas
2025-11-30 19:28:57 +08:00

308 lines
8.6 KiB
Rust
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.

use uuid::Uuid;
use crate::symbol_utils::CanonicalSymbol;
use crate::subjects::{NatsSubject, SubjectMessage};
use std::collections::HashMap;
use service_kit::api_dto;
use crate::configs::LlmConfig;
// --- Commands ---
// Topic: workflow.commands.start
/// Command to initiate a new workflow.
/// Published by: `api-gateway`
/// Consumed by: `workflow-orchestrator`
#[api_dto]
pub struct StartWorkflowCommand {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub market: String,
pub template_id: String,
}
impl SubjectMessage for StartWorkflowCommand {
fn subject(&self) -> NatsSubject {
NatsSubject::WorkflowCommandStart
}
}
// Topic: workflow.commands.sync_state
/// Command to request a state snapshot for re-alignment.
/// Published by: `api-gateway` (on client connect/reconnect)
/// Consumed by: `workflow-orchestrator`
#[api_dto]
pub struct SyncStateCommand {
pub request_id: Uuid,
}
impl SubjectMessage for SyncStateCommand {
fn subject(&self) -> NatsSubject {
NatsSubject::WorkflowCommandSyncState
}
}
/// Command to trigger data fetching.
/// Published by: `workflow-orchestrator` (previously api-gateway)
/// Consumed by: `*-provider-services`
#[api_dto]
pub struct FetchCompanyDataCommand {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub market: String,
pub template_id: Option<String>, // Optional trigger for analysis
pub output_path: Option<String>, // New: Unified I/O Binding
}
impl SubjectMessage for FetchCompanyDataCommand {
fn subject(&self) -> NatsSubject {
NatsSubject::DataFetchCommands
}
}
/// Command to start a full report generation workflow.
/// Published by: `workflow-orchestrator` (previously api-gateway)
/// Consumed by: `report-generator-service`
#[api_dto]
pub struct GenerateReportCommand {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub template_id: String,
/// The task_id in the workflow DAG that triggered this.
/// Used for reporting progress/content back to the specific node.
pub task_id: Option<String>,
pub module_id: Option<String>,
// --- New Fields for Refactored Context Mechanism ---
pub commit_hash: Option<String>,
pub input_bindings: Option<Vec<String>>, // Resolved physical paths
pub output_path: Option<String>,
pub llm_config: Option<LlmConfig>,
pub analysis_prompt: Option<String>,
}
impl SubjectMessage for GenerateReportCommand {
fn subject(&self) -> NatsSubject {
NatsSubject::AnalysisCommandGenerateReport
}
}
// --- Events ---
/// Metadata produced by a task execution.
#[api_dto]
pub struct TaskMetadata {
/// The primary output file path (e.g. analysis report)
pub output_path: Option<String>,
/// The execution trace log path
pub execution_log_path: Option<String>,
/// Additional arbitrary metadata
pub extra: HashMap<String, serde_json::Value>,
}
/// Comprehensive snapshot state for a single task
#[api_dto]
pub struct TaskStateSnapshot {
pub task_id: String,
pub status: TaskStatus,
pub logs: Vec<String>, // Historical logs for this task
pub content: Option<String>, // Current streamed content buffer
pub input_commit: Option<String>,
pub output_commit: Option<String>,
pub metadata: Option<TaskMetadata>,
}
#[api_dto]
#[derive(Copy, PartialEq, Eq, Hash)]
pub enum WorkflowEventType {
WorkflowStarted,
TaskStateChanged,
TaskStreamUpdate,
TaskLog,
WorkflowCompleted,
WorkflowFailed,
WorkflowStateSnapshot,
}
// Topic: events.workflow.{request_id}
/// Unified event stream for frontend consumption.
#[api_dto]
#[serde(tag = "type", content = "payload")]
pub enum WorkflowEvent {
// 1. 流程初始化 (携带完整的任务依赖图)
WorkflowStarted {
timestamp: i64,
// 定义所有任务及其依赖关系,前端可据此绘制流程图或进度条
task_graph: WorkflowDag
},
// 2. 任务状态变更 (核心事件)
TaskStateChanged {
task_id: String, // e.g., "fetch:tushare", "process:clean_financials", "module:swot_analysis"
task_type: TaskType, // DataFetch | DataProcessing | Analysis
status: TaskStatus, // Pending, Scheduled, Running, Completed, Failed, Skipped
message: Option<String>,
timestamp: i64,
progress: Option<u8>, // 0-100
// New fields for Context Inspector
input_commit: Option<String>,
output_commit: Option<String>,
},
// 3. 任务流式输出 (用于 LLM 打字机效果)
TaskStreamUpdate {
task_id: String,
content_delta: String,
index: u32
},
// 3.5. 任务日志 (用于实时展示详细执行过程)
TaskLog {
task_id: String,
level: String, // INFO, WARN, ERROR
message: String,
timestamp: i64,
},
// 4. 流程整体结束
WorkflowCompleted {
result_summary: Option<serde_json::Value>,
end_timestamp: i64
},
WorkflowFailed {
reason: String,
is_fatal: bool,
end_timestamp: i64
},
// 5. 状态快照 (用于重连/丢包恢复)
// 当前端重连或显式发送 SyncStateCommand 时Orchestrator 发送此事件
WorkflowStateSnapshot {
timestamp: i64,
task_graph: WorkflowDag,
tasks_status: HashMap<String, TaskStatus>, // 当前所有任务的最新状态
tasks_output: HashMap<String, Option<String>>, // (可选) 已完成任务的关键输出摘要 (commit hash)
tasks_metadata: HashMap<String, TaskMetadata>, // (New) 任务的关键元数据
/// New: Detailed state for each task including logs and content buffer
#[serde(default)]
task_states: HashMap<String, TaskStateSnapshot>,
logs: Vec<String>, // (New) 当前Session的历史日志回放 (Global)
}
}
#[api_dto]
pub struct WorkflowDag {
pub nodes: Vec<TaskNode>,
pub edges: Vec<TaskDependency> // from -> to
}
#[api_dto]
pub struct TaskDependency {
pub from: String,
pub to: String,
}
#[api_dto]
pub struct TaskNode {
pub id: String,
pub name: String,
pub display_name: Option<String>,
pub r#type: TaskType,
pub initial_status: TaskStatus
}
#[api_dto]
#[derive(Copy, PartialEq)]
pub enum TaskType {
DataFetch, // 创造原始上下文
DataProcessing, // 消耗并转换上下文 (New)
Analysis // 读取上下文生成新内容
}
#[api_dto]
#[derive(Copy, PartialEq)]
pub enum TaskStatus {
Pending, // 等待依赖
Scheduled, // 依赖满足,已下发给 Worker
Running, // Worker 正在执行
Completed, // 执行成功
Failed, // 执行失败
Skipped // 因上游失败或策略原因被跳过
}
#[api_dto]
pub struct CompanyProfilePersistedEvent {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
}
#[api_dto]
pub struct FinancialsPersistedEvent {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub years_updated: Vec<u16>,
pub template_id: Option<String>, // Pass-through for analysis trigger
// Identity fix: Mandatory provider ID
#[serde(default)]
pub provider_id: Option<String>,
// Output pass-through: Optional data preview/summary
#[serde(default)]
pub data_summary: Option<String>,
}
impl SubjectMessage for FinancialsPersistedEvent {
fn subject(&self) -> NatsSubject {
NatsSubject::DataFinancialsPersisted
}
}
#[api_dto]
pub struct DataFetchFailedEvent {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub error: String,
// Identity fix: Mandatory provider ID
#[serde(default)]
pub provider_id: Option<String>,
}
impl SubjectMessage for DataFetchFailedEvent {
fn subject(&self) -> NatsSubject {
NatsSubject::DataFetchFailed
}
}
// Topic: events.analysis.report_generated
/// Event emitted when a report generation task (or sub-module) is completed.
/// Consumed by: `workflow-orchestrator`
#[api_dto]
pub struct ReportGeneratedEvent {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub module_id: String, // Which part of the analysis finished
pub content_snapshot: Option<String>, // Optional short preview
pub model_id: Option<String>,
}
impl SubjectMessage for ReportGeneratedEvent {
fn subject(&self) -> NatsSubject {
NatsSubject::AnalysisReportGenerated
}
}
// Topic: events.analysis.report_failed
#[api_dto]
pub struct ReportFailedEvent {
pub request_id: Uuid,
pub symbol: CanonicalSymbol,
pub module_id: String,
pub error: String,
}
impl SubjectMessage for ReportFailedEvent {
fn subject(&self) -> NatsSubject {
NatsSubject::AnalysisReportFailed
}
}