fix: resolve 6 remaining defects (P2-18, P2-21, P3-04, P3-05, P3-06, P3-02)
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

- P2-18: TOTP QR code local generation via qrcode lib (no external service)
- P2-21: Suspend foreign LLM providers (OpenAI/Anthropic/Gemini) for early stage
- P3-04: get_progress() now calculates actual percentage from completed/total steps
- P3-05: saveSaaSSession calls now have .catch() error logging
- P3-06: SaaS relay chatStream passes session_key/agent_id to backend
- P3-02: Whiteboard unification plan document created

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
iven
2026-04-06 09:52:28 +08:00
parent d3da7d4dbb
commit 828be3cc9e
13 changed files with 414 additions and 58 deletions

View File

@@ -458,6 +458,8 @@ impl KernelConfig {
LlmConfig::openai(api_key).with_model(model)
}
}
// P2-21: Gemini 暂停支持 — 前期不使用非国内大模型
// 保留代码,但前端已标记为暂停,不再可选
"gemini" => LlmConfig::new(
base_url.unwrap_or("https://generativelanguage.googleapis.com/v1beta"),
api_key,

View File

@@ -86,6 +86,7 @@ impl PipelineExecutor {
let run_id = run_id.to_string();
// Create run record
let total_steps = pipeline.spec.steps.len();
let run = PipelineRun {
id: run_id.clone(),
pipeline_id: pipeline_id.clone(),
@@ -95,6 +96,7 @@ impl PipelineExecutor {
step_results: HashMap::new(),
outputs: None,
error: None,
total_steps,
started_at: Utc::now(),
ended_at: None,
};
@@ -466,12 +468,26 @@ impl PipelineExecutor {
pub async fn get_progress(&self, run_id: &str) -> Option<PipelineProgress> {
let run = self.runs.read().await.get(run_id)?.clone();
let (current_step, percentage) = if run.step_results.is_empty() {
("starting".to_string(), 0)
} else if let Some(step) = &run.current_step {
(step.clone(), 50)
} else {
let (current_step, percentage) = if run.total_steps == 0 {
// Empty pipeline or unknown total
match run.status {
RunStatus::Completed => ("completed".to_string(), 100),
_ => ("starting".to_string(), 0),
}
} else if run.status == RunStatus::Completed {
("completed".to_string(), 100)
} else if let Some(step) = &run.current_step {
// P3-04: Calculate actual percentage from completed steps
let completed = run.step_results.len();
let pct = ((completed as f64 / run.total_steps as f64) * 100.0).min(99.0) as u8;
(step.clone(), pct)
} else if run.step_results.is_empty() {
("starting".to_string(), 0)
} else {
// Not running, not completed (failed/cancelled)
let completed = run.step_results.len();
let pct = ((completed as f64 / run.total_steps as f64) * 100.0) as u8;
("stopped".to_string(), pct)
};
Some(PipelineProgress {

View File

@@ -465,6 +465,10 @@ pub struct PipelineRun {
/// Error message (if failed)
pub error: Option<String>,
/// Total number of steps (P3-04: for granular progress)
#[serde(default)]
pub total_steps: usize,
/// Start time
pub started_at: chrono::DateTime<chrono::Utc>,

View File

@@ -200,9 +200,16 @@ pub async fn chat_completions(
state.cache.relay_enqueue(&ctx.account_id);
// 异步派发操作日志(非阻塞,不占用关键路径 DB 连接)
// P3-06: Include session_key/agent_id in log for traceability
let log_meta = serde_json::json!({
"model": model_name,
"stream": stream,
"session_key": req.get("session_key").and_then(|v| v.as_str()),
"agent_id": req.get("agent_id").and_then(|v| v.as_str()),
});
state.dispatch_log_operation(
&ctx.account_id, "relay.request", "relay_task", &task.id,
Some(serde_json::json!({"model": model_name, "stream": stream})), ctx.client_ip.as_deref(),
Some(log_meta), ctx.client_ip.as_deref(),
).await;
// 执行中转:根据解析结果选择执行路径

View File

@@ -13,6 +13,12 @@ pub struct RelayChatRequest {
pub max_tokens: Option<u32>,
#[serde(default)]
pub stream: bool,
/// P3-06: Client session key for continuity
#[serde(default, rename = "session_key")]
pub session_key: Option<String>,
/// P3-06: Agent ID for context routing
#[serde(default, rename = "agent_id")]
pub agent_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]